1 // ******************************************************************* 2 // NFC Library for Custom DPA Handlers, chip is ST25DV04K(C) * 3 // ******************************************************************* 4 // Copyright (c) MICRORISC s.r.o. 5 // 6 // File: $RCSfile: NFC.c,v $ 7 // Version: $Revision: 1.27 $ 8 // Date: $Date: 2025/09/22 15:44:55 $ 9 // 10 // Revision history: 11 // 2025/05/30 Release for DPA 4.33 12 // 2024/11/29 Release for DPA 4.3x 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 // 17 // ********************************************************************* 18 19 #ifndef __I2C_NFC_LIB__ 20 #define __I2C_NFC_LIB__ 21 22 //############################################################################################ 23 24 // Define to avoid deadlock when the NFC chip is not connect to the I2C bus. Pull-up resistors are required anyway! 25 // #define NFC_UPDATE_IGNORE_IF_MISSING 26 27 // I2C chips addresses 28 #define I2C_ADDRESS_NFC 0b1010.0110 29 #define I2C_ADDRESS_NFC_SYS 0b1010.1110 30 31 // Values of IT_STS_Dyn @ ST25DVxxx 32 #define IT_STS_Dyn_RF_USER 0x01 33 #define IT_STS_Dyn_RF_ACTIVITY 0x02 34 #define IT_STS_Dyn_RF_INTERRUPT 0x04 35 #define IT_STS_Dyn_FIELD_FALLING 0x08 36 #define IT_STS_Dyn_FIELD_RISING 0x10 37 #define IT_STS_Dyn_RF_PUT_MSG 0x20 38 #define IT_STS_Dyn_RF_GET_MSG 0x40 39 #define IT_STS_Dyn_RF_WRITE 0x80 40 41 // Supported NFC chip IDs 42 // 0x24 // ST25DV04K (default) 43 // 0x50 // ST25DV04KC 44 45 // NFC chip ID 46 #ifndef NFC_IC_REF 47 #define NFC_IC_REF 0x24 // ST25DV04K 48 #endif 49 50 // NFC routines 51 bit NfcIsPresent(); 52 bit NfcUpdateIQRFcode(); 53 bit NfcConfigure(); 54 void NfcWaitIsReady( uns8 device ); 55 56 // NFC low level routines 57 uns8 NfcReadByte( uns16 addr, uns8 device ); 58 void NfcSysWriteByte( uns8 addrLow, uns8 data ); 59 // Reads bytes to bufferRF 60 void NfcReadBytes( uns16 addr, uns8 length, uns8 device ); 61 // Writes bytes from bufferRF 62 void NfcWriteBytes( uns16 addr, uns8 length, uns8 device ); 63 // Reads regsiter IT_STS_Dyn 64 uns8 NfcRead_IT_STS_Dyn(); 65 66 #ifndef USE_FSRx 67 void setINDF1inc( uns8 data ); 68 #else 69 #define setINDF1inc( data ) do { *FSR1++ = data; } while(0) 70 #endif 71 72 #if DPA_VERSION_MASTER >= 0x0416 73 #define _i2c_start _DpaApiI2Cstart 74 #define _i2c_stop _DpaApiI2Cstop 75 #define _i2c_read _DpaApiI2Cread 76 #define _i2c_write _DpaApiI2Cwrite 77 #define _i2c_waitForIdle _DpaApiI2CwaitForIdle 78 #define _i2c_shutdown _DpaApiI2Cshutdown 79 #else 80 #define _i2c_start i2c_start 81 #define _i2c_stop i2c_stop 82 #define _i2c_read i2c_read 83 #define _i2c_write i2c_write 84 #define _i2c_waitForIdle i2c_waitForIdle 85 #define _i2c_shutdown i2c_shutdown 86 87 #ifndef __I2C_MASTER__ 88 #define __INCLUDE__I2C_MASTER__ 89 #include "lib/I2Cmaster.c" 90 #endif 91 92 #endif 93 94 //############################################################################################ 95 #else 96 97 #pragma library 1 // Compile only used methods 98 99 #ifdef __INCLUDE__I2C_MASTER__ 100 #include "lib/I2Cmaster.c" 101 #endif 102 103 #ifndef USE_FSRx 104 // ############################################################################################ 105 void setINDF1inc( uns8 data @ W ) 106 // ############################################################################################ 107 { 108 #pragma updateBank exit = UserBank_01 109 setINDF1( data ); 110 FSR1++; 111 } 112 #endif 113 114 // ############################################################################################ 115 uns8 NfcCfgByte( uns8 addr @ W ) 116 // ############################################################################################ 117 { 118 skip( addr ); 119 #pragma computedGoto 1 120 121 #if NFC_IC_REF == 0x24 // ST25DV04K 122 return 0xC6; // GPO : GPO-generuje impuls pokud dojde k RF zapisu do EEPROM a RF command EOF to response EOF. 123 return 0x00; // IT_TIME : IT_TIME-delka pulsu GPO 301us - (0x00 * 37.5us) 124 return 0x01; // EH_MODE : EH_MODE-energy harvesting 0x01 na vyzadani 125 return 0x00; // RF_MNGT : RF_MNGT-RF komunikace povolena 126 return 0x0C; // RFA1SS : RFA1SS-Area1 bez hesla a povoleno pouze RF cteni, RF zapis je zakazany (tam prave ulozim IQRF code) 127 return 0x03; // ENDA1 : ENDA1-Area1 adresa 0 až 127B 128 return 0x06; // RFA2SS : RFA2SS-Area2 RF cteni bez hesla a RF zapis s heslem RF_PWD1 (zde je mozne zapsat pouze pomoci RF hesla) 129 return 0x07; // ENDA2 : ENDA2-Area2 adresa 128 až 255B 130 return 0x00; // RFA3SS : RFA3SS-Area3 RF cteni/RF zapis bez hesla 131 return 0x0B; // ENDA3 : ENDA3-Area3 adresa 256 až 383B, zbytek je Area4 384 až 512B 132 //return 0x00; // RFA4SS : RFA4SS-Area4 RF cteni/RF zapis bez hesla (default) 133 //return 0x00; // I2CSS : I2CSS-I2C pristup do pameti bez hesla (default) 134 return 0xFF; // End 135 136 #elif NFC_IC_REF == 0x50 // ST25DV04KC 137 return 0x8D; // GPO1 : GPO-generuje impuls pokud dojde k RF zapisu do EEPROM a RF command EOF to response EOF. 138 return 0x00; // GPO2 : IT_TIME-delka pulsu GPO 301us - (0x00 * 37.5us) 139 return 0x01; // EH_MODE : EH_MODE-energy harvesting 0x01 na vyzadani 140 return 0x00; // RF_MNGT : RF_MNGT-RF komunikace povolena 141 return 0x0C; // RFA1SS : RFA1SS-Area1 bez hesla a povoleno pouze RF cteni, RF zapis je zakazany (tam prave ulozim IQRF code) 142 return 0x03; // ENDA1 : ENDA1-Area1 adresa 0 až 127B 143 return 0x06; // RFA2SS : RFA2SS-Area2 RF cteni bez hesla a RF zapis s heslem RF_PWD1 (zde je mozne zapsat pouze pomoci RF hesla) 144 return 0x07; // ENDA2 : ENDA2-Area2 adresa 128 až 255B 145 return 0x00; // RFA3SS : RFA3SS-Area3 RF cteni/RF zapis bez hesla 146 return 0x0B; // ENDA3 : ENDA3-Area3 adresa 256 až 383B, zbytek je Area4 384 až 512B 147 //return 0x00; // RFA4SS : RFA4SS-Area4 RF cteni/RF zapis bez hesla (default) 148 //return 0x00; // I2CSS : I2CSS-I2C pristup do pameti bez hesla (default) 149 return 0xFF; // End 150 151 #else 152 #error Unsupported NFC chip 153 #endif 154 155 #pragma computedGoto 0 156 } 157 158 //############################################################################################ 159 void nfcConfigureInternal() 160 //############################################################################################ 161 { 162 // Enter I2C password (8x zero) 163 clearBufferRF(); 164 165 // I2C password validation code between 2 repeated passwords 166 bufferRF[8] = 0x09; 167 // Write password (password+0x90+password) 168 NfcWriteBytes( 0x0900, 8 + 1 + 8, I2C_ADDRESS_NFC_SYS ); 169 170 // Check the password was correct (I2C_SSO_Dyn register) 171 if ( ( NfcReadByte( 0x2004/*I2C_SSO_Dyn*/, I2C_ADDRESS_NFC ) & 1/*I2C_SSO*/ ) == 0 ) 172 { 173 _NfcError: 174 // No, pulse both LEDs 175 userReg0 = 0; 176 do 177 { 178 clrwdt(); 179 pulseLEDR(); 180 pulseLEDG(); 181 waitDelay( 20 ); 182 } while ( --userReg0 != 0 ); 183 return; 184 } 185 186 // Now configure NFC 187 uns8 addr = 0; // System configuration memory address 188 for ( ;; ++addr ) 189 { 190 uns8 cfgByte = NfcCfgByte( addr ); 191 if ( cfgByte == 0xFF ) 192 break; 193 194 NfcSysWriteByte( addr, cfgByte ); 195 // Check the configuration was written 196 if ( NfcReadByte( addr, I2C_ADDRESS_NFC_SYS ) != cfgByte ) 197 goto _NfcError; 198 } 199 } 200 201 //############################################################################################ 202 bit NfcIsPresent() 203 //############################################################################################ 204 { 205 return NfcReadByte( 0x0017/* IC_REF */, I2C_ADDRESS_NFC_SYS ) == NFC_IC_REF; 206 } 207 208 //############################################################################################ 209 bit NfcConfigure() 210 //############################################################################################ 211 { 212 #pragma updateBank exit = UserBank_01 213 214 #ifdef NFC_UPDATE_IGNORE_IF_MISSING 215 if ( !NfcIsPresent() ) 216 return Carry; 217 #endif 218 219 nfcConfigureInternal(); 220 return TRUE; 221 } 222 223 //############################################################################################ 224 void moduleInfoAndSetFSRs() 225 //############################################################################################ 226 { 227 #if defined( TR7xG ) || defined( NFC_FULL_IQRF_Code ) 228 getNetworkParams(); 229 #endif 230 moduleInfo(); 231 setFSR01( _FSR_INFO, _FSR_RF ); 232 } 233 234 //############################################################################################ 235 bit NfcUpdateIQRFcode() 236 //############################################################################################ 237 { 238 #if _HWPID_ > 0xFfFf 239 #error _HWPID_ > 0xFfFf 240 #endif 241 242 #if _HWPIDver_ > 0xFfFf 243 #error _HWPIDver_ > 0xFfFf 244 #endif 245 246 #ifdef NFC_UPDATE_IGNORE_IF_MISSING 247 if ( !NfcIsPresent() ) 248 return Carry; 249 #endif 250 251 // ---------------------------------------------------- 252 #if !defined( TR7xG ) && !defined( NFC_FULL_IQRF_Code ) 253 // Old "D" style, when only MID is checked 254 #define IQRFcodeLength ( 1/*Nop+tag*/ + sizeof( ModuleInfo.MID ) + 1/*Nop+tag*/ + 16/*IBK*/ + 1/*Nop+tag*/ + sizeof( uns16 )/*HWPID*/ + 1/*End*/ ) 255 256 // Check MID for the valid IQRF Code at the NFC EEPROM, read user area from address 1 where the reversed (Big Endian) MID is supposed to be 257 uns8 addr = 1 + sizeof( ModuleInfo.MID ); 258 // My MID address to the FSR1 259 #if &ModuleInfo.MID[0] == &bufferINFO[0] 260 moduleInfoAndSetFSRs(); 261 #else 262 #error Cannot optimize FSR to MID address 263 #endif 264 do 265 { 266 // MID matches? 267 if ( NfcReadByte( --addr, I2C_ADDRESS_NFC ) != *FSR0 ) 268 { 269 // No, configure NFC and write IQRF Code 270 nfcConfigureInternal(); 271 272 // Writes IQRF Code to the EEPROM to the address 0, prepare it at bufferRF 273 274 // Prepare MID reversed, i.e. MSB first 275 moduleInfoAndSetFSRs(); 276 FSR0 += offsetof( TModuleInfo, MID ) + sizeof( ModuleInfo.MID ); 277 // Example: 0x15 ,0x81,0x11,0x2f,0x0e 278 setINDF1inc( 0x15 ); // Nop tag + MID tag 279 uns8 loop = sizeof( ModuleInfo.MID ); 280 do { 281 setINDF1inc( *--FSR0 ); 282 } while ( --loop != 0 ); 283 284 // Prepare IBK 285 memoryOffsetFrom |= 16; 286 moduleInfoAndSetFSRs(); 287 FSR1 += 1 + sizeof( ModuleInfo.MID ); 288 // Example: 0x25 ,0xb6,0x03,0x3e,0x8f,0xb0,0x8c,0x9b,0xd1,0x74,0xa1,0x9f,0xc0,0x91,0xb8,0xb9,0xbf 289 setINDF1inc( 0x25 ); // Nop tag + IBK tag 290 loop |= 16; // IBK size 291 do { 292 setINDF1inc( *FSR0++ ); 293 } while ( --loop != 0 ); 294 295 // Prepare HWPID 296 // Example: 0x35 ,0x50,0x02 297 setINDF1inc( 0x35 ); // Nop tag + HWPID tag 298 setINDF1inc( _HWPID_ >> 8 ); 299 setINDF1inc( _HWPID_ & 0xFF ); 300 301 // End tag 302 setINDF1inc( 0 ); 303 304 // Write prepared IQRF Code to NFC EEPROM at address 0 305 NfcWriteBytes( 0, IQRFcodeLength, I2C_ADDRESS_NFC ); 306 307 break; 308 } 309 310 // Note: *FSR0++ cannot be used in the "if" condition above, because CC5X cannot generate code 311 FSR0++; 312 } while ( addr != 1 ); 313 314 #else 315 // ---------------------------------------------------- 316 // non-D line, full IQRF Code is compared, construct IQRF Code at bufferRF 317 #define IQRFcodeLength ( 1/*tags HWPID+MID*/ + sizeof( uns16 )/*HWPID*/ + sizeof( ModuleInfo.MID ) + 1/*tags HWPIDver+IBK*/ + sizeof( uns16 )/*HWPIDver*/ + 16/*IBK*/ + 1/*tags Nop+LogicalAddress*/ + sizeof( ntwADDR )/*LogicalAddress*/ + 1/*End*/ ) 318 319 moduleInfoAndSetFSRs(); 320 321 //// Prepare HWPID 322 // Example: HwpId:ABCD => 0xB3, 0xDA, 0x1C 323 setINDF1inc( ( ( _HWPID_ >> 4 ) & 0xF0 ) | 0x03 ); // HWPID.8-11 + HWPID tag 324 setINDF1inc( ( ( _HWPID_ & 0x0F ) << 4 ) | ( _HWPID_ >> 12 ) ); // HWPID.0-3 + HWPID.12-15 325 setINDF1inc( 0x10 | ( ( _HWPID_ >> 4 ) & 0x0F ) ); // MID tag + HWPID.4-7 326 327 //// Prepare MID reversed, i.e. MSB first 328 FSR0 += offsetof( TModuleInfo, MID ) + sizeof( ModuleInfo.MID ); 329 uns8 loop = sizeof( ModuleInfo.MID ); 330 do { 331 setINDF1inc( *--FSR0 ); 332 } while ( --loop != 0 ); 333 334 //// Prepare HWPIDver 335 // Example: HwpIdver:ABCDE => 0xB8, 0xDA, 0x2C 336 setINDF1inc( ( ( _HWPIDver_ >> 4 ) & 0xF0 ) | 0x08 ); // HWPIDver.8-11 + HWPIDver tag 337 setINDF1inc( (uns8)( ( _HWPIDver_ & 0x0F ) << 4 ) | ( _HWPIDver_ >> 12 ) ); // HWPIDver.0-3 + HWPIDver.12-15 338 setINDF1inc( 0x20 | ( ( _HWPIDver_ >> 4 ) & 0x0F ) ); // IBK tag + HWPIDver.4-7 339 340 //// Prepare IBK 341 memoryOffsetFrom |= 16; 342 moduleInfoAndSetFSRs(); 343 FSR1 += 1/*tags HWPID+MID*/ + sizeof( uns16 )/*HWPID*/ + sizeof( ModuleInfo.MID ) + 1/*tags HWPIDver+IBK*/ + sizeof( uns16 )/*HWPIDver*/; 344 loop |= 16; // IBK size (loop was 0) 345 do { 346 setINDF1inc( *FSR0++ ); 347 } while ( --loop != 0 ); 348 349 //// Prepare logical address 350 setINDF1inc( 0x45 ); // Nop tag + Logical address tag 351 W = 0; // Coordinator address 352 // Not Coordinator( _networkingMode == 1 && _networkTwo == 0 ) ? 353 if ( _networkingMode != 1 || _networkTwo != 0 ) // Note: must not modify W 354 { 355 Carry = amIBonded(); 356 W = ntwADDR; // Bonded value, Note: must not modify Carry 357 if ( !Carry ) // Note: must not modify W 358 W = 0xFF; // Not bonded value 359 } 360 setINDF1inc( W ); 361 362 //// End tag 363 setINDF1inc( 0 ); 364 // FSR1 is behind the end of generated IQRF Code 365 366 // loop used both as counter and NFC address 367 loop = IQRFcodeLength; 368 do 369 { 370 FSR1--; 371 // IQRF Code matches byte by byte? 372 if ( NfcReadByte( --loop, I2C_ADDRESS_NFC ) != *FSR1 ) 373 { 374 // No, set IQRF Code aside 375 copyBufferRF2INFO(); 376 // Configure NFC chip 377 nfcConfigureInternal(); 378 // Get IQRF Code back 379 copyBufferINFO2RF(); 380 // Write prepared IQRF Code to NFC EEPROM at address 0 381 NfcWriteBytes( 0, IQRFcodeLength, I2C_ADDRESS_NFC ); 382 break; 383 } 384 } while ( loop != 0 ); 385 #endif 386 // ---------------------------------------------------- 387 388 #undef IQRFcodeLength 389 return TRUE; 390 } 391 392 //############################################################################################ 393 void NfcWaitIsReady( uns8 device ) 394 //############################################################################################ 395 { 396 do 397 { 398 _i2c_start( device ); 399 _i2c_waitForIdle(); 400 #if defined( TR7xG ) || defined( TR8xG ) 401 } while ( SSP1CON2.6 /*ACKSTAT*/ ); 402 #else 403 } while ( ACKSTAT ); 404 #endif 405 } 406 407 //############################################################################################ 408 void NfcWaitIsReadyStop( uns8 device @ W ) 409 //############################################################################################ 410 { 411 NfcWaitIsReady( device ); 412 _i2c_stop(); 413 } 414 415 //############################################################################################ 416 void NfcSysWriteByte( uns8 addrLow, uns8 data ) 417 //############################################################################################ 418 { 419 NfcWaitIsReady( I2C_ADDRESS_NFC_SYS ); 420 _i2c_write( 0 ); 421 _i2c_write( addrLow ); 422 _i2c_write( data ); 423 _i2c_stop(); 424 NfcWaitIsReadyStop( I2C_ADDRESS_NFC_SYS ); 425 } 426 427 //############################################################################################ 428 uns8 NfcReadByte( uns16 addr, uns8 device ) 429 //############################################################################################ 430 { 431 #pragma updateBank exit = UserBank_01 432 NfcWaitIsReady( device ); 433 _i2c_write( addr.high8 ); 434 _i2c_write( addr.low8 ); 435 _i2c_start( device | 1 ); 436 uns8 data = _i2c_read( FALSE ); 437 _i2c_stop(); 438 return data; 439 } 440 441 //############################################################################################ 442 uns8 NfcRead_IT_STS_Dyn() 443 //############################################################################################ 444 { 445 return NfcReadByte( 0x2005 /* IT_STS_Dyn */, I2C_ADDRESS_NFC ); 446 } 447 448 //############################################################################################ 449 void NfcWriteBytes( uns16 addr, uns8 length, uns8 device ) 450 //############################################################################################ 451 { 452 NfcWaitIsReady( device ); 453 _i2c_write( addr.high8 ); 454 _i2c_write( addr.low8 ); 455 setFSR1( _FSR_RF ); 456 do { 457 _i2c_write( *FSR1++ ); 458 } while ( --length != 0 ); 459 _i2c_stop(); 460 NfcWaitIsReadyStop( device ); 461 } 462 463 //############################################################################################ 464 void NfcReadBytes( uns16 addr, uns8 length, uns8 device ) 465 //############################################################################################ 466 { 467 NfcWaitIsReady( device ); 468 _i2c_write( addr.high8 ); 469 _i2c_write( addr.low8 ); 470 _i2c_start( device | 1 ); 471 setFSR1( _FSR_RF ); 472 do { 473 setINDF1inc( _i2c_read( length != 1 ) ); 474 } while ( --length != 0 ); 475 _i2c_stop(); 476 } 477 //############################################################################################ 478 479 #pragma library 0 480 481 #endif 482 //############################################################################################