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