4. 采集芯片通信接口选型
任务定义
在电池模组采集芯片选型中,通信接口决定了数据吞吐量、线束复杂度与抗干扰能力。本案例针对一款典型采集芯片(以LTC6813-1为参考模型),完成其通信接口的选型分析,并给出SPI菊花链与isoSPI两种拓扑的驱动初始化代码,最终通过逻辑分析仪观测报文验证时序正确性。
接口选型约束分析
采集芯片需将12~18串电芯电压、温度数据上传至BMS主控。选型需满足:
- 隔离耐压:≥1kV(动力电池侧与控制器侧电气隔离);
- 速率:≥1Mbps(18串×3字节×10ms周期);
- 线束:≤4根(减少连接器与屏蔽成本);
- 拓扑:支持多片级联(≥15片)。
对比三种候选接口:
| 接口 | 速率 | 隔离方式 | 线束 | 级联 | 结论 |
|---|---|---|---|---|---|
| SPI(非隔离) | 4MHz | 需外置数字隔离器 | 4+2 | 菊花链 | 成本低,但隔离器件增加延迟 |
| isoSPI | 2Mbps | 内置变压器隔离 | 2(双绞线) | 菊花链 | 推荐:线束最少,隔离集成 |
| I²C | 400kHz | 需隔离 | 2+2 | 不支持长距离 | 速率不足,排除 |
本案例选定isoSPI主模式作为主通信接口,SPI菊花链作为备选方案。以下代码实现两种模式的驱动初始化与单次读取命令帧构造。
驱动实现(C语言,基于STM32F4 HAL库)
// isoSPI_interface.h
#ifndef ISO_SPI_H
#define ISO_SPI_H
#include "stm32f4xx_hal.h"
// LTC6813-1命令定义(节选)
#define CMD_RDCV 0x0404 // 读所有电压寄存器组
#define CMD_RDAUX 0x0406 // 读辅助寄存器(温度)
typedef struct {
SPI_HandleTypeDef *hspi; // 已初始化的SPI外设
GPIO_TypeDef *cs_port;
uint16_t cs_pin;
uint8_t chain_len; // 菊花链中芯片数量
} ISOSPI_Handle;
void ISOSPI_Init(ISOSPI_Handle *dev);
uint8_t ISOSPI_ReadReg(ISOSPI_Handle *dev, uint16_t cmd,
uint8_t *rx_buf, uint8_t reg_group);
#endif
// isoSPI_interface.c
#include "isoSPI_interface.h"
// LTC6813-1 isoSPI帧格式:8位命令低字节 + 8位命令高字节 + 4位PEC + 4位填充
// 此处使用简化的无PEC校验帧(教学演示),实际产品需附加CRC
void ISOSPI_Init(ISOSPI_Handle *dev) {
// 配置CS为推挽输出,默认高电平
GPIO_InitTypeDef gpio = {0};
gpio.Pin = dev->cs_pin;
gpio.Mode = GPIO_MODE_OUTPUT_PP;
gpio.Pull = GPIO_PULLUP;
HAL_GPIO_Init(dev->cs_port, &gpio);
HAL_GPIO_WritePin(dev->cs_port, dev->cs_pin, GPIO_PIN_SET);
// SPI已由CubeMX配置为:2Mbps,CPOL=1,CPHA=1(isoSPI模式要求)
// 使能SPI
__HAL_SPI_ENABLE(dev->hspi);
}
uint8_t ISOSPI_ReadReg(ISOSPI_Handle *dev, uint16_t cmd,
uint8_t *rx_buf, uint8_t reg_group) {
uint8_t tx_cmd[2];
uint8_t dummy[2] = {0x00, 0x00};
// 构造命令字(低字节在前)
tx_cmd[0] = (uint8_t)(cmd & 0xFF);
tx_cmd[1] = (uint8_t)((cmd >> 8) & 0xFF);
// 片选拉低
HAL_GPIO_WritePin(dev->cs_port, dev->cs_pin, GPIO_PIN_RESET);
// 发送命令 + 2字节填充(等待芯片内部处理)
HAL_SPI_Transmit(dev->hspi, tx_cmd, 2, 10);
HAL_SPI_Transmit(dev->hspi, dummy, 2, 10);
// 读取数据:每个寄存器组6字节,菊花链每片累加
uint8_t bytes_per_chip = 6;
uint8_t total_bytes = bytes_per_chip * dev->chain_len;
HAL_SPI_Receive(dev->hspi, rx_buf, total_bytes, 50);
// 片选拉高
HAL_GPIO_WritePin(dev->cs_port, dev->cs_pin, GPIO_PIN_SET);
return 0; // 成功
}
// main.c 调用示例(单芯片,chain_len=1)
#include "isoSPI_interface.h"
ISOSPI_Handle iso_dev;
uint8_t voltage_buf[6]; // 存储一组电压原始数据
void BMS_ReadVoltage(void) {
iso_dev.hspi = &hspi2;
iso_dev.cs_port = GPIOB;
iso_dev.cs_pin = GPIO_PIN_12;
iso_dev.chain_len = 1;
ISOSPI_Init(&iso_dev);
ISOSPI_ReadReg(&iso_dev, CMD_RDCV, voltage_buf, 0);
// 此时voltage_buf[0..5]为第1组电压的6字节原始数据
// 实际工程需解析为电压值:V = (raw * 0.0001) V(LTC6813-1的16位ADC)
}
SPI菊花链备选驱动(关键差异)
// 菊花链模式:所有芯片CS并联,数据从最后一片串行移出
// 初始化时需将每片的配置位写入,此处仅展示命令发送时序差异
void SPI_DaisyChain_Read(SPI_HandleTypeDef *hspi, uint16_t cmd,
uint8_t *rx_buf, uint8_t chip_count) {
uint8_t tx_cmd[2] = {(uint8_t)(cmd & 0xFF), (uint8_t)(cmd >> 8)};
uint8_t dummy[2] = {0, 0};
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); // CS低
// 发送命令后,需发送 (chip_count-1)*2 个填充字节以驱动数据移出
HAL_SPI_Transmit(hspi, tx_cmd, 2, 10);
for (uint8_t i = 0; i < chip_count - 1; i++) {
HAL_SPI_Transmit(hspi, dummy, 2, 10);
}
// 接收:每片6字节,共 chip_count*6 字节
HAL_SPI_Receive(hspi, rx_buf, chip_count * 6, 50);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
}
验证方法与判定标准
硬件连接:将LTC6813-1评估板的isoSPI端口(A/B引脚)通过双绞线连接至LTC6820隔离收发器,再接入STM32F4的SPI2引脚(SCK=PB13,MOSI=PB15,MISO=PB14,CS=PB12)。
测试步骤:
- 编译烧录后,用逻辑分析仪(采样率≥10MHz)夹在SPI2的SCK与MOSI线上;
- 触发BMS_ReadVoltage(),捕获一段通信波形;
- 观察MOSI线上是否出现0x04 0x04(CMD_RDCV命令)后跟2字节0x00;
- 观察MISO线上在命令后约2字节延迟后返回6字节非零数据(芯片有供电且电芯接入时)。
判定通过标准:
- 命令字节顺序正确(低字节0x04先发,高字节0x04后发);
- CS低电平持续时间≥命令+填充+读取总时长(约20μs@2MHz);
- MISO返回的数据长度等于6×chain_len字节,且非全0xFF(若全0xFF说明通信失败或芯片未响应)。
预期输出(基于代码逻辑直接推出):当chain_len=1且芯片正常供电时,voltage_buf数组将包含6字节数据,其中前2字节为第1组电压的16位ADC值(高位在前),后4字节为后续通道数据。具体数值取决于实际电芯电压,无法预先确定。
选型结论:本案例推荐isoSPI接口,因其在2Mbps速率下仅需2根双绞线即可实现隔离通信,且驱动代码与SPI兼容,仅需调整CPOL/CPHA配置。SPI菊花链模式适合成本敏感且无需隔离的场合,但需额外增加数字隔离器,且线束增加至6根。