1 // *********************************************************************************** 2 // Custom DPA Handler code example - User peripheral implementation - i2c * 3 // *********************************************************************************** 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-UserPeripheral-i2c.c,v $ 7 // Version: $Revision: 1.16 $ 8 // Date: $Date: 2018/01/03 09:55:12 $ 9 // 10 // Revision history: 11 // 2017/03/13 Release for DPA 3.00 12 // 2015/12/01 Release for DPA 2.24 13 // 2015/08/05 Release for DPA 2.20 14 // 15 // ********************************************************************* 16 17 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 18 19 // This example implements the user peripheral reading from MCP9802 at DDC-SE-01 20 // PNUM = 0x20 and PCMD = 0 returns 2 bytes with result read from MCP9802 21 // Based on example DDC-SE-01-i2c.c 22 23 // Default IQRF include (modify the path according to your setup) 24 #include "IQRF.h" 25 26 // Default DPA header (modify the path according to your setup) 27 #include "DPA.h" 28 // Default Custom DPA Handler header (modify the path according to your setup) 29 #include "DPAcustomHandler.h" 30 31 //############################################################################################ 32 33 void i2c_init(); 34 void i2c_shutdown(); 35 void i2c_waitForIdle(); 36 void i2c_start(); 37 void i2c_repStart(); 38 void i2c_stop(); 39 uns8 i2c_read( bit ack ); 40 void i2c_write( uns8 i2cWriteData ); 41 42 #define I2C_ADR 0b10010110 43 #define PWR_SENSOR_TRIS TRISC.7 44 #define PWR_SENSOR_IO LATC.7 45 46 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 47 //############################################################################################ 48 bit CustomDpaHandler() 49 //############################################################################################ 50 { 51 // Handler presence mark 52 clrwdt(); 53 54 // Detect DPA event to handle 55 switch ( GetDpaEvent() ) 56 { 57 // ------------------------------------------------- 58 case DpaEvent_Interrupt: 59 // Do an extra quick background interrupt work 60 // ! The time spent handling this event is critical.If there is no interrupt to handle return immediately otherwise keep the code as fast as possible. 61 // ! Make sure the event is the 1st case in the main switch statement at the handler routine.This ensures that the event is handled as the 1st one. 62 // ! It is desirable that this event is handled with immediate return even if it is not used by the custom handler because the Interrupt event is raised on every MCU interrupt and the “empty” return handler ensures the shortest possible interrupt routine response time. 63 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 64 // ! Make sure race condition does not occur when accessing those variables at other places. 65 // ! Make sure( inspect.lst file generated by C compiler ) compiler does not create any hidden temporary local variable( occurs when using division, multiplication or bit shifts ) at the event handler code.The name of such variable is usually Cnumbercnt. 66 // ! Do not call any OS functions except setINDFx(). 67 // ! Do not use any OS variables especially for writing access. 68 // ! All above rules apply also to any other function being called from the event handler code, although calling any function from Interrupt event is not recommended because of additional MCU stack usage. 69 70 DpaHandleReturnTRUE: 71 return TRUE; 72 73 // ------------------------------------------------- 74 case DpaEvent_Init: 75 // Do a one time initialization work before main loop starts 76 case DpaEvent_AfterSleep: 77 // Called after woken up after sleep 78 79 i2c_init(); 80 break; 81 82 // ------------------------------------------------- 83 case DpaEvent_BeforeSleep: 84 // Called before going to sleep 85 86 i2c_shutdown(); 87 break; 88 89 // ------------------------------------------------- 90 case DpaEvent_DpaRequest: 91 // Called to interpret DPA request for peripherals 92 // ------------------------------------------------- 93 // Peripheral enumeration 94 if ( IsDpaEnumPeripheralsRequest() ) 95 { 96 // We implement 1 user peripheral 97 _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1; 98 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 ); 99 _DpaMessage.EnumPeripheralsAnswer.HWPID = 0x000F; 100 _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0xAbCd; 101 102 goto DpaHandleReturnTRUE; 103 } 104 // ------------------------------------------------- 105 // Get information about peripheral 106 else if ( IsDpaPeripheralInfoRequest() ) 107 { 108 if ( _PNUM == PNUM_USER + 0 ) 109 { 110 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA; 111 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ; 112 goto DpaHandleReturnTRUE; 113 } 114 115 break; 116 } 117 // ------------------------------------------------- 118 else 119 { 120 // Handle peripheral command 121 if ( _PNUM == PNUM_USER + 0 ) 122 { 123 // Check command 124 switch ( _PCMD ) 125 { 126 case 0: 127 // ------------------------------------------------- 128 // Read temperature 129 if ( _DpaDataLength != 0 ) 130 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 131 132 i2c_start(); 133 i2c_write( I2C_ADR ); // MCP9802 address 134 i2c_write( 0x01 ); // pointer: 1 = configuration register 135 i2c_write( 0x60 ); // configuration: 12-bit ADC 136 i2c_stop(); 137 138 i2c_start(); 139 i2c_write( I2C_ADR ); // MCP9802 address 140 i2c_write( 0 ); // pointer: 0 = temperature 141 i2c_stop(); 142 143 i2c_start(); 144 i2c_write( I2C_ADR | 1 ); // MCP9802 address + read 145 uns16 temperature @ _DpaMessage.Response.PData; 146 temperature.high8 = i2c_read( TRUE ); // store the result 147 temperature.low8 = i2c_read( FALSE ); 148 i2c_stop(); 149 150 _DpaDataLength = sizeof( temperature ); 151 goto DpaHandleReturnTRUE; 152 153 default: 154 // ------------------------------------------------- 155 // Invalid command 156 DpaApiReturnPeripheralError( ERROR_PCMD ); 157 } 158 } 159 } 160 } 161 162 return FALSE; 163 } 164 165 //############################################################################################ 166 167 #pragma library 1 // Compile only used functions 168 169 // ********************************************************************* 170 171 void writeToSSPCON2( uns8 value @ param4.high8 ) 172 { 173 writeToRAM( &SSPCON2, value ); 174 } 175 //---------------------------------------------------------------------- 176 177 void writeOredToSSPCON2( uns8 value @ param4.high8 ) 178 { 179 writeToSSPCON2( SSPCON2 | value ); 180 } 181 182 //---------------------------------------------------------------------- 183 184 void i2c_init() 185 { 186 PORTC = 0x80; // port 187 188 TRISC.3 = 1; // SCL as input (SIM C6) 189 TRISC.4 = 1; // SDA as input (SIM C7) 190 191 PWR_SENSOR_TRIS = 0; // sensor power as output (SIM C8) 192 TRISC.5 = 1; // shared with SIM C8 193 194 TRISA.5 = 1; // sensor ALERT as input (SIM C5) 195 TRISB.4 = 1; // shared with SIM C5 196 TRISC.6 = 1; // shared with SIM C5 197 198 writeToRAM( &SSPCON1, 0x38 ); // I2C master mode SSPCON = 0b00111000 199 writeToSSPCON2( 0x00 ); 200 201 SSPADD = ( F_OSC / 50000 / 4 ) - 2; // 50 kHz SCL frequency 202 203 SMP = 1; // Disable slew rate control 204 } 205 206 //------------------------------------------------------------------------ 207 208 void i2c_shutdown() 209 { 210 writeToRAM( &SSPCON1, 0x00 ); // I2C master mode SSPCON = 0 211 } 212 213 //------------------------------------------------------------------------ 214 void i2c_waitForIdle() 215 { 216 while ( SSPCON2 & 0x1F ); // Wait for idle and not writing 217 while ( RW_ ); // Wait for idle and not writing 218 } 219 //---------------------------------------------------------------------- 220 221 void i2c_start() 222 { 223 i2c_waitForIdle(); 224 writeOredToSSPCON2( 0x01 ); // SEN = 1 225 } 226 //---------------------------------------------------------------------- 227 228 void i2c_repStart() 229 { 230 i2c_waitForIdle(); 231 writeOredToSSPCON2( 0x02 ); // RSEN = 1 232 } 233 //---------------------------------------------------------------------- 234 235 void i2c_stop() 236 { 237 i2c_waitForIdle(); 238 writeOredToSSPCON2( 0x04 ); // PEN = 1 239 } 240 //---------------------------------------------------------------------- 241 242 uns8 i2c_read( bit ack ) 243 { 244 i2c_waitForIdle(); 245 writeOredToSSPCON2( 0x08 ); // RCEN = 1 246 247 i2c_waitForIdle(); 248 249 uns8 i2cReadData @ userReg0; 250 i2cReadData = SSPBUF; 251 252 i2c_waitForIdle(); 253 254 if ( ack ) 255 writeToSSPCON2( SSPCON2 & 0xDF ); // Acknowledge, ACKDT = 0 256 else 257 writeOredToSSPCON2( 0x20 ); // Not acknowledge, ACKDT = 1 258 259 writeOredToSSPCON2( 0x10 ); // Send acknowledge sequence, ACKEN = 1 260 return i2cReadData; 261 } 262 //---------------------------------------------------------------------- 263 264 void i2c_write( uns8 i2cWriteData @ param2 ) 265 { 266 i2c_waitForIdle(); 267 SSPBUF = i2cWriteData; 268 } 269 270 // ############################################################################################ 271 #pragma library 0 // Compile all 272 //############################################################################################ 273 // 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) 274 #include "DPAcustomHandler.h" 275 //############################################################################################