打印
[N32L4xx]

adc和dma的例程

[复制链接]
744|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
qinlicn|  楼主 | 2022-10-24 10:19 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
AD, ADC, DM, DMA, dc
请问有没有adc多通道采样dma的例程?官方的例程太少了啊。

使用特权

评论回复
沙发
GGG3| | 2022-10-25 09:49 | 只看该作者
好像只有单通道ADC加DMA的例程,不过这个只需要在单通道例程上修改一下即可

9bde3eb8dab596140d7654179b535cf.png (584.14 KB )

9bde3eb8dab596140d7654179b535cf.png

使用特权

评论回复
板凳
modesty3jonah| | 2022-11-1 16:39 | 只看该作者
adc多通道采集可以不采用dma。

使用特权

评论回复
地板
cashrwood| | 2022-11-1 16:54 | 只看该作者
网上有很多ADC与DMA结合的例程  

使用特权

评论回复
5
hudi008| | 2022-11-1 17:15 | 只看该作者
adc+dma传输 传输完成标志得不到

使用特权

评论回复
6
modesty3jonah| | 2022-11-1 17:44 | 只看该作者
DMA会自动递增地址存放数据,递增设置的长度之后会自动复位地址重新开始从第一个地址写数据,覆盖掉之前的数据。

使用特权

评论回复
7
elsaflower| | 2022-11-1 18:25 | 只看该作者
ADC连续扫描模式必须要用DMA吗

使用特权

评论回复
8
pixhw| | 2022-11-1 19:14 | 只看该作者
ADC DMA多通道采集到的数据相互有干扰,该怎么破?

使用特权

评论回复
9
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);
        }
    };
}


使用特权

评论回复
10
bitterheart| | 2022-11-21 18:37 | 只看该作者
N32L40x系列的DMA搬运ADC数据有bug?能说一下是什么bug吗?
我用的是N32L406CB,使用DMA后,波特率太高的话,很容易卡死,复位也没用,只能断电重启才行,不知道是代码的问题,还是什么原因

使用特权

评论回复
11
sy12138| | 2022-11-22 09:42 | 只看该作者
qinlicn 发表于 2022-11-2 10:21
我是用于对两个2Hz的波形采样其中的40ms片段;两通道采样,40ms采样100~200次,用DMA比较方便,当然也可以 ...

HSI是8M吧

使用特权

评论回复
12
sy12138| | 2022-11-22 09:43 | 只看该作者
bitterheart 发表于 2022-11-21 18:37
N32L40x系列的DMA搬运ADC数据有bug?能说一下是什么bug吗?
我用的是N32L406CB,使用DMA后,波特率太高的话 ...

代码贴出来看看

使用特权

评论回复
13
GGG3| | 2022-11-22 09:50 | 只看该作者
感觉多通道ADC+DMA就容易出现错位的情况

使用特权

评论回复
14
bitterheart| | 2022-11-22 15:59 | 只看该作者
本帖最后由 bitterheart 于 2022-11-23 10:21 编辑

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[len-1] = '\r';
    pbuf[len++] = '\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[print_buf_wrcnt], pbuf, DMA_PRINTBUF_LEN-print_buf_wrcnt);
        len1 = DMA_PRINTBUF_LEN;
        dma_print_err_cnt++;
    } else {
        memcpy(&p_wr[print_buf_wrcnt], 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;
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

20

帖子

0

粉丝