0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

STM32G0开发笔记:多通道ADC与DMA的使用

CHANBAEK 来源:电子技术攻城狮 作者:MakerInChina.cn 2023-01-17 10:41 次阅读

使用Platformio平台的libopencm3开发框架来开发STM32G0,以下为多通道ADCDMA的使用。

1 新建项目

  • 建立adc_dma项目

PIO的Home页面新建项目,项目名称adc_dma,选择开发板为 MonkeyPi_STM32_G070RB,开发框架选择libopencm3;

  • 项目建立完成后在src目录下新建main.c主程序文件;
  • 修改下载和调试方式,这里开发板使用的是DAPLink仿真器,因此修改platformio.ini文件如下:
1upload_protocol = cmsis-dap
2debug_tool = cmsis-dap

2 编写程序

2.1 ADC 设置

这里设置PA0、PA1、PA2、PA3四个引脚为ADC:

1static void adc_setup(void)
 2{
 3    rcc_periph_clock_enable(RCC_ADC);
 4    rcc_periph_clock_enable(RCC_GPIOA);
 5
 6    gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO0);
 7    gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1);
 8    gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO2);
 9    gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO3);
10
11    adc_power_off(ADC1);
12    adc_set_clk_prescale(ADC1, ADC_CCR_PRESC_DIV2);
13    adc_set_single_conversion_mode(ADC1);
14    adc_set_right_aligned(ADC1);
15    adc_set_sample_time_on_all_channels(ADC1, ADC_SMPTIME_160DOT5);
16
17    uint8_t channel_array[16] = {0};
18    channel_array[0] = 0;
19    channel_array[1] = 1;
20    channel_array[2] = 2;
21    channel_array[3] = 3;
22    adc_set_regular_sequence(ADC1, ADC_CHAN_CNT, channel_array);
23    adc_enable_dma_circular_mode(ADC1);
24    adc_set_resolution(ADC1, ADC_CFGR1_RES_12_BIT);
25    adc_power_on(ADC1);
26
27    /* Wait for ADC starting up. */
28    delay_ms(10); 
29}
2.2 DMA配置
1static void dma_setup(void *data, int size)
 2{
 3    dma_channel_reset(DMA1, DMA_CHANNEL1);
 4    dma_set_peripheral_address(DMA1, DMA_CHANNEL1, (uint32_t)&ADC_DR(ADC1));
 5    dma_set_memory_address(DMA1, DMA_CHANNEL1, (uint32_t)data);
 6    dma_set_number_of_data(DMA1, DMA_CHANNEL1, size);
 7    dma_set_read_from_peripheral(DMA1, DMA_CHANNEL1);
 8    dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL1);
 9    dma_set_peripheral_size(DMA1, DMA_CHANNEL1, DMA_CCR_PSIZE_16BIT);
10    dma_set_memory_size(DMA1, DMA_CHANNEL1, DMA_CCR_MSIZE_16BIT);
11    dma_enable_circular_mode(DMA1, DMA_CHANNEL1);
12    dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL1);
13    dma_enable_channel(DMA1, DMA_CHANNEL1);
14
15    dmamux_reset_dma_channel(DMAMUX1, DMA_CHANNEL1);
16    dmamux_set_dma_channel_request(DMAMUX1, DMA_CHANNEL1, DMAMUX_CxCR_DMAREQ_ID_ADC);
17}

主要是设置DMA的外设地址为ADC数据寄存器 ADC_DR;并设置内存地址为定义的buff,size为需要缓存的数据大小:

1#define ADC_CHAN_CNT        4
2#define ADC_FILETER_SIZE    32
3
4int16_t adc_values[ADC_FILETER_SIZE*ADC_CHAN_CNT];
2.3 ADC配置为DMA读取和Timer触发
1void tim3_setup(void)
 2{
 3    /* Enable TIM3 clock. */
 4    rcc_periph_clock_enable(RCC_TIM3);
 5
 6    /* Enable TIM3 interrupt. */
 7    nvic_enable_irq(NVIC_TIM3_IRQ);
 8
 9    /* Reset TIM3 peripheral to defaults. */
10    rcc_periph_reset_pulse(RST_TIM3);
11
12    /* Timer global mode:
13     * - No divider
14     * - Alignment edge
15     * - Direction up
16     * (These are actually default values after reset above, so this call
17     * is strictly unnecessary, but demos the api for alternative settings)
18     */
19    timer_set_mode(TIM3, TIM_CR1_CKD_CK_INT,
20                   TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
21
22    /*
23     * Please take note that the clock source for STM32 timers
24     * might not be the raw APB1/APB2 clocks.  In various conditions they
25     * are doubled.  See the Reference Manual for full details!
26     * In our case, TIM3 on APB1 is running at double frequency, so this
27     * sets the prescaler to have the timer run at 5kHz
28     */
29    timer_set_prescaler(TIM3, 64-1);
30
31    /* Disable preload. */
32    timer_disable_preload(TIM3);
33    timer_continuous_mode(TIM3);
34
35    timer_set_period(TIM3, 20000-1); //100Hz
36
37    timer_set_master_mode(TIM3, TIM_CR2_MMS_UPDATE);
38
39    timer_enable_irq(TIM3, TIM_DIER_UIE);
40}
41
42void tim3_enable_counter(bool en)
43{
44    if(en){
45        timer_enable_counter(TIM3);
46    }else{
47        timer_disable_counter(TIM3);
48    }
49}
50
51void tim3_isr(void)
52{
53    if (timer_get_flag(TIM3, TIM_SR_UIF)) {
54
55        /* Clear compare interrupt flag. */
56        timer_clear_flag(TIM3, TIM_SR_UIF);
57    }
58}
  • DMA设置和Timer触发
1    rcc_periph_clock_enable(RCC_DMA);
 2    nvic_set_priority(NVIC_DMA1_CHANNEL1_IRQ, 3);
 3    nvic_enable_irq(NVIC_DMA1_CHANNEL1_IRQ);
 4
 5    adc_setup();
 6
 7    dma_setup(adc_values, ADC_CHAN_CNT*ADC_FILETER_SIZE);
 8
 9    adc_enable_overrun_interrupt(ADC1);
10
11    adc_enable_dma(ADC1);
12
13    ADC_CFGR1(ADC1) = (ADC_CFGR1(ADC1) & ~(0x3<<10)) | (0x1<<10);    // Hardware trigger detection on the rising edge
14    ADC_CFGR1(ADC1) = (ADC_CFGR1(ADC1) & ~ADC_CFGR1_EXTSEL) | (3<1_EXTSEL_SHIFT);    // toggle by tim3
15
16    tim3_setup();
17
18    adc_start_conversion_regular(ADC1);
19
20
21    tim3_enable_counter(true);
22
23    delay_ms(100);

DMA中断时候即准备好读取ADC数据,因此在DMA中断中先把定时器关闭,读取数据后再次打开:

1void dma1_channel1_isr(void)
 2{
 3
 4    if ((DMA1_ISR &DMA_ISR_TCIF1) != 0) {
 5        DMA1_IFCR |= DMA_IFCR_CTCIF1;
 6    }
 7
 8    tim3_enable_counter(false);
 9
10}
2.4 ADC读取
1void adc_sample(void)
 2{
 3    uint32_t sum_val1 = 0;
 4    uint32_t sum_val2 = 0;
 5    uint32_t sum_val3 = 0;
 6    uint32_t sum_val4 = 0;
 7
 8    for(int i=0; i9        sum_val1 += adc_values[ADC_CHAN_CNT*i + 0];
10        sum_val2 += adc_values[ADC_CHAN_CNT*i + 1];
11        sum_val3 += adc_values[ADC_CHAN_CNT*i + 2];
12        sum_val4 += adc_values[ADC_CHAN_CNT*i + 3];
13    }
14
15    uint32_t filter_val1 = sum_val1/ADC_FILETER_SIZE;
16    uint32_t filter_val2 = sum_val2/ADC_FILETER_SIZE;
17    uint32_t filter_val3 = sum_val3/ADC_FILETER_SIZE;
18    uint32_t filter_val4 = sum_val4/ADC_FILETER_SIZE;
19
20    printf("adc:%d  %d  %d  %d\\r\\n", filter_val1, filter_val2, filter_val3, filter_val4);
21
22    tim3_enable_counter(true);
23}

读取时候按照通道的顺序从buff中取出,这里做了简单的过滤;

3 烧写测试

将程序烧写到开发板,然后打开串口可以看到四个ADC通道的数据,在PA0/PA1/PA3/PA4四个引脚连接不同电压可以看到变化:

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    30

    文章

    4991

    浏览量

    117417
  • adc
    adc
    +关注

    关注

    95

    文章

    5629

    浏览量

    538911
  • STM32
    +关注

    关注

    2232

    文章

    10649

    浏览量

    347874
  • dma
    dma
    +关注

    关注

    3

    文章

    533

    浏览量

    98915
  • PIO
    PIO
    +关注

    关注

    0

    文章

    18

    浏览量

    6116
收藏 人收藏

    评论

    相关推荐

    基于STM32的USB程序开发笔记 汇总

    忙了一下午终于有时间整理了,基于STM32的USB程序开发笔记汇总,需要的亲们点击链接阅读哈!{:4_95:}基于STM32的USB程序开发笔记(一)https://bbs.elecf
    发表于 03-20 16:08

    坛友经验分享之STM32的USB程序开发笔记

    基于STM32的USB程序开发笔记(一)基于STM32的USB程序开发笔记(二)基于STM32的USB程序
    发表于 09-04 17:42

    STM32通道DMAADC采样 精选资料推荐

    title: STM32通道DMAADC采样tags: STM32date: 2019-02
    发表于 08-04 07:19

    关于ADC通道DMA配置的顺序

    我所选用的芯片是STM32F030C6,采用官方STM32CubeMX配置ADC通道时只需勾选相应的A
    发表于 08-04 06:10

    stm32 定时器触发ADC通道采样+DMA提取数据相关资料下载

    stm32g0 定时器触发ADC通道采样+DMA提取数据stm32g0 定时器触发
    发表于 02-15 06:46

    STM32的USB程序开发笔记

    STM32的USB程序开发笔记
    发表于 09-29 14:55 27次下载
    <b class='flag-5'>STM32</b>的USB程序<b class='flag-5'>开发笔记</b>

    STM32开发笔记56: STM32F407VGT6的解释

    STM32开发笔记56: STM32F407VGT6的解释
    发表于 12-02 16:51 45次下载
    <b class='flag-5'>STM32</b><b class='flag-5'>开发笔记</b>56: <b class='flag-5'>STM32</b>F407VGT6的解释

    stm32 定时器触发ADC通道采样+DMA提取数据

    stm32g0 定时器触发ADC通道采样+DMA提取数据stm32g0 定时器触发ADC
    发表于 12-16 16:56 62次下载
    <b class='flag-5'>stm32</b> 定时器触发<b class='flag-5'>ADC</b>多<b class='flag-5'>通道</b>采样+<b class='flag-5'>DMA</b>提取数据

    STM32G0开发笔记:FreeRTOS和FreeModbus库使用

    使用Platformio平台的libopencm3开发框架来开发STM32G0,以下为FreeRTOS和FreeModbus库使用。
    的头像 发表于 01-16 14:44 3702次阅读
    <b class='flag-5'>STM32G0</b><b class='flag-5'>开发笔记</b>:FreeRTOS和FreeModbus库使用

    STM32G0开发笔记:使用FreeRTOS系统

    使用Platformio平台的libopencm3开发框架来开发STM32G0,下面为使用FreeRTOS系统。
    的头像 发表于 01-16 15:07 1493次阅读
    <b class='flag-5'>STM32G0</b><b class='flag-5'>开发笔记</b>:使用FreeRTOS系统

    STM32G0开发笔记:使用ADC进行NTC温度采集

    使用Platformio平台的libopencm3开发框架来开发STM32G0,以下使用ADC进行NTC温度采集。
    的头像 发表于 01-16 15:12 6282次阅读
    <b class='flag-5'>STM32G0</b><b class='flag-5'>开发笔记</b>:使用<b class='flag-5'>ADC</b>进行NTC温度采集

    STM32G0开发笔记:SD卡模块的使用方法

    使用Platformio平台的libopencm3开发框架来开发STM32G0,下面介绍SD卡模块的使用方法。
    的头像 发表于 01-19 16:27 1339次阅读
    <b class='flag-5'>STM32G0</b><b class='flag-5'>开发笔记</b>:SD卡模块的使用方法

    STM32G0开发笔记:SPI接口的基本使用

    使用Platformio平台的libopencm3开发框架来开发STM32G0,下面介绍SPI接口的基本使用。
    的头像 发表于 01-17 10:38 2434次阅读
    <b class='flag-5'>STM32G0</b><b class='flag-5'>开发笔记</b>:SPI接口的基本使用

    STM32G0开发笔记:LED灯示例

    使用Platformio平台的libopencm3开发框架来开发STM32G0,下面为LED灯示例。
    的头像 发表于 01-17 10:52 936次阅读
    <b class='flag-5'>STM32G0</b><b class='flag-5'>开发笔记</b>:LED灯示例

    STM32G0开发笔记:使用libopencm3库

    使用Platformio平台的libopencm3开发框架来开发STM32G0开发环境为VSCode+PIO插件,这里以开发
    的头像 发表于 01-17 10:56 1277次阅读
    <b class='flag-5'>STM32G0</b><b class='flag-5'>开发笔记</b>:使用libopencm3库