stm32如何用dma搬运数据

  1.0 DMA的简介

stm32 如何用DMA搬运数据

  1) DMA:直接存储器存取(direct memory1090492304

access)。作用:主要是实现数据的高速搬运,为CPU完成简单性重复性数据搬运工作。这个过程无需CPU干预。当数据搬运完成后,会有相应的状态标识位来告知CPU。

  2) 特性:

  双AHB 主总线架构,一个用于存储器访问,另一个用于外设访问;

  STM32F4共有两个DMA,两个DMA 控制器总共有16 个数据流(每个控制器8 个);

  每个数据流有单独的四级32 位先进先出存储器缓冲区(FIFO);

  DMA 流控制器:要传输的数据项的数目是1 到65535,可用软件编程;

  DMA数据搬运方向可以灵活设置,可以实现三种数据搬运:

  从芯片内部搬运到→芯片外部

  从芯片外部搬运到→芯片内部

  从芯片内部搬到芯片内部

  注意:芯片内部:指STM32内部存储器.    芯片外部:指STM32片上外设,如串口。

  3) 弊端:如果需要接收大量的数据时,需要频繁触发中断,而且这个过程需要CPU参与。

  1.1 DMA框图

  1.2 DMA请求通道映射表

  1.3 DMA数据流的配置编程步骤

  1) 使能外设的DMA功能。举例:使能串口1的DMA发送或者DMA接收。

  2) 使能DMA时钟

  3) DMA_SxCR 寄存器中的 EN 位清零,禁止DMA数据流

  4) 阻塞判断EN位是否置0了。

  5) 在 DMA_SxPAR 寄存器中设置外设寄存器地址

  6) 在 DMA_SxM0AR 寄存器中设置存储器地址。

  7) 在 DMA_SxNDTR 寄存器中配置要传输的数据个数的总数

  8) 使用 DMA_SxCR 寄存器中的 CHSEL[2:0] 选择 DMA 通道

  9) 使用 DMA_SxCR 寄存器中的 PL[1:0] 位配置数据流优先级

  10) 禁止FIFO

  11) 配置数据流传输方向

  12) 设置外设地址是增量模式还是固定模式

  13) 设置存储器地址是增量模式还是固定模式

  14) 设置外设数据宽度

  15) 设置存储器数据宽度

  16) 通过将 DMA_SxCR 寄存器中的 EN 位置 1 激活数据流。

  注意:只有“禁止了数据流”,才可以更改寄存器的配置。

  1.4 源和目标的地址设置

  1.5 DMA控制器相关寄存器

  1.5.0 DMA 数据流 x 配置寄存器 (DMA_SxCR) (x = 0..7)

  每个数据流都有一个自己的“配置寄存器”,举例:

  1) DMA1的数据流0的“配置寄存器”在写代码是应该写:DMA1_Stream0->CR

  2) DMA2的数据流5的“配置寄存器”在写代码是应该写:DMA2_Stream5->CR

  3) DMA1的数据流3的“配置寄存器”在写代码是应该写:DMA1_Stream3->CR

  4) DMA2的数据流6的“配置寄存器”在写代码是应该写:DMA2_Stream6->CR

  位 27:25 CHSEL[2:0]:通道选择 (Channel selection)

  这些位将由软件置 1 和清零。

  000:选择通道 0

  001:选择通道 1

  010:选择通道 2

  011:选择通道 3

  100:选择通道 4

  101:选择通道 5

  110:选择通道 6

  111:选择通道 7

  提问:数据流7的请求通道选择为通道4,即USART1_TX功能,对应代码:DMA2_Stream7->CR |=

4<<25;

  位 17:16 PL[1:0]:优先级 (Priority level)

  设置数据流的优先级

  这些位将由软件置 1 和清零。

  00:低

  01:中

  10:高

  11:非常高

  举例:数据流7的请求通道选择为通道4,即USART1_TX功能,数据流7的优先级设置为“中”,对应代码:DMA2_Stream7->CR |=

1<<16;

  位 14:13 MSIZE[1:0]:存储器数据大小 (Memory data size)

  00:字节(8 位)

  01:半字(16 位)

  10:字(32 位)

  11:保留

  举例:

  如果存储器是自定的一个数组,自定的数组是:u8 dataBuf1[2] = {1,2};那么存储器的数据大小是8位

  如果存储器是自定的一个数组,自定的数组是:u16 dataBuf2[2] = {1,2};那么存储器的数据大小是16位

  如果存储器是自定的一个数组,自定的数组是:u32 dataBuf2[2] = {1,2};那么存储器的数据大小是32位

  举例:数据流7的请求通道选择为通道4,即USART1_TX功能,如果想实现串口1发送自定的一个数组,   自定的数组是:u8 dataBuf1[2]

= {1,2}; ,那么存储器的数据大小要设置为“8位”,DMA2_Stream7->CR &=~(3<<13);

  位 12:11 PSIZE[1:0]:外设数据大小 (Peripheral data size)

  00:字节(8 位)

  01:半字(16 位)

  10:字(32 位)

  11:保留

  举例:

  如果外设是USART1_DR寄存器,由于USART1_DR寄存器是8位有效的,所以外设大小需要设置为"8位"

  举例:数据流7的请求通道选择为通道4,即USART1_TX功能,如果想实现串口1发送自定的一个数组,自定义的数组是:u8 dataBuf1[2] =

{1,2}; ,   那么外设的数据大小要设置为“8位”,DMA2_Stream7->CR &=~(3<<11);

  位 10 MINC:存储器递增模式 (Memory increment mode)

  0:存储器地址是固定的

  1:每次传输完一个数据,存储器地址递增(增量为 MSIZE 值)

  举例:数据流7的请求通道选择为通道4,即USART1_TX功能,如果想实现串口1发送自定的一个数组,自定的数组是:u8 dataBuf1[2] =

{1,2};    需要告诉DMA控制器,每发送一个数据后,需要进行地址偏移(地址递增),对应代码:DMA2_Stream7->CR

|=1<<10;

  类比:串口发送数据

  u8 dataBuf1[2] = {1,2};

  for(i=0;i<2;i++)

  {

  USART1->DR = dataBuf1[i]; // 数组下标偏移→地址偏移

  }

  位 9 PINC:外设递增模式 (Peripheral increment mode)

  0:外设地址固定

  1:每次传输完一个数据,外设地址递增(增量为 PSIZE 值)

  举例:数据流7的请求通道选择为通道4,即USART1_TX功能,如果想实现串口1发送自定的一个数组,自定的数组是:u8 dataBuf1[2] =

{1,2};    由于一个芯片设置定型后,外设的地址都是固定的,所以一般都将外设地址设置为固定的。对应的代码:DMA2_Stream7->CR

&=~(1<<9);

  位 7:6 DIR[1:0]:数据传输方向 (Data transfer direction)

  这些位将由软件置 1 和清零。

  00:外设到存储器

  01:存储器到外设

  10:存储器到存储器

  11:保留

  举例:数据流7的请求通道选择为通道4,即USART1_TX功能,如果想实现串口1DMA发送数据,数据传输方向需要配置为“存储器到外设”。

对应代码:DMA2_Stream7->CR |= 1<<6;

  位 4 TCIE:传输完成中断使能 (Transfer complete interrupt enable)

  DMA搬运完成后,可以触发DMA中断,前提是将该位置1

  0:禁止 TC 中断

  1:使能 TC 中断

  位 0 EN:数据流使能/读作低电平时数据流就绪标志 (Stream enable / flag stream ready when read

low)

  功能1:用于使能数据流

  0:禁止数据流

  1:使能数据流

  功能2:用于指示状态

  读取该位,如果为0,则允许"对器寄存器进行配置"

  读取该位,如果为1,则不允许"对器寄存器进行配置"

  注意:只有“禁止了数据流”,才可以更改寄存器的配置。

  1.5.1 DMA 数据流 x 数据项数寄存器 (DMA_SxNDTR) (x = 0..7)

  位 15:0 NDT[15:0]:要传输(发送或接收)的数据个数 (Number of data items to transfer)

  写入的值是要传输的数据个数(0 到 65535)。

  如果读取该寄存器,则可以知道剩余需要传输的数据有多少个。

  DMA每传输一个数据后,此寄存器将递减。

  举例:数据流7的请求通道选择为通道4,即USART1_TX功能,如果想实现串口1的DMA发送自定的一个数组,自定的数组是:u8 dataBuf[ ]

= {“hello world”};    对应的代码:DMA2_Stream7->NDTR = sizeof(dataBuf);

  1.5.2 DMA 数据流 x 外设地址寄存器 (DMA_SxPAR) (x = 0..7)

  位 31:0 PAR[31:0]:外设地址 (Peripheral address)

  写入的的是外设寄存器,作用是:用于告诉DMA控制将数据搬运到哪个外设寄存器或者从哪个外设寄存器取数据。

  DMA发送:将数据搬运到USART1_DR

  u8 dataBuf[ ] = {“hello world”}; → DMA发送 →USART1_DR

  DMA接收:从USART1_DR取数据,搬运到dataBuf

  u8 dataBuf[50 ] = {0}; ←DMA 接收←USART1_DR

  这两种搬运,都需要将USART1_DR的地址写入到PAR寄存器。

  举例:数据流7的请求通道选择为通道4,即USART1_TX功能,如果想实现串口1的DMA发送自定的一个数组,自定的数组是:u8 dataBuf[ ]

= {“hello world”};    需要将USART1_DR的地址写入到PAR寄存器,对应代码:DMA2_Stream7->PAR =

(u32)&USART1->DR;

  1.5.3 DMA 数据流 x 存储器 0 地址寄存器 (DMA_SxM0AR) (x = 0..7)

  需要写入的是:存储器的首地址(可以简单的理解为数组首地址)。

  举例:数据流7的请求通道选择为通道4,即USART1_TX功能,如果想实现串口1的DMA发送自定的一个数组,自定的数组是:u8 dataBuf[ ]

= {“hello world”}; 需要将数组的地址写入到M0AR寄存器,对应代码:DMA2_Stream7->M0AR =

(u32)&dataBuf[0];

  1.5.4 DMA 低中断状态寄存器 (DMA_LISR)

  1.5.5 DMA 高中断状态寄存器 (DMA_HISR)

  TCIFx:数据流 x 传输完成标志位 (Stream x transfer complete interrupt flag)

(x=0..7)

  此位将由硬件置 1,由软件清零,清零方法:将 1 写入 DMA_HIFCR或者 DMA_LIFCR 寄存器的相应位。

  0:数据流 x 上无传输完成事件

  1:数据流 x 上发生传输完成事件,即:数据搬运完成

  注意:清零不是直接操作LISR、HISR。而是操作HIFCR、LIFCR

  举例:数据流7的请求通道选择为通道4,即USART1_TX功能,如果想实现串口1的DMA发送自定的一个数组,自定的数组是:u8 dataBuf[ ]

= {“hello world”};如何判断是否发送完成?

  方法1:阻塞判断法→while(!(DMA2->HISR&(1<<27)));

  方法2:中断方法

  1.5.6 DMA 低中断标志清零寄存器 (DMA_LIFCR)

  1.5.7 DMA 高中断标志清零寄存器 (DMA_HIFCR)

  CTCIFx:数据流 x 传输完成中断标志清零 (Stream x clear transfer complete interrupt flag)

(x = 0..7)

  将 1 写入此位时, DMA_LISR 和DMA_HISR寄存器中相应的 TCIFx 标志将清零

  举例:数据流7的请求通道选择为通道4,即USART1_TX功能,如果想实现串口1的DMA发送自定的一个数组,自定的数组是:u8 dataBuf[ ]

= {“hello world”};如何判断是否发送完成?

  阻塞判断法→while(!(DMA2->HISR&(1<<27)));

  清零代码:DMA2->HIFCR |= 1<<27;

  1.6 DMA实例代码

  从开发板发一串信息到电脑串口助手并显示助手软件屏幕上。

  PA9----TXD

  PA10---RXD

  1.6.0 main.c

View Code

  1.6.1 usart1.c

View Code

  1.6.1 dma.c

View Code

  1.6.1 dma.h

View Code

  1.6.1 usart1.h

View Code

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342