1 // *********************************************************************************** 2 // Custom DPA Handler code example - User peripheral implementation - Dallas 18B20 * 3 // *********************************************************************************** 4 // Copyright (c) MICRORISC s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-UserPeripheral-18B20.c,v $ 7 // Version: $Revision: 1.43 $ 8 // Date: $Date: 2022/02/25 09:41:25 $ 9 // 10 // Revision history: 11 // 2022/02/24 Release for DPA 4.17 12 // 2017/03/13 Release for DPA 3.00 13 // 2016/09/12 Release for DPA 2.28 14 // 2015/08/05 Release for DPA 2.20 15 // 2014/05/26 Release for DPA 2.11 16 // 2014/10/31 Release for DPA 2.10 17 // 2014/05/26 Release for DPA 2.01 18 // 19 // ********************************************************************* 20 21 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/ 22 23 // This example implements the user peripheral reading from Dallas 18B20 24 // PNUM = 0x20 and PCMD = 0 returns 2 bytes with result read from Dallas 18B20 25 // Dallas 18B20 is connected to MCU pin (see below) with 10k pull-up resistor and not using parasite power 26 27 // Default IQRF include (modify the path according to your setup) 28 #include "IQRF.h" 29 30 // Default DPA header (modify the path according to your setup) 31 #include "DPA.h" 32 // Default Custom DPA Handler header (modify the path according to your setup) 33 #include "DPAcustomHandler.h" 34 35 //############################################################################################ 36 37 // If defined then CRC is checked 38 #define USE_ONEWIRE_CRC 39 40 // Special temperature value to indicate a sensor error 41 #define DS18B20_ERROR_TEMPERATURE 0xF800 42 43 // Sensor connected to PORT C.3 (compatible with DDC-SE-01) 44 #define OneWire_TRIS TRISC.3 45 #define OneWire_IO_IN PORTC.3 46 #define OneWire_IO_OUT LATC.3 47 48 // Reads temperature from sensor 49 uns16 Ds18B20GetTemp(); 50 // Writes sensor configuration (resolution) 51 bit Ds18B20WriteConfig( uns8 value ); 52 53 // DS18B20 commands 54 #define CMD_READROM 0x33 55 #define CMD_CONVERTTEMP 0x44 56 #define CMD_CPYSCRATCHPAD 0x48 57 #define CMD_WSCRATCHPAD 0x4e 58 #define CMD_MATCHROM 0x55 59 #define CMD_RPWRSUPPLY 0xb4 60 #define CMD_RECEEPROM 0xb8 61 #define CMD_RSCRATCHPAD 0xbe 62 #define CMD_SKIPROM 0xcc 63 #define CMD_ALARMSEARCH 0xec 64 #define CMD_SEARCHROM 0xf0 65 66 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 67 //############################################################################################ 68 bit CustomDpaHandler() 69 //############################################################################################ 70 { 71 // Handler presence mark 72 clrwdt(); 73 74 // Detect DPA event to handle 75 switch ( GetDpaEvent() ) 76 { 77 // ------------------------------------------------- 78 case DpaEvent_Interrupt: 79 // Do an extra quick background interrupt work 80 // ! 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. 81 // ! 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. 82 // ! 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. 83 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 84 // ! Make sure race condition does not occur when accessing those variables at other places. 85 // ! 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. 86 // ! Do not call any OS functions except setINDFx(). 87 // ! Do not use any OS variables especially for writing access. 88 // ! 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. 89 90 DpaHandleReturnTRUE: 91 return TRUE; 92 93 // ------------------------------------------------- 94 case DpaEvent_Init: 95 // Do a one time initialization before main loop starts 96 97 // Setup DS18B20 for 9bit precision, conversion takes 94ms (see datasheet) 98 //Ds18B20WriteConfig( 0b0.00.00000 ); 99 100 //// Setup DS18B20 for 12bit precision, conversion takes 750ms (see datasheet) 101 Ds18B20WriteConfig( 0b0.11.00000 ); 102 103 break; 104 105 // ------------------------------------------------- 106 case DpaEvent_DpaRequest: 107 // Called to interpret DPA request for peripherals 108 // ------------------------------------------------- 109 // Peripheral enumeration 110 if ( IsDpaEnumPeripheralsRequest() ) 111 { 112 // We implement 1 user peripheral 113 _DpaMessage.EnumPeripheralsAnswer.UserPerNr |= 1; 114 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 ); 115 _DpaMessage.EnumPeripheralsAnswer.HWPID |= 0x000F; 116 _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= 0x9876; 117 118 goto DpaHandleReturnTRUE; 119 } 120 // ------------------------------------------------- 121 // Get information about peripheral 122 else if ( IsDpaPeripheralInfoRequest() ) 123 { 124 if ( _PNUM == PNUM_USER + 0 ) 125 { 126 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA; 127 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ; 128 goto DpaHandleReturnTRUE; 129 } 130 131 break; 132 } 133 // ------------------------------------------------- 134 else 135 { 136 // Handle peripheral command 137 if ( _PNUM == PNUM_USER + 0 ) 138 { 139 // Check command 140 switch ( _PCMD ) 141 { 142 case 0: 143 // ------------------------------------------------- 144 // Read temperature 145 if ( _DpaDataLength != 0 ) 146 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 147 148 uns16 temperature @ _DpaMessage.Response.PData; 149 temperature = Ds18B20GetTemp(); 150 if ( temperature == DS18B20_ERROR_TEMPERATURE ) 151 DpaApiReturnPeripheralError( ERROR_FAIL ); 152 153 _DpaDataLength = sizeof( temperature ); 154 goto DpaHandleReturnTRUE; 155 } 156 } 157 } 158 } 159 160 return FALSE; 161 } 162 163 //############################################################################################ 164 // OneWire and Dallas 18B20 routines 165 // If there is an interrupt running that consumes a lot of MCU time (>450us once per 1ms) then use GIE=1/GIE=0 at whole OneWireResetAndCmd() for sure 166 //############################################################################################ 167 168 //############################################################################################ 169 void Delay5us( uns8 val @ W ) // Absolutely precise timing but val != 0 170 //############################################################################################ 171 { 172 // 16 MHz 173 // + 0.75us ( W=val, Call ) 174 for ( ;; ) 175 { // loop time 176 nop2(); // 0.50us 177 nop2(); // 1.00us 178 nop2(); // 1.50us 179 nop2(); // 2.00us 180 nop2(); // 2.50us 181 nop2(); // 3.00us 182 nop(); // 3.25us 183 if ( --val == 0 ) // + 0.75us (W--, BTFS ) 184 return; // + 0.25us 185 nop2(); // 4.50us 186 } // 5.00us (Goto) 187 } 188 //############################################################################################ 189 190 #define OneWireData0() { OneWire_TRIS = 0; } // 0.5us @ 16MHz 191 #define OneWireData1() { OneWire_TRIS = 1; } // 0.5us @ 16MHz 192 193 //############################################################################################ 194 void OneWireWriteByte( uns8 byte ) 195 //############################################################################################ 196 { 197 uns8 bitLoop = 8; 198 do 199 { 200 // Next sequence is time precision critical 201 GIE = FALSE; 202 203 OneWireData0(); 204 nop2(); // 1 us [0.5 us] 205 nop2(); // [1.0 us] 206 if ( byte & 1 ) // 2.5 us [1.75us] 207 OneWireData1(); 208 209 // End of time precision critical sequence 210 GIE = TRUE; 211 212 // 60us minimum in total, does not have to be precise 213 Delay5us( ( 60 - 3 ) / 5 + 1 ); 214 OneWireData1(); 215 216 byte >>= 1; 217 } while ( --bitLoop != 0 ); 218 } 219 220 //############################################################################################ 221 uns8 OneWireReadByte() 222 //############################################################################################ 223 { 224 uns8 result; 225 uns8 bitLoop = 8; 226 do 227 { 228 // Next sequence is time precision critical 229 GIE = FALSE; 230 231 OneWireData0(); 232 nop2(); // 1 us [0.5 us] 233 nop2(); // [1.0 us] 234 OneWireData1(); // 2 us [1.5 us] 235 Delay5us( 15 / 5 ); // 17 us [16.5 us] 236 237 Carry = 0; // 17.5 us [16.75 us] 238 if ( OneWire_IO_IN ) // 18.5 us [ 17.25 us] (condition must not modify Carry) 239 Carry = 1; 240 241 // End of time precision critical sequence 242 GIE = TRUE; // must not modify Carry 243 result = rr( result ); 244 245 // 60us minimum in total, does not have to be precise 246 Delay5us( ( 60 - 20 ) / 5 + 1 ); 247 } while ( --bitLoop != 0 ); 248 249 return result; 250 } 251 252 //############################################################################################ 253 bit OneWireResetAndCmd( uns8 cmd ) 254 //############################################################################################ 255 { 256 // Setting the pin once to low is enough 257 OneWire_IO_OUT = 0; 258 // Reset pulse 259 OneWireData0(); 260 Delay5us( 500 / 5 ); 261 // Reset pulse end 262 OneWireData1(); 263 // Next sequence is time precision critical 264 GIE = FALSE; 265 // Wait for presence pulse 266 Delay5us( 70 / 5 ); 267 // End of time precision critical sequence 268 GIE = TRUE; 269 // Presence pulse? 270 if ( OneWire_IO_IN ) 271 { 272 // No presence, finish initialization sequence 273 Delay5us( ( 500 - 70 ) / 5 ); 274 return FALSE; 275 } 276 else 277 { 278 // Presence OK, finish initialization sequence 279 Delay5us( ( 500 - 70 ) / 5 ); 280 // OneWire: Skip ROM 281 OneWireWriteByte( CMD_SKIPROM ); 282 // OneWire: Send command 283 OneWireWriteByte( cmd ); 284 return TRUE; 285 } 286 } 287 288 //############################################################################################ 289 290 #ifdef USE_ONEWIRE_CRC 291 // One Wire CRC accumulator 292 uns8 OneWireCrc; 293 294 //############################################################################################ 295 void UpdateOneWireCrc( uns8 value ) 296 //############################################################################################ 297 { 298 OneWireCrc = DpaApiCrc8( OneWireCrc, value ); 299 } 300 301 #endif 302 303 //############################################################################################ 304 uns16 Ds18B20GetTemp() 305 //############################################################################################ 306 { 307 // OneWire: Convert T 308 if ( OneWireResetAndCmd( CMD_CONVERTTEMP ) ) 309 { 310 // Wait for conversion to finish 311 startCapture(); 312 for ( ;; ) 313 { 314 // 1s timeout 315 captureTicks(); 316 if ( param3.low8 > ( 1000 / 10 ) ) 317 { 318 // Timeout 319 Carry = FALSE; 320 break; 321 } 322 323 if ( OneWireReadByte() == 0xff ) 324 { 325 // Temperature ready to be read 326 Carry = TRUE; 327 break; 328 } 329 } 330 331 // OneWire: Read Scratchpad 332 if ( Carry && OneWireResetAndCmd( CMD_RSCRATCHPAD ) ) 333 { 334 // Read Scratchpad bytes 335 uns16 temperature; 336 337 #ifdef USE_ONEWIRE_CRC 338 // Initialize CRC 339 OneWireCrc = 0; 340 // Will read later rest of scratchpad bytes and update CRC (initialization is here to avoid MOVLB later) 341 uns8 byteLoop = 9 - 2; 342 343 // Temperature LSB into result & CRC 344 UpdateOneWireCrc( temperature.low8 = OneWireReadByte() ); 345 // Temperature MSB into result & CRC 346 UpdateOneWireCrc( temperature.high8 = OneWireReadByte() ); 347 348 // Read rest of scratchpad 349 do 350 { 351 UpdateOneWireCrc( OneWireReadByte() ); 352 } while ( --byteLoop != 0 ); 353 354 // Check correct CRC 355 if ( OneWireCrc == 0 ) 356 return temperature; 357 #else 358 temperature.low8 = OneWireReadByte(); 359 temperature.high8 = OneWireReadByte(); 360 return temperature; 361 #endif 362 } 363 } 364 // Some error occurred 365 return DS18B20_ERROR_TEMPERATURE; 366 } 367 368 //############################################################################################ 369 bit Ds18B20WriteConfig( uns8 value ) 370 //############################################################################################ 371 { 372 // OneWire: Write Scratchpad 373 if ( OneWireResetAndCmd( CMD_WSCRATCHPAD ) ) 374 { 375 // Write TL = ? (we dot not care the value) 376 OneWireWriteByte( W ); 377 // Write TH = ? (we dot not care the value) 378 OneWireWriteByte( W ); 379 // Write Config byte 380 OneWireWriteByte( value ); 381 382 // OneWire: Copy Scratchpad 383 if ( OneWireResetAndCmd( CMD_CPYSCRATCHPAD ) ) 384 return TRUE; 385 } 386 return FALSE; 387 } 388 389 //############################################################################################ 390 // 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) 391 #include "DPAcustomHandler.h" 392 //############################################################################################