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