项目背景:
BPA项目, 使用的是一个模拟前端芯片,该AFE集成了24bit的ADC和BIM模块,与主控SOC的通信采用SPI通信。
遇到的问题描述:
在读取AD值过程中,发现读出的AD值全部为0,不论是内short模式,还是外load模式。
功能如下:
1)开启测量,丢掉前4笔数据(ADC有一个建立的过程,此时AD值还未达到稳定值)。
2)ADC的输出速率设置为 Data Rate=40hz, 也就是说每25ms左右会输出一个AD值。读取AD值,如果相邻两个AD在固定阈值范围内且连续8个AD符合此条件时,则AD值为有效数据,此时计算的AD结果取8个AD值的平均值;
U32 ReadSumADCRes(U8 times)
{
U8 i,k=0,k1=0;
U32 lastADC,currentADC,tempADC,sumADC;
sumADC=0;
SDAInput;
for(i=0;i<FILTERADTIMES;i++) //丢4笔
{
while(SDAInputLow) //等待ADC Readay信号
{
DelayTimeUs(20);
if(k1++>100)//超时判断
{
sumADC=0;
break;
}
}
currentADC=ReadADC();//读取24位ADC
}
tempADC = 0;
for(i=0;i<times;i++)
{
// DelayTimeMs(30);//等待ADC Readay信号
k1=0;
while(SDAInputLow) //等待ADC Readay信号
{
DelayTimeUs(20);
if(k1++>100)//超时判断
{
sumADC=0;
break;
}
}
currentADC=ReadADC();//读取24位ADC
if(k++>100)//超时判断
{
sumADC=0;
break;
}
//求2次ADC绝对值
if(i>0){
if(lastADC >= currentADC){
tempADC = lastADC-currentADC;
}
else{
tempADC = currentADC-lastADC;
}
}
lastADC = currentADC;
//在稳定范围
if(tempADC <= RESSTABLECOUNT){
sumADC += lastADC;
}
else{//超过稳定范围
sumADC=0;
i = 0;
}
}
if(k > 100){
myPrintf(MY_PRINTF_ERROR,"%s(%d)-k=%d\r\n",__func__,__LINE__,k);
}
sumADC/=(times);
return sumADC;
}
遇到问题的原理分析:
如下图所示,AFE在每次ADC转换完成后,会在SPI通信的SDA线上,输出一个25.12us的高电平。
上述程序中,读取ADC的条件 是按照下述实现的:当低电平时,超时20us*100=2ms内,如果未采集到高电平信号,即当做超时,直接进行ADC的读取。而在40hz下,每25ms实现AD转换,输出一个AD值,很显然,即使此时超时,ADC也还没有转换完成,因此读取到的AD值为0。
while(SDAInputLow) //等待ADC Readay信号
{
DelayTimeUs(20);
if(k1++>100)//超时判断
{
sumADC=0;
break;
}
}
currentADC=ReadADC();//读取24位ADC
那么如何纠正这种问题呢? 在开启测量使能后,将超时判断的时间更正到大于25ms, 才能读取到正确的值,尽管,在延时这段时间可能会错过几个周期。
while(SDAInputLow) //等待ADC Readay信号
{
DelayTimeUs(20);
if(k1++>10000)//超时判断 //200ms
{
sumADC=0;
break;
}
}
currentADC=ReadADC();//读取24位ADC
实际上,利用该方式去计算单次的值,在丢掉前几笔AD值数据的前提下,还也是勉强可以的,但最好还是检测ADC转换完成的下降沿,这样既不会丢数据,也可以及时的正确的读取到AD转换完成的ADC值。程序如下:
/* 等待AD READY信号*/
U8 CS1259Ready()
{
SDAInput;
uint8 adcReadyFlag=0;
if (SDAInputHigh)
{
DelayTimeUs(50);
if (SDAInputLow)
{
adcReadyFlag=1;
}
}
//CLRSDA;
SDAOutput;
return adcReadyFlag;
}
// 读取程序:
if(CS1259Ready()) //等待ADC Readay信号
{
currentADC=ReadADC();//读取24位ADC
printf("ADC: %d.\r\n",currentADC);
}
值得一提的是,该款ADC芯片的ADC在转换完成后,存储ADC的寄存器值是一直存在的。 因此上述现象只存在于在开启测量使能后,第一个转换周期中。