前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >M-Arch(番外8)GD32L233评测-ADC和DMA(官方没有例程哦)

M-Arch(番外8)GD32L233评测-ADC和DMA(官方没有例程哦)

作者头像
滚神大人
发布2022-04-18 14:16:20
6950
发布2022-04-18 14:16:20
举报
文章被收录于专栏:趣Python趣Python

前言

开工第一天,今天是DMA方式的ADC采样。

什么是ADC?

ADC即模拟数字转换器,ADC的精度一般用位来表示,位数越多,表示相同模拟量范围内的采样点数越多,那么相应的精度就越高。

比如:12位表示的范围是0 ~ 2^12 (4096),8位表示的范围是0 ~ 2^8 (256),前者的精度是后者的16倍。

ADC一般需要配置的内容包括:

  1. IO配置(时钟,模拟输入)
  2. ADC参数配置(模式-扫描模式,连续模式;触发方式;通道配置-规则组or注入组;ADC校正)
  3. 中断和DMA(使能)配置

【注】ADC的规则组和注入组的区别可简单理解为:规则组是周期执行的程序,注入组是中断程序。

什么是DMA?

DMA即直接存储器访问控制器,DMA提供了一种硬件的方式在外设和存储器之间或者存储器和存储器之间传输数据,而无需CPU的介入,避免了CPU多次进入中断进行大规模的数据拷贝,最终提高整体的系统性能。

简单而言,DMA相当于是外请(DMA硬件)的搬运工(数据拷贝),节约宝贵的CPU资源。

DMA一般需要配置的内容包括:

  1. IO配置(时钟)
  2. DMA参数配置(拷贝的方向,内容,地址,通道,模式和数量等)
  3. 中断(使能)配置

DMA的配置需要注意通道的匹配:

STM32F103 DMA通道配置

GD32F450 DMA通道配置

注意,在GD32L233中新增了一个DMAMUX的设计,即在DMA控制器前一级增加了的多路选择器,相比如上图,它的好处是更灵活,缺点当然也是更灵活了。

GD32L233 DMAMUX结构

从设计的角度来看,这种配置个人觉得固定成一张表更好理解和处理。

ADC如何DMA?

基本说明

先把DMA的概念代入,ADC属于外设,我们一般使用ADC的DMA是把ADC的采样数据传送到内存中供程序使用,那么它的处理数据链是:ADC通道数据地址-DMA缓存数据-滤波-业务层数据,DMA的确是省了很多软件的事

架构和流程

基本架构:

流程和数据结构:

代码设计

由于单片机内置了CPU温度值,Vrefint和Vbatt(STM32无Vbatt)的采样通道,这里的示例用这几个通道来做示例。

GD32L233的温度计算公式跟GD32F450不一样,在用户手册中写清楚了:

代码语言:javascript
复制
温度(°C) = ((Dtemperature – D30) / Avg_Slope) + 30

D30在芯片内固定:

代码语言:javascript
复制
#define ADC_TEMP_CALIBRATION_VALUE        REG16(0x1FFFF7F8)
adc和dma

adc配置:

代码语言:javascript
复制
void adc1_init(int32_t channel_num)
{
    /* enable ADC clock */
    rcu_periph_clock_enable(RCU_ADC);    
    rcu_periph_clock_enable(RCU_GPIOA);

    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0);
    /* config ADC clock */
    rcu_adc_clock_config(RCU_ADCCK_APB2_DIV16);
    /* ADC SCAN function enable */
    adc_special_function_config(ADC_SCAN_MODE, ENABLE);
    /* conyinuous mode */
    adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE);
    adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);
    adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE);
    adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
    adc_channel_length_config(ADC_REGULAR_CHANNEL, channel_num);

    /* ADC temperature and Vrefint enable */
    adc_channel_16_to_19(ADC_TEMP_CHANNEL_SWITCH, ENABLE);
    adc_channel_16_to_19(ADC_INTERNAL_CHANNEL_SWITCH, ENABLE);
    adc_channel_16_to_19(ADC_VBAT_CHANNEL_SWITCH, ENABLE);

    adc_regular_channel_config(0, ADC_CHANNEL_adc_test,   ADC_SAMPLETIME_239POINT5);
    adc_regular_channel_config(1, ADC_CHANNEL_cpu_temper, ADC_SAMPLETIME_239POINT5);
    adc_regular_channel_config(2, ADC_CHANNEL_cpu_vref,   ADC_SAMPLETIME_239POINT5);
    adc_regular_channel_config(3, ADC_CHANNEL_vbatt,      ADC_SAMPLETIME_239POINT5);

    /* enable ADC interface */
    adc_enable();
    adc_dma_mode_enable();
    delay_ms(1U);

    /* ADC calibration and reset calibration */
    adc_calibration_enable();
    adc_software_trigger_enable(ADC_REGULAR_CHANNEL);
}

DMA配置:

代码语言:javascript
复制
void adc1_dma_init(uint32_t addr, uint32_t number)
{
    /* ADC_DMA_channel configuration */
    dma_parameter_struct dma_parameter;

    /* enable DMA0 clock */
    rcu_periph_clock_enable(RCU_DMA);

    /* ADC DMA_channel configuration */
    dma_deinit(DMA_CH0);

    /* initialize DMA data mode */
    dma_struct_para_init(&dma_parameter);
    dma_parameter.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_parameter.periph_addr = (uint32_t)(&ADC_RDATA);
    dma_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_parameter.periph_width = DMA_PERIPHERAL_WIDTH_32BIT;
    dma_parameter.memory_addr = addr;
    dma_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_parameter.memory_width = DMA_MEMORY_WIDTH_32BIT;
    dma_parameter.number = number;
    dma_parameter.priority = DMA_PRIORITY_HIGH;
    dma_parameter.request = DMA_REQUEST_ADC;
    dma_init(DMA_CH0, &dma_parameter);
    dma_circulation_enable(DMA_CH0);

    dma_interrupt_enable(DMA_CH0, DMA_CHXCTL_FTFIE);
    nvic_irq_enable(DMA_Channel0_IRQn, 2);
    
    dma_channel_enable(DMA_CH0);
}
业务代码

头文件:

代码语言:javascript
复制

#define COFF_33_4096_10000000x          8057    ///< 3.3/4096 (10000000)

#if defined(GD32M0)

#define COFF_VBATT  3
#define CPU_TEMP_AD_BASE_1000x          30000   ///< 30度
#define ADC_TEMP_CALIBRATION_VALUE        REG16(0x1FFFF7F8)

#define GET_CPU_TEMPERATURE(data) CPU_TEMP_AD_BASE_1000x + (data - (int32_t)ADC_TEMP_CALIBRATION_VALUE) * COFF_1_4096_10000000x / 10
#define GET_CPU_VREF(data) COFF_33_4096_10000000x*data/10000
#define GET_CPU_VBATT(data) COFF_33_4096_10000000x*data*COFF_VBATT/10000

#define ADC_CHANNEL_adc_test    ((uint8_t)ADC_CHANNEL_1)
#define ADC_CHANNEL_cpu_temper  ((uint8_t)ADC_CHANNEL_16)
#define ADC_CHANNEL_cpu_vref    ((uint8_t)ADC_CHANNEL_17)
#define ADC_CHANNEL_vbatt       ((uint8_t)ADC_CHANNEL_18)

#endif

DMA中断函数:

测试结果

数据扩大1000倍,其中2~4依次是温度,参考电压和电池电压。

代码语言:javascript
复制
adc = [1143] [23654] [1198] [3304]
adc = [1144] [22677] [1198] [3304]
adc = [1144] [22922] [1198] [3304]
adc = [1144] [23410] [1198] [3304]
adc = [1144] [23654] [1198] [3304]
adc = [1144] [22922] [1198] [3304]
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-04-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 趣Python 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 什么是ADC?
  • 什么是DMA?
  • ADC如何DMA?
    • 基本说明
      • 架构和流程
        • 代码设计
          • adc和dma
          • 业务代码
      • 测试结果
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档