diff --git a/AGENTS.md b/AGENTS.md index c23e361..3419519 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -66,8 +66,9 @@ LDC1612(电涡流/电感数字转换器)+ TMP112(板载温度),RS485 VTOR 0x2000;版本从 V1.0.3 起(首个双固件 A 版本,码 26)。 - **B 线 = release/golden**:链接 0x0800B000 / LENGTH 0x4BF8(19K−8B,B 记录由打包 工具写入,链接区不含尾 8B——与 MB 的 .fw_tail 方案等价),VTOR 0xB000; - **版本冻结 V1.0.2**(保底判定值 = M999 返回 `v26.1.0.2` ⇔ 在跑 FW_B,该版本号 - 永不再用于 OTA 升级包)。此分支改动不得合回 dev/main。 + **版本冻结 V1.0.3 = 生产实装版原样复制(2026-10-25 起,见开发进度)**。保底判定值 + = M999 返回 `v26.1.0.3` ⇔ 在跑 FW_B;`v26.1.0.2`(旧 golden)与 `v26.1.0.3` 均永不 + 再用于 OTA 升级包版本,dev 线后续 A 版本必须 > V1.0.3。此分支改动不得合回 dev/main。 - 打包:`hulk-mcu-firmware` skill / merge tool profile **`CeramixNano_EDDY_Dual_FW`** (布局与 `CeramixNano_MB_Dual_FW` 逐字节相同),产出 `_UPDATE/_FULL/_FACTORY + MD5`。 - 升级链路:上位机(原 SOC 职责)—RS485—> BL(Ymodem);APP 用 `M9999` 软复位进 @@ -105,11 +106,26 @@ LDC1612(电涡流/电感数字转换器)+ TMP112(板载温度),RS485 再毁B体→拒跳坏固件停留 BL(PC=0x080001B6) / OTA 第4包 CA 中止→落B / 非整页裸 bin 包→头部预检 CA×2 拒收→落B / M3/M4/M6 功能全通 +- **2026-10-25:golden 托底线整体替换为生产实装版原样复制**(用户决策:生产版已在 + 机器上实装,托底必须与其同源,不做任何"顺手改进";IIC 新驱动等留给后续 A 线新版本): + - 来源:生产仓库(GitLab `ceramixnano_eddy_cmake_vscode`,dev@151828f,v26.1.0.3, + 2026-03-23 已含驱动电流调参 GEN(18)→GEN(8));复制 8 文件(Src: command.c/i2c.c/ + ldc1612.c/tmp112.c;Inc: command.h/i2c.h/ldc1612.h;CommunicationProtocol.md), + 复制后 `fc /b` 逐字节核验一致 + - golden 从此与 dev 线的功能差异(**属预期,勿"修复"**):LDC1612 驱动电流 **GEN(8)** + (dev 线仍为 GEN(18),后续 A 线新版本需评估回合生产调参);命令集 **M1~M4 + + M999/M9999(无 M5/M6)**;M4 温度为生产版无符号算法;i2c 为旧 8 位寄存器地址 API + 驱动(与 tmp112.c/ldc1612.c 配套,整组生效) + - golden 保留项(B 槽专属构建):LD 0x0800B000/0x4BF8、VTOR 0xB000、gap-fill 0xFF、 + BUILD_VARIANT=golden;仅 VERSION_PATCH 2→3 与生产对齐 + - **保底判定值改为 `v26.1.0.3`**;注意 dev 线当前同为 V1.0.3(10-24 的 FULL 测试包 + A=V1.0.3)——后续 A 线正式版本必须升到 V1.0.4 以上,否则 M999 无法区分保底 + ### 计划 / TODO - dev → main 合并待发布节奏(V1.0.3 为首个双固件 A 版本,main 仍是 54K 单槽布局) - M5 温度补偿系数目前为 0(TEMP_COMP_COEFF_*),待标定后填入实际温漂系数 -- 上位机/SOC 侧需预存保底判定值 `v26.1.0.2`(跑 B ⇒ 升级未生效重推) +- 上位机/SOC 侧需预存保底判定值 `v26.1.0.3`(跑 B ⇒ 升级未生效重推;2026-10-25 起判定值随生产版复制从 v26.1.0.2 改为 v26.1.0.3) - (可选)模板侧 SEGGER RTT / CFG_ENABLE 宏体系同步 ### 已删除的历史分支(2026-10-24 清理,均为开发过程产物) diff --git a/CommunicationProtocol.md b/CommunicationProtocol.md index e1f1bf6..451a69d 100644 --- a/CommunicationProtocol.md +++ b/CommunicationProtocol.md @@ -58,28 +58,5 @@ ### 4. 单次读取并发送板载温度传感器数据 -- M4 指令 单次读取并发送板载温度传感器数据(TMP112,返回温度值×10000,4 字节有符号大端) +- M3 指令 单次读取并发送板载温度传感器数据 - `D5 03 02 4D 34 86` - - 示例回复:`B5 F0 04 00 04 28 74 94`,有效数据 `0x00042874` = 272500,即 `27.25°C` - -### 5. 单次读取并发送温度补偿后的涡流传感器数据 - -- M5 指令 单次读取并发送温度补偿后的涡流传感器数据(补偿系数默认为 0,与 M3 等价) - - `D5 03 02 4D 35 87` - -### 6. 单次读取并发送标定数据(涡流原始值 + 温度值) - -- M6 指令 单次读取涡流原始值和板载温度值,用于温度标定 - - `D5 03 02 4D 36 88` - - 回复 9 字节:涡流原始值(4字节大端) + 0xFF + 温度值×10000(4字节大端) - - 示例回复:`B5 F0 09 01 AD BA DC FF 00 04 28 74 DC` - -### 7. 查询固件版本号 - -- M999 指令 返回固件版本号字符串,如 `v23.1.0.1`(板卡类型.主版本.次版本.修订号) - - `D5 03 04 4D 39 39 39 FF` - -### 8. 复位 MCU - -- M9999 指令 立即复位 MCU(无回复) - - `D5 03 05 4D 39 39 39 39 39` diff --git a/Inc/command.h b/Inc/command.h index 7541fc9..23db45b 100644 --- a/Inc/command.h +++ b/Inc/command.h @@ -105,8 +105,4 @@ void eddy_current_report(void); void temperature_raw_value_report(void); -void eddy_current_compensated_report(void); - -void calibration_data_report(void); - #endif // COMMAND_H diff --git a/Inc/i2c.h b/Inc/i2c.h index 79a6d90..eaa7097 100644 --- a/Inc/i2c.h +++ b/Inc/i2c.h @@ -89,9 +89,9 @@ i2c_result_t i2c_bus_reset(void); void i2c_scan(void); /*! - \brief write 16-bit data to I2C device (8-bit register address + 2 data bytes) + \brief write 16-bit data to I2C device \param[in] slave_addr: 7-bit slave address - \param[in] reg_addr: register address (8-bit) + \param[in] reg_addr: register address \param[in] data: pointer to 2-byte data array \param[out] none \retval i2c_result_t @@ -99,9 +99,9 @@ void i2c_scan(void); i2c_result_t i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[2]); /*! - \brief read 16-bit data from I2C device (8-bit register address + 2 data bytes) + \brief read 16-bit data from I2C device \param[in] slave_addr: 7-bit slave address - \param[in] reg_addr: register address (8-bit) + \param[in] reg_addr: register address \param[out] data: pointer to 2-byte data buffer \retval i2c_result_t */ @@ -111,33 +111,70 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data /*! \brief write data to I2C device with configurable length \param[in] slave_addr: slave device address (7-bit) - \param[in] reg_addr: register address (16-bit, high byte first) + \param[in] reg_addr: register address \param[in] data: pointer to data buffer \param[in] length: number of bytes to write (1-255) \param[out] none \retval i2c_result_t: operation result */ -i2c_result_t i2c_write(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint8_t length); +i2c_result_t i2c_write(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length); /*! \brief read data from I2C device with configurable length \param[in] slave_addr: slave device address (7-bit) - \param[in] reg_addr: register address (16-bit, high byte first) + \param[in] reg_addr: register address \param[out] data: pointer to data buffer \param[in] length: number of bytes to read (1-255) \retval i2c_result_t: operation result */ -i2c_result_t i2c_read(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint8_t length); +i2c_result_t i2c_read(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length); -/* Pure read response without sub-address phase (for commands that already sent read request parameters) */ +/* Convenience functions for common operations */ /*! - \brief read data from I2C device without register/sub-address phase + \brief write single byte to I2C device \param[in] slave_addr: slave device address (7-bit) - \param[out] data: pointer to data buffer - \param[in] length: number of bytes to read (1-255) + \param[in] reg_addr: register address + \param[in] data: data byte to write \retval i2c_result_t: operation result */ -i2c_result_t i2c_read_raw(uint8_t slave_addr, uint8_t *data, uint8_t length); +i2c_result_t i2c_write_8bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data); + +/*! + \brief read single byte from I2C device + \param[in] slave_addr: slave device address (7-bit) + \param[in] reg_addr: register address + \param[out] data: pointer to data byte + \retval i2c_result_t: operation result +*/ +i2c_result_t i2c_read_8bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data); + +/*! + \brief write 32-bit data to I2C device + \param[in] slave_addr: slave device address (7-bit) + \param[in] reg_addr: register address + \param[in] data: pointer to 4-byte data array + \retval i2c_result_t: operation result +*/ +i2c_result_t i2c_write_32bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[4]); + +/*! + \brief read 32-bit data from I2C device + \param[in] slave_addr: slave device address (7-bit) + \param[in] reg_addr: register address + \param[out] data: pointer to 4-byte data buffer + \retval i2c_result_t: operation result +*/ +i2c_result_t i2c_read_32bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data); + +/*! + \brief read display panel parameters (multi-byte) + \param[in] slave_addr: slave device address (7-bit) + \param[in] reg_addr: register address + \param[out] data: pointer to data buffer + \param[in] length: number of bytes to read (1-13) + \retval i2c_result_t: operation result +*/ +i2c_result_t i2c_read_display_params(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length); #ifdef DEBUG_VERBOSE /*! diff --git a/Inc/ldc1612.h b/Inc/ldc1612.h index f2b21a2..b79d6a4 100644 --- a/Inc/ldc1612.h +++ b/Inc/ldc1612.h @@ -445,7 +445,7 @@ // 参数 idrive: 0-31之间的整数 #define LDC1612_DRIVE_CURRENT_GEN(idrive) ( (uint16_t)(idrive) << 11 ) -#define LDC1612_DRIVE_CURRENT LDC1612_DRIVE_CURRENT_GEN(18) // 0x9000 +#define LDC1612_DRIVE_CURRENT LDC1612_DRIVE_CURRENT_GEN(8) // 0x9000 /**************************IDs (Read Only 0x7E 0x7F)***********************************/ diff --git a/README.md b/README.md index 7bfe552..472caca 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CeramixNano-EDDY(LDC1612)传感器固件 -本仓库基于 GD32E23x CMake + VSCode 工程模板(`gd32e23x_template_cmake_vscode`),包含 LDC1612 电感采样、TMP112 温度采集及补偿、RS485 命令处理。**版本按分支区分**:`release/golden` = 出厂保底线 **V1.0.2(冻结)**;`dev` = 双固件 A 线 **V1.0.3(开发中)**;`main` = 旧单槽布局线(LDC1612 旧名,V1.0.2)。固件采用双固件(出厂救援)布局:dev 线 APP 链接在 `0x08002000`(36KB A 槽 / 8KB RAM),golden 线链接 `0x0800B000`(B 槽),启动时自设向量表偏移;布局详情见下文「固件布局与 Bootloader」,开发进度见 `AGENTS.md`。 +本仓库基于 GD32E23x CMake + VSCode 工程模板(`gd32e23x_template_cmake_vscode`),包含 LDC1612 电感采样、TMP112 温度采集及补偿、RS485 命令处理。**版本按分支区分**:`release/golden` = 出厂保底线 **V1.0.3(冻结,生产实装版原样复制)**;`dev` = 双固件 A 线 **V1.0.3(开发中)**;`main` = 旧单槽布局线(LDC1612 旧名,V1.0.2)。固件采用双固件(出厂救援)布局:dev 线 APP 链接在 `0x08002000`(36KB A 槽 / 8KB RAM),golden 线链接 `0x0800B000`(B 槽),启动时自设向量表偏移;布局详情见下文「固件布局与 Bootloader」,开发进度见 `AGENTS.md`。 ## 本地编译 @@ -49,7 +49,7 @@ GD32E230F8(64KB Flash)采用与 CeramixNano-MB 相同的双固件(出厂 |---|---|---| | Bootloader | `0x08000000` - `0x08001FFF`(8KB,页 0~7) | **专属分支 `bootloader_CeramixNano_EDDY`**(V0.1.0,4,040B,LED=PB1,Ymodem 每烧录一包翻转一次;与 MB 分支并列、版本独立编号)——启动判定链 + RS485 Ymodem OTA;PA14 不占用,升级会话期间 SWD 可用 | | FW_A 运行槽(本仓库 dev/main) | `0x08002000` - `0x0800AFFF`(36KB,页 8~43) | 唯一 OTA/Ymodem 接收区;链接 `ORIGIN=0x08002000, LENGTH=36K`(上限防溢出 B 槽);槽尾锚点 A 记录 @`0x0800AFFC` | -| FW_B 出厂保底槽(release/golden 分支) | `0x0800B000` - `0x0800FBFF`(19KB,页 44~62) | 出厂救援固件(版本冻结 V1.0.2),OTA 永不擦写;B 记录 @`0x0800FBF8` | +| FW_B 出厂保底槽(release/golden 分支) | `0x0800B000` - `0x0800FBFF`(19KB,页 44~62) | 出厂救援固件(版本冻结 V1.0.3,生产实装版原样复制),OTA 永不擦写;B 记录 @`0x0800FBF8` | | 末页标志页 | `0x0800FC00` - `0x0800FFFF`(1KB,页 63) | legacy 标志 `0xEEEE` @`0x0800FFFC` | 启动判定:A 记录在位 ⇒ trailer 比对 + 固件体 CRC 复算 + 向量校验 ⇒ 跳 A(不过直落 B,防降级);锚点擦除态 ⇒ legacy flag ⇒ 跳 A;B 记录 CRC 复算通过 ⇒ 跳 B;否则留 BL 等 Ymodem。OTA 中途断电/中止 ⇒ 重启落 B 跑出厂固件,**设备不变砖**。 @@ -58,7 +58,7 @@ GD32E230F8(64KB Flash)采用与 CeramixNano-MB 相同的双固件(出厂 - `LD/gd32e23x_flash.ld`:FLASH `ORIGIN = 0x08002000, LENGTH = 36K`; - `Src/system_gd32e23x.c`:`VECT_TAB_OFFSET = 0x2000`——Bootloader 不写 VTOR,APP 必须自己把向量表指到 `0x08002000`,否则中断会落回 Bootloader 向量表(现象:收到第一个 RS485 字节即死机); -- 出厂保底固件在 `release/golden` 分支构建(`ORIGIN=0x0800B000 / LENGTH=0x4BF8`、`VECT_TAB_OFFSET=0xB000`,版本冻结 V1.0.2,判定值 `v26.1.0.2`); +- 出厂保底固件在 `release/golden` 分支构建(`ORIGIN=0x0800B000 / LENGTH=0x4BF8`、`VECT_TAB_OFFSET=0xB000`,版本冻结 V1.0.3 = **生产实装版原样复制**——命令集 M1~M4 + M999/M9999、LDC1612 驱动电流 `GEN(8)`、旧 8 位寄存器地址 i2c 驱动;判定值 `v26.1.0.3`); - 打包(`_UPDATE/_FULL/_FACTORY` + MD5)用 merge tool / `hulk-mcu-firmware` skill,profile `CeramixNano_EDDY_Dual_FW`;产物命名 `CeramixNano-EDDY_*`(板卡码 26)。 ⚠️ 与旧版 54K 单槽布局不兼容:需整片烧录一次(FACTORY/FULL 镜像)。RS485 协议、命令集(M1-M6/M999/M9999)与回包格式无任何变化。方案完全体文档见 MB 仓库 `doc/双固件方案_完全体说明.md`;开发约定与实测记录见本项目 `AGENTS.md`。 diff --git a/Src/command.c b/Src/command.c index d5fc993..ba13289 100644 --- a/Src/command.c +++ b/Src/command.c @@ -74,15 +74,6 @@ #define RESP_TYPE_LEN_ERR 0xF4 /**< 长度错误 */ /** @} */ -/* 温度补偿参数定义 - * TEMP_COMP_REF_TEMP_X10000: 参考温度,单位 0.0001°C - * TEMP_COMP_COEFF_NUMERATOR / TEMP_COMP_COEFF_DENOMINATOR: 温漂系数,默认表示 counts/°C - * 补偿公式: compensated = raw - (temp - ref) * coeff - */ -#define TEMP_COMP_REF_TEMP_X10000 (250000L) -#define TEMP_COMP_COEFF_NUMERATOR (0L) -#define TEMP_COMP_COEFF_DENOMINATOR (10000L) - /* ============================================================================ * 模块内部变量 * ============================================================================ */ @@ -104,9 +95,6 @@ static const uint8_t s_report_status_ok[] = { 'o', 'k' }; /**< 成功响应 static const uint8_t s_report_status_err[] = { 'e','r','r' }; /**< 错误响应数据 */ /** @} */ -static int32_t tmp112_get_temperature_x10000(void); -static int64_t calculate_temperature_compensation_offset(int32_t temperature_x10000); - /* ============================================================================ * 公共接口函数 * ============================================================================ */ @@ -344,14 +332,6 @@ void handle_command(const uint8_t *frame, uint8_t len) { temperature_raw_value_report(); return; - case 5u: - eddy_current_compensated_report(); - return; - - case 6u: - calibration_data_report(); - return; - // case 201u: // M201命令 // send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok)); // return; @@ -533,82 +513,20 @@ void eddy_current_report(void) { send_response(RESP_TYPE_OK, sensor_data, sizeof(sensor_data)); } -static int32_t tmp112_get_temperature_x10000(void) -{ - uint8_t value[2] = {0}; - int16_t temp_raw; - - tmp112a_get_raw_temperature_value(value); - - temp_raw = (int16_t)(((uint16_t)value[0] << 8) | value[1]); - temp_raw >>= 4; - - return (int32_t)temp_raw * 625; -} - -static int64_t calculate_temperature_compensation_offset(int32_t temperature_x10000) -{ - int32_t delta_temp_x10000 = temperature_x10000 - TEMP_COMP_REF_TEMP_X10000; - - return ((int64_t)delta_temp_x10000 * TEMP_COMP_COEFF_NUMERATOR) / - TEMP_COMP_COEFF_DENOMINATOR; -} - void temperature_raw_value_report(void) { + // if (!g_temperature_sensor_report_enabled) return; uint8_t raw_result[4]; - int32_t raw_value = tmp112_get_temperature_x10000(); + uint8_t value[2] = {0}; + uint32_t raw_value = 0; - raw_result[0] = (uint8_t)((uint32_t)raw_value >> 24); - raw_result[1] = (uint8_t)((uint32_t)raw_value >> 16); - raw_result[2] = (uint8_t)((uint32_t)raw_value >> 8); - raw_result[3] = (uint8_t)((uint32_t)raw_value & 0xFF); + // i2c_read_16bits(TMP112A_ADDR, TMP112A_TEMP_REG, value); + tmp112a_get_raw_temperature_value(value); + raw_value = (uint32_t)((uint16_t) (value[0] << 4) | (value[1]>>4)) * 625; + raw_result[0] = (uint8_t)(raw_value >> 24); + raw_result[1] = (uint8_t)(raw_value >> 16); + raw_result[2] = (uint8_t)(raw_value >> 8); + raw_result[3] = (uint8_t)(raw_value & 0xFF); send_response(RESP_TYPE_OK, raw_result, sizeof(raw_result)); } - -void eddy_current_compensated_report(void) -{ - uint8_t sensor_data[4]; - uint32_t raw_result = ldc1612_get_raw_channel_result(CHANNEL_0); - - if ((raw_result & 0xF0000000u) == 0u) { - int32_t temperature_x10000 = tmp112_get_temperature_x10000(); - int64_t compensated_value = (int64_t)raw_result - - calculate_temperature_compensation_offset(temperature_x10000); - - if (compensated_value < 0) { - raw_result = 0; - } else if (compensated_value > 0x0FFFFFFFLL) { - raw_result = 0x0FFFFFFFu; - } else { - raw_result = (uint32_t)compensated_value; - } - } - - sensor_data[0] = (uint8_t)(raw_result >> 24); - sensor_data[1] = (uint8_t)(raw_result >> 16); - sensor_data[2] = (uint8_t)(raw_result >> 8); - sensor_data[3] = (uint8_t)(raw_result & 0xFF); - - send_response(RESP_TYPE_OK, sensor_data, sizeof(sensor_data)); -} - -void calibration_data_report(void) -{ - uint8_t payload[9]; - uint32_t eddy_raw_value = ldc1612_get_raw_channel_result(CHANNEL_0); - int32_t temperature_raw_value = tmp112_get_temperature_x10000(); - - payload[0] = (uint8_t)(eddy_raw_value >> 24); - payload[1] = (uint8_t)(eddy_raw_value >> 16); - payload[2] = (uint8_t)(eddy_raw_value >> 8); - payload[3] = (uint8_t)(eddy_raw_value & 0xFF); - payload[4] = 0xFF; - payload[5] = (uint8_t)((uint32_t)temperature_raw_value >> 24); - payload[6] = (uint8_t)((uint32_t)temperature_raw_value >> 16); - payload[7] = (uint8_t)((uint32_t)temperature_raw_value >> 8); - payload[8] = (uint8_t)((uint32_t)temperature_raw_value & 0xFF); - - send_response(RESP_TYPE_OK, payload, sizeof(payload)); -} \ No newline at end of file diff --git a/Src/i2c.c b/Src/i2c.c index 814535b..44ba655 100644 --- a/Src/i2c.c +++ b/Src/i2c.c @@ -34,7 +34,6 @@ void i2c_gpio_config(void) { i2c_result_t i2c_config(void) { /* configure I2C GPIO */ i2c_gpio_config(); - /* enable I2C clock */ rcu_periph_clock_enable(RCU_I2C); /* configure I2C clock */ @@ -150,7 +149,7 @@ i2c_result_t i2c_bus_reset(void) { } #ifdef DEBUG_VERBOSE - printf("I2C bus reset: bus recovered\r\n"); + printf("I2C bus reset: bus recovered\r\n"); #endif /* 8. Reconfigure & enable peripheral */ i2c_config(); @@ -198,12 +197,10 @@ void i2c_scan(void) { i2c_master_addressing(I2C0, (address << 1), I2C_TRANSMITTER); timeout = 0; - // 等待地址发送完成或错误 - while (!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND) && !i2c_flag_get(I2C0, I2C_FLAG_AERR) && (timeout < I2C_TIME_OUT)) + // 等待地址发送完成 + while (!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND) && (timeout < I2C_TIME_OUT)) timeout++; - - if (timeout < I2C_TIME_OUT && i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) { - // 设备响应 - 清除地址标志 + if (timeout < I2C_TIME_OUT) { i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); // printf("Found device at 0x%02X\r\n", address); const char* msg2_prefix = "Found device at 0x"; @@ -224,9 +221,6 @@ void i2c_scan(void) { } while (usart_flag_get(I2C_DEBUG_UART, USART_FLAG_TC) == RESET) {} found_devices++; - } else if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) { - // 设备无响应 - 清除错误标志 - i2c_flag_clear(I2C0, I2C_FLAG_AERR); } // 生成停止条件 @@ -269,53 +263,6 @@ void i2c_scan(void) { } } -/** - * @brief 内部辅助函数:等待指定的I2C标志位被设置,带有超时。 - * @param[in] flag: 要等待的I2C事件标志。 - * @retval i2c_result_t: I2C_RESULT_SUCCESS 或 I2C_RESULT_TIMEOUT。 - */ -static i2c_result_t _i2c_wait_flag_timeout(uint32_t flag) -{ - uint16_t timeout = 0; - while(!i2c_flag_get(I2C0, flag)){ - if(timeout++ > I2C_TIME_OUT){ -#ifdef DEBUG_VERBOSE - const char* fname = "UNKNOWN"; - switch (flag) { - case I2C_FLAG_SBSEND: fname = "SBSEND"; break; - case I2C_FLAG_ADDSEND: fname = "ADDSEND"; break; - case I2C_FLAG_TBE: fname = "TBE"; break; - case I2C_FLAG_RBNE: fname = "RBNE"; break; - case I2C_FLAG_BTC: fname = "BTC"; break; - case I2C_FLAG_AERR: fname = "AERR"; break; - case I2C_FLAG_BERR: fname = "BERR"; break; - case I2C_FLAG_LOSTARB: fname = "LOSTARB"; break; - case I2C_FLAG_I2CBSY: fname = "I2CBSY"; break; - } - printf("I2C wait flag timeout: flag=0x%08X (%s)\r\n", (unsigned int)flag, fname); -#endif - return I2C_RESULT_TIMEOUT; - } - } - return I2C_RESULT_SUCCESS; -} - -/** - * @brief 内部辅助函数:等待指定的I2C标志位被清除,带有超时。 - * @param[in] flag: 要等待的I2C事件标志。 - * @retval i2c_result_t: I2C_RESULT_SUCCESS 或 I2C_RESULT_TIMEOUT。 - */ -static i2c_result_t _i2c_wait_flag_clear_timeout(uint32_t flag) -{ - uint16_t timeout = 0; - while(i2c_flag_get(I2C0, flag)){ - if(timeout++ > I2C_TIME_OUT){ - return I2C_RESULT_TIMEOUT; - } - } - return I2C_RESULT_SUCCESS; -} - i2c_result_t i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[2]) { i2c_state_t state = I2C_STATE_START; uint16_t timeout = 0; @@ -378,7 +325,7 @@ i2c_result_t i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data } else { i2c_flag_clear(I2C0, I2C_FLAG_AERR); timeout =0; -#ifdef DEBUG_VERBOSE +#ifdef DEBUG_VERBOES printf("IIC write failed for Error Slave Address. \n"); #endif return I2C_RESULT_NACK; @@ -386,28 +333,39 @@ i2c_result_t i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data case I2C_STATE_TRANSMIT_REG: /* wait until the transmit data buffer is empty */ - if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) { + while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send register address */ i2c_data_transmit(I2C0, reg_addr); + timeout = 0; state = I2C_STATE_TRANSMIT_DATA; break; case I2C_STATE_TRANSMIT_DATA: /* wait until the transmit data buffer is empty */ - if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) { + while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send register MSB value */ i2c_data_transmit(I2C0, data[0]); - + timeout = 0; + /* wait until the transmit data buffer is empty */ - if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) { + while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } @@ -423,9 +381,13 @@ i2c_result_t i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data /* send register LSB value */ i2c_data_transmit(I2C0, data[1]); - + timeout = 0; + /* wait until BTC bit is set */ - if(_i2c_wait_flag_timeout(I2C_FLAG_BTC) != I2C_RESULT_SUCCESS) { + while (!i2c_flag_get(I2C0, I2C_FLAG_BTC) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } @@ -451,13 +413,25 @@ i2c_result_t i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data return I2C_RESULT_SUCCESS; case I2C_STATE_ERROR: - /* I2C bus error, try to reset the bus and retry */ - i2c_bus_reset(); + /* send a stop condition to I2C bus */ + i2c_stop_on_bus(I2C0); + + timeout = 0; + while ((I2C_CTL0(I2C0) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { + return I2C_RESULT_ERROR; + } + + i2c_flag_clear(I2C0, I2C_FLAG_AERR); + i2c_flag_clear(I2C0, I2C_FLAG_BERR); + i2c_flag_clear(I2C0, I2C_FLAG_LOSTARB); retry_count ++; if (retry_count >= I2C_MAX_RETRY) { -#ifdef DEBUG_VERBOSE +#ifdef DEBUG_VERBOES printf("IIC write failed after %d retries\n", I2C_MAX_RETRY); #endif return I2C_RESULT_ERROR; @@ -470,7 +444,7 @@ i2c_result_t i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data /* small delay before retry */ delay_10us(10); break; - + default: state = I2C_STATE_START; break; @@ -498,8 +472,11 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data case I2C_STATE_START: timeout = 0; - /* wait for bus to be idle */ - if(_i2c_wait_flag_clear_timeout(I2C_FLAG_I2CBSY) != I2C_RESULT_SUCCESS) { + // wait for bus to be idle + while (i2c_flag_get(I2C0, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } @@ -507,11 +484,15 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data // send start condition i2c_start_on_bus(I2C0); state = I2C_STATE_SEND_ADDRESS; + timeout = 0; break; case I2C_STATE_SEND_ADDRESS: /* wait for start condition to be sent */ - if(_i2c_wait_flag_timeout(I2C_FLAG_SBSEND) != I2C_RESULT_SUCCESS) { + while ((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } @@ -559,7 +540,10 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data case I2C_STATE_TRANSMIT_DATA: /* wait for transmit buffer to be empty */ - if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) { + while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } @@ -567,20 +551,28 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data /* send register address */ i2c_data_transmit(I2C0, reg_addr); state = I2C_STATE_RESTART; + timeout = 0; break; case I2C_STATE_RESTART: /* wait for byte transfer complete BTC: Bit Transfer Complete */ - if(_i2c_wait_flag_timeout(I2C_FLAG_BTC) != I2C_RESULT_SUCCESS) { + while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* generate repeated start condition */ i2c_start_on_bus(I2C0); - + /* wait for repeated start condition to be sent */ - if(_i2c_wait_flag_timeout(I2C_FLAG_SBSEND) != I2C_RESULT_SUCCESS) { + timeout = 0; + while ((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } @@ -596,7 +588,10 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data case I2C_STATE_RECEIVE_DATA: /* Wait for BTC (both bytes received) */ - if(_i2c_wait_flag_timeout(I2C_FLAG_BTC) != I2C_RESULT_SUCCESS) { + while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } @@ -626,13 +621,13 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data return I2C_RESULT_SUCCESS; case I2C_STATE_ERROR: - /* I2C bus error, try to reset the bus and retry */ - i2c_bus_reset(); + /* send stop condition to release bus */ + i2c_stop_on_bus(I2C0); retry_count++; if (retry_count >= I2C_MAX_RETRY) { -#ifdef DEBUG_VERBOSE - printf("IIC read failed after %d retries\n", I2C_MAX_RETRY); +#ifdef DEBUG_VERBOES + printf("IIC read failed after %d retries\n", I2C_RETRY_MAX); #endif return I2C_RESULT_ERROR; } @@ -657,13 +652,13 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data /*! \brief write data to I2C device with configurable length \param[in] slave_addr: slave device address (7-bit) - \param[in] reg_addr: register address (16-bit, high byte first) + \param[in] reg_addr: register address \param[in] data: pointer to data buffer \param[in] length: number of bytes to write (1-255) \param[out] none \retval i2c_result_t: operation result */ -i2c_result_t i2c_write(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint8_t length) { +i2c_result_t i2c_write(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length) { i2c_state_t state = I2C_STATE_START; uint16_t timeout = 0; uint8_t retry_count = 0; @@ -671,9 +666,6 @@ i2c_result_t i2c_write(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uin /* parameter validation */ if (data == NULL || slave_addr > 0x7F || length == 0) { -#ifdef DEBUG_VERBOSE - printf("I2C write invalid param: slave=0x%02X, len=%u, data=%p\r\n", slave_addr, length, data); -#endif return I2C_RESULT_INVALID_PARAM; } @@ -727,71 +719,67 @@ i2c_result_t i2c_write(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uin state = I2C_STATE_TRANSMIT_REG; break; } else { - /* NACK received - address not acknowledged */ i2c_flag_clear(I2C0, I2C_FLAG_AERR); - i2c_stop_on_bus(I2C0); timeout = 0; #ifdef DEBUG_VERBOSE - printf("I2C write failed for Error Slave Address. \n"); + printf("IIC write failed for Error Slave Address. \n"); #endif return I2C_RESULT_NACK; } case I2C_STATE_TRANSMIT_REG: /* wait until the transmit data buffer is empty */ - if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) { + while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } - /* send register address, high byte first */ - if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - i2c_data_transmit(I2C0, (uint8_t)(reg_addr >> 8)); - - if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - i2c_data_transmit(I2C0, (uint8_t)(reg_addr & 0xFF)); + /* send register address */ + i2c_data_transmit(I2C0, reg_addr); + timeout = 0; state = I2C_STATE_TRANSMIT_DATA; break; case I2C_STATE_TRANSMIT_DATA: /* wait until the transmit data buffer is empty */ - while (data_index < length) { - if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - - /* send data byte */ - i2c_data_transmit(I2C0, data[data_index]); - data_index++; - - /* check for errors */ - if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) { - i2c_stop_on_bus(I2C0); - return I2C_RESULT_NACK; - } else if (i2c_flag_get(I2C0, I2C_FLAG_BERR) || i2c_flag_get(I2C0, I2C_FLAG_LOSTARB)) { - i2c_stop_on_bus(I2C0); - return I2C_RESULT_ERROR; - } + while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { + state = I2C_STATE_ERROR; + break; } - if(state == I2C_STATE_ERROR) break; + /* send data byte */ + i2c_data_transmit(I2C0, data[data_index]); + data_index++; + + /* check for errors */ + if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) { + i2c_stop_on_bus(I2C0); + return I2C_RESULT_NACK; + } else if (i2c_flag_get(I2C0, I2C_FLAG_BERR) || i2c_flag_get(I2C0, I2C_FLAG_LOSTARB)) { + i2c_stop_on_bus(I2C0); + return I2C_RESULT_ERROR; + } /* check if all data has been sent */ if (data_index >= length) { /* wait until BTC bit is set for last byte */ - if(_i2c_wait_flag_timeout(I2C_FLAG_BTC) != I2C_RESULT_SUCCESS) { + timeout = 0; + while (!i2c_flag_get(I2C0, I2C_FLAG_BTC) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } state = I2C_STATE_STOP; } + timeout = 0; break; case I2C_STATE_STOP: @@ -811,8 +799,17 @@ i2c_result_t i2c_write(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uin return I2C_RESULT_SUCCESS; case I2C_STATE_ERROR: - /* I2C bus error, try to reset the bus and retry */ - i2c_bus_reset(); + /* send a stop condition to I2C bus */ + i2c_stop_on_bus(I2C0); + + timeout = 0; + while ((I2C_CTL0(I2C0) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + + i2c_flag_clear(I2C0, I2C_FLAG_AERR); + i2c_flag_clear(I2C0, I2C_FLAG_BERR); + i2c_flag_clear(I2C0, I2C_FLAG_LOSTARB); retry_count++; if (retry_count >= I2C_MAX_RETRY) { @@ -829,7 +826,7 @@ i2c_result_t i2c_write(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uin /* small delay before retry */ delay_10us(10); break; - + default: state = I2C_STATE_START; break; @@ -841,12 +838,12 @@ i2c_result_t i2c_write(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uin /*! \brief read data from I2C device with configurable length \param[in] slave_addr: slave device address (7-bit) - \param[in] reg_addr: register address (16-bit, high byte first) + \param[in] reg_addr: register address \param[out] data: pointer to data buffer \param[in] length: number of bytes to read (1-255) \retval i2c_result_t: operation result */ -i2c_result_t i2c_read(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint8_t length) { +i2c_result_t i2c_read(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length) { i2c_state_t state = I2C_STATE_START; uint16_t timeout = 0; uint8_t retry_count = 0; @@ -861,10 +858,6 @@ i2c_result_t i2c_read(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint /* enable acknowledge */ i2c_ack_config(I2C0, I2C_ACK_ENABLE); -#ifdef DEBUG_VERBOSE - printf("I2C read start: slave=0x%02X reg=0x%02X len=%u\r\n", slave_addr, reg_addr, length); -#endif - while (retry_count < (uint8_t)I2C_MAX_RETRY) { switch (state) { case I2C_STATE_START: @@ -872,7 +865,10 @@ i2c_result_t i2c_read(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint data_index = 0; /* wait for bus to be idle */ - if(_i2c_wait_flag_clear_timeout(I2C_FLAG_I2CBSY) != I2C_RESULT_SUCCESS) { + while (i2c_flag_get(I2C0, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } @@ -880,11 +876,15 @@ i2c_result_t i2c_read(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint /* send start condition */ i2c_start_on_bus(I2C0); state = I2C_STATE_SEND_ADDRESS; + timeout = 0; break; case I2C_STATE_SEND_ADDRESS: /* wait for start condition to be sent */ - if(_i2c_wait_flag_timeout(I2C_FLAG_SBSEND) != I2C_RESULT_SUCCESS) { + while ((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } @@ -912,92 +912,67 @@ i2c_result_t i2c_read(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint break; } - /* debug: show address ack and error flags */ -#ifdef DEBUG_VERBOSE - printf("I2C CLEAR_ADDRESS: write_phase=%d ADDSEND=%d AERR=%d\r\n", - (int)write_phase, - (int)i2c_flag_get(I2C0, I2C_FLAG_ADDSEND), - (int)i2c_flag_get(I2C0, I2C_FLAG_AERR)); -#endif - if (write_phase) { /* clear address flag (write phase) */ i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); state = I2C_STATE_TRANSMIT_DATA; } else { - /* READ phase: handle ACK/ACKPOS based on requested length - - length == 1: disable ACK before clearing ADDR - - length == 2: set ACKPOS_NEXT and disable ACK before clearing ADDR - - length > 2: keep ACK enabled and clear ADDR; we'll handle N-2/BTF sequence later */ + /* read phase setup based on length */ if (length == 1) { + /* single byte read: disable ACK before clearing ADDR */ i2c_ack_config(I2C0, I2C_ACK_DISABLE); -#ifdef DEBUG_VERBOSE - printf("I2C READ phase: length=1, disabling ACK before clearing ADDSEND\r\n"); -#endif + i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); + /* send STOP immediately after clearing ADDR for single byte */ + i2c_stop_on_bus(I2C0); } else if (length == 2) { + /* two bytes read: set POS=NEXT and disable ACK before clearing ADDR */ i2c_ackpos_config(I2C0, I2C_ACKPOS_NEXT); i2c_ack_config(I2C0, I2C_ACK_DISABLE); -#ifdef DEBUG_VERBOSE - printf("I2C READ phase: length=2, set ACKPOS_NEXT and disabling ACK before clearing ADDSEND\r\n"); -#endif + i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); } else { - /* length > 2: keep ACK enabled so slave will clock out data */ - i2c_ack_config(I2C0, I2C_ACK_ENABLE); -#ifdef DEBUG_VERBOSE - printf("I2C READ phase: length=%u (>2), keeping ACK enabled\r\n", length); -#endif + /* multi-byte read: clear ADDR with ACK enabled */ + i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); } - - /* now clear address flag to release SCL and enter data phase */ - i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); - state = I2C_STATE_RECEIVE_DATA; } - timeout = 0; break; case I2C_STATE_TRANSMIT_DATA: /* wait for transmit buffer to be empty */ - if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) { + while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } - /* send register address, high byte first */ - if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - i2c_data_transmit(I2C0, (uint8_t)(reg_addr >> 8)); - - if(_i2c_wait_flag_timeout(I2C_FLAG_TBE) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - i2c_data_transmit(I2C0, (uint8_t)(reg_addr & 0xFF)); + /* send register address */ + i2c_data_transmit(I2C0, reg_addr); state = I2C_STATE_RESTART; + timeout = 0; break; case I2C_STATE_RESTART: /* wait for byte transfer complete */ - if(_i2c_wait_flag_timeout(I2C_FLAG_BTC) != I2C_RESULT_SUCCESS) { + while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } -#ifdef DEBUG_VERBOSE - printf("I2C RESTART: after BTC, delay 5ms and issuing repeated START\r\n"); -#endif - /* small delay to allow slave device to prepare multi-byte data before repeated start */ - /* increased to 5ms to improve reliability for DLPC multi-byte reads */ - delay_ms(5); - /* generate repeated start condition */ i2c_start_on_bus(I2C0); - + /* wait for repeated start condition to be sent */ - if(_i2c_wait_flag_timeout(I2C_FLAG_SBSEND) != I2C_RESULT_SUCCESS) { + timeout = 0; + while ((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } @@ -1009,18 +984,15 @@ i2c_result_t i2c_read(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint write_phase = false; state = I2C_STATE_CLEAR_ADDRESS; timeout = 0; -#ifdef DEBUG_VERBOSE - printf("I2C addressing sent for read (slave=0x%02X)\r\n", slave_addr); -#endif break; case I2C_STATE_RECEIVE_DATA: -#ifdef DEBUG_VERBOSE - printf("I2C RECEIVE_DATA: expecting %u bytes\r\n", length); -#endif if (length == 1) { /* single byte read */ - if(_i2c_wait_flag_timeout(I2C_FLAG_RBNE) != I2C_RESULT_SUCCESS) { + while ((!i2c_flag_get(I2C0, I2C_FLAG_RBNE)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } @@ -1028,7 +1000,10 @@ i2c_result_t i2c_read(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint state = I2C_STATE_STOP; } else if (length == 2) { /* two bytes read */ - if(_i2c_wait_flag_timeout(I2C_FLAG_BTC) != I2C_RESULT_SUCCESS) { + while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } @@ -1041,39 +1016,40 @@ i2c_result_t i2c_read(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint } else { /* multi-byte read (length > 2) */ while (data_index < length) { - if (data_index < length - 2) { - /* normal bytes: wait for RBNE and read with ACK */ - if(_i2c_wait_flag_timeout(I2C_FLAG_RBNE) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - data[data_index] = i2c_data_receive(I2C0); - data_index++; - } else if (data_index == length - 2) { - /* second to last byte: wait for BTF, then disable ACK and read */ - if(_i2c_wait_flag_timeout(I2C_FLAG_BTC) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - /* disable ACK before reading N-1 byte */ - i2c_ack_config(I2C0, I2C_ACK_DISABLE); - /* send STOP before reading N-1 byte */ - i2c_stop_on_bus(I2C0); - /* read N-1 byte */ - data[data_index] = i2c_data_receive(I2C0); - data_index++; - } else { - /* last byte: wait for RBNE and read */ - if(_i2c_wait_flag_timeout(I2C_FLAG_RBNE) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - /* read last byte */ - data[data_index] = i2c_data_receive(I2C0); - data_index++; + /* wait for RBNE (receive buffer not empty) */ + while ((!i2c_flag_get(I2C0, I2C_FLAG_RBNE)) && (timeout < I2C_TIME_OUT)) { + timeout++; } + if (timeout >= I2C_TIME_OUT) { + state = I2C_STATE_ERROR; + break; + } + + /* special handling for last 3 bytes */ + if (data_index == length - 3) { + /* wait for BTF (byte transfer finished) before reading N-2 */ + while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout >= I2C_TIME_OUT) { + state = I2C_STATE_ERROR; + break; + } + /* disable ACK for last 2 bytes */ + i2c_ack_config(I2C0, I2C_ACK_DISABLE); + } + + /* read data byte */ + data[data_index] = i2c_data_receive(I2C0); + data_index++; + + /* send STOP after reading N-1 byte */ + if (data_index == length - 1) { + i2c_stop_on_bus(I2C0); + } + + timeout = 0; } - if(state == I2C_STATE_ERROR) break; state = I2C_STATE_STOP; } break; @@ -1096,11 +1072,8 @@ i2c_result_t i2c_read(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint return I2C_RESULT_SUCCESS; case I2C_STATE_ERROR: - /* I2C bus error, try to reset the bus and retry */ -#ifdef DEBUG_VERBOSE - printf("I2C_STATE_ERROR: resetting bus and retrying (retry_count=%u)\r\n", retry_count); -#endif - i2c_bus_reset(); + /* send stop condition to release bus */ + i2c_stop_on_bus(I2C0); /* reset ACK configuration */ i2c_ack_config(I2C0, I2C_ACK_ENABLE); @@ -1109,13 +1082,7 @@ i2c_result_t i2c_read(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint retry_count++; if (retry_count >= I2C_MAX_RETRY) { #ifdef DEBUG_VERBOSE - /* Print diagnostic flags to help root-cause analysis */ - printf("I2C read final failure after %d retries, last_state=%d\r\n", I2C_MAX_RETRY, state); - printf(" FLAGS: AERR=%d BERR=%d LOSTARB=%d I2CBSY=%d\r\n", - (int)i2c_flag_get(I2C0, I2C_FLAG_AERR), - (int)i2c_flag_get(I2C0, I2C_FLAG_BERR), - (int)i2c_flag_get(I2C0, I2C_FLAG_LOSTARB), - (int)i2c_flag_get(I2C0, I2C_FLAG_I2CBSY)); + printf("I2C read failed after %d retries\n", I2C_MAX_RETRY); #endif return I2C_RESULT_ERROR; } @@ -1134,179 +1101,39 @@ i2c_result_t i2c_read(uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint break; } } - /* timeout path: provide debug info */ -#ifdef DEBUG_VERBOSE - printf("I2C read timeout (end state). slave=0x%02X, len=%u\r\n", slave_addr, length); - printf(" FLAGS: AERR=%d BERR=%d LOSTARB=%d I2CBSY=%d\r\n", - (int)i2c_flag_get(I2C0, I2C_FLAG_AERR), - (int)i2c_flag_get(I2C0, I2C_FLAG_BERR), - (int)i2c_flag_get(I2C0, I2C_FLAG_LOSTARB), - (int)i2c_flag_get(I2C0, I2C_FLAG_I2CBSY)); -#endif return I2C_RESULT_TIMEOUT; } -/*! - \brief read data from I2C device without register/sub-address phase - \param[in] slave_addr: slave device address (7-bit) - \param[out] data: pointer to data buffer - \param[in] length: number of bytes to read (1-255) - \retval i2c_result_t: operation result -*/ -i2c_result_t i2c_read_raw(uint8_t slave_addr, uint8_t *data, uint8_t length) -{ - i2c_state_t state = I2C_STATE_START; - uint16_t timeout = 0; - uint8_t retry_count = 0; - uint8_t data_index = 0; +/* convenience functions for common operations */ +i2c_result_t i2c_write_8bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data) { + return i2c_write(slave_addr, reg_addr, &data, 1); +} - if (data == NULL || slave_addr > 0x7F || length == 0) { +i2c_result_t i2c_read_8bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data) { + return i2c_read(slave_addr, reg_addr, data, 1); +} + +i2c_result_t i2c_write_32bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[4]) { + return i2c_write(slave_addr, reg_addr, data, 4); +} + +i2c_result_t i2c_read_32bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data) { + return i2c_read(slave_addr, reg_addr, data, 4); +} + +/* 显示面板专用函数 - 支持读取显示界面参数 */ +i2c_result_t i2c_read_display_params(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length) { + /* 针对显示面板的多字节读取,支持13字节的完整参数读取 */ + if (length > 13) { return I2C_RESULT_INVALID_PARAM; } - - i2c_ack_config(I2C0, I2C_ACK_ENABLE); - - while (retry_count < (uint8_t)I2C_MAX_RETRY) { - switch (state) { - case I2C_STATE_START: - timeout = 0; - data_index = 0; - - if (_i2c_wait_flag_clear_timeout(I2C_FLAG_I2CBSY) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - - i2c_start_on_bus(I2C0); - state = I2C_STATE_SEND_ADDRESS; - break; - - case I2C_STATE_SEND_ADDRESS: - if (_i2c_wait_flag_timeout(I2C_FLAG_SBSEND) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - - i2c_master_addressing(I2C0, (slave_addr << 1), I2C_RECEIVER); - state = I2C_STATE_CLEAR_ADDRESS; - timeout = 0; - break; - - case I2C_STATE_CLEAR_ADDRESS: - while ((!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) && (!i2c_flag_get(I2C0, I2C_FLAG_AERR)) && (timeout < I2C_TIME_OUT)) { - timeout++; - } - if (timeout >= I2C_TIME_OUT) { - state = I2C_STATE_ERROR; - break; - } - if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) { - i2c_flag_clear(I2C0, I2C_FLAG_AERR); - i2c_stop_on_bus(I2C0); - return I2C_RESULT_NACK; - } - - if (length == 1) { - i2c_ack_config(I2C0, I2C_ACK_DISABLE); - } else if (length == 2) { - i2c_ackpos_config(I2C0, I2C_ACKPOS_NEXT); - i2c_ack_config(I2C0, I2C_ACK_DISABLE); - } else { - i2c_ack_config(I2C0, I2C_ACK_ENABLE); - } - - i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); - state = I2C_STATE_RECEIVE_DATA; - timeout = 0; - break; - - case I2C_STATE_RECEIVE_DATA: - if (length == 1) { - if (_i2c_wait_flag_timeout(I2C_FLAG_RBNE) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - data[0] = i2c_data_receive(I2C0); - state = I2C_STATE_STOP; - } else if (length == 2) { - if (_i2c_wait_flag_timeout(I2C_FLAG_BTC) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - i2c_stop_on_bus(I2C0); - data[0] = i2c_data_receive(I2C0); - data[1] = i2c_data_receive(I2C0); - state = I2C_STATE_STOP; - } else { - while (data_index < length) { - if (data_index < length - 2) { - if (_i2c_wait_flag_timeout(I2C_FLAG_RBNE) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - data[data_index++] = i2c_data_receive(I2C0); - } else if (data_index == length - 2) { - if (_i2c_wait_flag_timeout(I2C_FLAG_BTC) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - i2c_ack_config(I2C0, I2C_ACK_DISABLE); - i2c_stop_on_bus(I2C0); - data[data_index++] = i2c_data_receive(I2C0); - } else { - if (_i2c_wait_flag_timeout(I2C_FLAG_RBNE) != I2C_RESULT_SUCCESS) { - state = I2C_STATE_ERROR; - break; - } - data[data_index++] = i2c_data_receive(I2C0); - } - } - if (state == I2C_STATE_ERROR) break; - state = I2C_STATE_STOP; - } - break; - - case I2C_STATE_STOP: - while ((I2C_CTL0(I2C0) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) { - timeout++; - } - if (timeout >= I2C_TIME_OUT) { - state = I2C_STATE_ERROR; - break; - } - - i2c_ack_config(I2C0, I2C_ACK_ENABLE); - i2c_ackpos_config(I2C0, I2C_ACKPOS_CURRENT); - return I2C_RESULT_SUCCESS; - - case I2C_STATE_ERROR: - i2c_bus_reset(); - i2c_ack_config(I2C0, I2C_ACK_ENABLE); - i2c_ackpos_config(I2C0, I2C_ACKPOS_CURRENT); - - retry_count++; - if (retry_count >= I2C_MAX_RETRY) { - return I2C_RESULT_ERROR; - } - - state = I2C_STATE_START; - timeout = 0; - delay_10us(10); - break; - - default: - state = I2C_STATE_START; - break; - } - } - - return I2C_RESULT_TIMEOUT; + return i2c_read(slave_addr, reg_addr, data, length); } #ifdef DEBUG_VERBOSE /*! \brief get status string for debugging - \param[in] status: i2c_result_t value + \param[in] status: i2c_status_t value \param[out] none \retval const char* status string */ diff --git a/Src/ldc1612.c b/Src/ldc1612.c index fb52e1d..f671e75 100644 --- a/Src/ldc1612.c +++ b/Src/ldc1612.c @@ -148,17 +148,11 @@ ldc1612_status_t ldc1612_init(void) { */ ldc1612_status_t ldc1612_config_single_channel(uint8_t channel) { i2c_result_t status; - uint16_t freq_divider; if (channel > 1) { return LDC1612_STATUS_INVALID_PARAM; } - freq_divider = ldc1612_calculate_freq_divider(channel); - if (freq_divider == 0) { - return LDC1612_STATUS_INVALID_PARAM; - } - /* 配置顺序严格按照TI官方文档要求 */ /* Step 1: 确保传感器处于睡眠模式 - 配置前必须 */ @@ -167,34 +161,28 @@ ldc1612_status_t ldc1612_config_single_channel(uint8_t channel) { delay_ms(10); /* Step 2: 配置频率分频 - 必须在其他配置之前 */ - status = ldc1612_write_register(SET_FREQ_REG_START + channel, freq_divider); - if (status != I2C_RESULT_SUCCESS) return LDC1612_STATUS_ERROR; + uint16_t freq_divider = ldc1612_calculate_freq_divider(channel); + ldc1612_write_register(SET_FREQ_REG_START + channel, freq_divider); delay_ms(5); /* Step 3: 配置LC稳定时间 - 影响测量精度 */ - status = ldc1612_write_register(SET_SETTLECOUNT_REG_START + channel, LDC1612_SETTLECOUNT_CH0); - if (status != I2C_RESULT_SUCCESS) return LDC1612_STATUS_ERROR; + ldc1612_write_register(SET_SETTLECOUNT_REG_START + channel, LDC1612_SETTLECOUNT_CH0); /* Step 4: 配置转换时间 - 影响测量速度和精度 */ - status = ldc1612_write_register(SET_CONVERSION_TIME_REG_START + channel, LDC1612_RCOUNT_TIME_CH0); - if (status != I2C_RESULT_SUCCESS) return LDC1612_STATUS_ERROR; + ldc1612_write_register(SET_CONVERSION_TIME_REG_START + channel, LDC1612_RCOUNT_TIME_CH0); /* Step 5: 配置转换偏移 */ - status = ldc1612_write_register(SET_CONVERSION_OFFSET_REG_START + channel, SET_CONVERSION_OFFSET_CH0); - if (status != I2C_RESULT_SUCCESS) return LDC1612_STATUS_ERROR; + ldc1612_write_register(SET_CONVERSION_OFFSET_REG_START + channel, SET_CONVERSION_OFFSET_CH0); /* Step 6: 配置驱动电流 - 影响传感器灵敏度 */ - status = ldc1612_write_register(SET_DRIVER_CURRENT_REG + channel, LDC1612_DRIVE_CURRENT); - if (status != I2C_RESULT_SUCCESS) return LDC1612_STATUS_ERROR; + ldc1612_write_register(SET_DRIVER_CURRENT_REG + channel, LDC1612_DRIVE_CURRENT); /* Step 7: 配置多路复用器 - 设置通道选择和滤波 */ // ldc1612_configure_mux_register(LDC1612_MUX_AUTOSCAN_DISABLE, LDC1612_MUX_RR_SEQUENCE_0, LDC1612_MUX_FILTER_ALL_LOW, LDC1612_MUX_FILTER_NONE); - status = ldc1612_write_register(MUX_CONFIG_REG, LDC1612_MUX_CONFIG); - if (status != I2C_RESULT_SUCCESS) return LDC1612_STATUS_ERROR; + ldc1612_write_register(MUX_CONFIG_REG, LDC1612_MUX_CONFIG); /* Step 8: 配置错误输出 */ - status = ldc1612_write_register(ERROR_CONFIG_REG, LDC1612_ERROR_CONFIG_DEFAULT); - if (status != I2C_RESULT_SUCCESS) return LDC1612_STATUS_ERROR; + ldc1612_write_register(ERROR_CONFIG_REG, LDC1612_ERROR_CONFIG_DEFAULT); /* Step 9: 最后启动传感器 - 必须最后一步 */ status = ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SENSOR_CONFIG_CH0); @@ -344,4 +332,4 @@ uint16_t ldc1612_check_status_and_log_errors(void) { // 读取STATUS寄存器会自动清除错误标志,但不会清除DRDY和UNREADCONV标志 return status; -} +} \ No newline at end of file diff --git a/Src/tmp112.c b/Src/tmp112.c index 63e2f01..7f5c71f 100644 --- a/Src/tmp112.c +++ b/Src/tmp112.c @@ -86,7 +86,8 @@ tmp112a_status_t tmp112a_read_temperature(tmp112a_result_t *result) { } void tmp112a_get_raw_temperature_value(uint8_t *value) { - i2c_read_16bits(TMP112A_ADDR, TMP112A_TEMP_REG, value); + // i2c_read_16bits(TMP112A_ADDR, TMP112A_TEMP_REG, value); + i2c_read(TMP112A_ADDR, TMP112A_TEMP_REG, value, 2); return; } diff --git a/cmake/project_config.cmake b/cmake/project_config.cmake index 66426af..c6f7a60 100644 --- a/cmake/project_config.cmake +++ b/cmake/project_config.cmake @@ -1,11 +1,12 @@ # Project basic info -# golden 出厂保底线:版本号冻结 V1.0.2(保底判定值 v26.1.0.2,永不再用于 OTA 升级包) +# golden 出厂保底线:生产实装版原样复制(GitLab ceramixnano_eddy_cmake_vscode dev@151828f,v26.1.0.3,2026-10-25) +# 保底判定值 = M999 返回 v26.1.0.3 ⇔ 在跑 FW_B;v26.1.0.2(旧 golden)与 v26.1.0.3 均永不再用于 OTA 升级包版本 # 此分支改动不得合回 dev/main(链接基址 0x0800B000 为 B 槽专属) set(PROJECT_NAME "CeramixNano-EDDY") set(BOARD_TYPE_CODE 26) set(VERSION_MAJOR 1) set(VERSION_MINOR 0) -set(VERSION_PATCH 2) +set(VERSION_PATCH 3) set(VERSION "V${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") string(TIMESTAMP BUILD_DATE "%Y-%m-%d")