打印
[其他ST产品]

[经验] (学习经验)不用库函数自己动手配置STM32中的DMA

[复制链接]
275|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
onlycook|  楼主 | 2023-12-20 11:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
今天调试的STM32的DMA部分,第一次接触这部分,8位的单片机没有这部分的功能,一开始感觉这东西很神秘,所以怀着敬畏的心情来学习它。慢慢的发现这确实是个好东西,功能强大,可以分担CPU的任务。但它没有想象中那么棘手。
DMA英文全称是DirectMemory Access,意思是直接存储器访问。他的作用就是不需要经过CUP进行数据传输,也就是替CPU分担点事情做,什么事情?数据传输方面的事情。也就是说,你只要使能并配置好了DMA,DMA就可以将一批数据从源地址搬运到目的地址去而不经过CPU的干预,这样可以为CPU节省好多精力去干更重要的事情很人性化。就像我们人一样,我们平常习惯性的动作是不用经过大脑思考的,比如说眨眼睛,呼吸等。DMA就是负责这些工作的,但它没人这么智能,需要将它设置好了它才会正常工作。
要进行数据传输就必须有两个条件:数据从哪传(源地址),数据传到哪里去(目的地址)。是的DMA的确有这两项设置,通过软件设置,设置好源地址和目的地址。在一个重要的条件就是触发源是什么,就是说什么时候进行DMA数据传输呢?这叫触发信号。也可以通过软件编程设置具体时间,具体条件来触发DMA数据传输。
总之,要使用DMA就要将各种参数,条件配置好才可以用。就提的DMA寄存器说明见STM32的参考手册。下面举一简单的历程来说明DMA的用法,本历程将串口数据发送设置为DMA模式,串口1将持续从RAM中的一段连续的地址中取数据,然后发送出去。用串口调试助手可以监测DMA的工作和CPU互不冲突,串口发送就相当于后台运行的一段程序。具体配置如下:
寄存器定义:




#define DMA_ISR    (*((volatile unsigned long *)0x40020000)) //中断状态寄存器

#define DMA_IFCR  (*((volatile unsigned long *)0x40020004))//中断标志清零寄存器



#define DMA_CCR1    (*((volatile unsigned long *)0x40020008))  //通道1配置寄存器

#define DMA_CCR2    (*((volatile unsigned long *)0x4002001C))  //通道2配置寄存器

#define DMA_CCR3    (*((volatile unsigned long *)0x40020030))  //通道3配置寄存器

#define DMA_CCR4    (*((volatile unsigned long *)0x40020044))  //通道4配置寄存器

#define DMA_CCR5    (*((volatile unsigned long *)0x40020058))  //通道5配置寄存器

#define DMA_CCR6    (*((volatile unsigned long *)0x4002006C))  //通道6配置寄存器

#define DMA_CCR7    (*((volatile unsigned long *)0x40020080))  //通道7配置寄存器



#define DMA_CNDTR1  (*((volatile unsigned long *)0x4002000C))   //通道1传输数量寄存器

#define DMA_CNDTR2    (*((volatile unsigned long *)0x40020020))  //通道2传输数量寄存器

#define DMA_CNDTR3    (*((volatile unsigned long *)0x40020034))  //通道3传输数量寄存器

#define DMA_CNDTR4    (*((volatile unsigned long *)0x40020048))  //通道4传输数量寄存器

#define DMA_CNDTR5    (*((volatile unsigned long *)0x4002005C))  //通道5传输数量寄存器

#define DMA_CNDTR6    (*((volatile unsigned long *)0x40020070))  //通道6传输数量寄存器

#define DMA_CNDTR7    (*((volatile unsigned long *)0x40020084))  //通道7传输数量寄存器



#define DMA_CPAR1    (*((volatile unsigned long *)0x40020010))  //通道1外设地址寄存器

#define DMA_CPAR2    (*((volatile unsigned long *)0x40020024))  //通道2外设地址寄存器

#define DMA_CPAR3    (*((volatile unsigned long *)0x40020038))  //通道3外设地址寄存器

#define DMA_CPAR4    (*((volatile unsigned long *)0x4002004C))  //通道4外设地址寄存器

#define DMA_CPAR5    (*((volatile unsigned long *)0x40020060))  //通道5外设地址寄存器

#define DMA_CPAR6    (*((volatile unsigned long *)0x40020074))  //通道6外设地址寄存器

#define DMA_CPAR7    (*((volatile unsigned long *)0x40020088))  //通道7外设地址寄存器



#define DMA_CMAR1    (*((volatile unsigned long *)0x40020014))  //通道1 存储器地址寄存器

#define DMA_CMAR2    (*((volatile unsigned long *)0x40020028))  //通道2 存储器地址寄存器

#define DMA_CMAR3    (*((volatile unsigned long *)0x4002003C))  //通道3 存储器地址寄存器

#define DMA_CMAR4    (*((volatile unsigned long *)0x40020050))  //通道4 存储器地址寄存器

#define DMA_CMAR5    (*((volatile unsigned long *)0x40020064))  //通道5 存储器地址寄存器

#define DMA_CMAR6    (*((volatile unsigned long *)0x40020078))  //通道6 存储器地址寄存器

#define DMA_CMAR7    (*((volatile unsigned long *)0x4002008C))  //通道7 存储器地址寄存器

配置DMA,手册上表示可以将串口UART1的发送Tx功能配置为DMA发送,在DMA通道4:

void DMA_configration(void)

{

     //DMA设置:

    //设置DMA源:内存地址&串口数据寄存器地址

    //方向:内存-->外设

    //每次传输位:8bit

    //传输大小:10字节

    //地址自增模式:外设地址不增,内存地址自增1

    //DMA模式:循环

    //优先级:高

RCC_AHBENR|=0x00000001; //位0 DMAEN DMA 时钟使能

DMA_CCR4&=0xFFFF800E;//0: 通道禁用

DMA_CPAR4=(unsigned long)&USART1_DR;

DMA_CMAR4=(unsigned long)Data_Buffer;

DMA_CNDTR4=10;

DMA_CCR4=0x00000000;

DMA_CCR4|=0x000030B0;

//DMA_CCR4|=0x00000001;//DMA使能



}

Main函数:

unsigned char Data_Buffer[10]={0x11,0x22,0x33,0x44,0x55};

//将Data_Buffer设为全局变量。

int main()

{

   

  SystemInit0();    //系统(时钟)初始化

stm32_UsartSetup ();   //串口初始化 ,前面的文章中有介绍

DMA_configration();  // DMA配置

USART1_CR3|=0x00000080; //将USART1模块发送数据Tx设置成DMA方式工作

DMA_CCR4|=0x00000001; //使能DMA

while(1)

{

  //CPU可以不受打扰的做其他事情

}

}
复制代码

打开串口助手就可以看到Data_Buffer[]中的数据,其实这只是一个简单的演示实例,DMA的用处是很大的,先学会配置,以后会有它大显身手的时候。
USART1_CR3|=0x00000080; //将USART1模块发送数据Tx设置成DMA方式工作
DMA_CCR4|=0x00000001; //使能DMA
上面这两句就是触发源,你可以把这两句放到定时器TIMx中,比如定时1S触发DMA,这些都是可以任意设置的,不难吧!

使用特权

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

本版积分规则

428

主题

1578

帖子

3

粉丝