78248a1cdf
前一笔立契约与门禁(`Drivers/BSP/bsp_err.h` + `bsp-err` 钩子 + RS485 试点);这一笔按用户
指定顺序 C3 → C1 → C2 把三个模块真正收编,并让存储失败第一次变得可读、可分类。
**C3 · SD2506 整模块(11 个公共 API + 6 个内部 helper)**:三枚私有宏 `SD2506_OK`/
`SD2506_ERROR`/`SD2506_I2C_ERROR` **删除而不是留别名**——留别名等于新代码还能用旧形状,
把迁移洗掉;编译器替我们找全所有调用点。新增 `sd2506_err_from_hal()`,**把 I2C 超时从
"和没人应答共用一个 −2"里拆出来归成 `BSP_ERR_TIMEOUT`(可重试)**——SD2506 是启动链第一站、
I2C1 上电时序敏感,这是本波唯一真正的语义改善,不是改名。`sd2506_init` 的 charge 寄存器
**回读校验不符**原返参数类错误,改归 `BSP_ERR_IO`(那不是调用方的错)。
**C1 · 同形两义**:`GD5F_BUSY_TIMEOUT` → `GD5F_WAIT_EXPIRED`(**值 −2 不变**,纯消"名字叫
TIMEOUT 其实是返回码")。**GD5F 私有码集整体收编刻意没做**:169 处引用里 48 处在板级套件、
还要动 Trap 记录用词,属另一波带真机+套件回归的工作,不夹带。TPAFE5160 收编 23 处:
`BUSY_TIMEOUT → BSP_ERR_TIMEOUT`、`ERROR → BSP_ERR_PARAM`(**同值 −1,行为零变化**)、
`FRSTDATA_ERR → BSP_ERR_NO_DEVICE`(E-44 的本义就是"芯片没驱动 DB 总线",归到器件无响应比
私有 −3 有用,且避开与 `BSP_ERR_TIMEOUT` 撞值)。实测 `tpafe5160.o`/`gd5f2gq5ue.o` 的 Code
增量为 **0**——改名不产生一条指令。
⚠ **`tpafe5160_snapshot()` 刻意不套成败码**:它是 1=有新帧 / 0=无新帧 / −1=参数错 的三态
**状态**返回,0 不是错误而是"这一拍没有新数据",强行收编会把慢消费者的正常路径变成失败。
顺带订正我上一版在 `bsp_err.h` 的断言——"本层只有 `net_*` 把数量与错误挤同一返回值"是错的,
`snapshot`/`adc_input_poll` 就是第二族;两族现都已写明并各注保留理由。
**C2 · FTL 坍缩点分类**:`ftl_flush_cache`/`ftl_read_page` 不再把 dhara 失败压成
`GD5F_ERROR`,
按**处置差异**分三类,并在最早同时知道 LPN 与原始码的位置就地打印:`ECC`/`TOO_BAD` →
`BSP_ERR_CRC`(页级,重试或换页,不代表卷坏);`JOURNAL_FULL`/`MAP_FULL` →
`BSP_ERR_NO_SPACE`(介质健康但块池/日志见底,此时重格式化只是把问题推回去);
`BAD_BLOCK`/`RECOVER`/`CORRUPT_MAP`/越界 → `BSP_ERR_IO`(完整性故障,保卷 + 上报,不许自愈
重格式化)。这与 **E-31** 是同一条纪律的两端。可读名用自建短表:**本仓 dhara 没有编
`error.c`,用 `dhara_strerror()` 会直接链接失败**。`disk_read`/`disk_write` 仍回
`RES_ERROR`
(FatFs 契约);要让 defaultTask 卷健康探针按类分支还差跨调用存活的快照 → C4 待还。
**两次靠核实拦住的自我错误**:① 我一度认定 `DBG_ERROR("... err=%d", err)` 是把结构体塞进
varargs 的格式 bug——核 `Lib/dhara/error.h` 后确认 `dhara_error_t` 是 `enum`(标量),那行日志
本来合法,改了反而是引入错误;② `bsp-err` 一次 `replace_all` 越界把 8 处 **GD5F 码空间**的
判据改成 `!= BSP_OK`(数值同为 0、无行为变化),但那正是"把两个码空间混起来",已逐一还原。
`cppcheck` 亦抓到 `cls` 声明作用域过宽,已收进失败分支。
**验证**:`@build` 0 错 0 警告(`Code` 213,648、RO 18,860、`ER_IROM1` 232,508 B /
22.2%、
`ROM 合计` 233,696;**RAM 三项零增量**);`@test` PASS(692 ms,烧入戳 `Oct 23 01:35:32`)
且逐条读到被改模块的锚点:`SD2506 init: OK (ret=0)` 与 ID/时间/温度/电池四条读回正常、
`ADC init: OK`、`NAND init: OK`、`Map resumed: 14094/97504`、`adc=` 帧计数持续递增(证明
snapshot 三态未被改坏)、`[ERR]`/Fault/FAIL 0 条。主机单测:系统时钟 100/100、dhara NAND
移植层 149/149(两者都因本次改动需补 `Drivers/BSP` include 路径,补后在钩子内实跑 Passed)。
`pre-commit run` 全量 RC=0(20 个实跑钩子 Passed);`bsp-err` 基线 **19 → 17**(还掉两个
`*_BUSY_TIMEOUT = -2`)、`--prune` 干净;`doc-links --all --sections-strict` 147 篇
0 问题;
`id-check --strict`、`layer-deps`、`mem-numbers`、`mem-budget`、`ui-golden` 全过;33
个文件
字节卫生 0 异常(无 CR / 无 U+FFFD / 无行尾空格 / 均有尾换行)。
**口径与数字联动**:新增 `docs/架构设计/STM32F4-Base存储架构说明.md` §10.4(三类码与处置
理由);`pre-commit使用说明.md` §2.27 与 `AGENTS.md` 基线计数 19 → 17;TPAFE README、
GD5F 测试指南与 Trap 记录均**保留旧名留痕**以便对旧日志;配图桶按 .map 对象级增量重算
(`dhara/FTL` 10,931 → 11,222,+291 全部落在 `nand_ftl.o`;应用代码/UI +36 落在
`app_main.o`;其余散量入"其他"7,557;桶和 = Code+RO 断言通过、文本溢出 0);
`ram_baseline --update/--write`、`ram_report_20261023.md` 快照、报告 §1.3/§5.1/§5.4
与
部署文档 §3.3 数字全部同步;报告 §0.4/§9 的 S-5 状态改为 🟡 主体已落地。
253 lines
11 KiB
C
253 lines
11 KiB
C
#ifndef TPAFE5160_H
|
||
#define TPAFE5160_H
|
||
|
||
/*
|
||
* 模块名称:TPAFE5160 16位8通道同步采样ADC驱动
|
||
* 模块功能:提供 TPAFE5160 并行接口模式下的初始化、过采样设置、转换启动、数据读取接口
|
||
* 适用平台:STM32F407ZGT6,并行16位数据总线接 GPIOG[15:0]
|
||
* 作者:王建锋
|
||
* 创建日期:2026-07-17
|
||
* 修改记录:
|
||
* 2026-07-17 王建锋 创建初始版本,参考 AD7606 并行驱动及 TPAFE5160 手册
|
||
* 2026-07-17 王建锋 增加 EXTI 中断读取模式
|
||
* 2026-09-20 王建锋 V0.1 引脚适配(引脚值随 main.h 宏,驱动逻辑不变)
|
||
* 2026-10-10 王建锋 消费者接入前置修复(历史审计 E-44 / E-45 / E-58,属主文档已删除):
|
||
* FRSTDATA 数据有效性校验 + 帧序号取代就绪电平标志 +
|
||
* 原子快照 API;移除会撕裂的 get_buf/data_ready/clear_ready
|
||
*/
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#include "main.h"
|
||
|
||
/* ======================== 宏定义 ======================== */
|
||
|
||
/* 通道数量 */
|
||
#define TPAFE5160_CH_NUM 8
|
||
|
||
/* 控制引脚操作宏 —— RD (PC8) */
|
||
#define TPAFE5160_RD_LOW() HAL_GPIO_WritePin(TP_RD_GPIO_Port, TP_RD_Pin, GPIO_PIN_RESET)
|
||
#define TPAFE5160_RD_HIGH() HAL_GPIO_WritePin(TP_RD_GPIO_Port, TP_RD_Pin, GPIO_PIN_SET)
|
||
|
||
/* 控制引脚操作宏 —— CONVST (PC9) */
|
||
#define TPAFE5160_CONVST_LOW() HAL_GPIO_WritePin(TP_CONVST_GPIO_Port, TP_CONVST_Pin, GPIO_PIN_RESET)
|
||
#define TPAFE5160_CONVST_HIGH() HAL_GPIO_WritePin(TP_CONVST_GPIO_Port, TP_CONVST_Pin, GPIO_PIN_SET)
|
||
|
||
/* 状态引脚读取宏 */
|
||
#define TPAFE5160_BUSY_READ() HAL_GPIO_ReadPin(TP_BUSY_GPIO_Port, TP_BUSY_Pin)
|
||
#define TPAFE5160_FRSTDATA_READ() HAL_GPIO_ReadPin(TP_FRSTDATA_GPIO_Port, TP_FRSTDATA_Pin)
|
||
|
||
/* 过采样引脚操作宏 —— OS0 (PA12), OS1 (PA11), OS2 (PA8) */
|
||
#define TPAFE5160_OS0(val) HAL_GPIO_WritePin(TP_OS0_GPIO_Port, TP_OS0_Pin, \
|
||
(val) ? GPIO_PIN_SET : GPIO_PIN_RESET)
|
||
#define TPAFE5160_OS1(val) HAL_GPIO_WritePin(TP_OS1_GPIO_Port, TP_OS1_Pin, \
|
||
(val) ? GPIO_PIN_SET : GPIO_PIN_RESET)
|
||
#define TPAFE5160_OS2(val) HAL_GPIO_WritePin(TP_OS2_GPIO_Port, TP_OS2_Pin, \
|
||
(val) ? GPIO_PIN_SET : GPIO_PIN_RESET)
|
||
|
||
/* 并行数据总线读取 —— DB[15:0] 接 GPIOG[15:0],单次读取16位 */
|
||
#define TPAFE5160_READ_BUS() ((uint16_t)GPIOG->IDR)
|
||
|
||
/* 过采样率枚举 (OS[2:0] 编码,OS2为MSB, OS0为LSB) */
|
||
typedef enum {
|
||
TPAFE5160_OS_NONE = 0, /* 000 — 无过采样,350 kSPS */
|
||
TPAFE5160_OS_X2 = 1, /* 001 — 2倍过采样,175 kSPS */
|
||
TPAFE5160_OS_X4 = 2, /* 010 — 4倍过采样,87.5 kSPS */
|
||
TPAFE5160_OS_X8 = 3, /* 011 — 8倍过采样,43.75 kSPS */
|
||
TPAFE5160_OS_X16 = 4, /* 100 — 16倍过采样,21.875 kSPS */
|
||
TPAFE5160_OS_X32 = 5, /* 101 — 32倍过采样,10.94 kSPS */
|
||
TPAFE5160_OS_X64 = 6, /* 110 — 64倍过采样,5.47 kSPS */
|
||
TPAFE5160_OS_HBW = 7 /* 111 — 高带宽模式 (~30kHz),350 kSPS */
|
||
} tpafe5160_os_t;
|
||
|
||
/* 输入量程枚举 */
|
||
typedef enum {
|
||
TPAFE5160_RANGE_5V = 0, /* ±5V (RANGE = LOW) */
|
||
TPAFE5160_RANGE_10V = 1 /* ±10V (RANGE = HIGH) */
|
||
} tpafe5160_range_t;
|
||
|
||
/* 返回值定义 */
|
||
/* 本模块的成败码已收编到 Drivers/BSP/bsp_err.h(2026-10-23,S-5 C1):
|
||
* 旧 TPAFE5160_OK(0) → BSP_OK;旧 TPAFE5160_ERROR(-1) → BSP_ERR_PARAM(三处全是参数校验,
|
||
* 数值也同为 -1,**行为零变化**);旧 TPAFE5160_BUSY_TIMEOUT(-2) → BSP_ERR_TIMEOUT,
|
||
* 于是 BUSY 不释放终于变成跨模块可判定的"可重试";
|
||
* 旧 TPAFE5160_FRSTDATA_ERR(-3) → BSP_ERR_NO_DEVICE——它就是 E-44 的"芯片没驱动 DB 总线",
|
||
* 语义是**器件不在响应**,归到 NO_DEVICE 比留在私有 -3 更有用(且避开与 BSP_ERR_TIMEOUT 撞值)。
|
||
* ⚠ 例外:**tpafe5160_snapshot() 不是成败 API**,它是 1=有新帧 / 0=无新帧 / -1=参数错 的
|
||
* 三态**状态**返回(0 不是错误,是"这一拍没有新数据"),因此**不套 bsp_err_t**,
|
||
* 只把参数错那一支写成 BSP_ERR_PARAM(同值)。强行收编会把"无新帧"变成失败。 */
|
||
#include "bsp_err.h"
|
||
|
||
/* 默认超时时间 (ms) */
|
||
#define TPAFE5160_CONV_TIMEOUT_MS 10
|
||
|
||
/* ======================== 函数声明 ======================== */
|
||
|
||
/*
|
||
* 函数功能:初始化 TPAFE5160(设置过采样、等待就绪)
|
||
* 入口参数:无
|
||
* 返回值:BSP_OK - 成功;BSP_ERR_TIMEOUT - BUSY 不释放(可重试)
|
||
* 限定条件:CubeMX 已完成 GPIO 初始化
|
||
* 函数说明:1. 设置过采样为无过采样 (000)
|
||
* 2. 确保 RD 为高、CONVST 为低
|
||
* 3. 等待 BUSY 释放(转换空闲)
|
||
*/
|
||
bsp_err_t tpafe5160_init(void);
|
||
|
||
/*
|
||
* 函数功能:设置过采样率
|
||
* 入口参数:os - 过采样率枚举值 tpafe5160_os_t
|
||
* 返回值:无
|
||
* 限定条件:GPIO 已初始化
|
||
* 函数说明:通过 OS[2:0] 引脚设置过采样率,在下一次转换时生效
|
||
*/
|
||
void tpafe5160_set_os(tpafe5160_os_t os);
|
||
|
||
/*
|
||
* 函数功能:启动一次转换(CONVST 上升沿触发)
|
||
* 入口参数:无
|
||
* 返回值:无
|
||
* 限定条件:GPIO 已初始化
|
||
* 函数说明:产生 CONVST 脉冲上升沿,启动全部8通道同步采样与转换
|
||
*/
|
||
void tpafe5160_start_conv(void);
|
||
|
||
/*
|
||
* 函数功能:等待转换完成
|
||
* 入口参数:timeout_ms - 超时时间 uint32_t > 0
|
||
* 返回值:BSP_OK - 转换完成;BSP_ERR_TIMEOUT - 超时(可重试:BSP_ERR_CAN_RETRY)
|
||
* 限定条件:已调用 tpafe5160_start_conv()
|
||
* 函数说明:轮询 BUSY 引脚等待下降沿
|
||
*/
|
||
bsp_err_t tpafe5160_wait_busy(uint32_t timeout_ms);
|
||
|
||
/*
|
||
* 函数功能:查询当前是否正在转换
|
||
* 入口参数:无
|
||
* 返回值:1 - 正在转换,0 - 空闲
|
||
* 限定条件:GPIO 已初始化
|
||
* 函数说明:读取 BUSY 引脚电平
|
||
*/
|
||
uint8_t tpafe5160_is_busy(void);
|
||
|
||
/*
|
||
* 函数功能:读取全部8通道转换结果
|
||
* 入口参数:buf - 8个int16_t的输出缓冲区 int16_t* 不为 NULL
|
||
* 返回值:BSP_OK - 成功;BSP_ERR_TIMEOUT - BUSY 超时;BSP_ERR_NO_DEVICE - FRSTDATA 无跳变
|
||
* (E-44:芯片没驱动 DB 总线,读回的是上拉残值,不可信)
|
||
* 限定条件:GPIO 已初始化
|
||
* 函数说明:1. 启动转换并等待 BUSY 释放
|
||
* 2. 连续8次拉低RD读取各通道数据
|
||
* 3. 校验 FRSTDATA 在这一帧内发生过跳变(= 芯片确实在驱动数据线,E-44)
|
||
*/
|
||
bsp_err_t tpafe5160_read_all(int16_t *buf);
|
||
|
||
/*
|
||
* 函数功能:读取指定通道的转换结果
|
||
* 入口参数:channel - 通道号 uint8_t 0 - 7
|
||
* value - 输出指针 int16_t* 不为 NULL
|
||
* 返回值:BSP_OK - 成功;BSP_ERR_PARAM - 通道号无效或指针空;BSP_ERR_TIMEOUT - BUSY 超时
|
||
* 限定条件:GPIO 已初始化
|
||
* 函数说明:启动转换并等待完成后,连续读取至指定通道
|
||
*/
|
||
bsp_err_t tpafe5160_read_channel(uint8_t channel, int16_t *value);
|
||
|
||
/*
|
||
* 函数功能:原始ADC值转电压值
|
||
* 入口参数:raw - ADC原始值 int16_t 有符号补码
|
||
* 返回值:电压值 float 单位 V
|
||
* 限定条件:无
|
||
* 函数说明:±5V量程时 LSB=152.59μV,±10V量程时 LSB=305.18μV
|
||
* 默认使用 ±5V 量程 (RANGE 接 GND)
|
||
*/
|
||
float tpafe5160_to_voltage(int16_t raw);
|
||
|
||
/*
|
||
* 函数功能:直接读取并行数据总线(不启动转换)
|
||
* 入口参数:无
|
||
* 返回值:16位原始数据 uint16_t
|
||
* 限定条件:RD 为低或CS与RD已拉低
|
||
* 函数说明:用于读取当前总线上的数据,需自行控制RD时序
|
||
*/
|
||
uint16_t tpafe5160_read_bus(void);
|
||
|
||
/* ======================== 中断模式 API ======================== */
|
||
|
||
/*
|
||
* 函数功能:使能 BUSY EXTI 中断(运行时重使能用)
|
||
* 入口参数:无
|
||
* 返回值:无
|
||
* 限定条件:CubeMX 已完成 GPIO 和 NVIC 配置
|
||
* 函数说明:正常启动流程无需调用,仅在 irq_disable() 后需要重新使能时使用
|
||
*/
|
||
void tpafe5160_irq_enable(void);
|
||
|
||
/*
|
||
* 函数功能:关闭 BUSY EXTI 中断
|
||
* 入口参数:无
|
||
* 返回值:无
|
||
* 限定条件:已调用 tpafe5160_irq_enable()
|
||
* 函数说明:仅禁用 NVIC 中断,GPIO 配置保持 CubeMX 设定
|
||
*/
|
||
void tpafe5160_irq_disable(void);
|
||
|
||
/*
|
||
* 函数功能:启动转换(中断模式)
|
||
* 入口参数:无
|
||
* 返回值:无
|
||
* 限定条件:已调用 tpafe5160_irq_enable()
|
||
* 函数说明:产生 CONVST 脉冲,转换完成后由 EXTI 中断自动读取 8 通道数据
|
||
*/
|
||
void tpafe5160_start_conv_irq(void);
|
||
|
||
/*
|
||
* 函数功能:查询已完成的帧序号(消费者判断"有没有新帧"的唯一依据)
|
||
* 入口参数:无
|
||
* 返回值:uint32_t 帧序号,EXTI 每读完一帧 +1
|
||
* 限定条件:中断模式已启用
|
||
* 函数说明:取代旧的 data_ready/clear_ready **电平标志**(E-45)——电平标志有三个
|
||
* 写者,其中 start_conv_irq 在触发前清 0,于是"重触发"本身就会抹掉一帧
|
||
* 还没被消费的数据(高速采样系统性丢样且无从发现)。序号只增不清,
|
||
* 消费者比较 seq 即可,重触发不会丢
|
||
*/
|
||
uint32_t tpafe5160_frame_seq(void);
|
||
|
||
/*
|
||
* 函数功能:原子快照最新一帧(消费者取数的唯一正确姿势)
|
||
* 入口参数:dst - 输出缓冲区 int16_t* 不为 NULL
|
||
* count - 拷贝通道数 uint8_t 1 - 8
|
||
* 返回值:1 - 取到新帧,0 - 无新帧,BSP_ERR_PARAM(-1) - 参数无效(**三态状态返回,故意不套成败码**:0 表示"这一拍没有新数据",不是错误)
|
||
* 限定条件:**任务上下文**调用(内部用 taskENTER_CRITICAL,不可在中断里调)
|
||
* 函数说明:E-58——旧 get_buf() 只返回缓冲区指针,任务再逐通道拷;两步之间被 BUSY
|
||
* EXTI 抢占并跨过一帧周期,拷回的就是**两帧混合**的 8 通道数据(同一时刻
|
||
* 的 8 路值互相错位),且没有任何错误指示。本函数把"选缓冲 + 拷数据 +
|
||
* 记游标"收进一个临界区(只盖 16 字节拷贝),撕裂在设计上消除
|
||
*/
|
||
int tpafe5160_snapshot(int16_t *dst, uint8_t count);
|
||
|
||
/*
|
||
* 函数功能:读取到"FRSTDATA 无跳变"帧的累计次数(芯片死亡 / 总线异常的留痕)
|
||
* 入口参数:无
|
||
* 返回值:uint16_t 计数(中断里只加计数不打日志)
|
||
* 限定条件:中断模式已启用
|
||
* 函数说明:E-44——非 0 表示至少有一帧的 8 个值不可信;消费者据此上报自检
|
||
*/
|
||
uint16_t tpafe5160_frstdata_err(void);
|
||
|
||
/*
|
||
* 函数功能:EXTI 中断处理(由 HAL_GPIO_EXTI_Callback 调用)
|
||
* 入口参数:GPIO_Pin - 触发的引脚号
|
||
* 返回值:无
|
||
* 限定条件:BUSY EXTI 已使能
|
||
* 函数说明:BUSY 下降沿时自动读取 8 通道数据到缓冲区
|
||
*/
|
||
void tpafe5160_exti_handler(uint16_t GPIO_Pin);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* TPAFE5160_H */
|