qinlicn 发表于 2022-10-24 10:19

adc和dma的例程

请问有没有adc多通道采样dma的例程?官方的例程太少了啊。

GGG3 发表于 2022-10-25 09:49

好像只有单通道ADC加DMA的例程,不过这个只需要在单通道例程上修改一下即可

modesty3jonah 发表于 2022-11-1 16:39

adc多通道采集可以不采用dma。

cashrwood 发表于 2022-11-1 16:54

网上有很多ADC与DMA结合的例程

hudi008 发表于 2022-11-1 17:15

adc+dma传输 传输完成标志得不到

modesty3jonah 发表于 2022-11-1 17:44

DMA会自动递增地址存放数据,递增设置的长度之后会自动复位地址重新开始从第一个地址写数据,覆盖掉之前的数据。

elsaflower 发表于 2022-11-1 18:25

ADC连续扫描模式必须要用DMA吗

pixhw 发表于 2022-11-1 19:14

ADC DMA多通道采集到的数据相互有干扰,该怎么破?

qinlicn 发表于 2022-11-2 10:21

我是用于对两个2Hz的波形采样其中的40ms片段;两通道采样,40ms采样100~200次,用DMA比较方便,当然也可以不用DMA。

谁知N32L40x系列的DMA搬运ADC数据有bug。最后放弃使用DMA了。
以下是ADC两通道采样+DMA的测试代码,供参考吧。
MCU为N32L403KB,时钟AHB=APB1=APB2=HSI 16M。

#define AD_NUM   200
staticu16 ADCConvertedValue={0};


//DMA初始化
void DMA_sl_Init(void)
{
    DMA_InitTypeDMA_InitStructure;

    DMA_DeInit(DMA_CH1);
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA, ENABLE);
    DMA_InitStructure.PeriphAddr   = (u32)&ADC->DAT;
    DMA_InitStructure.MemAddr      = (u32)ADCConvertedValue;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_SRC;
    DMA_InitStructure.BufSize      = AD_NUM;                  //非循环模式时,DMA接收够Size后,CHEN位=0,DMA停止
    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循环模式和ADC连续转换,可有4种组合
    DMA_InitStructure.Priority       = DMA_PRIORITY_HIGH;
    DMA_InitStructure.Mem2Mem      = DMA_M2M_DISABLE;
    DMA_Init(DMA_CH1, &DMA_InitStructure);
    DMA_RequestRemap(DMA_REMAP_ADC1, DMA, DMA_CH1, ENABLE);   
    DMA_EnableChannel(DMA_CH1, ENABLE);
}

//ADC多通道+DMA
void ADC_DMA_Sample(void)
{
    ADC_InitTypeADC_InitStructure;   
    GPIO_InitType GPIO_InitStructure;   

    //GPIO配置,两通道模拟输入
    GPIO_InitStruct(&GPIO_InitStructure);
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE);

    GPIO_InitStructure.Pin       = GPIO_PIN_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Analog;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);      

    GPIO_InitStructure.Pin       = GPIO_PIN_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Analog;
    GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);         

    //DMA配置
    DMA_sl_Init();   

    //ADC最好先Deinit再配置
    ADC_DeInit(ADC);
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC, ENABLE);            
    ADC_ConfigClk(ADC_CTRL3_CKMOD_AHB, RCC_ADCHCLK_DIV16);         //ADC时钟: AHB/16=16M/16=1M
    RCC_ConfigAdc1mClk(RCC_ADC1MCLK_SRC_HSI, RCC_ADC1MCLK_DIV16);//ADC1M: HSI=16M, 16M/16=1M   

    //ADC配置
    ADC_InitStructure.MultiChEn      = ENABLE;
    ADC_InitStructure.ContinueConvEn = ENABLE;                                 //ADC连续转换和DMA循环模式,可有4种组合
    ADC_InitStructure.ExtTrigSelect= ADC_EXT_TRIGCONV_NONE;
    ADC_InitStructure.DatAlign       = ADC_DAT_ALIGN_R;
    ADC_InitStructure.ChsNumber      = 2;
    ADC_Init(ADC, &ADC_InitStructure);

    //ADC通道序列配置
    ADC_ConfigRegularChannel(ADC, ADC_CH_1_PA0,1, ADC_SAMP_TIME_239CYCLES5);   //239.5+12.5=252个时钟=252us,1ms采4次
    ADC_ConfigRegularChannel(ADC, ADC_CH_10_PB1, 2, ADC_SAMP_TIME_239CYCLES5);

    //ADC使能
    ADC_EnableDMA(ADC, ENABLE);
    ADC_Enable(ADC, ENABLE);
    while(ADC_GetFlagStatusNew(ADC,ADC_FLAG_RDY) == RESET);

    //ADC校准
    ADC_StartCalibration(ADC);
    while (ADC_GetCalibrationStatus(ADC));

    //启动ADC
    ADC_EnableSoftwareStartConv(ADC, ENABLE);

    //用于测试DMA循环模式和ADC连续转换的4种组合
    while(1)
    {
      //DMA普通模式和循环模式的CHEN
      if ((DMA_CH1->CHCFG & DMA_CHCFG1_CHEN) == 0)
      {            
            //DMA停止后需要重新进行配置
            DMA_sl_Init();   
            ADC_EnableSoftwareStartConv(ADC, ENABLE);            
      }

      //ADC连续转换和单次转换的ENDC
      if (ADC_GetFlagStatus(ADC, ADC_FLAG_ENDC) != 0)
      {            
            ADC_EnableSoftwareStartConv(ADC, ENABLE);
      }
    };
}


bitterheart 发表于 2022-11-21 18:37

N32L40x系列的DMA搬运ADC数据有bug?能说一下是什么bug吗?
我用的是N32L406CB,使用DMA后,波特率太高的话,很容易卡死,复位也没用,只能断电重启才行,不知道是代码的问题,还是什么原因

sy12138 发表于 2022-11-22 09:42

qinlicn 发表于 2022-11-2 10:21
我是用于对两个2Hz的波形采样其中的40ms片段;两通道采样,40ms采样100~200次,用DMA比较方便,当然也可以 ...

HSI是8M吧

sy12138 发表于 2022-11-22 09:43

bitterheart 发表于 2022-11-21 18:37
N32L40x系列的DMA搬运ADC数据有bug?能说一下是什么bug吗?
我用的是N32L406CB,使用DMA后,波特率太高的话 ...

代码贴出来看看

GGG3 发表于 2022-11-22 09:50

感觉多通道ADC+DMA就容易出现错位的情况

bitterheart 发表于 2022-11-22 15:59

本帖最后由 bitterheart 于 2022-11-23 10:21 编辑

sy12138 发表于 2022-11-22 09:43
代码贴出来看看
DMA配置
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA, ENABLE);
   
    DMA_DeInit(DMA_CH7);
    DMA_StructInit(&DMA_InitStructure);
    DMA_InitStructure.PeriphAddr   = (uint32_t)(USART2_BASE + 0x04);
//    DMA_InitStructure.MemAddr      = (uint32_t)TxBuffer1;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_DST;
//    DMA_InitStructure.BufSize      = TxBufferSize1;
    DMA_InitStructure.PeriphInc      = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.DMA_MemoryInc= DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE;
    DMA_InitStructure.MemDataSize    = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.CircularMode   = DMA_MODE_NORMAL;
    DMA_InitStructure.Priority       = DMA_PRIORITY_HIGH;
    DMA_InitStructure.Mem2Mem      = DMA_M2M_DISABLE;
    DMA_Init(DMA_CH7, &DMA_InitStructure);
    DMA_RequestRemap(DMA_REMAP_USART2_TX, DMA, DMA_CH7, ENABLE);   void UART_DMA_Send(uint8 *pbuf, uint16 len)
{
    int len1;
   
    if (len == 0) {
      return ;
    }

    pbuf = '\r';
    pbuf = '\n';
   
    if (buf_sel == 0) {
      p_wr = print_buf_dma;
    } else {
      p_wr = print_buf_dma_bk;
    }
   
    len1 = print_buf_wrcnt + len;
    if (len1 > DMA_PRINTBUF_LEN) {
      memcpy(&p_wr, pbuf, DMA_PRINTBUF_LEN-print_buf_wrcnt);
      len1 = DMA_PRINTBUF_LEN;
      dma_print_err_cnt++;
    } else {
      memcpy(&p_wr, pbuf, len);
    }
    print_buf_wrcnt = len1;
   
    dma_wait_cnt = 0;
    if (print_dma_wait) {
      while (DMA_GetFlagStatus(DMA_FLAG_TC7, DMA) == RESET) {
            dma_wait_cnt++;         
            if (dma_wait_cnt >= DMA_WAIT_TIMEOUT) {
                return;
            }         
      }
    }
   
    DMA_ClearFlag(DMA_FLAG_TC7, DMA);   
    print_dma_wait = 1;            
    buf_sel = (buf_sel + 1) & 1;
    print_buf_wrcnt = 0;
      
    DMA_InitStructure.MemAddr      = (uint32_t)p_wr;
    DMA_InitStructure.BufSize      = len1;
    DMA_Init(DMA_CH7, &DMA_InitStructure);
    DMA_RequestRemap(DMA_REMAP_USART2_TX, DMA, DMA_CH7, ENABLE);   
    USART_EnableDMA(USART2, USART_DMAREQ_TX, ENABLE);
    DMA_EnableChannel(DMA_CH7, ENABLE);   
}
void print_dma_flush(void)
{
    dma_wait_cnt = 0;
   
    if (print_buf_wrcnt > 0) {   
      while (DMA_GetFlagStatus(DMA_FLAG_TC7, DMA) == RESET) {
            dma_wait_cnt++;         
            if (dma_wait_cnt >= 100000) {   // DMA_WAIT_TIMEOUT) {
//                dma_print_err_cnt++;
//                break;
            }         
      }
      DMA_ClearFlag(DMA_FLAG_TC7, DMA);
      
      print_dma_wait = 1;   
      DMA_InitStructure.MemAddr      = (uint32_t)p_wr;
      DMA_InitStructure.BufSize      = print_buf_wrcnt;
      DMA_Init(DMA_CH7, &DMA_InitStructure);
      DMA_RequestRemap(DMA_REMAP_USART2_TX, DMA, DMA_CH7, ENABLE);   
      USART_EnableDMA(USART2, USART_DMAREQ_TX, ENABLE);
      DMA_EnableChannel(DMA_CH7, ENABLE);
      
//      dma_print_err_cnt++;
    }
      
   
//    if (print_dma_wait) {
      while (DMA_GetFlagStatus(DMA_FLAG_TC7, DMA) == RESET) {
            dma_wait_cnt++;         
            if (dma_wait_cnt >= 100000) {   // DMA_WAIT_TIMEOUT) {
//                dma_print_err_cnt++;
//                break;
            }         
      }
      DMA_ClearFlag(DMA_FLAG_TC7, DMA);
//    }

    print_dma_wait = 0;
    print_buf_wrcnt = 0;
    buf_sel = 0;
}

页: [1]
查看完整版本: adc和dma的例程