本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站。作者:汪阳
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的行列。