1# 小凌派-RK2206开发板基础外设开发——I2C控制EEPROM读写 2 3本示例将演示如何在小凌派-RK2206开发板上使用I2C控制EEPROM读写 4 5 6 7## 程序设计 8 9### API分析 10 11#### eeprom_init() 12 13```c 14unsigned int eeprom_init(); 15``` 16 17**描述:** 18 19EEPROM初始化,包括i2c初始化。 20 21**参数:** 22 23无 24 25**返回值:** 26 270为成功,反之失败 28 29#### eeprom_deinit() 30 31```c 32unsigned int eeprom_deinit(); 33``` 34 35**描述:** 36 37EEPROM注销。 38 39**参数:** 40 41无 42 43**返回值:** 44 450为成功,反之失败 46 47#### eeprom_get_blocksize() 48 49```c 50unsigned int eeprom_get_blocksize(); 51``` 52 53**描述:** 54 55EEPROM获取页大小。 56 57**参数:** 58 59无 60 61**返回值:** 62 63返回页大小。 64 65#### eeprom_readbyte() 66 67```c 68unsigned int eeprom_readbyte(unsigned int addr, unsigned char *data); 69``` 70 71**描述:** 72 73EEPROM读一个字节。 74 75**参数:** 76 77* addr:EEPROM存储地址 78* data: 存放EERPOM的数据指针 79 80**返回值:** 81 82返回读取字节的长度,反之为错误。 83 84#### eeprom_writebyte() 85 86```c 87unsigned int eeprom_writebyte(unsigned int addr, unsigned char data); 88``` 89 90**描述:** 91 92EEPROM写一个字节。 93 94**参数:** 95 96* addr:EEPROM存储地址 97* data: 写ERPOM的数据 98 99**返回值:** 100 101返回写入字节的长度,反之为错误。 102 103#### eeprom_writepage() 104 105```c 106unsigned int eeprom_writepage(unsigned int addr, 107 unsigned char *data, 108 unsigned int data_len); 109``` 110 111**描述:** 112 113EEPROM写1个页字节。 114 115**参数:** 116 117* addr: EEPROM存储地址,必须是页地址 118* data: 写ERPOM的数据指针 119* data_len: 写EEPROM数据的长度,必须是小于或等于1个页大小 120 121**返回值:** 122 123返回写入字节的长度,反之为错误。 124 125#### eeprom_read() 126 127```c 128unsigned int eeprom_read(unsigned int addr, 129 unsigned char *data, 130 unsigned int data_len); 131``` 132 133**描述:** 134 135EEPROM读多个字节。 136 137**参数:** 138 139* addr: EEPROM存储地址,必须是页地址 140* data: 存放EERPOM的数据指针 141* data_len: 读取EERPOM数据的长度 142 143**返回值:** 144 145返回读取字节的长度,反之为错误。 146 147#### eeprom_write() 148 149```c 150unsigned int eeprom_write(unsigned int addr, 151 unsigned char *data, 152 unsigned int data_len); 153``` 154 155**描述:** 156 157EEPROM写多个字节。 158 159**参数:** 160 161* addr: EEPROM存储地址,必须是页地址 162* data: 写ERPOM的数据指针 163* data_len: 写EEPROM数据的长度 164 165**返回值:** 166 167返回写入数据的长度,反之为错误。 168 169### 主要代码分析 170 171#### i2c初始化源代码分析 172 173这部分代码为i2c初始化的代码。首先用 `I2cIoInit()` 函数将GPIO0_PA0复用为I2C0_SDA_M2,GPIO0_PA1复用为I2C1_SCL_M2。最后调用 `LzI2cInit()`函数初始化I2C1端口。 174 175```c 176if (I2cIoInit(m_i2cBus) != LZ_HARDWARE_SUCCESS) { 177 printf("%s, %d: I2cIoInit failed!\n", __FILE__, __LINE__); 178 return __LINE__; 179} 180if (LzI2cInit(EEPROM_I2C_BUS, m_i2c_freq) != LZ_HARDWARE_SUCCESS) { 181 printf("%s, %d: I2cIoInit failed!\n", __FILE__, __LINE__); 182 return __LINE__; 183} 184``` 185 186#### K24C02读操作 187 188本模块只采用K24C02读模式的连续读数据(Sequential Read)。具体如何控制i2c读K24C02数据的操作如下: 189 190```c 191/*************************************************************** 192* 函数名称: eeprom_readbyte 193* 说 明: EEPROM读一个字节 194* 参 数: 195* @addr: EEPROM存储地址 196* @data: 存放EERPOM的数据指针 197* 返 回 值: 返回读取字节的长度,反之为错误 198***************************************************************/ 199unsigned int eeprom_readbyte(unsigned int addr, unsigned char *data) 200{ 201 unsigned int ret = 0; 202 unsigned char buffer[1]; 203 LzI2cMsg msgs[2]; 204 205 /* K24C02的存储地址是0~255 */ 206 if (addr >= EEPROM_ADDRESS_MAX) { 207 printf("%s, %s, %d: addr(0x%x) >= EEPROM_ADDRESS_MAX(0x%x)\n", __FILE__, __func__, __LINE__, addr, EEPROM_ADDRESS_MAX); 208 return 0; 209 } 210 211 buffer[0] = (unsigned char)addr; 212 213 msgs[0].addr = EEPROM_I2C_ADDRESS; 214 msgs[0].flags = 0; 215 msgs[0].buf = &buffer[0]; 216 msgs[0].len = 1; 217 218 msgs[1].addr = EEPROM_I2C_ADDRESS; 219 msgs[1].flags = I2C_M_RD; 220 msgs[1].buf = data; 221 msgs[1].len = 1; 222 223 ret = LzI2cTransfer(EEPROM_I2C_BUS, msgs, 2); 224 if (ret != LZ_HARDWARE_SUCCESS) { 225 printf("%s, %s, %d: LzI2cTransfer failed(%d)!\n", __FILE__, __func__, __LINE__, ret); 226 return 0; 227 } 228 229 return 1; 230} 231``` 232 233#### K24C02写操作 234 235本模块采用K24C02写模式的字节写操作(Byte Write)。具体如何控制i2c往K24C02写字节的操作如下: 236 237```c 238/*************************************************************** 239* 函数名称: eeprom_writebyte 240* 说 明: EEPROM写一个字节 241* 参 数: 242* @addr: EEPROM存储地址 243* @data: 写EERPOM的数据 244* 返 回 值: 返回写入数据的长度,反之为错误 245***************************************************************/ 246unsigned int eeprom_writebyte(unsigned int addr, unsigned char data) 247{ 248 unsigned int ret = 0; 249 LzI2cMsg msgs[1]; 250 unsigned char buffer[2]; 251 252 /* K24C02的存储地址是0~255 */ 253 if (addr >= EEPROM_ADDRESS_MAX) { 254 printf("%s, %s, %d: addr(0x%x) >= EEPROM_ADDRESS_MAX(0x%x)\n", __FILE__, __func__, __LINE__, addr, EEPROM_ADDRESS_MAX); 255 return 0; 256 } 257 258 buffer[0] = (unsigned char)(addr & 0xFF); 259 buffer[1] = data; 260 261 msgs[0].addr = EEPROM_I2C_ADDRESS; 262 msgs[0].flags = 0; 263 msgs[0].buf = &buffer[0]; 264 msgs[0].len = 2; 265 266 ret = LzI2cTransfer(EEPROM_I2C_BUS, msgs, 1); 267 if (ret != LZ_HARDWARE_SUCCESS) { 268 printf("%s, %s, %d: LzI2cTransfer failed(%d)!\n", __FILE__, __func__, __LINE__, ret); 269 return 0; 270 } 271 272 /* K24C02芯片需要时间完成写操作,在此之前不响应其他操作*/ 273 eeprog_delay_usec(1000); 274 275 return 1; 276} 277``` 278 279本模块采用K24C02写模式的页写操作(Page Write)。具体如何控制i2c往K24C02写页的操作如下: 280 281```c 282/*************************************************************** 283* 函数名称: eeprom_writepage 284* 说 明: EEPROM写1个页字节 285* 参 数: 286* @addr: EEPROM存储地址,必须是页地址 287* @data: 写EERPOM的数据指针 288* @data_len: 写EEPROM数据的长度,必须是小于1个页大小 289* 返 回 值: 返回写入数据的长度,反之为错误 290***************************************************************/ 291unsigned int eeprom_writepage(unsigned int addr, unsigned char *data, unsigned int data_len) 292{ 293 unsigned int ret = 0; 294 LzI2cMsg msgs[1]; 295 unsigned char buffer[EEPROM_PAGE + 1]; 296 297 /* K24C02的存储地址是0~255 */ 298 if (addr >= EEPROM_ADDRESS_MAX) { 299 printf("%s, %s, %d: addr(0x%x) >= EEPROM_ADDRESS_MAX(0x%x)\n", __FILE__, __func__, __LINE__, addr, EEPROM_ADDRESS_MAX); 300 return 0; 301 } 302 303 if ((addr % EEPROM_PAGE) != 0) { 304 printf("%s, %s, %d: addr(0x%x) is not page addr(0x%x)\n", __FILE__, __func__, __LINE__, addr, EEPROM_PAGE); 305 return 0; 306 } 307 308 if ((addr + data_len) > EEPROM_ADDRESS_MAX) { 309 printf("%s, %s, %d: addr + data_len(0x%x) > EEPROM_ADDRESS_MAX(0x%x)\n", __FILE__, __func__, __LINE__, addr + data_len, EEPROM_ADDRESS_MAX); 310 return 0; 311 } 312 313 if (data_len > EEPROM_PAGE) { 314 printf("%s, %s, %d: data_len(%d) > EEPROM_PAGE(%d)\n", __FILE__, __func__, __LINE__, data_len, EEPROM_PAGE); 315 return 0; 316 } 317 318 buffer[0] = addr; 319 memcpy(&buffer[1], data, data_len); 320 321 msgs[0].addr = EEPROM_I2C_ADDRESS; 322 msgs[0].flags = 0; 323 msgs[0].buf = &buffer[0]; 324 msgs[0].len = 1 + data_len; 325 326 ret = LzI2cTransfer(EEPROM_I2C_BUS, msgs, 1); 327 if (ret != LZ_HARDWARE_SUCCESS) { 328 printf("%s, %s, %d: LzI2cTransfer failed(%d)!\n", __FILE__, __func__, __LINE__, ret); 329 return 0; 330 } 331 332 /* K24C02芯片需要时间完成写操作,在此之前不响应其他操作*/ 333 eeprog_delay_usec(1000); 334 335 return data_len; 336} 337``` 338 339## 编译调试 340 341### 修改 BUILD.gn 文件 342 343修改 `vendor/lockzhiner/lingpi/sample` 路径下 BUILD.gn 文件,指定 `b3_eeprom` 参与编译。 344 345```r 346"b3_eeprom", 347``` 348 349在主目录下输入编译命令。 350 351```shell 352hb build -f 353``` 354 355### 运行结果 356 357示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,显示如下: 358 359```c 360************ Eeprom Process ************ 361BlockSize = 0x8 362Write Byte: 3 = ! 363Write Byte: 4 = " 364Write Byte: 5 = # 365Write Byte: 6 = $ 366Write Byte: 7 = % 367Write Byte: 8 = & 368Write Byte: 9 = ' 369Write Byte: 10 = ( 370Write Byte: 11 = ) 371Write Byte: 12 = * 372Write Byte: 13 = + 373Write Byte: 14 = , 374Write Byte: 15 = - 375Write Byte: 16 = . 376Write Byte: 17 = / 377Write Byte: 18 = 0 378Write Byte: 19 = 1 379Write Byte: 20 = 2 380Write Byte: 21 = 3 381Write Byte: 22 = 4 382Write Byte: 23 = 5 383Write Byte: 24 = 6 384Write Byte: 25 = 7 385Write Byte: 26 = 8 386Write Byte: 27 = 9 387Write Byte: 28 = : 388Write Byte: 29 = ; 389Write Byte: 30 = < 390Write Byte: 31 = = 391Write Byte: 32 = > 392Read Byte: 3 = ! 393Read Byte: 4 = " 394Read Byte: 5 = # 395Read Byte: 6 = $ 396Read Byte: 7 = % 397Read Byte: 8 = & 398Read Byte: 9 = ' 399Read Byte: 10 = ( 400Read Byte: 11 = ) 401Read Byte: 12 = * 402Read Byte: 13 = + 403Read Byte: 14 = , 404Read Byte: 15 = - 405Read Byte: 16 = . 406Read Byte: 17 = / 407Read Byte: 18 = 0 408Read Byte: 19 = 1 409Read Byte: 20 = 2 410Read Byte: 21 = 3 411Read Byte: 22 = 4 412Read Byte: 23 = 5 413Read Byte: 24 = 6 414Read Byte: 25 = 7 415Read Byte: 26 = 8 416Read Byte: 27 = 9 417Read Byte: 28 = : 418Read Byte: 29 = ; 419Read Byte: 30 = < 420Read Byte: 31 = = 421Read Byte: 32 = > 422``` 423