A4:DAC63204 驱动 + rail_set_mv()

调压是**反向**的(DAC 码越大输出越低),所以整块换算只在 rail_mv_to_code()
里出现一次那个减法,除 rail.c 外任何地方都不许碰 dac63204_write_code()。
范围 3524~4010 mV,越界即拒(SR-13,第四道限制),4010 = Vd 0。

通道映射按 §26.18 重排过,五路里四路对不上「前三路在 U6、通道号 = rail−1」:
CH1→U6.OUT2 / CH2→U6.OUT0 / CH3→U7.OUT0 / CH4→U6.OUT1 / CH5→U7.OUT1。
四通道电气对等 ⇒ 接错了板子照样正常工作,只是调错了路。设计文档 §17.2 那张
过期的通道表一并改掉了。

驱动只经 hal_i2c_*:认件(DEVICE-ID=01h,53204/43204 当 BUS 错拒掉)、
开内部基准 → 写增益 2× → 写安全码 → 才给用到的通道上电(COMMON-CONFIG 因此写两次:
复位码 0 就是输出上限 4.010 V),未用通道 FBx 悬空一律保持 Hi-Z。

三个「一定会被写出来的错」逐个改进去验过测试拦得住:反向关系写反 → test_rail 红;
忘了码左对齐、通道按 rail−1 算 → test_dac63204 红。

留给下次的两条:越界请求还没记事件(TODO(A11));两点标定还没做,
现在走理论公式,将来顶替的是 RAIL_VOUT0_UV / RAIL_DAC_SPAN_UV 两个常量。

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QYuExfgyYa6DzRRcUso8M8
这个提交包含在:
zhou yang
2026-09-06 19:11:10 +08:00
共同撰写人 Claude Opus 5
父节点 ceadf08345
当前提交 9eb1b39da6
共修改 13 个文件,包含 1154 行新增和 40 行删除
+92
查看文件
@@ -0,0 +1,92 @@
/* 五路输出电压的换算与设定。与硬件无关,宿主机与 ESP32-S3 上编的是同一份。 */
#include "rail.h"
#include <assert.h>
#include <stddef.h>
#include "dac63204.h"
#include "phonerail.h"
/* 五路数与 DAC 侧的映射表必须是同一个数 —— 分家的那天就是错一路的那天。 */
_Static_assert(PHONERAIL_RAIL_COUNT == DAC63204_RAIL_COUNT, "五路数对不上");
bool rail_mv_in_range(int mv)
{
return mv >= RAIL_MV_MIN && mv <= RAIL_MV_MAX;
}
uint16_t rail_mv_to_code(int mv)
{
assert(rail_mv_in_range(mv)); /* 越界要在 rail_set_mv() 里被拒掉,不该走到这儿 */
/* code = (Vout0 − Vout) / 486416 µV × 4096,四舍五入。
**减法在这里**:Vout 越低,差越大,码越大 —— 反向关系只此一处。 */
int64_t diff_uv = (int64_t)RAIL_VOUT0_UV - (int64_t)mv * 1000;
int64_t code = (diff_uv * DAC63204_CODE_SPAN + RAIL_DAC_SPAN_UV / 2) / RAIL_DAC_SPAN_UV;
if (code < 0) {
code = 0;
}
if (code > DAC63204_CODE_MAX) {
code = DAC63204_CODE_MAX;
}
return (uint16_t)code;
}
int rail_code_to_mv(uint16_t code)
{
int64_t drop_uv = ((int64_t)code * RAIL_DAC_SPAN_UV + DAC63204_CODE_SPAN / 2)
/ DAC63204_CODE_SPAN;
int64_t uv = (int64_t)RAIL_VOUT0_UV - drop_uv;
return (int)((uv + 500) / 1000);
}
int32_t rail_code_to_vd_uv(uint16_t code)
{
return dac63204_code_to_uv(code);
}
hal_err_t rail_volt_init(void)
{
const uint16_t safe = rail_mv_to_code(RAIL_MV_SAFE);
for (int i = 0; i < DAC63204_COUNT; i++) {
uint8_t addr = dac63204_all_addr[i];
hal_err_t err = dac63204_probe(addr);
if (err != HAL_OK) {
return err;
}
/* init 自己就把用到的通道写成 safe 了(上电之前写,见 dac63204_init 的 ③)。 */
err = dac63204_init(addr, safe);
if (err != HAL_OK) {
return err;
}
}
return HAL_OK;
}
hal_err_t rail_set_mv(int rail, int mv)
{
if (rail < 1 || rail > PHONERAIL_RAIL_COUNT) {
return HAL_ERR_ARG;
}
if (!rail_mv_in_range(mv)) {
return HAL_ERR_ARG; /* SR-13。TODO(A11):这里要记一条事件 */
}
return dac63204_write_code(dac63204_rail_addr(rail), dac63204_rail_ch(rail),
rail_mv_to_code(mv));
}
hal_err_t rail_get_mv(int rail, int *mv)
{
if (rail < 1 || rail > PHONERAIL_RAIL_COUNT || mv == NULL) {
return HAL_ERR_ARG;
}
uint16_t code = 0;
hal_err_t err = dac63204_read_code(dac63204_rail_addr(rail), dac63204_rail_ch(rail), &code);
if (err != HAL_OK) {
return err;
}
*mv = rail_code_to_mv(code);
return HAL_OK;
}