/** * bq25756_hal.c — BQ25756 Hardware Abstraction Layer 实现 * * 所有 BQ25756 寄存器读写 + 物理量换算函数。 * 依赖 soft_i2c.c 提供 I2C 原语,平台无关。 */ #include "bq25756_hal.h" #include "soft_i2c.h" #include #define ADDR BQ25756_HAL_I2C_ADDR /* ──────────────── 全局故障标记 ──────────────── */ volatile uint8_t g_bq_fault = 0; volatile uint8_t g_bq_fault_status = 0; /* ════════════════════════════════════════════════════════════════ * ADC 读数 * ════════════════════════════════════════════════════════════════ */ int32_t bq_read_vbat_mv(void) { uint16_t raw = SoftI2C_ReadReg16(ADDR, BQ25756_REG_VBAT_ADC); return (int32_t)((uint32_t)raw * 2); } int32_t bq_read_ibat_ma(void) { uint16_t raw = SoftI2C_ReadReg16(ADDR, BQ25756_REG_IBAT_ADC); return (int32_t)((int16_t)raw) * 2; } int32_t bq_read_vin_mv(void) { uint16_t raw = SoftI2C_ReadReg16(ADDR, BQ25756_REG_VAC_ADC); return (int32_t)((uint32_t)raw * 2); } int32_t bq_read_iin_ma(void) { uint16_t raw = SoftI2C_ReadReg16(ADDR, BQ25756_REG_IAC_ADC); return (int32_t)((int16_t)raw) * 2; } /* ════════════════════════════════════════════════════════════════ * 寄存器写入 * ════════════════════════════════════════════════════════════════ */ int bq_write_charge_current(uint32_t mA) { if (mA < 400) mA = 400; if (mA > 20000) mA = 20000; uint16_t raw = (uint16_t)((mA / 50) << 2); return SoftI2C_WriteReg16(ADDR, BQ25756_REG_CHG_CURRENT, raw); } int bq_write_precharge_current(uint32_t mA) { if (mA < 250) mA = 250; if (mA > 10000) mA = 10000; uint16_t raw = (uint16_t)((mA / 50) << 2); return SoftI2C_WriteReg16(ADDR, BQ25756_REG_PRECHG_CURRENT, raw); } int bq_set_en_chg(uint8_t enable) { uint8_t val = SoftI2C_ReadReg(ADDR, BQ25756_REG_CHARGER_CTRL); if (enable) val |= BQ25756_EN_CHG; else val &= ~BQ25756_EN_CHG; return SoftI2C_WriteReg(ADDR, BQ25756_REG_CHARGER_CTRL, val); } int bq_reset_wd(void) { uint8_t val = SoftI2C_ReadReg(ADDR, BQ25756_REG_CHARGER_CTRL); val |= BQ25756_WD_RST; return SoftI2C_WriteReg(ADDR, BQ25756_REG_CHARGER_CTRL, val); } int bq_set_en_pfm(uint8_t enable) { uint8_t val = SoftI2C_ReadReg(ADDR, BQ25756_REG_POWER_PATH_REV); if (enable) val |= BQ25756_EN_PFM; else val &= ~BQ25756_EN_PFM; return SoftI2C_WriteReg(ADDR, BQ25756_REG_POWER_PATH_REV, val); } /* ════════════════════════════════════════════════════════════════ * MPPT * ════════════════════════════════════════════════════════════════ */ int bq_mppt_start(void) { return SoftI2C_WriteReg(ADDR, BQ25756_REG_MPPT_CTRL, 0x26); } int bq_mppt_stop(void) { uint8_t val = SoftI2C_ReadReg(ADDR, BQ25756_REG_MPPT_CTRL); val &= ~BQ25756_EN_MPPT; return SoftI2C_WriteReg(ADDR, BQ25756_REG_MPPT_CTRL, val); } int bq_mppt_force_sweep(void) { uint8_t val = SoftI2C_ReadReg(ADDR, BQ25756_REG_MPPT_CTRL); val |= BQ25756_FORCE_SWEEP; return SoftI2C_WriteReg(ADDR, BQ25756_REG_MPPT_CTRL, val); } /* ════════════════════════════════════════════════════════════════ * 软启动 * ════════════════════════════════════════════════════════════════ */ int bq_soft_start(uint32_t target_ma, void (*delay_ms)(uint32_t ms)) { uint32_t current_ma; const uint32_t step_ma = 200; const uint32_t step_ms = 250; for (current_ma = 400; current_ma < target_ma; current_ma += step_ma) { if (bq_write_charge_current(current_ma) != 0) return -1; if (delay_ms) delay_ms(step_ms); } return bq_write_charge_current(target_ma); } /* ════════════════════════════════════════════════════════════════ * VFB_ADC POST 自检 * ════════════════════════════════════════════════════════════════ */ int bq_vfb_post_check(float expected_divider_ratio, int32_t tolerance_mv, void (*delay_ms)(uint32_t ms)) { uint8_t adc_ch = SoftI2C_ReadReg(ADDR, BQ25756_REG_ADC_CHANNEL_CTRL); uint8_t adc_ch_saved = adc_ch; adc_ch &= ~0x02; /* bit1 VFB_ADC_DIS = 0 */ SoftI2C_WriteReg(ADDR, BQ25756_REG_ADC_CHANNEL_CTRL, adc_ch); if (delay_ms) delay_ms(500); uint16_t vfb_raw = SoftI2C_ReadReg16(ADDR, BQ25756_REG_VFB_ADC); int32_t vbat_meas = bq_read_vbat_mv(); int32_t vfb_meas = (int32_t)vfb_raw; SoftI2C_WriteReg(ADDR, BQ25756_REG_ADC_CHANNEL_CTRL, adc_ch_saved); if (vbat_meas <= 0 || vfb_meas <= 0) { printf("[WARN] VFB POST: I2C read failed (VBAT=%ldmV, VFB=%ldmV)\r\n", (long)vbat_meas, (long)vfb_meas); return -1; } int32_t vfb_expected = (int32_t)((float)vbat_meas / expected_divider_ratio); int32_t vfb_error = vfb_meas - vfb_expected; printf("[VFB] POST: Vbat=%ldmV VFB_act=%ldmV VFB_exp=%ldmV err=%ldmV (%d%%)\r\n", (long)vbat_meas, (long)vfb_meas, (long)vfb_expected, (long)vfb_error, (vbat_meas > 0) ? (int)(vfb_error * 100000 / vbat_meas) : 0); if (vfb_error < -tolerance_mv || vfb_error > tolerance_mv) { printf("[ERROR] VFB POST FAILED: divider ratio wrong!\r\n"); return -2; } return 0; } /* ════════════════════════════════════════════════════════════════ * TS_ADC 交叉校验 * ════════════════════════════════════════════════════════════════ */ void bq_ts_cross_check(int8_t mcu_temp_c) { uint16_t ts_raw = SoftI2C_ReadReg16(ADDR, BQ25756_REG_TS_ADC); float ts_pct = (float)ts_raw * 0.09765625f; if (ts_pct < 1.0f || ts_pct > 99.0f) return; float r_ntc_bq = 10000.0f * (ts_pct / 100.0f) / (1.0f - ts_pct / 100.0f); float r_ntc_mcu = 10000.0f; if (mcu_temp_c > -30 && mcu_temp_c < 120) { float invT0 = 1.0f / 298.15f; float temp_k = (float)mcu_temp_c + 273.15f; r_ntc_mcu = 10000.0f * expf(3435.0f * (1.0f/temp_k - invT0)); } float ratio_diff = (r_ntc_bq - r_ntc_mcu) / r_ntc_mcu * 100.0f; if (ratio_diff > 15.0f || ratio_diff < -15.0f) { printf("[WARN] TS mismatch: BQ_R=%.0fΩ MCU_R=%.0fΩ (diff=%.1f%%)\r\n", r_ntc_bq, r_ntc_mcu, ratio_diff); } } /* ════════════════════════════════════════════════════════════════ * PFM/FSW_SYNC 一致性检测 * ════════════════════════════════════════════════════════════════ */ void bq_pfm_sync_check(void) { uint8_t pwr = SoftI2C_ReadReg(ADDR, BQ25756_REG_POWER_PATH_REV); if (pwr & BQ25756_EN_PFM) { printf("[WARN] FSW_SYNC: EN_PFM=1 detected\r\n"); pwr &= ~BQ25756_EN_PFM; SoftI2C_WriteReg(ADDR, BQ25756_REG_POWER_PATH_REV, pwr); } } /* ════════════════════════════════════════════════════════════════ * INT 中断 * ════════════════════════════════════════════════════════════════ */ void bq_int_mask_only_fault(void) { SoftI2C_WriteReg(ADDR, BQ25756_REG_MASK_1, 0xFF); SoftI2C_WriteReg(ADDR, BQ25756_REG_MASK_2, 0xFF); SoftI2C_WriteReg(ADDR, BQ25756_REG_FAULT_MASK, 0x00); } /* ════════════════════════════════════════════════════════════════ * 快速初始化(从 soft_i2c.c 迁移) * ════════════════════════════════════════════════════════════════ */ uint8_t bq_watchdog_off(void) { return SoftI2C_WriteReg(0x6B, 0x15, 0x0D); } uint8_t bq_ntc_off(void) { return SoftI2C_WriteReg(0x6B, 0x1C, 0x56); } uint8_t bq_adc_continuous(void) { return SoftI2C_WriteReg(0x6B, 0x2B, 0xA0); }