1 // *********************************************************************************
    2 //   Custom DPA Handler code example - User peripheral implementation - I2C master *
    3 // *********************************************************************************
    4 // Copyright (c) MICRORISC s.r.o.
    5 //
    6 // File:    $RCSfile: CustomDpaHandler-UserPeripheral-I2Cmaster.c,v $
    7 // Version: $Revision: 1.11 $
    8 // Date:    $Date: 2021/08/18 20:43:06 $
    9 //
   10 // Revision history:
   11 //   2021/08/18  Release for DPA 4.16
   12 //   2020/01/02  Release for DPA 4.11
   13 //   2019/10/09  Release for DPA 4.10
   14 //
   15 // *********************************************************************
   16 
   17 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/
   18 
   19 // This example implements Master I2C as a user peripheral
   20 
   21 // Default IQRF include (modify the path according to your setup)
   22 #include "IQRF.h"
   23 
   24 // Default DPA header (modify the path according to your setup)
   25 #include "DPA.h"
   26 // Default Custom DPA Handler header (modify the path according to your setup)
   27 #include "DPAcustomHandler.h"
   28 
   29 /*********************************************************************
   30  I2C master is controlled by DPA Request data sent to the user peripheral PNUM=0x20, PCMD=0x00.
   31  The command allows to (optionally) write bytes to the I2C bus and then (optionally) read bytes from the bus.
   32 
   33  *** DPA Request format ***
   34   Byte index | Description
   35   ---------------------------------------------------------------------------------------------------------------------------
   36   0          | I2C 8-bit device address to write/read data to/from (bit.0 of the address is set when reading from the I2C bus).
   37   1          | Number of bytes to read from I2C after data are written to the I2C bus.
   38   2-55       | Optional bytes to write to the I2C before data are read from I2C bus.
   39 
   40   *** DPA Response format ***
   41   Byte index | Description
   42   ---------------------------------------------------------------------------------------------------------------------------
   43   0-55       | Byte read from I2C bus. If no bytes are read, no data is returned i.e. DPA Response is empty.
   44 
   45 
   46   *** Example #1 ***
   47   Configuring MCP9802 temperature sensor in the DDC-SE-01 connected to the DK-EVAL-04x for the 12-bit ADC, i.e. 0.0625 °C resolution.
   48 
   49   DPA Request:
   50   Byte index | Value [hex] | Description
   51   ---------------------------------------------------------------------------------------------------------------------------
   52   0          | 96          | MCP9802 I2C 8-bit address
   53   1          | 00          | Read no data
   54   2          | 01          | Write MCP9802 configuration register address
   55   3          | 60          | Write MCP9802 configuration register value: 12-bit ADC, i.e. 0.0625°C resolution
   56 
   57   DPA Response:
   58   Empty as no data is read.
   59 
   60 
   61   *** Example #2 ***
   62   Reading temperature from  MCP9802 temperature sensor in the DDC-SE-01 connected to the DK-EVAL-04x.
   63 
   64   DPA Request:
   65   Byte index | Value [hex] | Description
   66   ---------------------------------------------------------------------------------------------------------------------------
   67   0          | 96          | MCP9802 I2C 8-bit address
   68   1          | 02          | Read 2 bytes with the temperature value
   69   2          | 00          | Write MCP9802 ambient temperature register address
   70 
   71   DPA Response:
   72   Byte index | Value [hex] | Description
   73   ---------------------------------------------------------------------------------------------------------------------------
   74   0          | 17          | Upper half of the temperature register
   75   1          | E0          | Lower half of the temperature register (0x17E0 = 23.875 °C)
   76 
   77 *********************************************************************
   78 
   79   I2C signals to PIN assignment:
   80 
   81     TR module pin | DK-EVAL-04x pin | I2C
   82     -------------------------------------
   83     C7            | 2               | SDA
   84     C6            | 3               | SCL
   85     C4            | 7               | GND
   86 
   87   ! Do not forget to connect pull-up resistors (e.g. 10k) between SDA and SCL and Vcc = 3 Volts preferably at I2C master side!
   88 
   89 *********************************************************************/
   90 
   91 // I2C SCL frequency [Hz]
   92 #define I2Cfrequency                100000
   93 
   94 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   95 //############################################################################################
   96 bit CustomDpaHandler()
   97 //############################################################################################
   98 {
   99   // I2C master peripheral command data structure
  100   typedef struct
  101   {
  102     uns8  I2Caddress;
  103     uns8  ReadDataCount;
  104     uns8  WriteData[DPA_MAX_DATA_LENGTH - 2 * sizeof( uns8 )];
  105   } TI2Crequest;
  106 
  107   // Handler presence mark
  108   clrwdt();
  109 
  110   // Detect DPA event to handle
  111   switch ( GetDpaEvent() )
  112   {
  113     // -------------------------------------------------
  114     case DpaEvent_Interrupt:
  115       // Do an extra quick background interrupt work
  116       return Carry;
  117 
  118       // -------------------------------------------------
  119     case DpaEvent_DpaRequest:
  120       // Called to interpret DPA request for peripherals
  121       // -------------------------------------------------
  122       // Peripheral enumeration
  123       if ( IsDpaEnumPeripheralsRequest() )
  124       {
  125         // We implement 1 user peripheral
  126         _DpaMessage.EnumPeripheralsAnswer.UserPerNr |= 1;
  127         FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 );
  128         _DpaMessage.EnumPeripheralsAnswer.HWPID |= 0x123F;
  129         _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= 0xABCD;
  130 
  131 DpaHandleReturnTRUE:
  132         return TRUE;
  133       }
  134       // -------------------------------------------------
  135       // Get information about peripheral
  136       else if ( IsDpaPeripheralInfoRequest() )
  137       {
  138         if ( _PNUM == PNUM_USER + 0 )
  139         {
  140           _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA;
  141           _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE;
  142           goto DpaHandleReturnTRUE;
  143         }
  144 
  145         break;
  146       }
  147       // -------------------------------------------------
  148       else
  149       {
  150         // Handle peripheral command
  151         if ( _PNUM == PNUM_USER + 0 )
  152         {
  153           // Check DPA command value
  154           if ( _PCMD != 0 )
  155             DpaApiReturnPeripheralError( ERROR_PCMD );
  156 
  157           // Check for minimum request data length
  158           if ( _DpaDataLength < offsetof( TI2Crequest, WriteData ) )
  159             DpaApiReturnPeripheralError( ERROR_DATA_LEN );
  160 
  161           // Looping variable
  162           uns8 loop;
  163           // Count of bytes to write to I2C
  164           loop = _DpaDataLength - offsetof( TI2Crequest, WriteData );
  165           // Anything to write to I2C?
  166           if ( loop != 0 )
  167           {
  168             // Start I2C writing
  169             DpaApiI2Cstart( FSR0[offsetof( TI2Crequest, I2Caddress )] );
  170             // Pointer to the data to write
  171             FSR1 += offsetof( TI2Crequest, WriteData );
  172             // Now write byte by byte to the I2C
  173             do
  174             {
  175               DpaApiI2Cwrite( *FSR1++ );
  176             } while ( --loop != 0 );
  177             // Stop I2C
  178             DpaApiI2Cstop();
  179           }
  180 
  181           // FSR1 points to the DPA response/request data buffer
  182           FSR1 = _DpaMessage.Response.PData;
  183           // Number of bytes to read from I2C
  184           loop = _DpaDataLength = FSR1[offsetof( TI2Crequest, ReadDataCount )];
  185           // Anything to read from I2C?
  186           if ( loop == 0 )
  187           {
  188             // No, return with empty DPA response
  189             goto DpaHandleReturnTRUE;
  190           }
  191 
  192           // Start I2C reading
  193           DpaApiI2Cstart( FSR1[offsetof( TI2Crequest, I2Caddress )] | 1 );
  194           // Read byte by byte from I2C
  195           do
  196           {
  197             // Only very last read byte is not acknowledged
  198             setINDF1( DpaApiI2Cread( loop != 1 ) );
  199             FSR1++;
  200           } while ( --loop != 0 );
  201           // Stop I2C
  202           DpaApiI2Cstop();
  203 
  204           goto DpaHandleReturnTRUE;
  205         }
  206         break;
  207       }
  208 
  209       // -------------------------------------------------
  210     case DpaEvent_Init:
  211       // Do a one time initialization before main loop starts
  212       // Fall through!
  213       // -------------------------------------------------
  214     case DpaEvent_AfterSleep:
  215       // Called after woken up after sleep
  216       // Enable I2C master
  217       DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) );
  218       return Carry;
  219 
  220       // -------------------------------------------------
  221     case DpaEvent_BeforeSleep:
  222       // Called before going to sleep
  223       // Disable I2C master
  224       DpaApiI2Cshutdown();
  225       return Carry;
  226   }
  227 
  228   return FALSE;
  229 }
  230 
  231 //############################################################################################
  232 // Default Custom DPA Handler header; 2nd include to implement Code bumper to detect too long code of the Custom DPA Handler (modify the path according to your setup)
  233 #include "DPAcustomHandler.h"
  234 //############################################################################################