1 // ******************************************************************* 2 // NFC Library for Custom DPA Handlers, chip is ST25DV04K * 3 // ******************************************************************* 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: NFC.c,v $ 7 // Version: $Revision: 1.3 $ 8 // Date: $Date: 2020/03/20 12:07:39 $ 9 // 10 // Revision history: 11 // 2020/01/02 Release for DPA 4.11 12 // 13 // ********************************************************************* 14 15 #ifndef __I2C_NFC_LIB__ 16 #define __I2C_NFC_LIB__ 17 18 //############################################################################################ 19 20 // Define to avoid deadlock when the NFC chip is not connect to the I2C bus. Pull-up resistors are required anyway! 21 // #define NFC_UPDATE_IGNORE_IF_MISSING 22 23 // I2C chips addresses 24 #define I2C_ADDRESS_NFC 0b10100110 25 #define I2C_ADDRESS_NFC_SYS 0b10101110 26 27 // NFC chip ID 28 #ifndef NFC_IC_REF 29 #define NFC_IC_REF 0x24 // = ST25DV04K 30 #endif 31 32 // NFC routines 33 void NfcUpdateIQRFcode(); 34 35 // NFC low level routines 36 uns8 NfcReadByte( uns16 addr, uns8 device ); 37 void NfcSysWriteByte( uns8 addrLow, uns8 data ); 38 void NfcWriteBytes( uns16 addr, uns8 length, uns8 device ); 39 uns8 NfcCfgByte( uns8 addr ); 40 void setINDF1inc( uns8 data ); 41 42 //############################################################################################ 43 #else 44 45 #pragma library 1 // Compile only used methods 46 47 //############################################################################################ 48 void NfcUpdateIQRFcode() 49 //############################################################################################ 50 { 51 #ifdef NFC_UPDATE_IGNORE_IF_MISSING 52 if ( NfcReadByte( 0x0017 /* IC_REF */, I2C_ADDRESS_NFC_SYS ) != NFC_IC_REF ) 53 return; 54 #endif 55 56 // 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 57 uns8 addr = 1 + sizeof( ModuleInfo.MID ); 58 // My MID address to the FSR1 59 #if &ModuleInfo.MID[0] == &bufferINFO[0] 60 moduleInfo(); 61 setFSR1( _FSR_INFO ); 62 #else 63 #error Cannot optimize FSR to MID address 64 #endif 65 do 66 { 67 // MID matches? 68 if ( NfcReadByte( --addr, I2C_ADDRESS_NFC ) != *FSR1 ) 69 { 70 // No, configure NFC and write IQRF Code 71 72 // Enter I2C password (8x zero) 73 clearBufferRF(); 74 // I2C password validation code between 2 repeated passwords 75 bufferRF[8] = 0x09; 76 // Write password (password+0x90+password) 77 NfcWriteBytes( 0x0900, 8 + 1 + 8, I2C_ADDRESS_NFC_SYS ); 78 79 // Check the password was correct (I2C_SSO_Dyn register) 80 if ( NfcReadByte( 0x2004, I2C_ADDRESS_NFC ) != 1 ) 81 { 82 _NfcError: 83 // No, pulse both LEDs 84 pulsingLEDR(); 85 pulsingLEDG(); 86 for ( ;; ); 87 } 88 89 // Now configure NFC 90 addr = 0 /* GPO register */; 91 do { 92 uns8 cfgByte = NfcCfgByte( addr ); 93 NfcSysWriteByte( addr, cfgByte ); 94 // Check the configuration was written 95 if ( NfcReadByte( addr, I2C_ADDRESS_NFC_SYS ) != cfgByte ) 96 goto _NfcError; 97 } while ( ++addr != ( 0x0B /* I2CSS-I2C register */ + 1 ) ); 98 99 // Writes IQRF Code to the EEPROM to the address 0, prepare it at bufferRF 100 101 // Prepare MID reversed, i.e. MSB first 102 setFSR01( _FSR_INFO, _FSR_RF ); 103 FSR0 += offsetof( TModuleInfo, MID ) + sizeof( ModuleInfo.MID ); 104 // Example: 0x15 ,0x81,0x11,0x2f,0x0e 105 setINDF1inc( 0x15 ); // Nop tag + MID tag 106 uns8 loop = sizeof( ModuleInfo.MID ); 107 do { 108 setINDF1inc( *--FSR0 ); 109 } while ( --loop != 0 ); 110 111 // Prepare IBK 112 memoryOffsetFrom |= 16; 113 moduleInfo(); // FSR0 = BUFFER_INFO = IBK 114 setFSR01( _FSR_INFO, _FSR_RF ); 115 FSR1 += 1 + sizeof( ModuleInfo.MID ); 116 // Example: 0x25 ,0xb6,0x03,0x3e,0x8f,0xb0,0x8c,0x9b,0xd1,0x74,0xa1,0x9f,0xc0,0x91,0xb8,0xb9,0xbf 117 setINDF1inc( 0x25 ); // Nop tag + IBK tag 118 loop = 16; // IBK size 119 do { 120 setINDF1inc( *FSR0++ ); 121 } while ( --loop != 0 ); 122 123 // Prepare HWPID 124 // Example: 0x35 ,0x50,0x02 125 setINDF1inc( 0x35 ); // Nop tag + HWPID tag 126 setINDF1inc( _HWPID_ >> 8 ); 127 setINDF1inc( _HWPID_ & 0xFF ); 128 129 // End tag 130 setINDF1inc( 0 ); 131 132 // Write prepared IQRF Code to NFC EEPROM at address 0 133 NfcWriteBytes( 0, 1 + sizeof( ModuleInfo.MID ) + 1 + 16 + 1 + sizeof( _HWPID ) + 1, I2C_ADDRESS_NFC ); 134 135 return; 136 } 137 138 // Note: *FSR1++ cannot be used in the "if" condition above, because CC5X cannot generate code 139 FSR1++; 140 } while ( addr != 1 ); 141 } 142 143 //############################################################################################ 144 void NfcWaitIsReady() 145 //############################################################################################ 146 { 147 i2c_stop(); 148 do 149 { 150 i2c_start( I2C_ADDRESS_NFC ); 151 i2c_waitForIdle(); 152 } while ( ACKSTAT ); 153 i2c_stop(); 154 } 155 156 //############################################################################################ 157 void NfcSysWriteByte( uns8 addrLow, uns8 data ) 158 //############################################################################################ 159 { 160 i2c_start( I2C_ADDRESS_NFC_SYS ); 161 i2c_write( 0 ); 162 i2c_write( addrLow ); 163 i2c_write( data ); 164 NfcWaitIsReady(); 165 } 166 167 //############################################################################################ 168 uns8 NfcReadByte( uns16 addr, uns8 device ) 169 //############################################################################################ 170 { 171 i2c_start( device ); 172 i2c_write( addr.high8 ); 173 i2c_write( addr.low8 ); 174 i2c_start( device | 1 ); 175 uns8 data = i2c_read( FALSE ); 176 i2c_stop(); 177 return data; 178 } 179 180 //############################################################################################ 181 void NfcWriteBytes( uns16 addr, uns8 length, uns8 device @ W ) 182 //############################################################################################ 183 { 184 i2c_start( device ); 185 i2c_write( addr.high8 ); 186 i2c_write( addr.low8 ); 187 setFSR1( _FSR_RF ); 188 do { 189 i2c_write( *FSR1++ ); 190 } while ( --length != 0 ); 191 NfcWaitIsReady(); 192 } 193 194 // ############################################################################################ 195 uns8 NfcCfgByte( uns8 addr @ W ) 196 // ############################################################################################ 197 { 198 skip( addr ); 199 #pragma computedGoto 1 200 return 0xC4; // GPO-generuje impuls pokud dojde k RF zapisu do EEPROM 201 return 0x00; // IT_TIME-delka pulsu GPO 301us - (0x00 * 37.5us) 202 return 0x01; // EH_MODE-energy harvesting 0x01 na vyzadani 203 return 0x00; // RF_MNGT-RF komunikace povolena 204 return 0x0C; // RFA1SS-Area1 bez hesla a povoleno pouze RF cteni, RF zapis je zakazany (tam prave ulozim IQRF code) 205 return 0x03; // ENDA1-Area1 adresa 0 až 127B 206 return 0x06; // RFA2SS-Area2 RF cteni bez hesla a RF zapis s heslem RF_PWD1 (zde je mozne zapsat pouze pomoci RF hesla) 207 return 0x07; // ENDA2-Area2 adresa 128 až 255B 208 return 0x00; // RFA3SS-Area3 RF cteni/RF zapis bez hesla 209 return 0x0B; // ENDA3-Area3 adresa 256 až 383B, zbytek je Area4 384 až 512B 210 return 0x00; // RFA4SS-Area4 RF cteni/RF zapis bez hesla 211 return 0x00; // I2CSS-I2C pristup do pameti bez hesla 212 #pragma computedGoto 0 213 } 214 215 #ifndef USE_FSRx 216 // ############################################################################################ 217 void setINDF1inc( uns8 data @ W ) 218 // ############################################################################################ 219 { 220 setINDF1( data ); 221 FSR1++; 222 } 223 #else 224 #define setINDF1inc( data ) do { *FSR1++ = data; } while(0) 225 #endif 226 227 #pragma library 0 228 229 #endif 230 //############################################################################################