OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5341|回复: 2

定时器触发ADC多路采样,DMA双缓冲传输数据出错

[复制链接]

1

主题

2

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2021-6-4
在线时间
10 小时
发表于 2021-8-20 11:19:57 | 显示全部楼层 |阅读模式
3金钱
有个问题请教一下大家,我用TIM3的TRGO信号每0.25ms触发ADC采四路数据,然后使用DMA传输数据,在DMA传输指定长度后进入中断切换双缓冲,然后现在问题是在DMA中断中如果不先失能ADC再使能会出现通道乱序的问题,但是先失能再使能ADC跑了几个周期后就停止了,也就是不进入DMA中断了。用的是国民的N32芯片,基本可以和STM32F103的大部分适配,可以当成STM32的代码看,代码如下,大佬可以帮忙分析一下或者有什么方法解决吗?
/*******************************************************************************
* 功能描述  : 初始化ADC(开启通道1、2、4、11)
* 输入参数  :
* 输出参数  :
* 返回值    :
*******************************************************************************/
void Adc1_Init(void)
{
    ADC_InitType  ADC_InitStructure;
    GPIO_InitType GPIO_InitStructure;
   
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC1, ENABLE);                //使能ADC通道时钟
            
    ADC_ConfigClk(ADC_CTRL3_CKMOD_AHB,RCC_ADCHCLK_DIV2);                //设置ADC分频因子6 72M/6=12

    //PA0,1,2,3 作为模拟通道输入引脚  IA,IB,IN,IC
    GPIO_InitStructure.Pin        = ADC1_IA_GPIO | ADC1_IB_GPIO | ADC1_IC_GPIO | ADC1_IN_GPIO;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AIN;
    GPIO_InitPeripheral(ADC1_PORT, &GPIO_InitStructure);

    ADC_DeInit(ADC1);                                                   //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值

    ADC_InitStructure.WorkMode       = ADC_WORKMODE_INDEPENDENT;        //ADC工作模式:ADC1和ADC2工作在独立模式
    ADC_InitStructure.MultiChEn      = ENABLE;                          //模数转换工作在扫描(多通道)模式
    ADC_InitStructure.ContinueConvEn = DISABLE;                         //模数转换工作在单次转换模式
    ADC_InitStructure.ExtTrigSelect  = ADC_EXT_TRIGCONV_T3_TRGO;        //转换由TIM3触发
    ADC_InitStructure.DatAlign       = ADC_DAT_ALIGN_R;                 //ADC数据右对齐
    ADC_InitStructure.ChsNumber      = 4;                               //指定将使用常规通道组的定序器转换的 ADC 通道数
    ADC_Init(ADC1, &ADC_InitStructure);                                 //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器

    ADC_EnableExternalTrigConv(ADC1, ENABLE);

    ADC_ConfigRegularChannel(ADC1,ADC_CH_1,1,ADC_SAMP_TIME_239CYCLES5);
    ADC_ConfigRegularChannel(ADC1,ADC_CH_2,2,ADC_SAMP_TIME_239CYCLES5);
    ADC_ConfigRegularChannel(ADC1,ADC_CH_4,3,ADC_SAMP_TIME_239CYCLES5);
    ADC_ConfigRegularChannel(ADC1,ADC_CH_11,4,ADC_SAMP_TIME_239CYCLES5);

    ADC_Enable(ADC1, ENABLE);                                           //使能指定的ADC1
    //ADC_EnableDMA(ADC1, ENABLE);                                        //ADC1的DMA使能

    while(ADC_GetFlagStatusNew(ADC1,ADC_FLAG_RDY) == RESET);            //等待ADC1准备开始

    ADC_StartCalibration(ADC1);                                         //开启AD校准       
   
    while (ADC_GetCalibrationStatus(ADC1));                             //等待校准结束

    ADC_EnableDMA(ADC1, ENABLE);                                        //ADC1的DMA使能

    ADC_EnableSoftwareStartConv(ADC1, ENABLE);                          //使能指定的ADC1的软件转换启动功能
}

static DMA_InitType DMA_InitStructure;

/*******************************************************************************
* 功能描述  : DMA1配置
* 输入参数  :
* 输出参数  :
* 返回值    :
*******************************************************************************/
void DMA1_Init(void)
{
    NVIC_InitType NVIC_InitStructure;

    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE);

    /* DMA1 Channel1 Configuration ----------------------------------------------*/
    DMA_DeInit(DMA1_CH1);
    DMA_InitStructure.PeriphAddr = (uint32_t)&ADC1->DAT;
    DMA_InitStructure.MemAddr = (uint32_t)ADC_ConvertedValue0;
    DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC;                   //设置方向为外设-->存储器
    DMA_InitStructure.BufSize = ADC_BUFF_LEN*4;                         //设置传输数据的个数
    DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE;               //失能外设寄存器增量
    DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD;
    DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.CircularMode = DMA_MODE_NORMAL;
    DMA_InitStructure.Priority = DMA_PRIORITY_HIGH;
    DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE;                        //失能存储器之间的传输
    DMA_Init(DMA1_CH1, &DMA_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    DMA_ClearFlag(DMA_INT_TXC, DMA1);
    DMA_ConfigInt(DMA1_CH1, DMA_INT_TXC, ENABLE);

    DMA_EnableChannel(DMA1_CH1, ENABLE);

    //ADC_EnableDMA(ADC1, ENABLE);                                        //ADC1的DMA使能
    //ADC_EnableSoftwareStartConv(ADC1, ENABLE);                          //使能指定的ADC1的软件转换启动功能

    g_bAdBufIndex = 0;
}


/*******************************************************************************
* 功能描述  : DMA 双缓冲切换
* 输入参数  :
* 输出参数  :
* 返回值    :
*******************************************************************************/
void DMA1_SwitchBuffer(void)
{
    DMA_EnableChannel(DMA1_CH1, DISABLE);  
    //ADC_Enable(ADC1, DISABLE);

    if(g_bAdBufIndex == 0)
    {
        g_bAdBufIndex = 1;
        DMA_InitStructure.MemAddr = (uint32_t)ADC_ConvertedValue1;          // 设置接收缓冲区首地址
        DMA_Init(DMA1_CH1, &DMA_InitStructure);                             // 写入配置
    }
    else
    {
        g_bAdBufIndex = 0;
        DMA_InitStructure.MemAddr = (uint32_t)ADC_ConvertedValue0;          // 设置接收缓冲区首地址
        DMA_Init(DMA1_CH1, &DMA_InitStructure);                             // 写入配置   
    }

    DMA_EnableChannel(DMA1_CH1, ENABLE);
    //ADC_Enable(ADC1, ENABLE);

    //ADC_EnableSoftwareStartConv(ADC1, ENABLE);
}


/*******************************************************************************
* 功能描述  : DMA 中断
* 输入参数  :
* 输出参数  :
* 返回值    :
*******************************************************************************/
void DMA1_Channel1_IRQHandler(void)
{   
    if (DMA_GetIntStatus(DMA1_INT_TXC1, DMA1))
    {
        DMA_ClrIntPendingBit(DMA1_INT_GLB1, DMA1);
        DMA1_SwitchBuffer();
    }
    else
    {
        DMA_ClrIntPendingBit(DMA1_INT_GLB1, DMA1);
        DMA1_Init();
        //DMA_ClrIntPendingBit(DMA1_INT_ERR1, DMA1);
    }
}


/*******************************************************************************
* 功能描述  : TIM3 配置
* 输入参数  :
* 输出参数  :
* 返回值    :
*******************************************************************************/
void TIM3_Configuration(void)
{
    TIM_TimeBaseInitType TIM_TimeBaseStructure;
    NVIC_InitType NVIC_InitStructure;

    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM3, ENABLE);
    TIM_TimeBaseStructure.Period = 2000;                            //设置0.25s一次TIM2比较周期 2000*0.125us = 0.25ms
    TIM_TimeBaseStructure.Prescaler = 9;                            //系统主频72M,这里分频9,相当于8MHz定时器3时钟  //LUTHER
    TIM_TimeBaseStructure.ClkDiv = 0x00;
    TIM_TimeBaseStructure.CntMode = TIM_CNT_MODE_UP;
    TIM_InitTimeBase(TIM3, &TIM_TimeBaseStructure);

    TIM_SelectOutputTrig(TIM3,TIM_TRGO_SRC_UPDATE);                 //选择TRGO触发源为计时器更新时间

    //中断分组初始化
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;                 //TIM3中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4;       //先占优先级4级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;              //从优先级1级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //IRQ通道被使能
    NVIC_Init(&NVIC_InitStructure);                                 //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

    TIM_ClearFlag(TIM3, TIM_FLAG_UPDATE);
    TIM_ConfigInt(TIM3, TIM_INT_UPDATE, ENABLE);

    TIM_Enable(TIM3, ENABLE);
}

/*******************************************************************************
* 功能描述  : TIM3 0.25ms中断
* 输入参数  :
* 输出参数  :
* 返回值    :
*******************************************************************************/
void TIM3_IRQHandler(void)
{
    if(TIM_GetIntStatus(TIM3, TIM_INT_UPDATE) != RESET )
    {
        TIM_ClrIntPendingBit(TIM3, TIM_INT_UPDATE);
    }
}


/*******************************************************************************
* 功能描述  : ADC初始化
* 输入参数  :
* 输出参数  :
* 返回值    :
*******************************************************************************/
void Adcx_Init(void)
{
    Adc1_Init();

    BSP_Delay_Ms(200);                      //延时200ms,避免开始采集的数据为0

    DMA1_Init();

    TIM3_Configuration();
}

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

592

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1458
金钱
1458
注册时间
2019-7-28
在线时间
137 小时
发表于 2021-8-20 14:59:25 | 显示全部楼层
回复

使用道具 举报

0

主题

465

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1734
金钱
1734
注册时间
2021-4-11
在线时间
320 小时
发表于 2021-8-23 12:26:12 | 显示全部楼层
帮顶              
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-29 07:55

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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