[N32L4xx] adc和dma的例程

[复制链接]
1165|13
 楼主| qinlicn 发表于 2022-10-24 10:19 | 显示全部楼层 |阅读模式
AD, ADC, DM, DMA, dc
请问有没有adc多通道采样dma的例程?官方的例程太少了啊。

GGG3 发表于 2022-10-25 09:49 | 显示全部楼层
好像只有单通道ADC加DMA的例程,不过这个只需要在单通道例程上修改一下即可
9bde3eb8dab596140d7654179b535cf.png
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
static  u16 ADCConvertedValue[AD_NUM]={0};


//DMA初始化
void DMA_sl_Init(void)
{
    DMA_InitType  DMA_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_InitType  ADC_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 编辑

DMA配置
  1.     RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA, ENABLE);
  2.    
  3.     DMA_DeInit(DMA_CH7);
  4.     DMA_StructInit(&DMA_InitStructure);
  5.     DMA_InitStructure.PeriphAddr     = (uint32_t)(USART2_BASE + 0x04);
  6. //    DMA_InitStructure.MemAddr        = (uint32_t)TxBuffer1;
  7.     DMA_InitStructure.Direction      = DMA_DIR_PERIPH_DST;
  8. //    DMA_InitStructure.BufSize        = TxBufferSize1;
  9.     DMA_InitStructure.PeriphInc      = DMA_PERIPH_INC_DISABLE;
  10.     DMA_InitStructure.DMA_MemoryInc  = DMA_MEM_INC_ENABLE;
  11.     DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE;
  12.     DMA_InitStructure.MemDataSize    = DMA_MemoryDataSize_Byte;
  13.     DMA_InitStructure.CircularMode   = DMA_MODE_NORMAL;
  14.     DMA_InitStructure.Priority       = DMA_PRIORITY_HIGH;
  15.     DMA_InitStructure.Mem2Mem        = DMA_M2M_DISABLE;
  16.     DMA_Init(DMA_CH7, &DMA_InitStructure);
  17.     DMA_RequestRemap(DMA_REMAP_USART2_TX, DMA, DMA_CH7, ENABLE);   
  1. void UART_DMA_Send(uint8 *pbuf, uint16 len)
  2. {
  3.     int len1;
  4.    
  5.     if (len == 0) {
  6.         return ;
  7.     }

  8.     pbuf[len-1] = '\r';
  9.     pbuf[len++] = '\n';
  10.    
  11.     if (buf_sel == 0) {
  12.         p_wr = print_buf_dma;
  13.     } else {
  14.         p_wr = print_buf_dma_bk;
  15.     }  
  16.    
  17.     len1 = print_buf_wrcnt + len;
  18.     if (len1 > DMA_PRINTBUF_LEN) {
  19.         memcpy(&p_wr[print_buf_wrcnt], pbuf, DMA_PRINTBUF_LEN-print_buf_wrcnt);
  20.         len1 = DMA_PRINTBUF_LEN;
  21.         dma_print_err_cnt++;
  22.     } else {
  23.         memcpy(&p_wr[print_buf_wrcnt], pbuf, len);
  24.     }
  25.     print_buf_wrcnt = len1;
  26.    
  27.     dma_wait_cnt = 0;  
  28.     if (print_dma_wait) {
  29.         while (DMA_GetFlagStatus(DMA_FLAG_TC7, DMA) == RESET) {
  30.             dma_wait_cnt++;         
  31.             if (dma_wait_cnt >= DMA_WAIT_TIMEOUT) {
  32.                 return;
  33.             }           
  34.         }
  35.     }
  36.    
  37.     DMA_ClearFlag(DMA_FLAG_TC7, DMA);   
  38.     print_dma_wait = 1;            
  39.     buf_sel = (buf_sel + 1) & 1;
  40.     print_buf_wrcnt = 0;
  41.         
  42.     DMA_InitStructure.MemAddr        = (uint32_t)p_wr;
  43.     DMA_InitStructure.BufSize        = len1;
  44.     DMA_Init(DMA_CH7, &DMA_InitStructure);
  45.     DMA_RequestRemap(DMA_REMAP_USART2_TX, DMA, DMA_CH7, ENABLE);   
  46.     USART_EnableDMA(USART2, USART_DMAREQ_TX, ENABLE);
  47.     DMA_EnableChannel(DMA_CH7, ENABLE);   
  48. }
  49. void print_dma_flush(void)
  50. {
  51.     dma_wait_cnt = 0;
  52.    
  53.     if (print_buf_wrcnt > 0) {   
  54.         while (DMA_GetFlagStatus(DMA_FLAG_TC7, DMA) == RESET) {
  55.             dma_wait_cnt++;         
  56.             if (dma_wait_cnt >= 100000) {   // DMA_WAIT_TIMEOUT) {
  57. //                dma_print_err_cnt++;
  58. //                break;
  59.             }           
  60.         }
  61.         DMA_ClearFlag(DMA_FLAG_TC7, DMA);
  62.         
  63.         print_dma_wait = 1;   
  64.         DMA_InitStructure.MemAddr        = (uint32_t)p_wr;
  65.         DMA_InitStructure.BufSize        = print_buf_wrcnt;
  66.         DMA_Init(DMA_CH7, &DMA_InitStructure);
  67.         DMA_RequestRemap(DMA_REMAP_USART2_TX, DMA, DMA_CH7, ENABLE);   
  68.         USART_EnableDMA(USART2, USART_DMAREQ_TX, ENABLE);
  69.         DMA_EnableChannel(DMA_CH7, ENABLE);  
  70.         
  71. //        dma_print_err_cnt++;
  72.     }
  73.       
  74.    
  75. //    if (print_dma_wait) {
  76.         while (DMA_GetFlagStatus(DMA_FLAG_TC7, DMA) == RESET) {
  77.             dma_wait_cnt++;         
  78.             if (dma_wait_cnt >= 100000) {   // DMA_WAIT_TIMEOUT) {
  79. //                dma_print_err_cnt++;
  80. //                break;
  81.             }           
  82.         }
  83.         DMA_ClearFlag(DMA_FLAG_TC7, DMA);
  84. //    }  
  85.   
  86.     print_dma_wait = 0;
  87.     print_buf_wrcnt = 0;
  88.     buf_sel = 0;
  89. }

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

本版积分规则

3

主题

20

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部