1 // ********************************************************************* 2 // Custom DPA Handler code example - Standard Sensors - DDC-SE-01 * 3 // ********************************************************************* 4 // Copyright (c) MICRORISC s.r.o. 5 // 6 // File: $RCSfile: 0002_DDC-SE01.c,v $ 7 // Version: $Revision: 1.55 $ 8 // Date: $Date: 2024/01/29 14:20:03 $ 9 // 10 // Revision history: 11 // 2023/03/07 Release for DPA 4.30 12 // 2022/10/05 Release for DPA 4.18 13 // 2022/02/24 Release for DPA 4.17 14 // 2021/08/20 Release for DPA 4.16 15 // 2020/01/02 Release for DPA 4.11 16 // 2018/10/25 Release for DPA 3.03 17 // 2017/11/16 Release for DPA 3.02 18 // 2017/08/14 Release for DPA 3.01 19 // 20 // ********************************************************************* 21 22 // MCR-BuildStdHandler 23 #message '+CC5X -bu' 24 25 #define _HWPID_ HWPID_IQRF_TECH__DEMO_DDC_SE01 26 #define _HWPIDver_ 0x0001 27 28 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/ 29 // IQRF Standards documentation https://doc.iqrf.org/ 30 31 // This example implements 4 sensors according to the IQRF Sensors standard 32 // 1st sensor is on-board TR temperature sensor. 33 // 2nd sensor is either Dallas 18B20 or MCP9802 temperature sensor at DDC-SE-01 board (according to the HW jumper position) chosen at the runtime based on the SW detection. 34 // 3rd sensor is light intensity indicator at DDC-SE-01 board (value range is 0[max light]-127[max dark]). 35 // 4th sensor is potentiometer value at DDC-SE-01 board (value range is 0[left stop]-127[right stop]). 36 37 // Default IQRF include (modify the path according to your setup) 38 #include "IQRF.h" 39 40 // Default DPA header (modify the path according to your setup) 41 #include "DPA.h" 42 // Default Custom DPA Handler header (modify the path according to your setup) 43 #include "DPAcustomHandler.h" 44 // IQRF standards header (modify the path according to your setup) 45 #include "IQRFstandard.h" 46 #include "IQRF_HWPID.h" 47 48 //############################################################################################ 49 50 // Number of implemented sensors 51 #define SENSORS_COUNT 4 52 53 // Variable to store sensor value at Get?_????() methods. This example implements sensors returning maximum 2 bytes of data. 54 uns16 sensorValue @ param3; 55 56 // Reads sensor value to the sensorValue variable and to responseFRCvalue(2B) variable 57 bit Get0_TemperatureTR(); 58 bit Get1_Temperature(); 59 bit Get2_BinaryData_Light(); 60 bit Get3_BinaryData_Potentiometer(); 61 62 // Temperature sensors read routine for both DDC-SE-01 sensor types 63 void GetTemperature(); 64 65 // Stores sensor value byte(s) to the FSR1[+1...], in case of PCMD_STD_SENSORS_READ_TYPES_AND_VALUES sensor type is stored before value byte(s) 66 void StoreValue( uns8 sensorType ); 67 68 // Sensor connected to PORT C.3 (compatible with DDC-SE-01) 69 #define OneWire_TRIS TRISC.3 70 #define OneWire_IO_IN PORTC.3 71 #define OneWire_IO_OUT LATC.3 72 73 // Writes sensor configuration (resolution) 74 bit Ds18B20WriteConfig( uns8 value ); 75 76 // Resets OneWire 77 bit OneWireReset(); 78 // Reads OneWire byte 79 uns8 OneWireReadByte(); 80 // Writes OneWire byte 81 void OneWireWriteByte( uns8 byte ); 82 83 // DS18B20 commands 84 #define CMD_READROM 0x33 85 #define CMD_CONVERTTEMP 0x44 86 #define CMD_CPYSCRATCHPAD 0x48 87 #define CMD_WSCRATCHPAD 0x4e 88 #define CMD_MATCHROM 0x55 89 #define CMD_RPWRSUPPLY 0xb4 90 #define CMD_RECEEPROM 0xb8 91 #define CMD_RSCRATCHPAD 0xbe 92 #define CMD_SKIPROM 0xcc 93 #define CMD_ALARMSEARCH 0xec 94 #define CMD_SEARCHROM 0xf0 95 96 // I2C SCL frequency [Hz] 97 #define I2Cfrequency 50000 98 99 // MCP9802 address 100 #define I2C_ADR 0b1001.0110 101 102 // TRUE if DS18B20 is enabled at runtime at startup, FALSE in case of MCP9802 103 bit isDS18B20; 104 // Final DS18B20 temperature value read by state machine 105 uns16 temperature; 106 107 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 108 //############################################################################################ 109 bit CustomDpaHandler() 110 //############################################################################################ 111 { 112 // This forces CC5X to wisely use MOVLB instructions (doc says: The 'default' bank is used by the compiler for loops and labels when the algorithm gives up finding the optimal choice) 113 #pragma updateBank default = UserBank_01 114 115 // Finite machine states 116 typedef enum 117 { 118 S_ResetConvertT = 0, 119 S_SkipRomConvertT, 120 S_CmdConvertT, 121 122 S_WaitConvertT, 123 124 S_ResetReadTemp, 125 S_SkipRomReadTemp, 126 S_CmdReadTemp, 127 S_Byte1ReadTemp, 128 S_Byte2ReadTemp 129 } TState; 130 131 // Handler presence mark 132 clrwdt(); 133 134 // Sleeping parameters, valid when Time != 0 135 static TPerOSSleep_Request PerOSSleep_Request; 136 // Finite machine state 137 static uns8 state; // = S_ResetConvertT = 0 138 // Pre-read lower temperature byte 139 static uns8 temperatureByteLow; 140 // Conversion timeout counter 141 static uns8 timeout; 142 143 // Detect DPA event to handle 144 switch ( GetDpaEvent() ) 145 { 146 // ------------------------------------------------- 147 case DpaEvent_Interrupt: 148 // Do an extra quick background interrupt work 149 // ! 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. 150 // ! 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. 151 // ! 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. 152 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 153 // ! Make sure race condition does not occur when accessing those variables at other places. 154 // ! 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. 155 // ! Do not call any OS functions except setINDFx(). 156 // ! Do not use any OS variables especially for writing access. 157 // ! 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. 158 159 // ms per TMR6 interrupt 160 #define TICKS_LEN 10 161 162 // If TMR6 interrupt occurred 163 if ( TMR6IF ) 164 { 165 // Unmask interrupt 166 TMR6IF = 0; 167 // Decrement count 168 if ( timeout != 0 ) 169 timeout--; 170 } 171 return Carry; 172 173 // ------------------------------------------------- 174 case DpaEvent_Idle: 175 // Do a quick background work when RF packet is not received 176 177 // Should go to sleep? 178 if ( PerOSSleep_Request.Time != 0 ) 179 { 180 // Copy sleep parameters to the DPA request 181 _DpaMessage.PerOSSleep_Request.Time = PerOSSleep_Request.Time; 182 _DpaMessage.PerOSSleep_Request.Control = PerOSSleep_Request.Control; 183 // Switch off sleeping time=flag 184 PerOSSleep_Request.Time = 0; 185 // Finalize OS Sleep DPA Request 186 _DpaDataLength = sizeof( _DpaMessage.PerOSSleep_Request ); 187 _PNUM = PNUM_OS; 188 _PCMD = CMD_OS_SLEEP; 189 // I2C down 190 if ( !isDS18B20 ) 191 _DpaApiI2Cshutdown(); 192 // Perform local DPA Request to go to sleep 193 DpaApiLocalRequest(); 194 // I2C up 195 if ( !isDS18B20 ) 196 _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) ); 197 } 198 199 // Run finite state machine to read temperature from DS18B20 at background so the temperature value is immediately ready for FRC 200 if ( !isDS18B20 ) 201 break; 202 203 // Make sure 1Wire data pin at LATX.y is low as it might be set by another PORTX.? pin manipulation 204 OneWire_IO_OUT = 0; 205 206 skip( state ); 207 #pragma computedGoto 1 208 goto _S_ResetConvertT; 209 goto _S_SkipRomConvertT; 210 goto _S_CmdConvertT; 211 goto _S_WaitConvertT; 212 goto _S_ResetReadTemp; 213 goto _S_SkipRomReadTemp; 214 goto _S_CmdReadTemp; 215 goto _S_Byte1ReadTemp; 216 goto _S_Byte2ReadTemp; 217 #pragma computedGoto 0 218 ; 219 // -------------- 220 _S_Byte2ReadTemp: 221 temperature.high8 = OneWireReadByte(); 222 temperature.low8 = temperatureByteLow; 223 224 ResetMachine: 225 state = S_ResetConvertT; 226 goto ExitMachine; 227 228 // -------------- 229 _S_ResetConvertT: 230 _S_ResetReadTemp: 231 if ( !OneWireReset() ) 232 { 233 _S_Error_Reset: 234 STD_SENSOR_TYPE_TEMPERATURE_SET_ERROR( temperature ); 235 goto ResetMachine; 236 } 237 goto NextState; 238 239 // -------------- 240 _S_SkipRomConvertT: 241 _S_SkipRomReadTemp: 242 // OneWire: Skip ROM 243 OneWireWriteByte( CMD_SKIPROM ); 244 goto NextState; 245 246 // -------------- 247 _S_CmdConvertT: 248 // OneWire: Convert temperature 249 OneWireWriteByte( CMD_CONVERTTEMP ); 250 // Setup timeout for approx 750 ms (the longest conversion time) 251 timeout = 2 + 750 / TICKS_LEN; 252 goto NextState; 253 254 // -------------- 255 _S_WaitConvertT: 256 if ( OneWireReadByte() == 0xff ) 257 goto NextState; 258 259 // Timeout? 260 if ( timeout == 0 ) 261 goto _S_Error_Reset; 262 263 goto ExitMachine; 264 265 // -------------- 266 _S_CmdReadTemp: 267 // OneWire: Read scratchpad 268 OneWireWriteByte( CMD_RSCRATCHPAD ); 269 goto NextState; 270 271 // -------------- 272 _S_Byte1ReadTemp: 273 temperatureByteLow = OneWireReadByte(); 274 goto NextState; 275 276 // -------------- 277 NextState: 278 ++state; 279 280 ExitMachine: 281 break; 282 283 // ------------------------------------------------- 284 case DpaEvent_Init: 285 // Do a one time initialization before main loop starts 286 287 // Initialize sensors 288 // C5 (AN4) as input 289 moduleInfo(); 290 // Connected TR pins? 291 if ( !bufferINFO[5].7 ) 292 { 293 TRISC.6 = 1; 294 TRISB.4 = 1; 295 } 296 // C5 as input 297 TRISA.5 = 1; 298 // C1 as input 299 TRISA.0 = 1; 300 301 // Prescaler 16, Postscaler 10, 16 * 10 * 250 = 40000 = 4MHz * 10ms 302 #if defined( TR7xG ) 303 TMR6MD = 0; 304 T6CON = 0b1.100.1001; 305 // Timer2/4/6 Clock Select bits = FOSC/4 306 T6CLKCON |= 0b0000.0001; 307 #else 308 T6CON = 0b0.1001.1.10; 309 #endif 310 // Setup TMR6 to generate ticks on the background (ticks every 10ms) 311 _PR6 = 250 - 1; 312 313 TMR6IE = TRUE; 314 315 // Setup DS18B20 for 9bit precision, conversion takes 94ms (see datasheet) 316 if ( Ds18B20WriteConfig( 0b0.00.00000 ) ) 317 // DS18B20 is enabled 318 isDS18B20 = TRUE; 319 else 320 { 321 // Expect MCP9802 is enabled 322 I2Ctimeout = 0xFF; 323 324 #if defined( TR7xG ) 325 // Do PPS for I2C 326 unlockPPS(); 327 SSP1CLKPPS = 0x13; // RC3 328 SSP1DATPPS = 0x14; // RC4 329 RC3PPS = 0x14; // SCK1/SCL1 330 RC4PPS = 0x15; // SD01/SDA1 331 lockPPS(); 332 #endif 333 334 _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) ); 335 } 336 337 break; 338 339 // ------------------------------------------------- 340 case DpaEvent_AfterSleep: 341 // Called after woken up after sleep 342 if ( !isDS18B20 ) 343 _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) ); 344 345 // Called on wake-up from sleep 346 TMR6IE = TRUE; 347 _TMR6ON = TRUE; 348 break; 349 350 // ------------------------------------------------- 351 case DpaEvent_BeforeSleep: 352 // Called before going to sleep 353 if ( !isDS18B20 ) 354 _DpaApiI2Cshutdown(); 355 356 // ------------------------------------------------- 357 case DpaEvent_DisableInterrupts: 358 // Called when device needs all hardware interrupts to be disabled (before Reset, Restart, LoadCode, Remove bond, and Run RFPGM) 359 // Must not use TMR6 any more 360 _TMR6ON = FALSE; 361 TMR6IE = FALSE; 362 break; 363 364 // ------------------------------------------------- 365 case DpaEvent_DpaRequest: 366 // Called to interpret DPA request for peripherals 367 // ------------------------------------------------- 368 // Peripheral enumeration 369 if ( IsDpaEnumPeripheralsRequest() ) 370 { 371 // We implement 1 standard user peripheral 372 _DpaMessage.EnumPeripheralsAnswer.UserPerNr |= 1; 373 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS ); 374 _DpaMessage.EnumPeripheralsAnswer.HWPID |= _HWPID_; 375 _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= _HWPIDver_; 376 377 DpaHandleReturnTRUE: 378 return TRUE; 379 } 380 // ------------------------------------------------- 381 // Get information about peripheral 382 else if ( IsDpaPeripheralInfoRequest() ) 383 { 384 if ( _PNUM == PNUM_STD_SENSORS ) 385 { 386 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_STD_SENSORS; 387 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ; 388 // Set standard version 389 _DpaMessage.PeripheralInfoAnswer.Par1 = STD_SENSORS_VERSION; 390 goto DpaHandleReturnTRUE; 391 } 392 393 break; 394 } 395 // ------------------------------------------------- 396 else 397 { 398 // Handle peripheral command 399 400 // Supported peripheral number? 401 if ( _PNUM == PNUM_STD_SENSORS ) 402 { 403 // Supported commands? 404 switch ( _PCMD ) 405 { 406 // Invalid command 407 default: 408 // Return error 409 DpaApiReturnPeripheralError( ERROR_PCMD ); 410 411 // Sensor enumeration 412 case PCMD_STD_ENUMERATE: 413 if ( _DpaDataLength != 0 ) 414 goto _ERROR_DATA_LEN; 415 416 // Then just enumerate their types 417 _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_TEMPERATURE; 418 _DpaMessage.Response.PData[1] = STD_SENSOR_TYPE_TEMPERATURE; 419 _DpaMessage.Response.PData[2] = STD_SENSOR_TYPE_BINARYDATA7; 420 _DpaMessage.Response.PData[3] = STD_SENSOR_TYPE_BINARYDATA7; 421 W = SENSORS_COUNT; 422 goto _W2_DpaDataLength; 423 424 // Supported commands. They are handled the same way except one "if" at StoreValue() method 425 case PCMD_STD_SENSORS_READ_VALUES: 426 case PCMD_STD_SENSORS_READ_TYPES_AND_VALUES: 427 { 428 // No sensor bitmap specified? W = _DpaDataLength. Note: W is used to avoid MOVLB at next if 429 W = _DpaDataLength; 430 if ( W == 0 ) // Note: must not modify W 431 { 432 // Actually clears the bitmap 433 #if &_DpaMessage.Request.PData[0] != &bufferRF[0] 434 #error 435 #endif 436 clearBufferRF(); 437 // Simulate 1st only sensor in the bitmap (states of the other unimplemented sensors do not care) 438 _DpaMessage.Request.PData[0].0 = 1; 439 // Bitmap is 32 bits long = 4 440 _DpaDataLength = W = sizeof( _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap ); 441 } 442 443 // Invalid bitmap (data) length (W = _DpaDataLength)? 444 if ( W != sizeof( _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap ) ) 445 { 446 _ERROR_DATA_LEN: 447 // Return error 448 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 449 } 450 451 // Now read the sensors 452 453 // Prepare pointer (minus 1, see below) to store sensor (types and) values to 454 // Note: 4 sensors at this example cannot return more than DPA_MAX_DATA_LENGTH bytes of data, so it does not have to be checked... 455 // ... If it would be the case, then ERROR_FAIL must be returned 456 FSR1 = &_DpaMessage.Response.PData[-1]; 457 458 // Store bitmap of sensors to get values from 459 uns8 sensorsBitmap = FSR1[1]; 460 461 // 1st sensor (index 0) selected? 462 if ( sensorsBitmap.0 ) 463 { 464 Get0_TemperatureTR(); 465 StoreValue( STD_SENSOR_TYPE_TEMPERATURE ); 466 } 467 468 // 2nd sensor (index 1) selected? 469 if ( sensorsBitmap.1 ) 470 { 471 Get1_Temperature(); 472 StoreValue( STD_SENSOR_TYPE_TEMPERATURE ); 473 } 474 475 // 3rd sensor (index 2) selected? 476 if ( sensorsBitmap.2 ) 477 { 478 Get2_BinaryData_Light(); 479 StoreValue( STD_SENSOR_TYPE_BINARYDATA7 ); 480 } 481 482 // 4th sensor (index 3) selected? 483 if ( sensorsBitmap.3 ) 484 { 485 Get3_BinaryData_Potentiometer(); 486 StoreValue( STD_SENSOR_TYPE_BINARYDATA7 ); 487 } 488 489 // Compute returned data bytes count 490 W = FSR1L - ( (uns16)&_DpaMessage.Response.PData[0] & 0xFF ) + 1; 491 // Optimization: return W long block of bytes at response 492 _W2_DpaDataLength: 493 _DpaDataLength = W; 494 goto DpaHandleReturnTRUE; 495 } 496 } 497 } 498 499 break; 500 } 501 502 // ------------------------------------------------- 503 case DpaEvent_FrcValue: 504 // Called to get FRC value 505 506 // FSR1 for optimization purposes (avoid MOVLB) will be used to point to DataOutBeforeResponseFRC[0...] 507 FSR1 = &DataOutBeforeResponseFRC[0]; 508 // Check for correct FRC user data 509 if ( *FSR1++ /*DataOutBeforeResponseFRC[0]*/ == PNUM_STD_SENSORS ) 510 { 511 // Actually used sensor index 512 uns8 sensorIndex = FSR1[1] /*DataOutBeforeResponseFRC[2]*/ & 0x1f; 513 // Test sensor type 514 switch ( *FSR1++ /*DataOutBeforeResponseFRC[1]*/ ) 515 { 516 default: 517 goto DpaHandleReturnFALSE; 518 519 // No type specified, use specified index value 520 case 0x00: 521 goto _KeepSensorIndex; 522 523 // For other types make the index value based on the requested index value and sensor type 524 case STD_SENSOR_TYPE_TEMPERATURE: 525 if ( sensorIndex > 1 ) 526 goto DpaHandleReturnFALSE; 527 W = 0 + sensorIndex; 528 break; 529 530 case STD_SENSOR_TYPE_BINARYDATA7: 531 if ( sensorIndex > 1 ) 532 goto DpaHandleReturnFALSE; 533 W = 2 + sensorIndex; 534 break; 535 } 536 537 // New sensor index based on type and requested index 538 sensorIndex = W; 539 _KeepSensorIndex: 540 541 // Test for supported FRC commands 542 switch ( _PCMD ) 543 { 544 default: 545 goto DpaHandleReturnFALSE; 546 547 case FRC_STD_SENSORS_BIT: 548 case FRC_STD_SENSORS_1B: 549 case FRC_STD_SENSORS_2B: 550 switch ( sensorIndex ) 551 { 552 default: 553 goto DpaHandleReturnFALSE; 554 555 case 0: 556 Carry = Get0_TemperatureTR(); 557 break; 558 559 case 1: 560 Carry = Get1_Temperature(); 561 break; 562 563 case 2: 564 Carry = Get2_BinaryData_Light(); 565 break; 566 567 case 3: 568 Carry = Get3_BinaryData_Potentiometer(); 569 break; 570 } 571 572 // This type of FRC is not valid for the specified sensor 573 if ( !Carry ) 574 goto DpaHandleReturnFALSE; 575 576 break; 577 } 578 579 // Some sensor was measured by FRC, check if there is a sleep request 580 FSR1++; 581 if ( INDF1.0 ) // Note: same as DataOutBeforeResponseFRC[3].0 582 { 583 // Remember sleep parameters to go to sleep at the Idle event later 584 PerOSSleep_Request.Time.low8 = FSR1[4 - 3]; // Note: same as DataOutBeforeResponseFRC[4]; 585 PerOSSleep_Request.Time.high8 = FSR1[5 - 3]; // Note: same as DataOutBeforeResponseFRC[5]; 586 PerOSSleep_Request.Control = FSR1[6 - 3]; // Note: same as DataOutBeforeResponseFRC[6]; 587 } 588 } 589 590 break; 591 592 // ------------------------------------------------- 593 case DpaEvent_FrcResponseTime: 594 // Called to get FRC response time 595 596 // In this example the FRC commands are fast 597 switch ( DataOutBeforeResponseFRC[0] ) 598 { 599 case FRC_STD_SENSORS_BIT: 600 case FRC_STD_SENSORS_1B: 601 case FRC_STD_SENSORS_2B: 602 responseFRCvalue = _FRC_RESPONSE_TIME_40_MS; 603 break; 604 } 605 break; 606 } 607 DpaHandleReturnFALSE: 608 return FALSE; 609 } 610 611 //############################################################################################ 612 // Increases FSR1 and then stores the byte 613 void setPlusPlusINDF1( uns8 data @ W ) 614 //############################################################################################ 615 { 616 FSR1++; // Note: must not modify W 617 setINDF1( data ); 618 } 619 620 //############################################################################################ 621 // Stores measured sensor value byte(s) and optionally sensor type to the FSR[+1...] 622 void StoreValue( uns8 sensorType ) 623 //############################################################################################ 624 { 625 // Is the sensor type to be stored too? 626 if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES ) 627 setPlusPlusINDF1( sensorType ); 628 629 // Store lower value byte 630 setPlusPlusINDF1( sensorValue.low8 ); 631 632 // No more value bytes to store? 633 if ( sensorType.7 != 0 ) 634 return; 635 636 // Store higher value byte 637 setPlusPlusINDF1( sensorValue.high8 ); 638 639 // Note: this example implements sensors returning only 1 or 2 bytes of data. If another data widths are returned, then it must be implemented explicitly. 640 } 641 642 //############################################################################################ 643 bit setFRCerror() 644 //############################################################################################ 645 { 646 responseFRCvalue2B = FRC_STD_FRC_ERROR_VALUE; 647 return TRUE; 648 } 649 650 //############################################################################################ 651 bit sensorError; 652 bit AdjustFrcTemperature() 653 //############################################################################################ 654 { 655 // Test for supported FRC commands 656 switch ( _PCMD ) 657 { 658 default: 659 return FALSE; 660 661 case FRC_STD_SENSORS_1B: 662 // Return sensor FRC value 1B 663 // Check for out of limits 664 if ( sensorError || (int16)sensorValue > (int16)( 105.5 * 16 ) || (int16)sensorValue < ( (int16)-20 * 16 ) ) 665 return setFRCerror(); 666 667 // Convert to the "F = ( T + 22 ) * 2 " from 1/16 resolution 668 responseFRCvalue2B = sensorValue + 4; // Note: do rounding when /8 669 responseFRCvalue2B /= 8; 670 responseFRCvalue += 44; 671 break; 672 673 case FRC_STD_SENSORS_2B: 674 // Return sensor FRC value 2B 675 if ( sensorError ) 676 return setFRCerror(); 677 678 responseFRCvalue2B = sensorValue ^ 0x8000; 679 break; 680 } 681 682 return TRUE; 683 } 684 685 //############################################################################################ 686 // Sensor index 0: measure temperature using the TR sensor 687 bit Get0_TemperatureTR() 688 //############################################################################################ 689 { 690 // Make sure FSR1 is not modified 691 692 // When error, then adjust the standard error values 693 sensorError = FALSE; 694 // Measure temperature using TR sensor 695 if ( getTemperature() == -128 ) 696 { 697 sensorError = TRUE; 698 STD_SENSOR_TYPE_TEMPERATURE_SET_ERROR( sensorValue ); 699 } 700 else 701 { 702 // Extent minus sign bit 703 if ( param3.11 ) 704 param3 |= 0xF000; 705 // Return sensor value 706 sensorValue = param3; 707 } 708 // Handler FRC 709 return AdjustFrcTemperature(); 710 } 711 712 //############################################################################################ 713 // Sensor index 1: measure temperature using one of the DDC-SE-01 sensors 714 bit Get1_Temperature() 715 //############################################################################################ 716 { 717 // Make sure FSR1 is not modified 718 719 // Measure temperature using DDC-SE-01 sensors 720 sensorError = FALSE; 721 // Read temperature and check for an error 722 GetTemperature(); 723 // When error, return standard (FRC) error value(s) 724 if ( STD_SENSOR_TYPE_TEMPERATURE_IS_ERROR( sensorValue ) ) 725 sensorError = TRUE; 726 727 // FrcValues 728 return AdjustFrcTemperature(); 729 } 730 731 //############################################################################################ 732 bit AdjustFrcBinaryData() 733 //############################################################################################ 734 { 735 // Test for supported FRC commands 736 switch ( _PCMD ) 737 { 738 default: 739 return FALSE; 740 741 case FRC_STD_SENSORS_BIT: 742 // If there is a sensor error, 2-bit FRC cannot indicate it, it returns [01] 743 744 // Number of shifts to get the bit out of the return value 745 uns8 bitLoop = ( INDF1 >> 5 ) + 1; 746 // Value to get the bit from 747 W = sensorValue.low8; 748 do 749 { 750 // Get the bit to Carry 751 W = rr( W ); 752 // Next bit 753 } while ( --bitLoop != 0 ); // Note: must not modify W and Carry 754 // Carry = bit = x 755 // Current (prepared by DPA) FRC value is [01], change it to [1x] 756 responseFRCvalue = rl( responseFRCvalue ); 757 break; 758 759 case FRC_STD_SENSORS_1B: 760 responseFRCvalue = sensorValue.low8 + 4; 761 break; 762 } 763 return TRUE; 764 } 765 766 #if defined( TR7xG ) 767 //############################################################################################ 768 // Might not be needed if ADC registers are kept default 769 void resetADCregs() 770 //############################################################################################ 771 { 772 // Start reseting ADC registers from ADCON0 to ADPCH 773 FSR0 = &ADCON0; 774 do 775 { 776 setINDF0( 0 ); 777 FSR0++; 778 // Stop reseting at 1st GPR register, ADPCH is the last implemented register before GPR 779 } while ( !FSR0L.5 ); 780 } 781 #endif 782 783 //############################################################################################ 784 uns8 ReadAdc() 785 //############################################################################################ 786 { 787 #if defined( TR7xG ) 788 // ADC is enabled, ADGO is cleared upon completion, Clock supplied according to ADCLK register, left-justified 789 ADCON0 = 0b1000.0000; 790 // ADC Conversion Clock = FOSC/8 791 ADCLK = 8 / 2 - 1; 792 #else 793 // ADC result - left justified, Fosc/8 794 ADCON1 = 0b0001.0000; 795 #endif 796 797 // Short delay to stabilize 798 updateCRC16( W ); 799 800 // start ADC 801 _GO = 1; 802 // wait for ADC finish 803 while ( _GO ); 804 return ADRESH; 805 } 806 807 //############################################################################################ 808 // Sensor index 2: returns light intensity indicator value using DDC-SE-01 809 bit Get2_BinaryData_Light() 810 //############################################################################################ 811 { 812 // Make sure FSR1 is not modified 813 814 #if defined( TR7xG ) 815 // Enable ADC 816 ADCMD = 0; 817 // Resets all ADC registers 818 // VREF- is connected to AVSS, VREF+ is connected to VDD 819 resetADCregs(); 820 // ADC Positive Input Channel = ANA0 821 setADPCH( 0x00 ); 822 #else 823 // ADC setting (AN0 channel) 824 ADCON0 = 0b0.00000.01; 825 #endif 826 // ADC initialization (for more info see PIC datasheet) pin C1 (AN0-D/ANA0-G) as analog input 827 ANSELA.0 = 1; 828 // Read ADC 829 sensorValue.low8 = ReadAdc() / 2; 830 // Return sensor FRC value 831 return AdjustFrcBinaryData(); 832 } 833 834 //############################################################################################ 835 // Sensor index 3: returns potentiometer value using DDC-SE-01 836 bit Get3_BinaryData_Potentiometer() 837 //############################################################################################ 838 { 839 // Make sure FSR1 is not modified 840 841 #if defined( TR7xG ) 842 // Enable ADC 843 ADCMD = 0; 844 // Resets all ADC registers 845 // VREF- is connected to AVSS, VREF+ is connected to VDD 846 resetADCregs(); 847 // ADC Positive Input Channel = ANA5 848 setADPCH( 0x05 ); 849 #else 850 // ADC setting (AN4 channel) 851 ADCON0 = 0b0.00100.01; 852 #endif 853 // ADC initialization (for more info see PIC datasheet) pin C5 (AN4-D/ANA5-G) as analog input 854 ANSELA.5 = 1; 855 // Read ADC 856 sensorValue.low8 = ReadAdc() / 2; 857 // Return sensor FRC value 858 return AdjustFrcBinaryData(); 859 } 860 861 //############################################################################################ 862 // OneWire and Dallas 18B20 routines 863 //############################################################################################ 864 865 //############################################################################################ 866 void Delay5us( uns8 val @ W ) // Absolutely precise timing but val != 0 867 //############################################################################################ 868 { 869 // 16 MHz 870 // + 0.75us ( W=val, Call ) 871 for ( ;; ) 872 { // loop time 873 nop2(); // 0.50us 874 nop2(); // 1.00us 875 nop2(); // 1.50us 876 nop2(); // 2.00us 877 nop2(); // 2.50us 878 nop2(); // 3.00us 879 nop(); // 3.25us 880 if ( --val == 0 ) // + 0.75us (W--, BTFS ) 881 return; // + 0.25us 882 nop2(); // 4.50us 883 } // 5.00us (Goto) 884 } 885 //############################################################################################ 886 887 #define OneWireData0() { OneWire_TRIS = 0; } // 0.5us @ 16MHz 888 #define OneWireData1() { OneWire_TRIS = 1; } // 0.5us @ 16MHz 889 890 //############################################################################################ 891 void OneWireWriteByte( uns8 byte ) 892 //############################################################################################ 893 { 894 uns8 bitLoop = 8; 895 do 896 { 897 // Next sequence is time precision critical 898 GIE = FALSE; 899 900 OneWireData0(); 901 nop2(); // 1 us [0.5 us] 902 nop2(); // [1.0 us] 903 if ( byte.0 ) // 2.5 us [1.75us] 904 OneWireData1(); 905 906 // End of time precision critical sequence 907 GIE = TRUE; 908 909 // 60us minimum in total, does not have to be precise 910 Delay5us( ( 60 - 3 ) / 5 + 1 ); 911 912 OneWireData1(); 913 914 byte >>= 1; 915 } while ( --bitLoop != 0 ); 916 } 917 918 //############################################################################################ 919 uns8 OneWireReadByte() 920 //############################################################################################ 921 { 922 uns8 result; 923 uns8 bitLoop = 8; 924 do 925 { 926 // Next sequence is time precision critical 927 GIE = FALSE; 928 929 OneWireData0(); 930 nop2(); // 1 us [0.5 us] 931 nop2(); // [1.0 us] 932 OneWireData1(); // 2 us [1.5 us] 933 Delay5us( 15 / 5 ); // 17 us [16.5 us] 934 935 Carry = 0; // 17.5 us [16.75 us] 936 if ( OneWire_IO_IN ) // 18.5 us [ 17.25 us] (condition must not modify Carry) 937 Carry = 1; 938 939 // End of time precision critical sequence 940 GIE = TRUE; // must not modify Carry 941 result = rr( result ); 942 943 // 60us minimum in total, does not have to be precise 944 Delay5us( ( 60 - 20 ) / 5 + 1 ); 945 } while ( --bitLoop != 0 ); 946 947 return result; 948 } 949 950 //############################################################################################ 951 bit OneWireReset() 952 //############################################################################################ 953 { 954 // Setting the pin once to low is enough 955 OneWire_IO_OUT = 0; 956 // Reset pulse 957 OneWireData0(); 958 Delay5us( 500 / 5 ); 959 // Reset pulse end 960 OneWireData1(); 961 // Next sequence is time precision critical 962 GIE = FALSE; 963 // Wait for presence pulse 964 Delay5us( 70 / 5 ); 965 // End of time precision critical sequence 966 GIE = TRUE; 967 // Presence pulse? 968 if ( OneWire_IO_IN ) 969 { 970 // No presence, finish initialization sequence 971 Delay5us( ( 500 - 70 ) / 5 ); 972 return FALSE; 973 } 974 else 975 { 976 // Presence OK, finish initialization sequence 977 Delay5us( ( 500 - 70 ) / 5 ); 978 return TRUE; 979 } 980 } 981 982 //############################################################################################ 983 void OneWireCmd( uns8 cmd ) 984 //############################################################################################ 985 { 986 // OneWire: Skip ROM 987 OneWireWriteByte( CMD_SKIPROM ); 988 // OneWire: Send command 989 OneWireWriteByte( cmd ); 990 } 991 992 //############################################################################################ 993 bit Ds18B20WriteConfig( uns8 value ) 994 //############################################################################################ 995 { 996 if ( OneWireReset() ) 997 { 998 // Write Scratchpad 999 OneWireCmd( CMD_WSCRATCHPAD ); 1000 1001 // Write TL = ? (we dot not care the value) 1002 OneWireWriteByte( W ); 1003 // Write TH = ? (we dot not care the value) 1004 OneWireWriteByte( W ); 1005 // Write Config byte 1006 OneWireWriteByte( value ); 1007 1008 if ( OneWireReset() ) 1009 { 1010 // Copy Scratchpad 1011 OneWireCmd( CMD_CPYSCRATCHPAD ); 1012 return TRUE; 1013 } 1014 } 1015 return FALSE; 1016 } 1017 1018 //############################################################################################ 1019 void MCP9802GetTemp() 1020 //############################################################################################ 1021 { 1022 STD_SENSOR_TYPE_TEMPERATURE_SET_ERROR( sensorValue ); 1023 1024 // MCP9802 address 1025 _DpaApiI2Cstart( I2C_ADR ); 1026 if ( I2CwasTimeout ) 1027 return; 1028 1029 // pointer: 1 = configuration register 1030 _DpaApiI2Cwrite( 0x01 ); 1031 // configuration: 9-bit ADC 1032 _DpaApiI2CwriteAndStop( 0x00 ); 1033 1034 // MCP9802 address 1035 _DpaApiI2Cstart( I2C_ADR ); 1036 // pointer: 0 = temperature 1037 _DpaApiI2CwriteAndStop( 0 ); 1038 1039 // MCP9802 address + read 1040 _DpaApiI2Cstart( I2C_ADR | 1 ); 1041 // store the result 1042 sensorValue.high8 = _DpaApiI2Cread( TRUE ); 1043 sensorValue.low8 = _DpaApiI2Cread( FALSE ); 1044 _DpaApiI2Cstop(); 1045 } 1046 1047 //############################################################################################ 1048 // Other routines 1049 //############################################################################################ 1050 1051 //############################################################################################ 1052 void GetTemperature() 1053 //############################################################################################ 1054 { 1055 // Reads temperature from an enabled sensor 1056 if ( isDS18B20 ) 1057 // Temperature is ready at the background 1058 sensorValue = temperature; 1059 else 1060 { 1061 // Temperature value must be read from I2C sensor 1062 MCP9802GetTemp(); 1063 if ( !STD_SENSOR_TYPE_TEMPERATURE_IS_ERROR( sensorValue ) ) 1064 { 1065 sensorValue += 0x08; 1066 sensorValue /= 0x10; 1067 } 1068 } 1069 } 1070 1071 //############################################################################################ 1072 // 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) 1073 #include "DPAcustomHandler.h" 1074 //############################################################################################