1. ADN8810电流源与SPI总线基础

ADN8810是一款高精度可编程电流源芯片,通过SPI接口实现数字控制。在实际项目中,我经常用它来驱动激光二极管或精密传感器。它的核心优势在于12位分辨率,能够输出0-150mA的电流,步进精度可达36.6μA。

SPI通信是这类场景的首选方案。与I2C相比,SPI的全双工特性在需要高速数据传输时优势明显。ADN8810采用标准4线SPI接口(SCLK、MOSI、CS、RST),但有几个关键点需要注意:

  • 地址分配机制:前4位中的A3必须为逻辑低,A2-A0用于设备寻址,理论最多支持8个设备
  • 数据格式:16位传输中,前4位是地址,后12位是电流设置值
  • 时序要求:CS信号的建立/保持时间至少30ns,时钟频率上限12MHz

我在初次使用时曾遇到一个典型问题:按照默认的Low极性配置时钟,导致数据采样错误。后来通过逻辑分析仪抓取波形才发现,必须将SPI时钟极性(CPOL)设置为High才能匹配ADN8810的时序要求。

2. CubeMX配置避坑指南

使用STM32CubeMX配置SPI外设时,这些参数配置直接影响驱动稳定性:

/* SPI2参数配置示例 */
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES; // 全双工模式
hspi2.Init.DataSize = SPI_DATASIZE_16BIT;    // 16位传输
hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;  // 关键!必须设为HIGH
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;              // 软件控制CS
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; // 2.25MHz @72MHz主频
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;     // 数据手册要求的MSB优先

特别提醒三个易错点:

  1. 时钟极性配置:我曾在项目中花费2小时调试才发现CPOL设错
  2. NSS信号管理:建议使用软件控制而非硬件NSS,方便多设备切换
  3. 分频系数计算:确保最终时钟不超过ADN8810的12MHz限制

对于多设备场景,还需要配置GPIO矩阵。通常我会为每个ADN8810分配独立的CS引脚,例如:

  • CS1: PC0
  • CS2: PC1
  • CS3: PC2
    通过HAL_GPIO_WritePin()函数控制片选信号。

3. 多设备驱动优化策略

当总线上挂载多个ADN8810时,需要解决三个核心问题:

3.1 地址分配方案

推荐使用枚举类型管理设备地址:

typedef enum {
    CURRENT_SOURCE_1 = 0x01,  // A2=0, A1=0, A0=1
    CURRENT_SOURCE_2 = 0x02,
    CURRENT_SOURCE_3 = 0x04
} ADN8810_Address;

实际传输时,通过位运算组合地址和数据:

uint16_t pack_data(uint8_t addr, uint16_t value) {
    return ((addr & 0x07) << 12) | (value & 0x0FFF); 
}

3.2 时序同步技巧

为保证信号稳定性,我总结出以下时序控制要点:

  1. CS信号拉高后保持至少30ns
  2. 数据传输前确保RST处于高电平
  3. 关键操作间插入纳秒级延时

具体实现参考:

void delay_100ns(void) {
    __NOP(); __NOP(); __NOP(); __NOP(); // 72MHz下约56ns
}

void write_current(uint8_t addr, uint16_t value) {
    uint16_t packet = pack_data(addr, value);
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);
    delay_100ns();
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi2, (uint8_t*)&packet, 1, 10);
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);
}

3.3 DMA传输优化

对于需要频繁更新电流值的场景,可以采用DMA传输提升效率:

// 初始化DMA
hdma_spi2_tx.Instance = DMA1_Stream4;
hdma_spi2_tx.Init.Channel = DMA_CHANNEL_0;
hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
HAL_DMA_Init(&hdma_spi2_tx);

// 批量传输
void batch_update(ADN8810_Device* devices, uint8_t count) {
    uint16_t buffer[count];
    for(int i=0; i<count; i++) {
        buffer[i] = pack_data(devices[i].addr, devices[i].value);
    }
    HAL_SPI_Transmit_DMA(&hspi2, (uint8_t*)buffer, count);
}

4. 电流校准与实用技巧

ADN8810输出的实际电流值需要通过校准公式转换:

Iout = Code * (Vref/4096) * (1/Rsn) * (Rsn/(150000 + 0.1))

我在项目中封装了转换函数:

#define VREF 2.99728f  // 实测参考电压
#define RSN  2.2f      // 检测电阻

float code_to_current(uint16_t code) {
    return code * (VREF/4096.0f) * (1.0f/RSN) * (RSN/150000.0f + 0.1f);
}

uint16_t current_to_code(float current) {
    float ki = RSN * 61440.0f / ((RSN + 1500.0f) * VREF);
    uint32_t code = current * ki;
    return (code > 0x0FFF) ? 0x0FFF : code;
}

实用建议:

  1. 上电时对所有设备执行复位脉冲(RST低电平至少40ns)
  2. 定期校验输出电流,防止漂移
  3. 在结构体中保存设备状态:
typedef struct {
    char name[20];
    ADN8810_Address addr;
    float target_current;
    float measured_current;
} ADN8810_Device;

调试时推荐使用逻辑分析仪抓取SPI波形,重点检查:

  • 时钟极性与相位
  • CS信号与数据对齐情况
  • 数据传输间隔时间

通过上述优化,我在工业控制项目中成功实现了8路ADN8810的同步控制,电流输出稳定性达到±0.1%。这种方案特别适合需要多通道精密电流控制的场合,如光学检测设备和医疗仪器。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐