本文介绍stm8l051f3的dma相关知识。内容分为以下几部分:
dma简介dma传输adc数据dma(direct memory access):直接内存存储。dma可以提高外设和内存以及内存到内存直接的传输速率,数据能不经过cpu任何的参与快速地移动,这样可以节省cpu去处理其他事情。以stm8l051f3为例,它的dma控制器一共有4个人通道,每个通道专门用于从一个或多个外设内存访问请求,它也能仲裁dma请求的优先级。dma的主要特点如下:
4个通道在多个外设之间共享数据传输可以从外设到内存、内存到外设、内存到内存硬件/软件可以根据每个通道的优先级进行仲裁可编程传输数据量:最多达255个数据块(字节或字)递增和递减寻址模式可硬件和软件编程通道优先级在半发送和发送结束可选择中断可软件编程发送数据大小:8位或16位通道请求直接的优先级:可软件编程(非常高、高、中、低)或在相同的情况下硬件可编程软件触发器也支持内存通道,取决于硬件配置两个标志位(dma半传输,dma传输完成)对每个通道的单个中断请求进行逻辑上的或循环缓冲区管理(自动装载模式)挂起和重新开始dma发送能力运行在低功耗模式能力(wfi或wfe)dma模块的框图如下:
dma传输。一个事件之后,外设发送一个请求信号到dma控制器,dma控制器根据通道的优先级来对请求进行处理,一旦dma控制器访问外设,dma控制器就会发送一个应答给外设,如果外设没有其他等待的请求,得到dma控制器的应答后就会释放它的请求信号。
dma通道。4个通道:3个普通通道(通道0、通道1、通道2)和一个内存通道(通道3)。普通通道处理位于固定地址的外设寄存器和一个自动递增/递减指针指向的内存地址范围之间的数据传输。内存通道也是一个普通通道,但是它可以处理两个内存指针指向的内存地址之间的数据传输。
可编程的数据大小。发送的数据大小(8位或16位)可以通过dma_cxspr寄存器的tsize位来控制(当运行在16位模式是,系统处理字节存储地址在递增或递减模式,目标和源指针必须包含msb地址)。配置成16位模式,传输由4个连续的8位读写操作:
从源数据的偶地址读取msb从源数据的奇地址读取lsb往目标的偶地址写入msb数据往目标的奇地址写入lsb数据为了保证数据的连贯性,两个读操作和两个写操作是不可分割的。
指针增量。在内存到外设或外设到内存传输期间,每次传输后内存指针会自动地递增或递减,这取决于dma_cxcr寄存器的mincdec位,而外设的地址是固定的。
通道配置步骤。可根据以下步骤配置dma的通道x(x为通道号):
1)在dma_cxparl/h寄存器设置外设寄存器地址
2)在dma_cxparh/l和dma_cxm0arh/l寄存器设置内存地址
3)在dma_cxndtr寄存器配置发送数据的数量
4)在dma_cxspr寄存器的pl[1:0]位配置通道优先级
5)在dma_cxcr寄存器配置数据传输方向、循环模式、内存递增/递减模式、发送数据大小、在半传输或传输完成中断等
6)在dma_cxcr寄存器设置en位激活通道
7)在所有通道配置完成后,配置dma_gcsr寄存器gen位使能dma
其他的循环模式、内存到内存模式、dma传输暂停、等相关的详细说明可以参考官方手册rm0031的第13章内容。dma1(stm8l051f3的dma外设是dma1)通道请求映射如下:
2、 dma传输adc数据2.1 dma配置本小节介绍通过adc采集电压数据,通过dma把数据转送到内存,然后设置tim3_ch1(接的是pb1,也就是led1)为pwm1模式,再通过dma把内存中adc的数据传送到tim3的ccr1寄存器上,实现根据adc采集电压的变化来控制led1的亮度。
实验的过程可以理解为:外设--dma--内存--dma--外设。实验使用三个外设功能:
adc1--配置adc1_ch22,连续转换模式,12位分辨率,使用dma通道1(外设到内存)tim3--配置tim3_ch1为pwm1模式,使用通道0(内存到外设)dma--配置通道0与通道1的模式、参数以及使能使用的例程:stm8l051f3_12_dma,adc的配置步骤如下:
1)使能adc1外设时钟
2)初始化adc1通道22(pd0)io口为浮空输入模式
3)初始化adc1:连续转换模式,12位分辨率,adc时钟2分频
4)配置adc低速通道,采样周期384
5)使能adc1
6)使能adc1通道22
dma的配置步骤如下(包括adc-->内存与内存-->tim3):
1)使能dma1外设时钟
2)映射adc1到dma通道1
3)dma初始化:通道1、内存地址buffer_address、外设地址adc1_dr_address、数据大小buffer_size、传输方向外设到内存、dma模式循环、内存增长模式增长、dma优先级高、内存数据大小半字
4)dma初始化:通道0、内存地址buffer_address、外设地址tim3_ccr1_address、数据大小buffer_size、传输方向内存到外设、dma模式循环、内存增长模式增长、dma优先级高、内存数据大小半字
5)使能dma1通道1
6)使能dma1通道0
7)使能dma1
tim3配置(配置tim3_ch1为pwm输出)步骤如下:
1)使tim3外设时钟
2)tim3基本配置:时钟分频1、向上计数、周期0xfff
3)配置tim3的通道1作为pwm输出
4)使能tim3
5)配置tim3_ch1(pb1)的gpio
6)使能tim3通道1的pwm输出
2.2 例程介绍所有的函数实现都在main.c文件中,adc配置函数如下:
static void adc_config ( void**)**
{
/* 使能 adc1 时钟 */
clk_peripheralclockconfig ( clk_peripheral_adc1**,** enable**);**
//配置adc1通道22的io口为浮空输入模式
gpio_init ( gpiod**,** gpio_pin_0**,** gpio_mode_in_fl_no_it**);**
/* 初始化 adc1 连续转换,12位分辨率, adc时钟分频2 */
adc_init ( adc1**,** adc_conversionmode_continuous**,** adc_resolution_12bit**,** adc_prescaler_2**);**
/* 配置adc1 低速通道, 采样周期384 */
adc_samplingtimeconfig ( adc1**,** adc_group_slowchannels**,** adc_samplingtime_384cycles**);**
/* 使能 adc1 */
adc_cmd ( adc1**,** enable**);**
/* 使能adc1通道22 */
adc_channelcmd ( adc1**,** adc_channel_22**,** enable**);** /* connected to potentiometer */
}
tim3的配置函数如下:
static void tim3_config ( void**)**
{
/* 使能 tim3 时钟 */
clk_peripheralclockconfig ( clk_peripheral_tim3**,** enable**);**
/* tim3基本配置:时钟分频:1,向上计数,周期:0xfff */
tim3_timebaseinit ( tim3_prescaler_1**,** tim3_countermode_up**,** 0xfff**);**
/* 配置tim3_ch1作为pwm输出 */
tim3_oc1init ( tim3_ocmode_pwm1**,** tim3_outputstate_enable**,**
0x7ff**,** tim3_ocpolarity_low**,** tim3_ocidlestate_set**);**/* 使能 tim3 */
tim3_cmd ( enable**);**
/* 配置tim3_ch1的gpio (pd2)*/
gpio_init ( gpiob**,** gpio_pin_1 , gpio_mode_out_pp_low_fast**);**
/* 使能tim3的pwm输出*/
tim3_ctrlpwmoutputs ( enable**);**
}
dma配置函数如下:
static void dma_config ( void**)**
{
/* 使能 dma1 时钟 */
clk_peripheralclockconfig ( clk_peripheral_dma1**,** enable**);**
/* 连接adc1到dma1通道1 */
syscfg_remapdmachannelconfig ( remap_dma1channel_adc1tochannel1**);**
//*初始化dma1通道1, 内存地址:buffer_address,外设地址:adc1_dr_address,
//数据大小:buffer_size,传输方向:外设到内存,dma模式:循环,内存地址模式:增长,
//dma优先级:高,内存数据大小:半字
dma_init ( dma1_channel1**,** buffer_address**,** adc1_dr_address**,** buffer_size**,** dma_dir_peripheraltomemory**,**
dma_mode_circular**,** dma_memoryincmode_inc**,** dma_priority_high**,** dma_memorydatasize_halfword**);**// 初始化dma1通道0, 内存地址:buffer_address,外设地址:adc1_dr_address,
//数据大小:buffer_size,传输方向:内存到外设,dma模式:循环,内存地址模式:增长,
//dma优先级:高,内存数据大小:半字
dma_init ( dma1_channel0**,** buffer_address**,** tim3_ccr1_address**,** buffer_size**,** dma_dir_memorytoperipheral**,**
dma_mode_circular**,** dma_memoryincmode_inc**,** dma_priority_high**,** dma_memorydatasize_halfword**);**
/* 使能dma1通道1 */
dma_cmd ( dma1_channel1**,** enable**);**
/* 使能dma1通道0 */
dma_cmd ( dma1_channel0**,** enable**);**
/* dma1 使能 */
dma_globalcmd ( enable**);**
}
dma配置相关的地址定义如下:
//定义内存与外设的地址,用于dma传输
#define adc1_dr_address ((uint16_t)(adc1_base + 0x04))
#define tim3_ccr1_address ((uint16_t)(tim3_base + 0x11))
#define buffer_size ((uint8_t) 0x01)
#define buffer_address ((uint16_t)(&buffer))
uint16_t buffer = 0**;** //定义变量保存dma数据,作为dma传输内存地址
主函数如下:
void main ( void**)**
{
adc_config**();** //adc配置
dma_config**();** //dma配置
tim3_config (); //tim3配置
/* 使能 adc1 dma 请求*/
adc_dmacmd ( adc1**,** enable**);**
/* 使能 tim1 dma 请求*/
tim3_dmacmd ( tim3_dmasource_update**,** enable**);**
/* 起始adc1转换*/
adc_softwarestartconv ( adc1**);**
while ( 1**)**
{
;
}
}
使用st-link把程序下载到开发板,adc1_ch22(pd0)采样电压越高led1越亮,检测的测试方法:把pd0口接板子的gnd,led1灭;接板子的vcc,led1亮(如果把pd0接电位器,那么led1的亮度可以由电位器调节)。
威兆半导体:预计今年业绩实现翻番
英飞凌首个CoolMOS家族芯片现已开始面向全球发货
元件也能弯曲了,柔性材料打造微处理器降临!或将带来革命性变化
掌控频域的分析变换和其计算
中空式激光合束压电偏摆台
STM8L051F3的DMA相关知识
2021年国内电信运营商的发展预测
ABB机器人力控技术及汽车焊缝打磨方法 演讲主要内容
变频器的工作原理 变频器的控制方式有哪些
can节点隔离设计必知的一些技巧,马上学起来
玻璃板液位计和磁翻板液位计如何选择使用
无线寻呼通信是什么意思
区块链技术让车联网数据焕发新价值
如何使用固态继电器驱动恒温器
过载保护器是什么_过载保护器工作原理
天马武汉G6 AMOLED产线实现量产出货,车载市场表现抢眼
GNSS监测站介绍
智能验布系统提升缺陷识别效率
压电式传感器的介绍带你详细了解压电式传感器
再获工信部认可!海泰方圆方案获评“2022年信息技术应用创新解决方案”