复旦微FM33LE0x单片机之多通道ADC DMA

一、简介

  本例程以FM33LE026为例,已经过验证,其他型号不保证适用。
  工欲善其事必先利其器,官方手册就是利器,在接触新开发平台时,仔细阅读手册能大幅提升开发进度,避免很多掉头发事件,光头强除外。

  1. FM33LE0系列带有2Msps 12bit SAR-ADC,可实现温度、内部基准和外部输入信号的测量功能。主要特点为:
  • 工作电压 1.65~5.5V;
  • 输入信号幅度 0~ VREF+;
  • 最高采样率 2Msps(FADC=32MHz);
  • 16 个单端输入通道, 包含温度传感器、 内部基准电压、 12 个外部通道;
  • 12 个外部通道(最大 2Msps), 2 个内部通道(温度传感器通道、 AVREF 采样通道);
  • 可配置的采样保持时间;
  • 支持单次转换和连续转换;
  • 支持 DMA;
  • 支持过采样硬件平均, 最高 16bit 输出(256 次平均);

ADC模块框图

  1. ADC 支持以下转换模式:
  • 单次转换
    • 半自动触发(SEMI-AUTOMATIC);
    • 全自动触发(AUTOMATIC);
  • 连续转换

  转换启动可以由软件或事件触发,通过寄存器选择多个事件触发源。

  1. 在多通道转换或连续转换时,使用 DMA 进行转换结果搬移是高效的解决方案。在使能了 DMAEN 的情况下,当每次转换完成后(EOC),ADC controller 模块会产生一个 DMA 请求,通知 DMA 将数据寄存器中的结果搬运到指定的 SRAM 地址。 ADC 的 DMA 接口支持单次模式和循环模式:
      在全自动触发模式下(ADC_CFGR2.SEMI=0)和半自动触发模式下(ADC_CFGR2.SEMI=1), ADC 的 DMA接口都可以支持单次模式和循环模式。
  • 单次模式
    转换完成后发起数据搬运,此过程会一直重复,直到软件配置的 DMA 传输长度完成,然后 ADC 控制器会自动停止转换(通过接收 DMA 的传输完成中断标志信号),关闭 ADC,不再向 DMA 发起请求。此模式主要用于对特定模拟信号进行一定长度的采样。
  • 循环模式
    与 DMA 的循环模式相配合, ADC 不断循环转换并发起 DMA 请求,直到软件停止转换。此模式可以用于处理连续不断模拟信号采样。
  1. FM33LE0 系列 DMA 主要特点为:
  • 7通道外设 PDMA,支持 Peripherals<>RAM 传输;
  • 1通道存储器 MDMA,支持 Flash<>RAM 传输;
  • 外设 DMA 传输由外设请求触发, DMA 工作期间不影响 CPU 运行;
  • 外设通道最大传输长度65536字节(64KB),支持 byte/half-word/word 传输;
  • Flash->RAM 通道最大传输长度8192字节,只支持 word 传输;
  • 支持 Flash 连续编程(RAM->Flash),需要预先进行擦除,一次编程固定为256字节;
  • RAM 指针递增、递减;
  • 可产生半程中断和全程中断;
  • 通道优先级可配置(4级优先级);
  1. DMA 工作流程如图所示:
    在这里插入图片描述
  2. 外设 DMA 通道支持循环模式(Circular mode)。循环模式下,当 CHxTSIZE 寄存器定义的传输长度完成后, DMA 不会自动停止,而是返回 RAM 指针寄存器定义的起始地址,继续传输。 DMA 的半程中断和全程中断还是会正常置起, DMA 不会终止传输,直到软件关闭通道。

  结合手册描述和框图可知,ADC 支持 DMA 搬运,为了能够随时取值,ADC 应配置成连续转换模式。同时 DMA 应配置为循环模式,以实时刷新指定的 RAM 区域。

二、代码实现

  可以明确 ADC 工作在连续转换模式下,DMA 工作在循环模式下。

  1. ADC 配置
static void adc_gpio_init(void)
{
    FL_GPIO_InitTypeDef       GPIO_InitStruct;
    FL_ADC_InitTypeDef        Sampling_InitStruct;
    FL_ADC_CommonInitTypeDef  CommonInitStruct;

    /* 初始化 ADC IO */ 
    GPIO_InitStruct.pin = ADC_S1_PIN | ADC_S2_PIN | ADC_S3_PIN;
    GPIO_InitStruct.mode = FL_GPIO_MODE_ANALOG;
    GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.pull = FL_DISABLE;
    GPIO_InitStruct.remapPin = FL_DISABLE;
    FL_GPIO_Init(ADC_GPIO_PORT, &GPIO_InitStruct);
    
    /* ADC 时钟设置 */
    CommonInitStruct.clockSource = FL_RCC_ADC_CLK_SOURCE_RCHF;
    CommonInitStruct.clockPrescaler = FL_RCC_ADC_PSC_DIV8;
    FL_ADC_CommonInit(&CommonInitStruct );

    /* ADC 寄存器设置 */
    Sampling_InitStruct.conversionMode = FL_ADC_CONV_MODE_CONTINUOUS;   // 连续转换
    Sampling_InitStruct.autoMode = FL_ADC_SINGLE_CONV_MODE_AUTO;
    Sampling_InitStruct.waitMode = FL_DISABLE;
    Sampling_InitStruct.overrunMode = FL_DISABLE;                       
    Sampling_InitStruct.scanDirection = FL_ADC_SEQ_SCAN_DIR_FORWARD;
    Sampling_InitStruct.externalTrigConv = FL_ADC_TRIGGER_EDGE_NONE;
    Sampling_InitStruct.triggerSource = FL_ADC_TRGI_PA8;
    Sampling_InitStruct.fastChannelTime = FL_ADC_FAST_CH_SAMPLING_TIME_16_ADCCLK;
    Sampling_InitStruct.lowChannelTime = FL_ADC_SLOW_CH_SAMPLING_TIME_16_ADCCLK;
    Sampling_InitStruct.oversamplingMode = FL_DISABLE;
    Sampling_InitStruct.overSampingMultiplier = FL_ADC_OVERSAMPLING_MUL_16X;
    Sampling_InitStruct.oversamplingShift = FL_ADC_OVERSAMPLING_SHIFT_4B;
    FL_ADC_Init(ADC, &Sampling_InitStruct);

    FL_ADC_EnableSequencerChannel(ADC, ADC_S1_CH);
    FL_ADC_EnableSequencerChannel(ADC, ADC_S2_CH);
    FL_ADC_EnableSequencerChannel(ADC, ADC_S3_CH);    
       
    FL_ADC_EnableDMAReq(ADC);  
}
  1. DMA 配置
#define  ADC_CH_NUM    3
uint16_t adc_temp[ADC_CH_NUM] = {0};       // 单次转换缓存

static void adc_dma_init(void)
{
    FL_DMA_InitTypeDef      DMA_InitStruct = {0};
    FL_DMA_ConfigTypeDef    DMA_ConfigStruct = {0};  
    
    DMA_InitStruct.periphAddress = FL_DMA_PERIPHERAL_FUNCTION1;             // 配置DMA通道功能
    DMA_InitStruct.direction = FL_DMA_DIR_PERIPHERAL_TO_RAM;                // 配置DMA通道方向
    DMA_InitStruct.memoryAddressIncMode = FL_DMA_MEMORY_INC_MODE_INCREASE;  // 配置RAM的增减方向
    DMA_InitStruct.dataSize = FL_DMA_BANDWIDTH_16B;                         // 配置DMA传输位宽
    DMA_InitStruct.priority = FL_DMA_PRIORITY_HIGH;                         // 配置DMA通道优先级
    DMA_InitStruct.circMode = FL_ENABLE;                                    // 配置DMA通道循环缓存
    FL_DMA_Init(DMA, &DMA_InitStruct, DMA_ADC_CH);

    DMA_ConfigStruct.memoryAddress = (uint32_t)&adc_temp;                   // 配置DMA_RAM地址
    DMA_ConfigStruct.transmissionCount = ADC_CH_NUM - 1;                    // 配置DMA传输长度
    FL_DMA_StartTransmission(DMA, &DMA_ConfigStruct, DMA_ADC_CH);  
}
  1. 全局初始化
void adc_init(void)
{
    adc_gpio_init();
    adc_dma_init();
    
    FL_ADC_Enable(ADC);                 // 启动ADC
    FL_DMA_Enable(DMA);                 // 配置DMA全局开关
    FL_ADC_EnableSWConversion(ADC);     // 开始转换
}

  配置完成后,可随时读取 ADC 值,果然拿来主义就是爽。当系统中使用了其他 DMA 功能,需注意 DMA 通道的优先级,以避免重要用户数据丢失。That’s all!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
FM33G0xx的主要特性如下:  宽电压范围: 1.8~5.5V  工作温度范围: -40℃~+85℃  处理器内核  ARM Cortex-M0+  支持用户/特权模式  支持中断向量表重定向(VTOR)  最高40MHz主频  SWD调试接口  低功耗技术平台  典型运行功耗180uA/MHz  32KHz下LPRUN功耗: 15uA  Sleep模式下带LCD显示: 6uA  DeepSleep模式, RTC走时+24KB RAM保持+CPU内核保持: 1.2uA  RTC Backup模式, RTC走时+512字节备份寄存器, 0.9uA  存储器  128/256KB Flash空间  Flash擦写寿命: >20,000次  Flash数据保存时间: 10年@85℃  用户代码保护  24KB RAM空间  最大支持73个GPIO,最多24个外部引脚中断, 最多8个异步唤醒引脚  丰富的模拟外设  高可靠、可配置BOR电路(支持4级可编程下电复位阈值)  超低功耗PDR电路(支持4级可编程下电复位阈值)  可编程电源监测模块(SVD)  2x低功耗模拟比较器  11-bit低功耗∑-△ADC,最大支持9个外部通道  高精度温度传感器,精度优于+/-2℃  通信接口  UART*6  7816智能卡接口*2  SPI*3,主从模式  I2C*1, 主机400K  7通道外设DMA  可编程CRC校验模块  定时资源  8-bit基本定时器*4  16-bit扩展定时器*4  16-bit通用定时器*1  24-bit Systick*1  16-bit低功耗定时器*1,可在休眠模式下工作  带窗口的CPU看门狗定时器*1  系统看门狗定时器*1  低功耗实时时钟日历(RTCC),带有数字调校功能, 最高调校精度+/-0.06ppm

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值