STM32F103与CS5532 ADC SPI通信故障:无法复位ADC求助
CS5532 ADC复位异常及增益寄存器读取失败问题排查建议
问题背景
使用STM32F103通过模拟SPI驱动Cirrus CS5532 ADC,调用ResetADC复位通信端口后,主循环周期性读取增益寄存器,预期结果为0x01000000,但实际无法得到该值。逻辑分析仪显示复位操作存在异常。

相关代码
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
相关产品推荐
相关产品推荐

