求助!AD7606的FIFO模式无法正常工作。
本帖最后由 习惯了寂寞 于 2024-4-8 22:29 编辑参考AD7606模块的资料,将程序移植到STM32F407ZGT6上,用于驱动AD7606。如图片所示,软件定时获取方式采集1 KHz的正弦波正常;但使用FIFO模式时,采集的结果完全看不懂,尝试过多种不同速率采集,波形始终不对。
硬件是自己设计的,其中ADC的CONVT引脚与PB15相连,BUSY引脚与PB13相连。
在这里,小可先感谢各位大神百忙之中的指点了!
代码采用库函数编写,相关配置代码如下。
AD7606.c文件里的相关函数。
/*------------------------------------------------------------------------------------------------------------------------------
*****-----功能介绍:配置硬件工作在自动采集模式,结果存储在FIFO缓冲区
*****-----函数名:AD7606_EnterAutoMode()
*****-----入口参数:ulFreq : 采样频率,单位Hz, 1k,2k,5k,10k,20K,50k,100k,200k
*****-----返回值:无
*****-----备 注:
CONVST 引脚,PB15使用TIM12_CH2输出PWM脉冲,触发AD7606启动ADC转换。
设置BUSY口线为下降沿中断。在中断服务程序保存ADC结果。
配置PB15为复用功能,TIM12_CH2 . 执行后AD7606_Init()对PB15口线的配置将失效
------------------------------------------------------------------------------------------------------------------------------*/
void AD7606_EnterAutoMode(uint32_t _ulFreq)
{
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM12, ENABLE);//使能TIM12的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB的时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_TIM12);//Connect TIM12 pins to AF2
}
{
TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure;
TIM_OCInitTypeDefTIM_OCInitStructure;//用于配置定制器的通道输出比较(Output Compare)功能。
uint32_t uiTIMxCLK;//时钟周期
uint16_t usPrescaler;//分频系数
uint16_t usPeriod;//自动重载计数周期值
//TIM_DeInit(TIM12); //复位TIM定时器
/*------------------------------------------------------------------------------------------------------------------------------
system_stm32f4xx.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:
HCLK = SYSCLK / 1 (AHB1Periph)
PCLK2 = HCLK / 2 (APB2Periph)
PCLK1 = HCLK / 4 (APB1Periph) 42 MHz
因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2; 84 MHz
因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM6, TIM12, TIM13,TIM14
APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11
------------------------------------------------------------------------------------------------------------------------------*/
uiTIMxCLK = SystemCoreClock / 2; //168000000/2=84000000 Hz
if (_ulFreq < 3000)//采样频率小于3 KHz
{
usPrescaler = 100 - 1; /* 分频比 = 10 */
usPeriod =(uiTIMxCLK / 100) / _ulFreq- 1; /* 自动重装的值 */
}
else /* 大于4K的频率,无需分频 */
{
usPrescaler = 0; /* 分频比 = 1 */
usPeriod = uiTIMxCLK / _ulFreq - 1; /* 自动重装的值 */
}
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = usPeriod;
TIM_TimeBaseStructure.TIM_Prescaler = usPrescaler;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM12, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM调试模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 4; //设置占空比为4个时钟周期
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性低
TIM_OC2Init(TIM12, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM12, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM12, ENABLE);
TIM_Cmd(TIM12, ENABLE);
}
/* 配置PB13, BUSY 作为中断输入口,下降沿触发 */
{
EXTI_InitTypeDef EXTI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
/* Configure PB13 pin as input floating */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Connect EXTI Line13 to PB13 pin */
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource13);
/* Configure EXTI Line13 */
EXTI_InitStructure.EXTI_Line = EXTI_Line13;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
//EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/* Enable and set EXTI Line6 Interrupt to the lowest priority */
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
}
/*------------------------------------------------------------------------------------------------------------------------------
*****-----功能介绍:定时采集中断服务程序
*****-----函数名:AD7606_ISR()
*****-----入口参数:无
*****-----返回值:无
*****-----备 注:
------------------------------------------------------------------------------------------------------------------------------*/
void AD7606_ISR(void)
{
uint8_t i;
AD7606_ReadNowAdc();
for (i = 0; i < 8; i++)
{
g_tAdcFifo.sBuf = g_tAD7606.sNowAdc;
if (++g_tAdcFifo.usWrite >= ADC_FIFO_SIZE)
{
g_tAdcFifo.usWrite = 0;
}
if (g_tAdcFifo.usCount < ADC_FIFO_SIZE)
{
g_tAdcFifo.usCount++;
// SEGGER_RTT_Write(1, &g_tAD7606.sNowAdc, 2);
// SEGGER_RTT_Write(1, &g_tAD7606.sNowAdc, 2);
// SEGGER_RTT_Write(1, &g_tAD7606.sNowAdc, 2);
// SEGGER_RTT_Write(1, &g_tAD7606.sNowAdc, 2);
// SEGGER_RTT_Write(1, &g_tAD7606.sNowAdc, 2);
// SEGGER_RTT_Write(1, &g_tAD7606.sNowAdc, 2);
// SEGGER_RTT_Write(1, &g_tAD7606.sNowAdc, 2);
// SEGGER_RTT_Write(1, &g_tAD7606.sNowAdc, 2);
SEGGER_RTT_Write(1, &g_tAD7606.sNowAdc, 2);
}
else
{
g_tAdcFifo.ucFull = 1; //FIFO 满,主程序来不及处理数据
}
}
}
/*------------------------------------------------------------------------------------------------------------------------------
*****-----功能介绍:外部中断服务程序入口
*****-----函数名:EXTI15_10_IRQHandler()
*****-----入口参数:无
*****-----返回值:无
*****-----备 注:PB13/AD7606_BUSY 下降沿中断触发
------------------------------------------------------------------------------------------------------------------------------*/
void EXTI15_10_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line13) != RESET)
{
AD7606_ISR();
EXTI_ClearITPendingBit(EXTI_Line13);//Clear the EXTI line 13 pending bit
}
}
main.c里的调用函数
int main(void)
{
u8 ucFifoMode=0;
int16_t sNowAdc3=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置系统中断优先级分组2
delay_init(168); //延时初始化
uart_init(115200); //串口初始化波特率为115200
LED_Init(); //初始化与LED连接的硬件接口
ucFifoMode = 1;
AD7606_Init(); //配置AD7606所用的GPIO
AD7606_SetOS(AD_OS_X4); //无过采样
AD7606_SetInputRange(0); //±5V
AD7606_StartConvst(); //启动1次转换
//SEGGER_RTT_ConfigUpBuffer(1, "JScope_i2i2i2i2i2i2i2i2", g_tAD7606.sNowAdc, 2048, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
SEGGER_RTT_ConfigUpBuffer(1, "JScope_i2", g_tAD7606.sNowAdc, 2048, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
while(1)
{
if(ucFifoMode == 0)//AD7606 普通工作模式
{
if(CONV_FLAG !=0 )//每隔500ms 进来一次. 由软件启动转换
{
AD7606_ReadNowAdc(); //读取采样结果
AD7606_StartConvst(); // 启动下次转换
CONV_FLAG=0;
SEGGER_RTT_Write(1, &g_tAD7606.sNowAdc, 2);
}
}
else
{
AD7606_StartRecord(1000);//启动采样速率
AD7606_SetOS(AD_OS_NO);
}
}
}
估计是FIFO处理不及时,缓存数据损坏了。当前配置速度多少采集的。 eric2013 发表于 2024-4-9 08:54
估计是FIFO处理不及时,缓存数据损坏了。当前配置速度多少采集的。
感谢您的回复。图片中我配置的采集速度是1KHz。但采用50Hz-100KHz任意值结果都是差不多,无论是采集正弦波还是方波,结果都是不正常的,但能看出输入波形是方波还是正弦波。
此外,我这边缓冲大小最大只能配置为4096,启动文件中的堆栈大小也是修改了的。
SEGGER_RTT_ConfigUpBuffer(1, "JScope_i2", g_tAD7606.sNowAdc, 4096, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
如果超过该值,就会提示图片中的内容“找不到RTT控制块”。
问题应该是由于我是用的老版本的库函数配置的FSMC,其中没有:
hsram.Init.ContinuousClock = FSMC_CONTINUOUS_CLOCK_SYNC_ONLY; /* 仅同步模式才做时钟输出 */
hsram.Init.WriteFifo = FSMC_WRITE_FIFO_ENABLE; /* 使能写FIFO */
这两项相关的配置。
不过目前暂时还没有找到库函数如何使用FIFO 确认了,就是上面的问题。感谢硬汉哥的指点 习惯了寂寞 发表于 2024-4-9 09:54
感谢您的回复。图片中我配置的采集速度是1KHz。但采用50Hz-100KHz任意值结果都是差不多,无论是采集正弦 ...
缓存些数据,串口打印即可 兄弟,我最近也在做这个ad7606数据采集,然后将数据通过串口发送到上位机,请问你调试好了吗,可以借鉴一下吗
页:
[1]