/* DAC63204 驱动。只经 hal_i2c_*,不碰任何平台头文件。 */ #include "dac63204.h" #include #include #include "hal_i2c.h" /* 设计文档 §8.2(两片地址)+ §26.18(按 PCB 几何重排过的通道分配)。 ⚠️ 不是「前三路在 U6、通道号 = rail−1」—— 五路里有四路对不上那个算式。 */ static const uint8_t s_rail_addr[DAC63204_RAIL_COUNT] = { DAC63204_ADDR_U6, /* CH1 */ DAC63204_ADDR_U6, /* CH2 */ DAC63204_ADDR_U7, /* CH3 ← 在 U7 上,不在 U6 */ DAC63204_ADDR_U6, /* CH4 */ DAC63204_ADDR_U7, /* CH5 */ }; static const uint8_t s_rail_ch[DAC63204_RAIL_COUNT] = { 2, 0, 0, 1, 1 }; const uint8_t dac63204_all_addr[DAC63204_COUNT] = { DAC63204_ADDR_U6, DAC63204_ADDR_U7 }; uint8_t dac63204_rail_addr(int rail) { assert(rail >= 1 && rail <= DAC63204_RAIL_COUNT); /* 越界是代码写错,不许悄悄返回一片 */ return s_rail_addr[rail - 1]; } uint8_t dac63204_rail_ch(int rail) { assert(rail >= 1 && rail <= DAC63204_RAIL_COUNT); return s_rail_ch[rail - 1]; } uint8_t dac63204_used_mask(uint8_t addr) { uint8_t mask = 0; for (int rail = 1; rail <= DAC63204_RAIL_COUNT; rail++) { if (s_rail_addr[rail - 1] == addr) { mask |= (uint8_t)(1u << s_rail_ch[rail - 1]); } } return mask; /* 不是这两片中的一片 -> 0,init 时会被 HAL_ERR_ARG 拦下 */ } bool dac63204_map_ok(void) { /* 同一条 I²C 上的其它器件(§8.2):撞上任何一个都是硬件表被改坏了。 */ static const uint8_t others[] = { 0x40, 0x41, 0x44, 0x45, 0x42, 0x43, 0x20, 0x48 }; if (dac63204_all_addr[0] == dac63204_all_addr[1]) { return false; } for (int i = 0; i < DAC63204_COUNT; i++) { if (dac63204_all_addr[i] > 0x7f) { return false; } for (size_t k = 0; k < sizeof(others); k++) { if (dac63204_all_addr[i] == others[k]) { return false; } } } for (int a = 1; a <= DAC63204_RAIL_COUNT; a++) { uint8_t addr = s_rail_addr[a - 1]; uint8_t ch = s_rail_ch[a - 1]; if (ch > 3) { return false; } if (addr != dac63204_all_addr[0] && addr != dac63204_all_addr[1]) { return false; } /* 一个 (片, 通道) 只能被一路占用 —— 两路撞在一起的现象是「调这路那路也动」。 */ for (int b = a + 1; b <= DAC63204_RAIL_COUNT; b++) { if (addr == s_rail_addr[b - 1] && ch == s_rail_ch[b - 1]) { return false; } } if ((dac63204_used_mask(addr) & (1u << ch)) == 0) { return false; } } return true; } /* ---- 寄存器读写 --------------------------------------------------------- 和 INA226 那份一样:**每次读之前重写寄存器指针**,不依赖指针自增。 sim 的假器件会自增,真器件的行为没在实物上验过(B1 上板时确认)。 */ static hal_err_t read_reg(uint8_t addr, uint8_t reg, uint16_t *raw) { uint8_t rd[2]; hal_err_t err = hal_i2c_write_read(addr, ®, 1, rd, sizeof(rd)); if (err != HAL_OK) { return err; } *raw = (uint16_t)(((uint16_t)rd[0] << 8) | rd[1]); /* 大端 */ return HAL_OK; } static hal_err_t write_reg(uint8_t addr, uint8_t reg, uint16_t val) { const uint8_t wr[3] = { reg, (uint8_t)(val >> 8), (uint8_t)(val & 0xff) }; return hal_i2c_write(addr, wr, sizeof(wr)); } static hal_err_t write_verify(uint8_t addr, uint8_t reg, uint16_t val) { hal_err_t err = write_reg(addr, reg, val); if (err != HAL_OK) { return err; } uint16_t back = 0; err = read_reg(addr, reg, &back); if (err != HAL_OK) { return err; } return back == val ? HAL_OK : HAL_ERR_BUS; } /* ---- COMMON-CONFIG 的两个形态 ------------------------------------------- */ /* ② 把 used 里的通道上电,其余保持 Hi-Z。电流输出一律掉电(本板只用电压输出)。 */ uint16_t dac63204_cc_run(uint8_t addr) { uint8_t used = dac63204_used_mask(addr); uint16_t v = DAC63204_CC_EN_INT_REF | DAC63204_CC_IOUT_PDN_ALL; for (int ch = 0; ch < 4; ch++) { if ((used & (1u << ch)) == 0) { v |= DAC63204_CC_VOUT_PDN(ch); /* 没用到:FBx 悬空,绝不能上电 */ } } return v; } /* ---- 对外 ---------------------------------------------------------------- */ hal_err_t dac63204_probe(uint8_t addr) { uint16_t st = 0; hal_err_t err = read_reg(addr, DAC63204_REG_GENERAL_STATUS, &st); if (err != HAL_OK) { return err; } /* 应答了但 ID 不对:多半贴成了 DAC53204(02h)/DAC43204(03h), 那两颗只有 10 位 / 8 位,码值左对齐的位数不一样,装上去电压全错。 */ return DAC63204_STATUS_ID(st) == DAC63204_DEVICE_ID ? HAL_OK : HAL_ERR_BUS; } hal_err_t dac63204_init(uint8_t addr, uint16_t safe_code) { uint8_t used = dac63204_used_mask(addr); if (used == 0 || safe_code > DAC63204_CODE_MAX) { return HAL_ERR_ARG; } /* ① 先开内部基准(输出还全部掉电着) */ hal_err_t err = write_verify(addr, DAC63204_REG_COMMON_CONFIG, DAC63204_CC_REF_ONLY); if (err != HAL_OK) { return err; } /* ② 增益 + ③ 安全码。**都要在上电之前**:复位码是 0,而 Vd=0 对应输出 4.010 V。 */ for (int ch = 0; ch < 4; ch++) { if ((used & (1u << ch)) == 0) { continue; } err = write_verify(addr, DAC63204_REG_VOUT_CMP_CONFIG(ch), DAC63204_CFG_GAIN_2X_INT); if (err != HAL_OK) { return err; } err = write_verify(addr, DAC63204_REG_DATA(ch), DAC63204_CODE_TO_REG(safe_code)); if (err != HAL_OK) { return err; } } /* ④ 用到的通道上电 */ return write_verify(addr, DAC63204_REG_COMMON_CONFIG, dac63204_cc_run(addr)); } hal_err_t dac63204_check(uint8_t addr) { uint8_t used = dac63204_used_mask(addr); if (used == 0) { return HAL_ERR_ARG; } uint16_t cc = 0; hal_err_t err = read_reg(addr, DAC63204_REG_COMMON_CONFIG, &cc); if (err != HAL_OK) { return err; } if (cc != dac63204_cc_run(addr)) { return HAL_ERR_BUS; } for (int ch = 0; ch < 4; ch++) { if ((used & (1u << ch)) == 0) { continue; } uint16_t cfg = 0; err = read_reg(addr, DAC63204_REG_VOUT_CMP_CONFIG(ch), &cfg); if (err != HAL_OK) { return err; } if (cfg != DAC63204_CFG_GAIN_2X_INT) { return HAL_ERR_BUS; } } return HAL_OK; } hal_err_t dac63204_write_code(uint8_t addr, uint8_t ch, uint16_t code) { if (ch > 3 || code > DAC63204_CODE_MAX) { return HAL_ERR_ARG; } return write_reg(addr, DAC63204_REG_DATA(ch), DAC63204_CODE_TO_REG(code)); } hal_err_t dac63204_read_code(uint8_t addr, uint8_t ch, uint16_t *code) { if (ch > 3 || code == NULL) { return HAL_ERR_ARG; } uint16_t raw = 0; hal_err_t err = read_reg(addr, DAC63204_REG_DATA(ch), &raw); if (err != HAL_OK) { return err; } *code = DAC63204_REG_TO_CODE(raw); return HAL_OK; } int32_t dac63204_code_to_uv(uint16_t code) { /* Vd = code / 2^12 × 2.424 V(datasheet 式 (1),增益 2× 内部基准)。 */ int64_t num = (int64_t)code * DAC63204_FULLSCALE_UV + DAC63204_CODE_SPAN / 2; return (int32_t)(num / DAC63204_CODE_SPAN); }