习惯了寂寞 发表于 2024-4-8 22:22:11

求助!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);   
      }   
    }
}


eric2013 发表于 2024-4-9 08:54:35

估计是FIFO处理不及时,缓存数据损坏了。当前配置速度多少采集的。

习惯了寂寞 发表于 2024-4-9 09:54:49

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控制块”。

习惯了寂寞 发表于 2024-4-9 15:50:38

问题应该是由于我是用的老版本的库函数配置的FSMC,其中没有:
hsram.Init.ContinuousClock    = FSMC_CONTINUOUS_CLOCK_SYNC_ONLY; /* 仅同步模式才做时钟输出 */
hsram.Init.WriteFifo          = FSMC_WRITE_FIFO_ENABLE;          /* 使能写FIFO */
这两项相关的配置。
不过目前暂时还没有找到库函数如何使用FIFO

习惯了寂寞 发表于 2024-4-9 22:42:25

确认了,就是上面的问题。感谢硬汉哥的指点

eric2013 发表于 2024-4-10 08:34:54

习惯了寂寞 发表于 2024-4-9 09:54
感谢您的回复。图片中我配置的采集速度是1KHz。但采用50Hz-100KHz任意值结果都是差不多,无论是采集正弦 ...

缓存些数据,串口打印即可

无限火力 发表于 2024-4-18 16:22:40

兄弟,我最近也在做这个ad7606数据采集,然后将数据通过串口发送到上位机,请问你调试好了吗,可以借鉴一下吗
页: [1]
查看完整版本: 求助!AD7606的FIFO模式无法正常工作。