You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32F103与CS5532 ADC SPI通信故障:无法复位ADC求助

CS5532 ADC复位异常及增益寄存器读取失败问题排查建议

问题背景

使用STM32F103通过模拟SPI驱动Cirrus CS5532 ADC,调用ResetADC复位通信端口后,主循环周期性读取增益寄存器,预期结果为0x01000000,但实际无法得到该值。逻辑分析仪显示复位操作存在异常。

SPI逻辑分析仪截图

相关代码

GPIO控制函数

void CSlow(void){
    LL_GPIO_ResetOutputPin(GPIOA, NSS1_Pin);
}
void CShi(void){
    LL_GPIO_SetOutputPin(GPIOA, NSS1_Pin);
}

模拟SPI写函数

void SPI_Write32(uint32_t dat)
{
    int i;
    if((dat<<0)&0x80000000)       LL_GPIO_SetOutputPin(GPIOA, MOSI1_Pin);//CS5532_SDI=1;   
    else  LL_GPIO_ResetOutputPin(GPIOA, MOSI1_Pin);//CS5532_SDI=0;

    Delay(1);

    for(i=1;i<32;i++)
    {
        LL_GPIO_SetOutputPin(GPIOA, SCLK1_Pin);//CS5532_SCLK=1;    //时钟高
        Delay(1);

        if((dat<<i)&0x80000000)     LL_GPIO_SetOutputPin(GPIOA, MOSI1_Pin);//CS5532_SDI=1;  
        else  LL_GPIO_ResetOutputPin(GPIOA, MOSI1_Pin);//CS5532_SDI=0;

        LL_GPIO_ResetOutputPin(GPIOA, SCLK1_Pin);//CS5532_SCLK=0;    
        Delay(1);

    }
     LL_GPIO_SetOutputPin(GPIOA, SCLK1_Pin);//CS5532_SCLK=1;    
     Delay(1);
     LL_GPIO_ResetOutputPin(GPIOA, SCLK1_Pin);//CS5532_SCLK=0;    
     Delay(1);

     Delay(1);
}

void SPI_Write(uint8_t dat)
{
    int i;

    if((dat<<0)&0x80)     LL_GPIO_SetOutputPin(GPIOA, MOSI1_Pin);//CS5532_SDI=1;   
    else  LL_GPIO_ResetOutputPin(GPIOA, MOSI1_Pin);//CS5532_SDI=0;

    Delay(1);

    for(i=1;i<8;i++)
    {
        LL_GPIO_SetOutputPin(GPIOA, SCLK1_Pin);//CS5532_SCLK=1;    
        Delay(1);

        if((dat<<i)&0x80)   LL_GPIO_SetOutputPin(GPIOA, MOSI1_Pin);//CS5532_SDI=1;   
        else  LL_GPIO_ResetOutputPin(GPIOA, MOSI1_Pin);//CS5532_SDI=0;

        LL_GPIO_ResetOutputPin(GPIOA, SCLK1_Pin);//CS5532_SCLK=0; 
        Delay(1);
    }
    LL_GPIO_SetOutputPin(GPIOA, SCLK1_Pin);//CS5532_SCLK=1;   
    Delay(1);
    LL_GPIO_ResetOutputPin(GPIOA, SCLK1_Pin);//CS5532_SCLK=0;  
    Delay(1);

    Delay(1);
}

模拟SPI读函数

uint32_t SPI_Read(uint8_t bitno)
{
    int i;
    uint32_t temp=0;

    LL_GPIO_ResetOutputPin(GPIOA, NSS1_Pin);
    Delay(1);
    for(i = 0; i < bitno; i++)
    {
        LL_GPIO_SetOutputPin(GPIOA, SCLK1_Pin);//CS5532_SCLK = 1; 
        temp <<= 1;
        if(LL_GPIO_IsInputPinSet(GPIOA,MISO1_Pin))//(CS5532_SDO)
            temp |= 0x1;
        else
            temp &= 0xFFFFFFFE;
        Delay(1);
        LL_GPIO_ResetOutputPin(GPIOA, SCLK1_Pin);//CS5532_SCLK = 0;
        Delay(1);
    }
    LL_GPIO_SetOutputPin(GPIOA, NSS1_Pin);
    Delay(1);
    return temp;
}

复位函数及主循环

void ResetADC(void){
    uint32_t resetcommand = 0x1 << 29 , RVbit = 0x1 << 28,
    VRS = 0x1 << 25, resetbit =  0x0 ;
    uint8_t i,write = 0x3 , read = 0xB , value[4]={1,1,1,1};

    uint8_t resetsequence[16]=  {0xFF, 0xFF, 0xFF, 0xFF,
                         0xFF, 0xFF, 0xFF, 0xFF,
                         0xFF, 0xFF, 0xFF, 0xFF,
                         0xFF, 0xFF, 0xFF, 0xFE};

    for(i=0;i<16;i++){
        CSlow();
        SPI_Write(resetsequence[i]);
        CShi();
        Delay(1);
     }
    Delay(50);
    CSlow();

    SPI_Write(write);
    SPI_Write32(resetcommand);
    CShi();

    Delay(200);

    CSlow();
    SPI_Write(write);
    SPI_Write32(resetbit);
    CShi();
}
while (1){
    ....
    CSlow();
    SPI_Write(0xa);
    CShi();
    receive=SPI_Read(32);
}

核心问题及解决建议

1. 复位序列时序错误

CS5532要求复位序列为连续发送127个高电平后接1个低电平,且必须在单次NSS拉低周期内完成。当前代码每发送1个字节就释放NSS,破坏了连续时序,导致复位失败。

修正代码:

void ResetADC(void){
    uint32_t resetcommand = 0x1 << 29;
    uint8_t write = 0x3;

    // 复位序列:单次NSS拉低,连续发送16字节
    CSlow();
    uint8_t resetsequence[16]=  {0xFF, 0xFF, 0xFF, 0xFF,
                                 0xFF, 0xFF, 0xFF, 0xFF,
                                 0xFF, 0xFF, 0xFF, 0xFF,
                                 0xFF, 0xFF, 0xFF, 0xFE};
    for(int i=0;i<16;i++){
        SPI_Write(resetsequence[i]);
    }
    CShi();
    Delay(50); // 等待内部复位完成

    // 发送复位命令
    CSlow();
    SPI_Write(write);
    SPI_Write32(resetcommand);
    CShi();
    Delay(200);

    // 清除复位标志
    CSlow();
    SPI_Write(write);
    SPI_Write32(0x0);
    CShi();
}

2. SPI采样时序不匹配

CS5532的SDI在SCLK上升沿采样,当前模拟SPI代码在SCLK上升沿期间更新SDI电平,导致采样时信号不稳定。需调整为SCLK低电平期间更新SDI,确保上升沿到来时信号已稳定。

修正SPI_Write函数逻辑:

void SPI_Write(uint8_t dat)
{
    int i;
    for(i=0;i<8;i++)
    {
        // SCLK低电平期间更新SDI
        if((dat<<i)&0x80)   
            LL_GPIO_SetOutputPin(GPIOA, MOSI1_Pin);
        else  
            LL_GPIO_ResetOutputPin(GPIOA, MOSI1_Pin);
        Delay(1);

        // 上升沿采样
        LL_GPIO_SetOutputPin(GPIOA, SCLK1_Pin);
        Delay(1);
        // 恢复低电平
        LL_GPIO_ResetOutputPin(GPIOA, SCLK1_Pin);
        Delay(1);
    }
}

3. 增益寄存器读命令错误

CS5532增益寄存器的读命令为0xB,当前主循环中发送的是0xA,导致读取错误寄存器。此外,读操作必须在单次NSS拉低周期内完成命令发送和数据读取,不能中途释放NSS。

修正主循环读操作:

while (1){
    ....
    uint32_t receive;
    CSlow();
    SPI_Write(0xB); // 发送增益寄存器读命令
    receive = SPI_Read(32); // 同一次NSS拉低期间读取32位数据
    CShi();
    // 后续处理receive数据
}

4. 优先改用硬件SPI

模拟SPI的时序精度依赖Delay函数,容易出现偏差。STM32F103的硬件SPI外设能精准匹配CS5532的时序要求,建议替换为硬件SPI驱动,避免模拟时序带来的不稳定问题。


内容的提问来源于stack exchange,提问作者magnetron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 13:12:03