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.20 $ 8 // Date: $Date: 2023/03/16 10:27:10 $ 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 | Bytes 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.0625°C 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 if ( FSR0[offsetof( TI2Crequest, ReadDataCount )] > DPA_MAX_DATA_LENGTH ) 159 DpaApiReturnPeripheralError( ERROR_DATA ); 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( FSR1[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 // Number of bytes to read from I2C 182 loop = _DpaDataLength = FSR0[offsetof( TI2Crequest, ReadDataCount )]; 183 // Anything to read from I2C? 184 if ( loop == 0 ) 185 { 186 // No, return with empty DPA response 187 goto DpaHandleReturnTRUE; 188 } 189 190 // Start I2C reading 191 _DpaApiI2Cstart( FSR0[offsetof( TI2Crequest, I2Caddress )] | 1 ); 192 // Read byte by byte from I2C 193 do 194 { 195 // Only very last read byte is not acknowledged 196 setINDF0( DpaApiI2Cread( loop != 1 ) ); 197 FSR0++; 198 } while ( --loop != 0 ); 199 // Stop I2C 200 _DpaApiI2Cstop(); 201 202 goto DpaHandleReturnTRUE; 203 } 204 break; 205 } 206 207 // ------------------------------------------------- 208 case DpaEvent_Init: 209 // Do a one time initialization before main loop starts 210 // Fall through! 211 // ------------------------------------------------- 212 case DpaEvent_AfterSleep: 213 // Called after woken up after sleep 214 // Enable I2C master 215 216 #if defined( TR7xG ) 217 // Do PPS for I2C 218 unlockPPS(); 219 SSP1CLKPPS = 0x13; // RC3 220 SSP1DATPPS = 0x14; // RC4 221 RC3PPS = 0x14; // SCK1/SCL1 222 RC4PPS = 0x15; // SD01/SDA1 223 lockPPS(); 224 #endif 225 226 DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) ); 227 return Carry; 228 229 // ------------------------------------------------- 230 case DpaEvent_BeforeSleep: 231 // Called before going to sleep 232 // Disable I2C master 233 DpaApiI2Cshutdown(); 234 return Carry; 235 } 236 237 return FALSE; 238 } 239 240 //############################################################################################ 241 // 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) 242 #include "DPAcustomHandler.h" 243 //############################################################################################