/* DAC63204 —— 板上 2 片(U6 = 0x4A、U7 = 0x4B),5 路调压用 5 个通道。 这颗 DAC **不做全范围调压**,只在固定中心点上做 ±0.24 V 的微调(设计文档 §4.1), 而且是**反向**的:写进去的码越大,手机看到的电压越低。换算一律走 `rail.h` 的 `rail_set_mv()`,本文件只负责「把一个 12 位码写进某片某通道」。 本驱动只通过 hal_i2c_* 访问总线,宿主机上用 sim 的假器件即可全部测完。 寄存器与位定义出处:TI SLASEX3A(DAC63204/53204/43204)表 7-21、7-26、7-32、7-33。 */ #ifndef DAC63204_H #define DAC63204_H #include #include #include "hal_err.h" #ifdef __cplusplus extern "C" { #endif /* ---- 寄存器(全部 16 位、大端) ---------------------------------------- */ /* 每通道 6 个寄存器一组:03h/09h/0Fh/15h。 */ #define DAC63204_REG_VOUT_CMP_CONFIG(ch) ((uint8_t)(0x03 + 0x06 * (ch))) /* 数据寄存器却是**连续**的:19h/1Ah/1Bh/1Ch。两种步长别记混。 */ #define DAC63204_REG_DATA(ch) ((uint8_t)(0x19 + (ch))) #define DAC63204_REG_COMMON_CONFIG 0x1F #define DAC63204_REG_COMMON_TRIGGER 0x20 #define DAC63204_REG_GENERAL_STATUS 0x22 /* ---- 位域 --------------------------------------------------------------- */ /* DAC-X-VOUT-CMP-CONFIG bit12-10 = VOUT-GAIN-X。 011b = 增益 2×、用内部基准 —— 这一路的满量程 1.212 V × 2 = **2.424 V** (不是 2.5 V,设计文档 §4.5 早期写错过一次)。 */ #define DAC63204_VOUT_GAIN_SHIFT 10 #define DAC63204_VOUT_GAIN_2X_INT 0x3 #define DAC63204_CFG_GAIN_2X_INT ((uint16_t)(DAC63204_VOUT_GAIN_2X_INT << DAC63204_VOUT_GAIN_SHIFT)) /* COMMON-CONFIG(1Fh,复位值 0FFFh = 八路输出全部掉电)。 bit12 EN-INT-REF —— 用内部基准增益之前**必须先置 1**(datasheet 原话) bit11-10 / 8-7 / 5-4 / 2-1 VOUT-PDN-3/2/1/0:00 = 上电,11 = Hi-Z 掉电 bit9 / 6 / 3 / 0 IOUT-PDN-3/2/1/0:1 = 掉电(本板不用电流输出) */ #define DAC63204_CC_EN_INT_REF ((uint16_t)(1u << 12)) #define DAC63204_CC_IOUT_PDN_ALL ((uint16_t)0x0249) /* bit 0/3/6/9 */ /* 某通道的 VOUT-PDN 两位全 1 = Hi-Z 掉电。ch: 0~3。 */ #define DAC63204_CC_VOUT_PDN(ch) ((uint16_t)(0x3u << (1 + 3 * (ch)))) /* `dac63204_init()` 第 ① 步写进去的值:**只开内部基准,八路输出仍全部 Hi-Z**。 必须先有这一步,安全码才来得及在上电之前写进数据寄存器。 */ #define DAC63204_CC_REF_ONLY ((uint16_t)0x1FFF) /* GENERAL-STATUS(22h)bit7-2 = DEVICE-ID。DAC63204 是 01h (DAC53204 = 02h、DAC43204 = 03h —— 贴错料就是这里露馅)。 */ #define DAC63204_DEVICE_ID 0x01 #define DAC63204_STATUS_ID(reg) ((uint8_t)(((reg) >> 2) & 0x3f)) #define DAC63204_STATUS_NVM_BUSY ((uint16_t)(1u << 8)) /* ---- 分辨率与量程 ------------------------------------------------------- */ #define DAC63204_BITS 12 #define DAC63204_CODE_MAX 4095 #define DAC63204_CODE_SPAN 4096 /* VOUT = code / 2^12 × VREF × GAIN,见 datasheet 式 (1) */ /* 内部基准 1.212 V × 增益 2 = 满量程 2.424 V。µV 为单位,整数运算用。 */ #define DAC63204_FULLSCALE_UV 2424000 /* ⚠️ **12 位码在 DAC-X-DATA 里是左对齐的**(bit15-4,低 4 位 don't care)。 忘了 `<< 4` 不会报错,只会让输出变成期望值的 1/16 —— 五路全部顶到 4.010 V, 而这在本板上是「正常满电」,看不出异常(设计文档 §4.4)。 */ #define DAC63204_DATA_SHIFT 4 #define DAC63204_CODE_TO_REG(code) ((uint16_t)((uint16_t)(code) << DAC63204_DATA_SHIFT)) #define DAC63204_REG_TO_CODE(reg) ((uint16_t)((reg) >> DAC63204_DATA_SHIFT)) /* ---- 两片的地址与「哪一路挂在哪片哪通道」(设计文档 §8.2 + §26.18) ----- */ #define DAC63204_COUNT 2 #define DAC63204_RAIL_COUNT 5 #define DAC63204_ADDR_U6 0x4A /* A0 接 SDA */ #define DAC63204_ADDR_U7 0x4B /* A0 接 SCL */ extern const uint8_t dac63204_all_addr[DAC63204_COUNT]; /* rail 是 1~5,越界直接 abort。 ⚠️ **「前三路在 U6、通道号 = rail−1」是错的**:2026-09-06 按 PCB 几何重排过 (§26.18),五路里有四路对不上那个算式。真表是 CH1 → U6.OUT2 CH2 → U6.OUT0 CH3 → **U7**.OUT0 CH4 → U6.OUT1 CH5 → U7.OUT1 四个通道在电气上完全对等,重排只改固件通道号,一根线都没动 —— 所以**接错了板子照样正常工作,只是调 CH1 的命令去调了 CH2**。查表,不要算。 */ uint8_t dac63204_rail_addr(int rail); uint8_t dac63204_rail_ch(int rail); /* 某片上被真正用到的通道位图(bit0..bit3)。没用到的通道 FBx 悬空, **不许上电**:电压输出模式下 FBx 是运放的反馈脚,悬空上电就是开环 (datasheet 表 5-1 要求 FBx 接到 OUTx)。 */ uint8_t dac63204_used_mask(uint8_t addr); /* 该片跑起来之后 COMMON-CONFIG 应该是什么:内部基准开、用到的通道上电、 其余 Hi-Z、四路电流输出全掉电。`dac63204_check()` 拿它对账。 */ uint16_t dac63204_cc_run(uint8_t addr); /* 两片地址不重复、不与 INA226 六片 / PCA9555 / LM75 撞车, 且五路映射覆盖到的 (片, 通道) 互不重复、都在 used_mask 里。 启动自检调一次;返回 false = 表被改坏了。 */ bool dac63204_map_ok(void); /* ---- 器件操作 ----------------------------------------------------------- */ /* 读 GENERAL-STATUS 认件。 不应答 → HAL_ERR_NAK;**应答了但 DEVICE-ID 不是 01h → HAL_ERR_BUS** (这个地址上有东西,但不是 DAC63204:多半贴成了 53204/43204,或地址脚焊错)。 */ hal_err_t dac63204_probe(uint8_t addr); /* 初始化一片。顺序是有讲究的,四步不能换: ① COMMON-CONFIG 先只开 EN-INT-REF,**输出仍全部掉电** (datasheet:用内部基准增益之前这一位必须已经是 1) ② 逐个用到的通道写 VOUT-CMP-CONFIG = 增益 2× 内部基准 ③ 逐个用到的通道写 `safe_code`(上电安全值),**在上电之前写** —— 否则输出会先在复位码 0 上停一下,那是 Vd = 0 V = 输出 4.010 V 的上限 ④ COMMON-CONFIG 再写一次,把**用到的**通道上电(没用到的保持 Hi-Z) 每一步都回读校验,不一致 → HAL_ERR_BUS。 */ hal_err_t dac63204_init(uint8_t addr, uint16_t safe_code); /* 只校验 COMMON-CONFIG 与各通道增益还在(巡检用)。 这两样掉了不会报错,只会让输出悄悄跑到别的量程上。 */ hal_err_t dac63204_check(uint8_t addr); /* 写 / 读某通道的 12 位码。code > 4095 → HAL_ERR_ARG;ch 越界 → HAL_ERR_ARG。 */ hal_err_t dac63204_write_code(uint8_t addr, uint8_t ch, uint16_t code); hal_err_t dac63204_read_code(uint8_t addr, uint8_t ch, uint16_t *code); /* 码 → DAC 输出电压 Vd(µV)。四舍五入。 */ int32_t dac63204_code_to_uv(uint16_t code); #ifdef __cplusplus } #endif #endif /* DAC63204_H */