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