汪阳 · 2023年01月07日 · 山东

【GD32F427开发板试用】04使用SPI与32位ADC(CS5552)通讯采集数据

CS5552 为一款 SPI 接口的双信道、32 位高精度 ADC 芯片,内置 1~128 倍可程序设计的低噪声仪表放大器、高精度 Sigma-Delta ADC,同时内部集成温度传感器、高精度基准电压源、晶体起振电路、高频内部 RC 时钟源。ADC 实际有效精度(ENOB)24.3BIT@1 倍 PGA,22.9BIT@64 倍 PGA,等效输入噪声低至 3nV/√𝐻𝑧,零漂 0.5uV,零漂温度系数低于 5nV/℃。输出码率可配置为 6.25Hz 至51200Hz。可用于各类电子秤、分析天平、工业过程控制、直流/交流电能测量、耳温枪等需要高精度、低零漂的应用场合。CS5552的SPI 接口支持最高 10MHz。

本来是使用GD32F427R的硬件SPI0与CS5552通信,但CS5552在连续模式下SPI的SDO会拉低表示数据转换完成。由于我的SPI连接线上MISO没有外部上拉电阻而5552在数据没准备完成是高阻状态,需要有外部上拉电阻才能读出高电平,否则一直是低电平,不能产生中断。尝试了打开GD32的上拉也是不管用,其实对于GD32的IO口还是要吐槽一点,IO口的设计比较中规中矩,没有太大亮点。像有些友商IO口缓冲电阻能配置(驱动强度),连I2C等上拉电阻都可以配置不需要外部上拉电阻以及缓冲电阻,硬件设计起来还是挺方便的,甚至有些厂商的IO口还支持滤波并且滤波时间可以配置,在工业上用起来还是很方便的。无奈只能使用软件模拟SPI了,这样把MISO引脚设置成输入,并且使能上拉,就能顺利通讯了。关键代码如下:
    1.SPI宏定义

/\*  
PA4 CS  
PA5 CLK  
PA6 miso  
PA7 mosi  
\*/  

#  #define SET\_SPI0\_NSS\_HIGH         gpio\_bit\_set(GPIOA,GPIO\_PIN\_4);  

#  #define SET\_SPI0\_NSS\_LOW           gpio\_bit\_reset(GPIOA,GPIO\_PIN\_4);  

#  #define CLK\_HIGH         gpio\_bit\_set(GPIOA,GPIO\_PIN\_5);  

# #define CLK\_LOW           gpio\_bit\_reset(GPIOA,GPIO\_PIN\_5);  

# #define MOSI\_HIGH          gpio\_bit\_set(GPIOA,GPIO\_PIN\_7);  

# #define MOSI\_LOW           gpio\_bit\_reset(GPIOA,GPIO\_PIN\_7);  

# #define READ\_MISO         gpio\_input\_bit\_get(GPIOA,GPIO\_PIN\_6) 

2.初始化SPI,保留了硬件SPI作为参考

void spi0\\\\\_init(void)  
{  
rcu\\\\\_periph\\\\\_clock\\\\\_enable(RCU\\\\\_GPIOA);  
//    rcu\\\\\_periph\\\\\_clock\\\\\_enable(RCU\\\\\_SPI0);  
//  
// /\* configure SPI0 GPIO \*/  
//    gpio\\\\\_af\\\\\_set(GPIOA, GPIO\\\\\_AF\\\\\_5, GPIO\\\\\_PIN\\\\\_5 | GPIO\\\\\_PIN\\\\\_6 | GPIO\\\\\_PIN\\\\\_7);  
//    gpio\\\\\_mode\\\\\_set(GPIOA, GPIO\\\\\_MODE\\\\\_AF, GPIO\\\\\_PUPD\\\\\_NONE, GPIO\\\\\_PIN\\\\\_5 | GPIO\\\\\_PIN\\\\\_6 | GPIO\\\\\_PIN\\\\\_7);  
//// gpio\\\\\_mode\\\\\_set(GPIOA, GPIO\\\\\_MODE\\\\\_AF, GPIO\\\\\_PUPD\\\\\_PULLUP, GPIO\\\\\_PIN\\\\\_6);  
//    gpio\\\\\_output\\\\\_options\\\\\_set(GPIOA, GPIO\\\\\_OTYPE\\\\\_PP, GPIO\\\\\_OSPEED\\\\\_50MHZ, GPIO\\\\\_PIN\\\\\_5 | GPIO\\\\\_PIN\\\\\_6 | GPIO\\\\\_PIN\\\\\_7);  
  
//    /\* set SPI0\\\\\_NSS as GPIO\*/  
//    gpio\\\\\_mode\\\\\_set(GPIOA, GPIO\\\\\_MODE\\\\\_OUTPUT, GPIO\\\\\_PUPD\\\\\_PULLUP, GPIO\\\\\_PIN\\\\\_4);  
//    gpio\\\\\_output\\\\\_options\\\\\_set(GPIOA, GPIO\\\\\_OTYPE\\\\\_PP, GPIO\\\\\_OSPEED\\\\\_50MHZ, GPIO\\\\\_PIN\\\\\_4);  
  
// spi\\\\\_parameter\\\\\_struct spi\\\\\_init\\\\\_struct;  
  
//    /\* configure SPI1 parameter \*/  
//    spi\\\\\_init\\\\\_struct.trans\\\\\_mode           = SPI\\\\\_TRANSMODE\\\\\_FULLDUPLEX;  
//    spi\\\\\_init\\\\\_struct.device\\\\\_mode          = SPI\\\\\_MASTER;  
//    spi\\\\\_init\\\\\_struct.frame\\\\\_size           = SPI\\\\\_FRAMESIZE\\\\\_8BIT;  
//    spi\\\\\_init\\\\\_struct.clock\\\\\_polarity\\\\\_phase = SPI\\\\\_CK\\\\\_PL\\\\\_LOW\\\\\_PH\\\\\_1EDGE;  
//    spi\\\\\_init\\\\\_struct.nss                  = SPI\\\\\_NSS\\\\\_SOFT;  
//    spi\\\\\_init\\\\\_struct.prescale             = SPI\\\\\_PSC\\\\\_128;//128-800k  
//    spi\\\\\_init\\\\\_struct.endian               = SPI\\\\\_ENDIAN\\\\\_MSB;  
//    spi\\\\\_init(SPI0, &spi\\\\\_init\\\\\_struct);  
//  
// SET\\\\\_SPI0\\\\\_NSS\\\\\_HIGH;  
//    /\* enable SPI \*/  
//    spi\\\\\_enable(SPI0);  
//    SET\\\\\_SPI0\\\\\_NSS\\\\\_LOW;  
  
/\*模拟IO-spi\*/  
/\* set SPI0\\\\\_NSS as GPIO\*/  
    gpio\\\\\_mode\\\\\_set(GPIOA, GPIO\\\\\_MODE\\\\\_OUTPUT, GPIO\\\\\_PUPD\\\\\_PULLUP, GPIO\\\\\_PIN\\\\\_4);  
    gpio\\\\\_output\\\\\_options\\\\\_set(GPIOA, GPIO\\\\\_OTYPE\\\\\_PP, GPIO\\\\\_OSPEED\\\\\_50MHZ, GPIO\\\\\_PIN\\\\\_4);  
  
gpio\\\\\_mode\\\\\_set(GPIOA, GPIO\\\\\_MODE\\\\\_OUTPUT, GPIO\\\\\_PUPD\\\\\_PULLUP, GPIO\\\\\_PIN\\\\\_5);  
    gpio\\\\\_output\\\\\_options\\\\\_set(GPIOA, GPIO\\\\\_OTYPE\\\\\_PP, GPIO\\\\\_OSPEED\\\\\_50MHZ, GPIO\\\\\_PIN\\\\\_5);  
  
gpio\\\\\_mode\\\\\_set(GPIOA, GPIO\\\\\_MODE\\\\\_OUTPUT, GPIO\\\\\_PUPD\\\\\_PULLUP, GPIO\\\\\_PIN\\\\\_7);  
   gpio\\\\\_output\\\\\_options\\\\\_set(GPIOA, GPIO\\\\\_OTYPE\\\\\_PP, GPIO\\\\\_OSPEED\\\\\_50MHZ, GPIO\\\\\_PIN\\\\\_7);  
  
gpio\\\\\_mode\\\\\_set(GPIOA, GPIO\\\\\_MODE\\\\\_INPUT, GPIO\\\\\_PUPD\\\\\_PULLUP, GPIO\\\\\_PIN\\\\\_6);  
    CLK\\\\\_LOW;  
    SET\\\\\_SPI0\\\\\_NSS\\\\\_HIGH;  
}  

3.SPI收发数据,保留硬件SPI收发

uint16\\\\\_t  spi\\\\\_data(uint16\\\\\_t data)  
{  
  
// while (spi\\\\\_i2s\\\\\_flag\\\\\_get(SPI0, SPI\\\\\_FLAG\\\\\_TBE) == RESET);  
  
//    spi\\\\\_i2s\\\\\_data\\\\\_transmit(SPI0, data);  
  
//    while (spi\\\\\_i2s\\\\\_flag\\\\\_get(SPI0, SPI\\\\\_FLAG\\\\\_RBNE) == RESET);  
  
//    return spi\\\\\_i2s\\\\\_data\\\\\_receive(SPI0);  
  
unsigned char i;  
uint8\\\\\_t rdata = 0;  
for(i=8;i>0;i--)  
{  
if((data&0x80)==0)  
{MOSI\\\\\_LOW;}  
else  
{MOSI\\\\\_HIGH;}  
Delay(10);  
CLK\\\\\_HIGH;  
Delay(20);  
rdata <<= 1;  
if(READ\\\\\_MISO == SET)  
rdata++;  
CLK\\\\\_LOW;  
data<<=1;  
Delay(10);  
}  
return rdata;  
}  

4.读写CS5552寄存器

void WRITE\\\\\_REGISTER(unsigned char COMMAND,unsigned char H\\\\\_DATA,unsigned char M\\\\\_DATA,unsigned char L\\\\\_DATA,unsigned char S\\\\\_DATA)  
{  
spi\\\\\_data(COMMAND);  
Delay(1);  
spi\\\\\_data(H\\\\\_DATA);  
spi\\\\\_data(M\\\\\_DATA);  
spi\\\\\_data(L\\\\\_DATA);  
spi\\\\\_data(S\\\\\_DATA);  
}  
  
uint32\\\\\_t READ\\\\\_REGISTER(unsigned char COMMAND)  
{  
uint32\\\\\_t data = 0;  
uint8\\\\\_t datav\[4\];  
spi\\\\\_data(COMMAND);  
Delay(1);  
datav\[0\] = spi\\\\\_data(0x00);  
datav\[1\] = spi\\\\\_data(0x00);  
datav\[2\] = spi\\\\\_data(0x00);  
datav\[3\] = spi\\\\\_data(0x00);  
data = (datav\[0\]<<24)|(datav\[1\]<<16) | (datav\[2\]<<8) | (datav\[3\]<<0);  
return data;  
}  

5.初始化CS5552

void cs5552\\\\\_init(void)  
{  
spi0\\\\\_init();  
SET\\\\\_SPI0\\\\\_NSS\\\\\_LOW;  
spi\\\\\_data(0x00);  
spi\\\\\_data(0xa5);  
spi\\\\\_data(0xff);  
spi\\\\\_data(0x5a);  
SET\\\\\_SPI0\\\\\_NSS\\\\\_HIGH;  
Delay(0xffff);  
SET\\\\\_SPI0\\\\\_NSS\\\\\_LOW;  
WRITE\\\\\_REGISTER(0x30,0x80,0x00,0x00,0x00); // RESET  
SET\\\\\_SPI0\\\\\_NSS\\\\\_HIGH;  
Delay(0xffff);  
SET\\\\\_SPI0\\\\\_NSS\\\\\_LOW;  
WRITE\\\\\_REGISTER(0x00,0x00,0x00,0x00,0x00); // OS\\\\\_CH0  
WRITE\\\\\_REGISTER(0x09,0x02,0x00,0x00,0x00); // GAIN\\\\\_CH0  
WRITE\\\\\_REGISTER(0x21,0x00,0x00,0x00,0x81); // CONV\\\\\_CONF0 //C1-PGA=128 DATA RATE=12.5Hz 81-128-200hz  
WRITE\\\\\_REGISTER(0x28,0x00,0x00,0x00,0x00); // CONV\\\\\_CONF1  
WRITE\\\\\_REGISTER(0x30,0x00,0x01,0x00,0x00); // SYS\\\\\_CONF0 //\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*HBF\\\\\_EN=0;  
WRITE\\\\\_REGISTER(0x39,0x00,0x11,0x02,0x10); // SYS\\\\\_CONF1 //\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*FR\\\\\_SEL=0;  
WRITE\\\\\_REGISTER(0x41,0x00,0x02,0x00,0x00); // SYS\\\\\_CONF2  
SET\\\\\_SPI0\\\\\_NSS\\\\\_HIGH;  
Delay(0xf);  
SET\\\\\_SPI0\\\\\_NSS\\\\\_LOW;  
/\*测试读出数据\*/  
uint32\\\\\_t data = READ\\\\\_REGISTER(0x24);//读SYS\\\\\_CONF0  
printf("CONF0 = %d\\r\\n",data);  
data = READ\\\\\_REGISTER(0x05);//读OS-CH0  
printf("OS-CH0 = %d\\r\\n",data);  
data = READ\\\\\_REGISTER(0xC0);//读GAIN-CH0  
printf("GAIN-CH0 = %d\\r\\n",data);  
data = READ\\\\\_REGISTER(0x14);//读OS-CH1  
printf("OS-CH1 = %d\\r\\n",data);  
data = READ\\\\\_REGISTER(0x1D);//读GAIN-CH1  
printf("GAIN-CH1 = %d\\r\\n",data);  
spi\\\\\_data(0x82);//开启连续转换  
SET\\\\\_SPI0\\\\\_NSS\\\\\_HIGH;  
}

6.SDO拉低连续读CS5552转换数据

uint32\\\\\_t read\\\\\_cs5552(void)  
{  
uint32\\\\\_t data = 0;  
SET\\\\\_SPI0\\\\\_NSS\\\\\_LOW;  
Delay(2);  
SDO\\\\\_L;//等待SDO拉低  
data = READ\\\\\_REGISTER(0xff);  
SET\\\\\_SPI0\\\\\_NSS\\\\\_HIGH;  
return data;  
}  

7.通过软件模拟SPI,使用sck为800k,cs5552采样速率为200次,读出数据精度比较好,经过滤波处理看来达到了高精度采样AD的行列。

推荐阅读
关注数
10693
内容数
187
中国高性能通用微控制器领域的领跑者兆易创新GD系列芯片技术专栏。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息