From 53de825c4c4d8325c02341177f62ab84897eb5ee Mon Sep 17 00:00:00 2001
From: guowenxue <guowenxue@gmail.com>
Date: Sat, 25 Jul 2026 22:09:43 +0800
Subject: [PATCH] update vscode task.json and add stm32flash tools
---
ex2.i2c-bitbang/Board/eeprom.c | 284 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 284 insertions(+), 0 deletions(-)
diff --git a/ex2.i2c-bitbang/Board/eeprom.c b/ex2.i2c-bitbang/Board/eeprom.c
new file mode 100644
index 0000000..fd489e3
--- /dev/null
+++ b/ex2.i2c-bitbang/Board/eeprom.c
@@ -0,0 +1,284 @@
+/**********************************************************************
+* Copyright: (C)2024 LingYun IoT System Studio
+* Author: GuoWenxue<guowenxue@gmail.com>
+* Description: I2C EEPROM device driver for ISKBoard (Internal Lock Version)
+*
+* ChangeLog:
+* Version Date Author Description
+* V1.5.0 2026.07.08 GuoWenxue Use goto cleanup for unified lock releasing
+***********************************************************************/
+
+#include "eeprom.h"
+#include "miscdev.h" /* 提供 mdelay() / udelay() */
+#include <stdio.h>
+#include <string.h>
+
+
+/* EEPROM 型号表:未来若有新芯片,只需在此处追加一行,其余代码不用更改 */
+static const eeprom_info_t eeprom_ids[] = {
+ { EEPROM_INFO("AT24C02", 256, 8, 1) },
+ { EEPROM_INFO("AT24C04", 512, 16, 1) },
+ { EEPROM_INFO("AT24C08", 1024, 16, 1) },
+ { EEPROM_INFO("AT24C16", 2048, 16, 1) },
+ { EEPROM_INFO("AT24C32", 4096, 32, 2) },
+ { EEPROM_INFO("AT24C64", 8192, 32, 2) },
+ { EEPROM_INFO("AT24C128", 16384, 64, 2) },
+ { EEPROM_INFO("AT24C256", 32768, 64, 2) },
+};
+#define EEPROM_IDS_NUM (sizeof(eeprom_ids) / sizeof(eeprom_ids[0]))
+
+/**
+ * @brief 根据芯片型号名称内部查找匹配的型号
+ */
+static const eeprom_info_t *eeprom_find_info_by_name(const char *name)
+{
+ uint32_t i;
+ for (i = 0; i < EEPROM_IDS_NUM; i++)
+ {
+ if (strcmp(eeprom_ids[i].name, name) == 0)
+ {
+ return &eeprom_ids[i];
+ }
+ }
+ return NULL;
+}
+
+/**
+ * @brief 初始化 EEPROM 设备参数(通过型号名称自动查表匹配)
+ */
+int eeprom_init(eeprom_dev_t *eeprom, i2c_bus_t *bus, uint8_t dev_addr, const char *chip_name)
+{
+ const eeprom_info_t *info = eeprom_find_info_by_name(chip_name);
+
+ if (!info || !eeprom || !bus)
+ {
+ printf("EEPROM: Named device [%s] not supported!\r\n", chip_name ? chip_name : "NULL");
+ return -1;
+ }
+
+ eeprom->bus = bus;
+ eeprom->dev_addr = dev_addr;
+ eeprom->info = info;
+
+ printf("Initialized EEPROM(%s), Capacity: %ld Bytes, Page Size: %ld\r\n",
+ info->name, info->capacity, info->page_size);
+ return 0;
+}
+
+/**
+ * @brief EEPROM 测试函数
+ */
+int eeprom_test(i2c_bus_t *bus)
+{
+ eeprom_dev_t my_at24c256;
+ uint8_t tx_buf[100];
+ uint8_t rx_buf[100];
+ int i;
+ int rv = -1;
+
+ /* 1. 初始化 EEPROM 参数 */
+ if (eeprom_init(&my_at24c256, bus, 0x50, "AT24C256") != 0)
+ {
+ return -1;
+ }
+
+ /* 2. 填充测试数据 */
+ for (i = 0; i < sizeof(tx_buf); i++)
+ {
+ tx_buf[i] = i;
+ }
+
+ /* 3. 测试跨页连续写 */
+ if (eeprom_write(&my_at24c256, 0x00A0, tx_buf, sizeof(tx_buf)) != I2C_OK)
+ {
+ goto cleanup;
+ }
+
+ /* 4. 测试任意地址连续读 */
+ if (eeprom_read(&my_at24c256, 0x00A0, rx_buf, sizeof(rx_buf)) != I2C_OK)
+ {
+ goto cleanup;
+ }
+
+ /* 5. 数据一致性校验 */
+ if (memcmp(tx_buf, rx_buf, sizeof(tx_buf)) == 0)
+ {
+ rv = 0;
+ }
+
+cleanup:
+ printf("AT24C256 Read/Write Test %s!\r\n", rv == 0 ? "Passed" : "Failed");
+ return rv;
+}
+
+/**
+ * @brief 24C16仅支持单字节地址(可寻址256字节),需借用I2C设备地址的低3位充当片内地址的高3位。
+ */
+static inline uint8_t eeprom_get_actual_addr(eeprom_dev_t *eeprom, uint16_t reg_addr)
+{
+ uint8_t actual_dev_addr = eeprom->dev_addr;
+ if (eeprom->info->addr_bytes == 1 && eeprom->info->capacity > 256)
+ {
+ actual_dev_addr |= (uint8_t)((reg_addr >> 8) & 0x07);
+ }
+ return actual_dev_addr;
+}
+
+/**
+ * @brief 从 EEPROM 任意地址读取指定长度数据
+ */
+i2c_status_t eeprom_read(eeprom_dev_t *eeprom, uint16_t reg_addr, uint8_t *buf, uint16_t len)
+{
+ uint8_t addr_buf[2];
+ uint8_t addr_len = 0;
+ i2c_msg_t msgs[2];
+ i2c_status_t status;
+
+ if ( len == 0 || !buf || !eeprom || !eeprom->bus || !eeprom->info )
+ {
+ return I2C_OK;
+ }
+
+ /* 1. 准备发送数据 */
+ if (eeprom->info->addr_bytes == 2)
+ {
+ addr_buf[addr_len++] = (uint8_t)(reg_addr >> 8);
+ }
+ addr_buf[addr_len++] = (uint8_t)(reg_addr & 0xFF);
+
+ /* 2. 封装 I2C 消息 */
+ msgs[0].addr = eeprom_get_actual_addr(eeprom, reg_addr);
+ msgs[0].flags = I2C_M_WR;
+ msgs[0].len = addr_len;
+ msgs[0].buf = addr_buf;
+
+ msgs[1].addr = msgs[0].addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = buf;
+
+ /* 3. 锁住 I2C 总线 */
+ if (i2c_lock(eeprom->bus) != I2C_OK)
+ {
+ return I2C_BUSY;
+ }
+
+ /* 4. 调用 i2c_transfer 发送消息 */
+ status = i2c_transfer(eeprom->bus, msgs, 2);
+
+ /* 5. 释放 I2C 总线 */
+ i2c_unlock(eeprom->bus);
+
+ return status;
+}
+
+/**
+ * @brief 轮询 EEPROM 硬件内部擦写就绪状态
+ */
+static void eeprom_wait_standby(eeprom_dev_t *eeprom, uint16_t reg_addr)
+{
+ i2c_msg_t msg;
+ uint32_t timeout = 2000;
+
+ msg.addr = eeprom_get_actual_addr(eeprom, reg_addr);
+ msg.flags = I2C_M_WR;
+ msg.len = 0;
+ msg.buf = NULL;
+
+ while (timeout--)
+ {
+ if (i2c_transfer(eeprom->bus, &msg, 1) == I2C_OK)
+ {
+ break; /* 芯片返回 ACK,擦写完成,退出轮询 */
+ }
+ udelay(50);
+ }
+}
+
+/**
+ * @brief 向 EEPROM 写入单页数据
+ */
+static i2c_status_t eeprom_write_page(eeprom_dev_t *eeprom, uint16_t reg_addr, uint8_t *buf, uint16_t len)
+{
+ uint8_t tx_payload[128];
+ uint8_t addr_len = 0;
+ i2c_msg_t msg;
+ i2c_status_t status = I2C_OK;
+
+ /* 1. 准备发送数据 */
+ if (eeprom->info->addr_bytes == 2)
+ {
+ tx_payload[addr_len++] = (uint8_t)(reg_addr >> 8);
+ }
+ tx_payload[addr_len++] = (uint8_t)(reg_addr & 0xFF);
+ memcpy(&tx_payload[addr_len], buf, len);
+
+ msg.addr = eeprom_get_actual_addr(eeprom, reg_addr);
+ msg.flags = I2C_M_WR;
+ msg.len = addr_len + len;
+ msg.buf = tx_payload;
+
+ /* 2. 锁住 I2C 总线 */
+ if (i2c_lock(eeprom->bus) != I2C_OK)
+ {
+ return I2C_BUSY;
+ }
+
+ /* 3. 调用 i2c_transfer 发送消息 */
+ status = i2c_transfer(eeprom->bus, &msg, 1);
+ if (status != I2C_OK)
+ {
+ status = I2C_ERROR;
+ goto cleanup;
+ }
+
+ /* 4. 轮询等待 EEPROM 内部擦写完成 */
+ eeprom_wait_standby(eeprom, reg_addr);
+
+cleanup:
+ /* 5. 释放 I2C 总线 */
+ i2c_unlock(eeprom->bus);
+
+ return status;
+}
+
+/**
+ * @brief 大批量数据动态跨页分包连续写入
+ */
+i2c_status_t eeprom_write(eeprom_dev_t *eeprom, uint16_t reg_addr, uint8_t *buf, uint16_t len)
+{
+ i2c_status_t status = I2C_OK;
+ uint16_t count = 0;
+ uint16_t page_offset;
+ uint16_t bytes_to_write;
+
+ if ( len == 0 || !buf || !eeprom || !eeprom->bus || !eeprom->info )
+ {
+ return I2C_OK;
+ }
+
+ while (len > 0)
+ {
+ page_offset = reg_addr % eeprom->info->page_size;
+
+ bytes_to_write = eeprom->info->page_size - page_offset;
+ if (bytes_to_write > len)
+ {
+ bytes_to_write = len;
+ }
+
+ /* 内部单页级连写带等就绪的一体化锁定 */
+ status = eeprom_write_page(eeprom, reg_addr, &buf[count], bytes_to_write);
+ if (status != I2C_OK)
+ {
+ goto cleanup;
+ }
+
+ reg_addr += bytes_to_write;
+ count += bytes_to_write;
+ len -= bytes_to_write;
+ }
+
+cleanup:
+ return status;
+}
--
Gitblit v1.10.0