• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 FuZhou Lockzhiner Electronic Co., Ltd. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "lz_hardware.h"
16 
17 #define EEPROM_I2C_BUS          0
18 #define EEPROM_I2C_ADDRESS      0x51
19 
20 /* EEPROM型号:K24C02,2Kbit(256Byte),32页,每页8个字节(Byte) */
21 #define EEPROM_ADDRESS_MAX      256
22 #define EEPROM_PAGE             8
23 
24 static I2cBusIo m_i2cBus = {
25     .scl =  {
26         .gpio = GPIO0_PA1,
27         .func = MUX_FUNC3,
28         .type = PULL_NONE,
29         .drv = DRIVE_KEEP,
30         .dir = LZGPIO_DIR_KEEP,
31         .val = LZGPIO_LEVEL_KEEP
32     },
33     .sda =  {
34         .gpio = GPIO0_PA0,
35         .func = MUX_FUNC3,
36         .type = PULL_NONE,
37         .drv = DRIVE_KEEP,
38         .dir = LZGPIO_DIR_KEEP,
39         .val = LZGPIO_LEVEL_KEEP
40     },
41     .id = FUNC_ID_I2C0,
42     .mode = FUNC_MODE_M2,
43 };
44 
45 static unsigned int m_i2c_freq = 100000;
46 
47 /* 等待时间 */
48 #define EEPROG_DELAY_USEC       1
49 #define K24C02_DELAY_USEC       1000
50 
51 /***************************************************************
52 * 函数名称: eeprog_delay_usec
53 * 说    明: 忙等待usec
54 * 参    数:
55 *       @usec:等待时间,单位:usec
56 * 返 回 值: 无
57 ***************************************************************/
eeprog_delay_usec(unsigned int usec)58 static inline void eeprog_delay_usec(unsigned int usec)
59 {
60     for (unsigned int i = 0; i < usec; i++) {
61         HAL_DelayUs(EEPROG_DELAY_USEC);
62     }
63 }
64 
65 /***************************************************************
66 * 函数名称: eeprom_init
67 * 说    明: EEPROM初始化
68 * 参    数: 无
69 * 返 回 值: 0为成功,反之为失败
70 ***************************************************************/
eeprom_init(void)71 unsigned int eeprom_init(void)
72 {
73     if (I2cIoInit(m_i2cBus) != LZ_HARDWARE_SUCCESS) {
74         printf("%s, %d: I2cIoInit failed!\n", __FILE__, __LINE__);
75         return __LINE__;
76     }
77     if (LzI2cInit(EEPROM_I2C_BUS, m_i2c_freq) != LZ_HARDWARE_SUCCESS) {
78         printf("%s, %d: I2cInit failed!\n", __FILE__, __LINE__);
79         return __LINE__;
80     }
81 
82     /* GPIO0_A0 => I2C1_SDA_M1 */
83     PinctrlSet(GPIO0_PA0, MUX_FUNC3, PULL_NONE, DRIVE_KEEP);
84     /* GPIO0_A1 => I2C1_SCL_M1 */
85     PinctrlSet(GPIO0_PA1, MUX_FUNC3, PULL_NONE, DRIVE_KEEP);
86 
87     return 0;
88 }
89 
90 /***************************************************************
91 * 函数名称: eeprom_deinit
92 * 说    明: EEPROM退出
93 * 参    数: 无
94 * 返 回 值: 0为成功,反之失败
95 ***************************************************************/
eeprom_deinit(void)96 unsigned int eeprom_deinit(void)
97 {
98     LzI2cDeinit(EEPROM_I2C_BUS);
99     LzGpioDeinit(m_i2cBus.scl.gpio);
100     LzGpioDeinit(m_i2cBus.sda.gpio);
101     return 0;
102 }
103 
104 /***************************************************************
105 * 函数名称: eeprom_get_blocksize
106 * 说    明: EEPROM获取页大小
107 * 参    数: 无
108 * 返 回 值: 返回页大小
109 ***************************************************************/
eeprom_get_blocksize(void)110 unsigned int eeprom_get_blocksize(void)
111 {
112     return EEPROM_PAGE;
113 }
114 
115 /***************************************************************
116 * 函数名称: eeprom_readbyte
117 * 说    明: EEPROM读一个字节
118 * 参    数:
119 *           @addr: EEPROM存储地址
120 *           @data: 存放EERPOM的数据指针
121 * 返 回 值: 返回读取字节的长度,反之为错误
122 ***************************************************************/
eeprom_readbyte(unsigned int addr,unsigned char * data)123 unsigned int eeprom_readbyte(unsigned int addr, unsigned char *data)
124 {
125 #define LZ_I2C_MSG_MAXSIZE      2
126     unsigned int ret = 0;
127     unsigned char buffer[1];
128     LzI2cMsg msgs[LZ_I2C_MSG_MAXSIZE];
129 
130     /* K24C02的存储地址是0~255 */
131     if (addr >= EEPROM_ADDRESS_MAX) {
132         printf("%s, %s, %d: addr(0x%x) >= EEPROM_ADDRESS_MAX(0x%x)\n",
133             __FILE__, __func__, __LINE__, addr, EEPROM_ADDRESS_MAX);
134         return 0;
135     }
136 
137     buffer[0] = (unsigned char)addr;
138 
139     msgs[0].addr = EEPROM_I2C_ADDRESS;
140     msgs[0].flags = 0;
141     msgs[0].buf = &buffer[0];
142     msgs[0].len = 1;
143 
144     msgs[1].addr = EEPROM_I2C_ADDRESS;
145     msgs[1].flags = I2C_M_RD;
146     msgs[1].buf = data;
147     msgs[1].len = 1;
148 
149     ret = LzI2cTransfer(EEPROM_I2C_BUS, msgs, LZ_I2C_MSG_MAXSIZE);
150     if (ret != LZ_HARDWARE_SUCCESS) {
151         printf("%s, %s, %d: LzI2cTransfer failed(%d)!\n", __FILE__, __func__, __LINE__, ret);
152         return 0;
153     }
154 
155     return 1;
156 }
157 
158 /***************************************************************
159 * 函数名称: eeprom_writebyte
160 * 说    明: EEPROM写一个字节
161 * 参    数:
162 *           @addr: EEPROM存储地址
163 *           @data: 写EERPOM的数据
164 * 返 回 值: 返回写入数据的长度,反之为错误
165 ***************************************************************/
eeprom_writebyte(unsigned int addr,unsigned char data)166 unsigned int eeprom_writebyte(unsigned int addr, unsigned char data)
167 {
168 #define BUFFER_MAXSIZE              2       /* 字符串长度 */
169 #define K24C02_WRITE_WAIT_USEC      1000    /* K24C02芯片写完成的等待时间 */
170     unsigned int ret = 0;
171     LzI2cMsg msgs[1];
172     unsigned char buffer[BUFFER_MAXSIZE];
173 
174     /* K24C02的存储地址是0~255 */
175     if (addr >= EEPROM_ADDRESS_MAX) {
176         printf("%s, %s, %d: addr(0x%x) >= EEPROM_ADDRESS_MAX(0x%x)\n",
177             __FILE__, __func__, __LINE__, addr, EEPROM_ADDRESS_MAX);
178         return 0;
179     }
180 
181     buffer[0] = (unsigned char)(addr & 0xFF);
182     buffer[1] = data;
183 
184     msgs[0].addr = EEPROM_I2C_ADDRESS;
185     msgs[0].flags = 0;
186     msgs[0].buf = &buffer[0];
187     msgs[0].len = BUFFER_MAXSIZE;
188 
189     ret = LzI2cTransfer(EEPROM_I2C_BUS, msgs, 1);
190     if (ret != LZ_HARDWARE_SUCCESS) {
191         printf("%s, %s, %d: LzI2cTransfer failed(%d)!\n", __FILE__, __func__, __LINE__, ret);
192         return 0;
193     }
194 
195     /* K24C02芯片需要时间完成写操作,在此之前不响应其他操作 */
196     eeprog_delay_usec(K24C02_WRITE_WAIT_USEC);
197 
198     return 1;
199 }
200 
201 /***************************************************************
202 * 函数名称: eeprom_writepage
203 * 说    明: EEPROM写1个页字节
204 * 参    数:
205 *           @addr: EEPROM存储地址,必须是页地址
206 *           @data: 写EERPOM的数据指针
207 *           @data_len: 写EEPROM数据的长度,必须是小于1个页大小
208 * 返 回 值: 返回写入数据的长度,反之为错误
209 ***************************************************************/
eeprom_writepage(unsigned int addr,unsigned char * data,unsigned int data_len)210 unsigned int eeprom_writepage(unsigned int addr, unsigned char *data, unsigned int data_len)
211 {
212     unsigned int ret = 0;
213     LzI2cMsg msgs[1];
214     unsigned char buffer[EEPROM_PAGE + 1];
215 
216     /* K24C02的存储地址是0~255 */
217     if (addr >= EEPROM_ADDRESS_MAX) {
218         printf("%s, %s, %d: addr(0x%x) >= EEPROM_ADDRESS_MAX(0x%x)\n",
219             __FILE__, __func__, __LINE__, addr, EEPROM_ADDRESS_MAX);
220         return 0;
221     }
222 
223     if ((addr % EEPROM_PAGE) != 0) {
224         printf("%s, %s, %d: addr(0x%x) is not page addr(0x%x)\n",
225             __FILE__, __func__, __LINE__, addr, EEPROM_PAGE);
226         return 0;
227     }
228 
229     if ((addr + data_len) > EEPROM_ADDRESS_MAX) {
230         printf("%s, %s, %d: addr + data_len(0x%x) > EEPROM_ADDRESS_MAX(0x%x)\n",
231             __FILE__, __func__, __LINE__, addr + data_len, EEPROM_ADDRESS_MAX);
232         return 0;
233     }
234 
235     if (data_len > EEPROM_PAGE) {
236         printf("%s, %s, %d: data_len(%d) > EEPROM_PAGE(%d)\n",
237             __FILE__, __func__, __LINE__, data_len, EEPROM_PAGE);
238         return 0;
239     }
240 
241     buffer[0] = addr;
242     memcpy(&buffer[1], data, data_len);
243 
244     msgs[0].addr = EEPROM_I2C_ADDRESS;
245     msgs[0].flags = 0;
246     msgs[0].buf = &buffer[0];
247     msgs[0].len = 1 + data_len;
248 
249     ret = LzI2cTransfer(EEPROM_I2C_BUS, msgs, 1);
250     if (ret != LZ_HARDWARE_SUCCESS) {
251         printf("%s, %s, %d: LzI2cTransfer failed(%d)!\n", __FILE__, __func__, __LINE__, ret);
252         return 0;
253     }
254 
255     /* K24C02芯片需要时间完成写操作,在此之前不响应其他操作 */
256     eeprog_delay_usec(K24C02_DELAY_USEC);
257 
258     return data_len;
259 }
260 
261 /***************************************************************
262 * 函数名称: eeprom_read
263 * 说    明: EEPROM读多个字节
264 * 参    数:
265 *           @addr:      EERPOM存储地址
266 *           @data:      存放EERPOM的数据指针
267 *           @data_len:  读取EERPOM数据的长度
268 * 返 回 值: 返回读取字节的长度,反之为错误
269 ***************************************************************/
eeprom_read(unsigned int addr,unsigned char * data,unsigned int data_len)270 unsigned int eeprom_read(unsigned int addr, unsigned char *data, unsigned int data_len)
271 {
272     unsigned int ret = 0;
273 
274     if (addr >= EEPROM_ADDRESS_MAX) {
275         printf("%s, %s, %d: addr(0x%x) >= EEPROM_ADDRESS_MAX(0x%x)\n",
276             __FILE__, __func__, __LINE__, addr, EEPROM_ADDRESS_MAX);
277         return 0;
278     }
279 
280     if ((addr + data_len) > EEPROM_ADDRESS_MAX) {
281         printf("%s, %s, %d: addr + len(0x%x) > EEPROM_ADDRESS_MAX(0x%x)\n",
282             __FILE__, __func__, __LINE__, addr + data_len, EEPROM_ADDRESS_MAX);
283         return 0;
284     }
285 
286     ret = eeprom_readbyte(addr, data);
287     if (ret != 1) {
288         printf("%s, %s, %d: EepromReadByte failed(%d)\n", __FILE__, __func__, __LINE__, ret);
289         return 0;
290     }
291 
292     if (data_len > 1) {
293         ret = LzI2cRead(EEPROM_I2C_BUS, EEPROM_I2C_ADDRESS, &data[1], data_len - 1);
294         if (ret < 0) {
295             printf("%s, %s, %d: LzI2cRead failed(%d)!\n", __FILE__, __func__, __LINE__, ret);
296             return 0;
297         }
298     }
299 
300     return data_len;
301 }
302 
303 /***************************************************************
304 * 函数名称: eeprom_write
305 * 说    明: EEPROM写多个字节
306 * 参    数:
307 *           @addr: EEPROM存储地址
308 *           @data: 写EERPOM的数据指针
309 *           @data_len: 写EEPROM数据的长度
310 * 返 回 值: 返回写入数据的长度,反之为错误
311 ***************************************************************/
eeprom_write(unsigned int addr,unsigned char * data,unsigned int data_len)312 unsigned int eeprom_write(unsigned int addr, unsigned char *data, unsigned int data_len)
313 {
314     unsigned int ret = 0;
315     unsigned int offset_current = 0;
316     unsigned int page_start, page_end;
317     unsigned char is_data_front = 0;
318     unsigned char is_data_back = 0;
319     unsigned int len;
320 
321     if (addr >= EEPROM_ADDRESS_MAX) {
322         printf("%s, %s, %d: addr(0x%x) >= EEPROM_ADDRESS_MAX(0x%x)\n",
323             __FILE__, __func__, __LINE__, addr, EEPROM_ADDRESS_MAX);
324         return 0;
325     }
326 
327     if ((addr + data_len) > EEPROM_ADDRESS_MAX) {
328         printf("%s, %s, %d: addr + len(0x%x) > EEPROM_ADDRESS_MAX(0x%x)\n",
329             __FILE__, __func__, __LINE__, addr + data_len, EEPROM_ADDRESS_MAX);
330         return 0;
331     }
332 
333     /* 判断addr是否是页地址 */
334     page_start = addr / EEPROM_PAGE;
335     if ((addr % EEPROM_PAGE) != 0) {
336         page_start += 1;
337         is_data_front = 1;
338     }
339 
340     /* 判断addr + data_len是否是页地址 */
341     page_end = (addr + data_len) / EEPROM_PAGE;
342     if ((addr + data_len) % EEPROM_PAGE != 0) {
343         page_end += 1;
344         is_data_back = 1;
345     }
346 
347     offset_current = 0;
348 
349     /* 处理前面非页地址的数据,如果是页地址则不执行 */
350     for (unsigned int i = addr; i < (page_start * EEPROM_PAGE); i++) {
351         ret = eeprom_writebyte(i, data[offset_current]);
352         if (ret != 1) {
353             printf("%s, %s, %d: EepromWriteByte failed(%d)\n", __FILE__, __func__, __LINE__, ret);
354             return offset_current;
355         }
356         offset_current++;
357     }
358 
359     /* 处理后续的数据,如果数据长度不足一个Page,则不执行 */
360     for (unsigned int page = page_start; page < page_end; page++) {
361         len = EEPROM_PAGE;
362         if ((page == (page_end - 1)) && (is_data_back)) {
363             len = (addr + data_len) % EEPROM_PAGE;
364         }
365 
366         ret = eeprom_writepage(page * EEPROM_PAGE, &data[offset_current], len);
367         if (ret != len) {
368             printf("%s, %s, %d: EepromWritePage failed(%d)\n", __FILE__, __func__, __LINE__, ret);
369             return offset_current;
370         }
371         offset_current += EEPROM_PAGE;
372     }
373 
374     return data_len;
375 }
376