硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1126|回复: 9
收起左侧

AD7606B 数据读取不定时异常

[复制链接]

15

主题

57

回帖

102

积分

初级会员

积分
102
发表于 2024-10-12 15:10:36 | 显示全部楼层 |阅读模式
使用AD7606B采集电压电流波形,采集原理:STM32定时器输出周期950us,占空比为50%的方波作为外部时钟输入给convst,通过检测BUSY下降沿SPI读取ADC数据。
AD7606B配置为软件模式,Dout线数为1,无过采样,±10V范围。
原理图(原理图存在错误,图上引脚用的7606,实际使用7606b,WR为低电平)如下:
测试中发现奇怪现象,对瞬时脉冲信号(每秒10ms高电平)的采集不定时丢失(有时候运行几个小时出现,有时运行几十分钟出现),而稳定信号或者高电平时间较长的脉冲信号未出现。
两通道同时输入10ms脉冲信号,不一定哪个通道会出现丢失;
两通道一个10ms脉冲,一个20ms脉冲输入,10ms脉冲会出现丢失;

正常脉冲波形(1s一个10ms高电平)
丢失时波形(隔1s丢失一次10ms高电平)
且丢失前会有一段时间 间隔21s丢一次数据的现象(为什么会间隔21s丢数据, 是否跟950us的convst时钟有关系)
同时刻另一通道的稳定电平信号正常采集
将脉冲信号改为每秒30ms高电平信号,采集波形经过十几分钟缓慢恢复正常。将脉冲信号改为稳定高电平信号,波形立即恢复正常。
使用示波器测量convst信号(下图黄色)和busy信号(下图蓝色),发现busy不连续,但stm32可以每毫秒都能检测到busy下降沿中断,不确定是不是示波器问题。
将stm32定时器改为输出周期1ms的方波后,该现象暂未复现,不理解为什么这个改动会起作用。
示波器测量7606B相关电压:
Vvcc :    有效值5.16V,峰值5.28V
Vdrive:有效值3.45V,峰值3.52V
Vregcap: 有效值1.95V,峰值2.08V
SPI通信配置及BUSY下降沿中断读取
[C] 纯文本查看 复制代码
/* SPI1 init function */[/font][/color][/align]
void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 7;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  __HAL_SPI_DISABLE(&hspi1);  
  __HAL_SPI_ENABLE(&hspi1); 

  /* USER CODE END SPI1_Init 2 */

}


void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(spiHandle->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspInit 0 */

  /* USER CODE END SPI1_MspInit 0 */
    /* SPI1 clock enable */
    __HAL_RCC_SPI1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI1 GPIO Configuration
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PB5     ------> SPI1_MOSI
    */
    GPIO_InitStruct.Pin = AD_SCLK_Pin|AD_SDI_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = AD_SDO_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(AD_SDO_GPIO_Port, &GPIO_InitStruct);



   /* SPI1 interrupt Init */

  /* USER CODE BEGIN SPI1_MspInit 1 */

  /* USER CODE END SPI1_MspInit 1 */
  }
  
}

/*
*********************************************************************************************************
*        函 数 名: SPI1_Write2Bytes
*        功能说明: 通过SPI1接口发送2字节数据
*        形    参:   TxData:要发送的数据
*        返 回 值: SPI接口返回值
*********************************************************************************************************
*/
u16 SPI1_Write2Bytes (u16 TxData)
{

	u16 rxdata;
    hspi1.Instance->DR = TxData;
    /* 等待发送完成 */
    while (!( hspi1.Instance->SR & TXE));
    	hspi1.Instance->DR;
	   
    /* 等待接收完成 */
    while (hspi1.Instance->SR & (BSY | RXNE))
        rxdata = hspi1.Instance->DR;
	return rxdata;

}

/*
*********************************************************************************************************
*        函 数 名: SPI1_Read2Bytes
*        功能说明: 通过SPI1接口接收2字节数据
*        形    参:   无
*        返 回 值: 接收数据值
*********************************************************************************************************
*/
u16 SPI1_Read2Bytes (void)
{

	u16 rxdata;

	hspi1.Instance->DR = 0x0000;
   // /* 等待发送完成 */
    while (!(hspi1.Instance->SR & TXE));
    	hspi1.Instance->DR;
   
    /* 等待接收完成 */
    while (hspi1.Instance->SR & (BSY | RXNE))
    {
          rxdata = hspi1.Instance->DR;
    }
	return rxdata;

	//HAL_SPI_TransmitReceive_DMA(&hspi1,(u8*)g_spi1TxBuf, (u8*)g_spi1RxBuf,size);

}

void AD7606_ISR(void) 		/* 此函数代码按照时序编写 */
{
	u8 i,j;
	u16 ADC_Value[8];



	ADC_CS = 0; 
	for (i = 0; i < AD_CH_NUM; i++)
	{			
		ADC_Value[i] = SPI1_Read2Bytes();  /* 读16位数据 */	
	}
	ADC_CS = 1;

	AD_Errcnt = 0;

	#if 1
	if((ADC_Data_Flag == 0)&& ADC_DataIndex1 < ADC_100MS_SIZE)  	  
	{
		for(j=0;j<AD_CH_NUM;j++)
		{
			if(ADC_Value[j]>50 && ADC_Value[j] <65480 )
				ADC_DataBuffer1[j][ADC_DataIndex1] = ADC_Value[j];
			else
				ADC_DataBuffer1[j][ADC_DataIndex1] = 0;
			
			if(ADC_DataBuffer1[j][ADC_DataIndex1]<0x8000)
				ADC_RealValue[j] = ADC_DataBuffer1[j][ADC_DataIndex1];	
			else
				ADC_RealValue[j] = 0xFFFF-ADC_DataBuffer1[j][ADC_DataIndex1];	
		}
		
		ADC_DataIndex1++;
		if(ADC_DataIndex1>= ADC_100MS_SIZE)
		{
			ADC_DataIndex1 = 0;
			ADC_DataFull1 = 1;
			ADC_Data_Flag = 1;
			Errorcode		&=~(1<<2);
			AD_timeout 		= 0;
		}
	}
	else if((ADC_Data_Flag == 1) && ADC_DataIndex2 < ADC_100MS_SIZE)  	  
	{
		for(j=0;j<AD_CH_NUM;j++)
		{
			if(ADC_Value[j]>50 && ADC_Value[j] <65480 )
				ADC_DataBuffer2[j][ADC_DataIndex2] = ADC_Value[j];
			else
				ADC_DataBuffer2[j][ADC_DataIndex2] = 0;

			if(ADC_DataBuffer2[j][ADC_DataIndex2]<0x8000)
				ADC_RealValue[j] = ADC_DataBuffer2[j][ADC_DataIndex2];	
			else
				ADC_RealValue[j] = 0xFFFF-ADC_DataBuffer2[j][ADC_DataIndex2];	
		}

		ADC_DataIndex2++;
		if(ADC_DataIndex2>= ADC_100MS_SIZE)
		{
			ADC_DataIndex2 = 0;
			ADC_DataFull2  = 1;
			ADC_Data_Flag  = 0;
			Errorcode		&=~(1<<2);
			AD_timeout 		= 0;
		}
	}

#endif

排查了很久,没找到根本原因,烦请帮忙看下,谢谢!

回复

使用道具 举报

15

主题

57

回帖

102

积分

初级会员

积分
102
 楼主| 发表于 2024-10-12 16:02:38 | 显示全部楼层
最新测试发现丢失数据也是缓慢过程(脉冲宽度越来越小),持续几分钟完全丢失。

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115653
QQ
发表于 2024-10-13 00:43:19 | 显示全部楼层
lishang4650 发表于 2024-10-12 16:02
最新测试发现丢失数据也是缓慢过程(脉冲宽度越来越小),持续几分钟完全丢失。

考虑把你每次的AD7606_ISR中断里面程序执行时间打印出来看下。我怀疑你这个存在超过950us的问题。导致EXTI外部中断有丢失的问题。
回复

使用道具 举报

15

主题

57

回帖

102

积分

初级会员

积分
102
 楼主| 发表于 2024-10-14 10:04:32 | 显示全部楼层
eric2013 发表于 2024-10-13 00:43
考虑把你每次的AD7606_ISR中断里面程序执行时间打印出来看下。我怀疑你这个存在超过950us的问题。导致EXT ...

大佬,之前怀疑过EXTI中断被打断或者丢失的问题,因为软件里还用了一个硬件定时器,优先级要比EXTI的高,但两个优先级调整后并没有作用。这个数据丢失问题我可能没有描述清楚:
1. 三个精密电源同时给7606三个通道10ms持续高电平、990ms持续低电平的周期信号,三通道AD随机一个通道丢,如果给三个通道三个不同宽度的脉冲(一个10ms,一个20ms,一个30ms),只有10ms的会丢。
2. 用一个电源并起来同时给两个通道10ms脉冲,两个通道同时丢数据;
3. 丢数据现象是间隔1s完全丢失10ms的脉冲,就是这一秒10ms完全采集到,下一秒10ms都采不到(全为0)

还做了俩测试:
1. 每进一次EXTI中断计数加1,100ms上报一次上位机,发现丢数据时中断数量并没有明显变化(0x67-0x6b(103-107)之间);

2. 进出SPI读取函数添加点灯,测量函数执行时间约4us。这个时间应该没什么问题。




另外我同时给了AD7606的不同通道不同的脉冲,一通道给的10ms持续高电平,990ms持续低电平这样的周期信号,另一通道给了20ms持续高电平,980ms持续低电平这样的周期信号
如果是EXTI中断丢失,同一时刻所有通道数据都应该丢失啊,解释不了为什么一个通道完全丢掉10ms高电平脉冲,另一个通道20ms高电平脉冲一点不丢的现象,因为SPI读取数据是两通道同时读出来。
我也怀疑过SPI通信和定时器PWM波驱动信号的问题:
测了丢数据时的PWM波,没有变化;
SPI没有详细验证,但是如果SPI通信有问题,为什么只有对这种瞬时脉冲信号有问题?而且将convst信号周期改为1ms又没有丢失现象。就很奇怪
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115653
QQ
发表于 2024-10-15 09:51:49 | 显示全部楼层
lishang4650 发表于 2024-10-14 10:04
大佬,之前怀疑过EXTI中断被打断或者丢失的问题,因为软件里还用了一个硬件定时器,优先级要比EXTI的高, ...

不是被打断的意思,我怀疑你的这个AD7606_ISR里面执行的程序本身,有时候有意外超时的问题,你看看是不是有这个问题。

如果这个排查了,可以大概率你的硬件设计或者软件驱动上是存在些问题的,还有就是务必使用正品7606B,不要买的翻新的。
回复

使用道具 举报

15

主题

57

回帖

102

积分

初级会员

积分
102
 楼主| 发表于 2024-10-15 10:10:02 | 显示全部楼层
本帖最后由 lishang4650 于 2024-10-15 10:31 编辑
eric2013 发表于 2024-10-15 09:51
不是被打断的意思,我怀疑你的这个AD7606_ISR里面执行的程序本身,有时候有意外超时的问题,你看看是不是 ...

我明白你的意思,就是说ISR执行时间太长导致新的EXTI中断没处理的问题。这个我也用两种方法验证了,就是昨天给你答复的:1.在ISR进出点灯,测量点灯操作时间也就几us,这个时间在丢数据时没有什么变化;2. 每进一次ISR计数加1,每100ms清零,通过上位机查看丢不丢数据计数都在103-107之间。
另外就是如果EXTI中断没来得及处理,那应该所有通道一起丢数据,现在只有某一个通道丢,也说明中断处理是应该没问题的。

硬件设计上AD芯片相关电压都测了在手册说明的范围内,再深入的PCB原因不太好找,软件驱动我改了好几版才发现把采样周期从950us改成1ms后这个丢失现象就没了。按说7606B 800k的采样率,950us的周期也不算快,芯片本身不应该有问题(采购渠道是立创),仅仅改成1ms就不复现了,而且只有这种短时脉冲才会丢,丢之后过个一两个小时又自己好了,没道理啊。
大佬能不能抽空帮忙审一下软件驱动,实在找不到原因了



链接:https://pan.baidu.com/s/1dsc0p-M4We1c-eXXgL5GOg
提取码:1357
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115653
QQ
发表于 2024-10-16 09:52:53 | 显示全部楼层
lishang4650 发表于 2024-10-15 10:10
我明白你的意思,就是说ISR执行时间太长导致新的EXTI中断没处理的问题。这个我也用两种方法验证了,就是 ...

1、测量的话,还是使用DWT时钟周期计数器或者定时器测量比较方便。
2、另外你的云盘分享不存在了。
回复

使用道具 举报

15

主题

57

回帖

102

积分

初级会员

积分
102
 楼主| 发表于 2024-10-16 10:17:14 | 显示全部楼层
本帖最后由 lishang4650 于 2024-10-16 10:20 编辑
eric2013 发表于 2024-10-16 09:52
1、测量的话,还是使用DWT时钟周期计数器或者定时器测量比较方便。
2、另外你的云盘分享不存在了。

我重新开个链接,昨天那个失效了。
另外我发现7606B的完全复位时间要求要比7606长,但是复位加了延时也没有效果。

static void AD7606_Reset(void)
{

        ADC_RST = 1;
        delay_us(10);
        ADC_RST = 0;
        ADC_RST = 0;
        ADC_RST = 0;       
        ADC_RST = 0;
        ADC_RST = 0;       
        ADC_RST = 0;
        delay_us(10);
        ADC_RST = 1;               

}
链接:https://pan.baidu.com/s/1rsgSdTxQfQCNKkyn6I7UvA
提取码:1357
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115653
QQ
发表于 2024-10-17 09:49:36 | 显示全部楼层
lishang4650 发表于 2024-10-16 10:17
我重新开个链接,昨天那个失效了。
另外我发现7606B的完全复位时间要求要比7606长,但是复位加了延时也 ...

看了你的程序,有两个无关紧要,但有时候却有影响的两个地方。
1、GPIO_InitStruct.Pull = GPIO_NOPULL; 使能上拉
2、速度等级设置为GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 中等
3、SPI是的时钟相位极性修改试试
4、SPI的收发使用HAL的API试试
回复

使用道具 举报

15

主题

57

回帖

102

积分

初级会员

积分
102
 楼主| 发表于 2024-10-17 09:59:00 | 显示全部楼层
eric2013 发表于 2024-10-17 09:49
看了你的程序,有两个无关紧要,但有时候却有影响的两个地方。
1、GPIO_InitStruct.Pull = GPIO_NOPULL; ...

感谢,第二条GPIO速度我改过Medium不行,我再按你说的这几条试试
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-5-10 04:13 , Processed in 0.391536 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表