1.0 DMA的簡(jiǎn)介
stm32 如何用DMA搬運(yùn)數(shù)據(jù)
1) DMA:直接存儲(chǔ)器存取(direct memory1090492304
access)。作用:主要是實(shí)現(xiàn)數(shù)據(jù)的高速搬運(yùn),為CPU完成簡(jiǎn)單性重復(fù)性數(shù)據(jù)搬運(yùn)工作。這個(gè)過(guò)程無(wú)需CPU干預(yù)。當(dāng)數(shù)據(jù)搬運(yùn)完成后,會(huì)有相應(yīng)的狀態(tài)標(biāo)識(shí)位來(lái)告知CPU。
2) 特性:
雙AHB 主總線架構(gòu),一個(gè)用于存儲(chǔ)器訪問(wèn),另一個(gè)用于外設(shè)訪問(wèn);
STM32F4共有兩個(gè)DMA,兩個(gè)DMA 控制器總共有16 個(gè)數(shù)據(jù)流(每個(gè)控制器8 個(gè));
每個(gè)數(shù)據(jù)流有單獨(dú)的四級(jí)32 位先進(jìn)先出存儲(chǔ)器緩沖區(qū)(FIFO);
DMA 流控制器:要傳輸?shù)臄?shù)據(jù)項(xiàng)的數(shù)目是1 到65535,可用軟件編程;
DMA數(shù)據(jù)搬運(yùn)方向可以靈活設(shè)置,可以實(shí)現(xiàn)三種數(shù)據(jù)搬運(yùn):
從芯片內(nèi)部搬運(yùn)到→芯片外部
從芯片外部搬運(yùn)到→芯片內(nèi)部
從芯片內(nèi)部搬到芯片內(nèi)部
注意:芯片內(nèi)部:指STM32內(nèi)部存儲(chǔ)器. 芯片外部:指STM32片上外設(shè),如串口。
3) 弊端:如果需要接收大量的數(shù)據(jù)時(shí),需要頻繁觸發(fā)中斷,而且這個(gè)過(guò)程需要CPU參與。
1.1 DMA框圖
1.2 DMA請(qǐng)求通道映射表
1.3 DMA數(shù)據(jù)流的配置編程步驟
1) 使能外設(shè)的DMA功能。舉例:使能串口1的DMA發(fā)送或者DMA接收。
2) 使能DMA時(shí)鐘
3) DMA_SxCR 寄存器中的 EN 位清零,禁止DMA數(shù)據(jù)流
4) 阻塞判斷EN位是否置0了。
5) 在 DMA_SxPAR 寄存器中設(shè)置外設(shè)寄存器地址
6) 在 DMA_SxM0AR 寄存器中設(shè)置存儲(chǔ)器地址。
7) 在 DMA_SxNDTR 寄存器中配置要傳輸?shù)臄?shù)據(jù)個(gè)數(shù)的總數(shù)
8) 使用 DMA_SxCR 寄存器中的 CHSEL[2:0] 選擇 DMA 通道
9) 使用 DMA_SxCR 寄存器中的 PL[1:0] 位配置數(shù)據(jù)流優(yōu)先級(jí)
10) 禁止FIFO
11) 配置數(shù)據(jù)流傳輸方向
12) 設(shè)置外設(shè)地址是增量模式還是固定模式
13) 設(shè)置存儲(chǔ)器地址是增量模式還是固定模式
14) 設(shè)置外設(shè)數(shù)據(jù)寬度
15) 設(shè)置存儲(chǔ)器數(shù)據(jù)寬度
16) 通過(guò)將 DMA_SxCR 寄存器中的 EN 位置 1 激活數(shù)據(jù)流。
注意:只有“禁止了數(shù)據(jù)流”,才可以更改寄存器的配置。
1.4 源和目標(biāo)的地址設(shè)置
1.5 DMA控制器相關(guān)寄存器
1.5.0 DMA 數(shù)據(jù)流 x 配置寄存器 (DMA_SxCR) (x = 0..7)
每個(gè)數(shù)據(jù)流都有一個(gè)自己的“配置寄存器”,舉例:
1) DMA1的數(shù)據(jù)流0的“配置寄存器”在寫代碼是應(yīng)該寫:DMA1_Stream0->CR
2) DMA2的數(shù)據(jù)流5的“配置寄存器”在寫代碼是應(yīng)該寫:DMA2_Stream5->CR
3) DMA1的數(shù)據(jù)流3的“配置寄存器”在寫代碼是應(yīng)該寫:DMA1_Stream3->CR
4) DMA2的數(shù)據(jù)流6的“配置寄存器”在寫代碼是應(yīng)該寫: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
提問(wèn):數(shù)據(jù)流7的請(qǐng)求通道選擇為通道4,即USART1_TX功能,對(duì)應(yīng)代碼:DMA2_Stream7->CR |=
4<<25;
位 17:16 PL[1:0]:優(yōu)先級(jí) (Priority level)
設(shè)置數(shù)據(jù)流的優(yōu)先級(jí)
這些位將由軟件置 1 和清零。
00:低
01:中
10:高
11:非常高
舉例:數(shù)據(jù)流7的請(qǐng)求通道選擇為通道4,即USART1_TX功能,數(shù)據(jù)流7的優(yōu)先級(jí)設(shè)置為“中”,對(duì)應(yīng)代碼:DMA2_Stream7->CR |=
1<<16;
位 14:13 MSIZE[1:0]:存儲(chǔ)器數(shù)據(jù)大小 (Memory data size)
00:字節(jié)(8 位)
01:半字(16 位)
10:字(32 位)
11:保留
舉例:
如果存儲(chǔ)器是自定的一個(gè)數(shù)組,自定的數(shù)組是:u8 dataBuf1[2] = {1,2};那么存儲(chǔ)器的數(shù)據(jù)大小是8位
如果存儲(chǔ)器是自定的一個(gè)數(shù)組,自定的數(shù)組是:u16 dataBuf2[2] = {1,2};那么存儲(chǔ)器的數(shù)據(jù)大小是16位
如果存儲(chǔ)器是自定的一個(gè)數(shù)組,自定的數(shù)組是:u32 dataBuf2[2] = {1,2};那么存儲(chǔ)器的數(shù)據(jù)大小是32位
舉例:數(shù)據(jù)流7的請(qǐng)求通道選擇為通道4,即USART1_TX功能,如果想實(shí)現(xiàn)串口1發(fā)送自定的一個(gè)數(shù)組, 自定的數(shù)組是:u8 dataBuf1[2]
= {1,2}; ,那么存儲(chǔ)器的數(shù)據(jù)大小要設(shè)置為“8位”,DMA2_Stream7->CR &=~(3<<13);
位 12:11 PSIZE[1:0]:外設(shè)數(shù)據(jù)大小 (Peripheral data size)
00:字節(jié)(8 位)
01:半字(16 位)
10:字(32 位)
11:保留
舉例:
如果外設(shè)是USART1_DR寄存器,由于USART1_DR寄存器是8位有效的,所以外設(shè)大小需要設(shè)置為"8位"
舉例:數(shù)據(jù)流7的請(qǐng)求通道選擇為通道4,即USART1_TX功能,如果想實(shí)現(xiàn)串口1發(fā)送自定的一個(gè)數(shù)組,自定義的數(shù)組是:u8 dataBuf1[2] =
{1,2}; , 那么外設(shè)的數(shù)據(jù)大小要設(shè)置為“8位”,DMA2_Stream7->CR &=~(3<<11);
位 10 MINC:存儲(chǔ)器遞增模式 (Memory increment mode)
0:存儲(chǔ)器地址是固定的
1:每次傳輸完一個(gè)數(shù)據(jù),存儲(chǔ)器地址遞增(增量為 MSIZE 值)
舉例:數(shù)據(jù)流7的請(qǐng)求通道選擇為通道4,即USART1_TX功能,如果想實(shí)現(xiàn)串口1發(fā)送自定的一個(gè)數(shù)組,自定的數(shù)組是:u8 dataBuf1[2] =
{1,2}; 需要告訴DMA控制器,每發(fā)送一個(gè)數(shù)據(jù)后,需要進(jìn)行地址偏移(地址遞增),對(duì)應(yīng)代碼:DMA2_Stream7->CR
|=1<<10;
類比:串口發(fā)送數(shù)據(jù)
u8 dataBuf1[2] = {1,2};
for(i=0;i<2;i++)
{
USART1->DR = dataBuf1[i]; // 數(shù)組下標(biāo)偏移→地址偏移
}
位 9 PINC:外設(shè)遞增模式 (Peripheral increment mode)
0:外設(shè)地址固定
1:每次傳輸完一個(gè)數(shù)據(jù),外設(shè)地址遞增(增量為 PSIZE 值)
舉例:數(shù)據(jù)流7的請(qǐng)求通道選擇為通道4,即USART1_TX功能,如果想實(shí)現(xiàn)串口1發(fā)送自定的一個(gè)數(shù)組,自定的數(shù)組是:u8 dataBuf1[2] =
{1,2}; 由于一個(gè)芯片設(shè)置定型后,外設(shè)的地址都是固定的,所以一般都將外設(shè)地址設(shè)置為固定的。對(duì)應(yīng)的代碼:DMA2_Stream7->CR
&=~(1<<9);
位 7:6 DIR[1:0]:數(shù)據(jù)傳輸方向 (Data transfer direction)
這些位將由軟件置 1 和清零。
00:外設(shè)到存儲(chǔ)器
01:存儲(chǔ)器到外設(shè)
10:存儲(chǔ)器到存儲(chǔ)器
11:保留
舉例:數(shù)據(jù)流7的請(qǐng)求通道選擇為通道4,即USART1_TX功能,如果想實(shí)現(xiàn)串口1DMA發(fā)送數(shù)據(jù),數(shù)據(jù)傳輸方向需要配置為“存儲(chǔ)器到外設(shè)”。
對(duì)應(yīng)代碼:DMA2_Stream7->CR |= 1<<6;
位 4 TCIE:傳輸完成中斷使能 (Transfer complete interrupt enable)
DMA搬運(yùn)完成后,可以觸發(fā)DMA中斷,前提是將該位置1
0:禁止 TC 中斷
1:使能 TC 中斷
位 0 EN:數(shù)據(jù)流使能/讀作低電平時(shí)數(shù)據(jù)流就緒標(biāo)志 (Stream enable / flag stream ready when read
low)
功能1:用于使能數(shù)據(jù)流
0:禁止數(shù)據(jù)流
1:使能數(shù)據(jù)流
功能2:用于指示狀態(tài)
讀取該位,如果為0,則允許"對(duì)器寄存器進(jìn)行配置"
讀取該位,如果為1,則不允許"對(duì)器寄存器進(jìn)行配置"
注意:只有“禁止了數(shù)據(jù)流”,才可以更改寄存器的配置。
1.5.1 DMA 數(shù)據(jù)流 x 數(shù)據(jù)項(xiàng)數(shù)寄存器 (DMA_SxNDTR) (x = 0..7)
位 15:0 NDT[15:0]:要傳輸(發(fā)送或接收)的數(shù)據(jù)個(gè)數(shù) (Number of data items to transfer)
寫入的值是要傳輸?shù)臄?shù)據(jù)個(gè)數(shù)(0 到 65535)。
如果讀取該寄存器,則可以知道剩余需要傳輸?shù)臄?shù)據(jù)有多少個(gè)。
DMA每傳輸一個(gè)數(shù)據(jù)后,此寄存器將遞減。
舉例:數(shù)據(jù)流7的請(qǐng)求通道選擇為通道4,即USART1_TX功能,如果想實(shí)現(xiàn)串口1的DMA發(fā)送自定的一個(gè)數(shù)組,自定的數(shù)組是:u8 dataBuf[ ]
= {“hello world”}; 對(duì)應(yīng)的代碼:DMA2_Stream7->NDTR = sizeof(dataBuf);
1.5.2 DMA 數(shù)據(jù)流 x 外設(shè)地址寄存器 (DMA_SxPAR) (x = 0..7)
位 31:0 PAR[31:0]:外設(shè)地址 (Peripheral address)
寫入的的是外設(shè)寄存器,作用是:用于告訴DMA控制將數(shù)據(jù)搬運(yùn)到哪個(gè)外設(shè)寄存器或者從哪個(gè)外設(shè)寄存器取數(shù)據(jù)。
DMA發(fā)送:將數(shù)據(jù)搬運(yùn)到USART1_DR
u8 dataBuf[ ] = {“hello world”}; → DMA發(fā)送 →USART1_DR
DMA接收:從USART1_DR取數(shù)據(jù),搬運(yùn)到dataBuf
u8 dataBuf[50 ] = {0}; ←DMA 接收←USART1_DR
這兩種搬運(yùn),都需要將USART1_DR的地址寫入到PAR寄存器。
舉例:數(shù)據(jù)流7的請(qǐng)求通道選擇為通道4,即USART1_TX功能,如果想實(shí)現(xiàn)串口1的DMA發(fā)送自定的一個(gè)數(shù)組,自定的數(shù)組是:u8 dataBuf[ ]
= {“hello world”}; 需要將USART1_DR的地址寫入到PAR寄存器,對(duì)應(yīng)代碼:DMA2_Stream7->PAR =
(u32)&USART1->DR;
1.5.3 DMA 數(shù)據(jù)流 x 存儲(chǔ)器 0 地址寄存器 (DMA_SxM0AR) (x = 0..7)
需要寫入的是:存儲(chǔ)器的首地址(可以簡(jiǎn)單的理解為數(shù)組首地址)。
舉例:數(shù)據(jù)流7的請(qǐng)求通道選擇為通道4,即USART1_TX功能,如果想實(shí)現(xiàn)串口1的DMA發(fā)送自定的一個(gè)數(shù)組,自定的數(shù)組是:u8 dataBuf[ ]
= {“hello world”}; 需要將數(shù)組的地址寫入到M0AR寄存器,對(duì)應(yīng)代碼:DMA2_Stream7->M0AR =
(u32)&dataBuf[0];
1.5.4 DMA 低中斷狀態(tài)寄存器 (DMA_LISR)
1.5.5 DMA 高中斷狀態(tài)寄存器 (DMA_HISR)
TCIFx:數(shù)據(jù)流 x 傳輸完成標(biāo)志位 (Stream x transfer complete interrupt flag)
(x=0..7)
此位將由硬件置 1,由軟件清零,清零方法:將 1 寫入 DMA_HIFCR或者 DMA_LIFCR 寄存器的相應(yīng)位。
0:數(shù)據(jù)流 x 上無(wú)傳輸完成事件
1:數(shù)據(jù)流 x 上發(fā)生傳輸完成事件,即:數(shù)據(jù)搬運(yùn)完成
注意:清零不是直接操作LISR、HISR。而是操作HIFCR、LIFCR
舉例:數(shù)據(jù)流7的請(qǐng)求通道選擇為通道4,即USART1_TX功能,如果想實(shí)現(xiàn)串口1的DMA發(fā)送自定的一個(gè)數(shù)組,自定的數(shù)組是:u8 dataBuf[ ]
= {“hello world”};如何判斷是否發(fā)送完成?
方法1:阻塞判斷法→while(!(DMA2->HISR&(1<<27)));
方法2:中斷方法
1.5.6 DMA 低中斷標(biāo)志清零寄存器 (DMA_LIFCR)
1.5.7 DMA 高中斷標(biāo)志清零寄存器 (DMA_HIFCR)
CTCIFx:數(shù)據(jù)流 x 傳輸完成中斷標(biāo)志清零 (Stream x clear transfer complete interrupt flag)
(x = 0..7)
將 1 寫入此位時(shí), DMA_LISR 和DMA_HISR寄存器中相應(yīng)的 TCIFx 標(biāo)志將清零
舉例:數(shù)據(jù)流7的請(qǐng)求通道選擇為通道4,即USART1_TX功能,如果想實(shí)現(xiàn)串口1的DMA發(fā)送自定的一個(gè)數(shù)組,自定的數(shù)組是:u8 dataBuf[ ]
= {“hello world”};如何判斷是否發(fā)送完成?
阻塞判斷法→while(!(DMA2->HISR&(1<<27)));
清零代碼:DMA2->HIFCR |= 1<<27;
1.6 DMA實(shí)例代碼
從開發(fā)板發(fā)一串信息到電腦串口助手并顯示助手軟件屏幕上。
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