日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

STM32系统学习——DMA(直接储存器访问)

發布時間:2025/3/21 windows 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32系统学习——DMA(直接储存器访问) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

DMA主要功能是傳輸數據,但是不需要占用CPU,即在傳輸數據時,CPU可以做別的事,像多線程。數據傳輸從外設到存儲器或者從存儲器到存儲器。DMA控制器包含了DMA1和DMA2,其中DMA1有7個通道,DMA2有5個通道,可以理解為傳輸數據的一種管道。要注意的是,DMA2只存在于大容量單片機中。?
一、DMA框圖解析?
DMA控制器獨立于內核,屬于一個單獨外設,結構結合下圖來看?
?
1.DMA請求?
如果外設想通過DMA傳輸數據,必須先向DMA控制器發送DMA請求,DMA收到請求信號后,控制器會給外設一個應答信號,當外設應答且DMA控制器收到應答信號后,就會啟動DMA傳輸,直到傳輸完畢。?
DMA有DMA1和DMA2兩個控制器,DMA1有兩個控制器,DMA1有7個通道,DMA2有5個通道,不同DMA控制器的通道有不同的外設請求。?
2、通道?
DMA有12個獨立可編程的通道,DMA1有7個通道,DMA2有5個通道,每個通道對應不同外設的DMA請求。雖然每個通道可以接收多個外設請求,但是同一時間只能接收一個,不能同時接收多個。?
3、仲裁器?
當同時有多個DMA請求時,就意味著有先后響應的問題,這個就由仲裁器管理。仲裁器管理DMA請求分為2個階段:第一階段屬于軟件階段,可以在MDA_CCRx寄存器中設置,有 4 個等級:非常高、高、中和低四個優先級。第二階段屬于硬件階段,如果兩個或以上的 DMA 通道請求設置的優先級一樣,則他們優先級取決于通道編號,編號越低優先權越高,比如通道 0 高于通道 1。在大容量產品和互聯型產品中,DMA1 控制器擁有高于 DMA2 控制器的優先級。

二、DMA數據配置?
使用DMA,最核心的就是配置要傳輸的數據。?
1、從哪兒來,到哪兒去?
DMA傳輸數據 的方向有3個:外設到存儲器,存儲器到外設,存儲器到存儲器。具體方向由DMA_CCR中第四位DIR配置:0表示外設到存儲器,1表示存儲器到外設。涉及的地址由DMA_CPAR配置,存儲器地址由DMA_CMAR配置。?
1)從外設到存儲器?
以ADC采集為例,DMA外部寄存器地址對應ADC數據寄存器地址,DMA存儲器地址是我們自定義的變量的地址。方向設置為源地址。?
2)存儲器到外設?
存儲器到外設傳輸以串口向電腦端發送為例,DMA 外設寄存器的地址對應的就是串口數據寄存器的地址,DMA 存儲器的地址就是我們自定義的變量(相當于一個緩沖區,用來存儲通過串口發送到電腦的數據)的地址。方向我們設置外設為目標地址。?
3)存儲器到存儲器?
當我們使用從存儲器到存儲器傳輸時,以內部 FLASH 向內部 SRAM 復制數據為例。?
DMA外設寄存器的地址對應的就是內部 FLASH(我們這里把內部 FALSH 當作一個外設來看)的地址,DMA 存儲器的地址就是我們自定義的變量(相當于一個緩沖區,用來存儲來自內部 FLASH 的數據)的地址。方向我們設置外設(即內部 FLASH)為源地址。跟上面兩個不一樣的是,這里需要把 DMA_CCR 位 14:MEM2MEM:存儲器到存儲器模式配置為 1,啟動 M2M 模式。?
2、要傳什么,單位是多少?
以串口向電腦發送數據為例,我們可以一次性給電腦發送很多數據,具體多少由DMA_CNDTR 配置,這是一個 32位的寄存器,一次最多只能傳輸 65535 個數據。?
要想數據傳輸正確,源和目標地址存儲的數據寬度還必須一致,串口數據寄存器是 8位的,所以我們定義的要發送的數據也必須是 8 位。外設的數據寬度由 DMA_CCR 的PSIZE[1:0]配置,可以是 8/16/32位,存儲器的數據寬度由 DMA_CCR 的 MSIZE[1:0]配置,可以是 8/16/32 位。?
在 DMA 控制器的控制下,數據要想有條不紊的從一個地方搬到另外一個地方,還必須正確設置兩邊數據指針的增量模式。外設的地址指針由 DMA_CCRx 的 PINC 配置,存儲器的地址指針由 MINC 配置。以串口向電腦發送數據為例,要發送的數據很多,每發送完一個,那么存儲器的地址指針就應該加 1,而串口數據寄存器只有一個,那么外設的地址指針就固定不變。具體的數據指針的增量模式由實際情況決定。?
3、什么時候傳輸完成?
數據什么時候傳輸完成,我們可以通過查詢標志位或者通過中斷的方式來鑒別。每個DMA 通道在 DMA 傳輸過半、傳輸完成和傳輸錯誤時都會有相應的標志位,如果使能了該類型的中斷后,則會產生中斷。有關各個標志位的詳細描述請參考 DMA 中斷狀態寄存器DMA_ISR的詳細描述。?
傳輸完成還分兩種模式,是一次傳輸還是循環傳輸,一次傳輸很好理解,即是傳輸一次之后就停止,要想再傳輸的話,必須關斷 DMA 使能后再重新配置后才能繼續傳輸。循環傳輸則是一次傳輸完成之后又恢復第一次傳輸時的配置循環傳輸,不斷的重復。具體的由 DMA_CCR寄存器的 CIRC 循環模式位控制。

三、DMA初始化結構體?
結構體 xxx_InitTypeDef 定義在stm32f10x_xxx.h(后面xxx為外設名稱)文件中,庫函數xxx_Init定義在stm32f10x_xxx.c文件中。

DMA_ InitTypeDef 初始化結構體 1 typedef struct 2 { 3 uint32_t DMA_PeripheralBaseAddr; // 外設地址 4 uint32_t DMA_MemoryBaseAddr; // 存儲器地址 5 uint32_t DMA_DIR; // 傳輸方向 6 uint32_t DMA_BufferSize; // 傳輸數目 7 uint32_t DMA_PeripheralInc; // 外設地址增量模式 8 uint32_t DMA_MemoryInc; // 存儲器地址增量模式 9 uint32_t DMA_PeripheralDataSize; // 外設數據寬度 10 uint32_t DMA_MemoryDataSize; // 存儲器數據寬度 11 uint32_t DMA_Mode; // 模式選擇 12 uint32_t DMA_Priority; // 通道優先級 13 uint32_t DMA_M2M; // 存儲器到存儲器模式 14 } DMA_InitTypeDef;

1) DMA_PeripheralBaseAddr:外設地址,設定 DMA_CPAR 寄存器的值;一般設置為外設的數據寄存器地址,如果是存儲器到存儲器模式則設置為其中一個存儲器地址。?
2) DMA_Memory0BaseAddr:存儲器地址,設定 DMA_CMAR 寄存器值;一般設置為我們自定義存儲區的首地址。?
3) DMA_DIR:傳輸方向選擇,可選外設到存儲器、存儲器到外設。它設定DMA_CCR 寄存器的 DIR[1:0]位的值。這里并沒有存儲器到存儲器的方向選擇,當使用存儲器到存儲器時,只需要把其中一個存儲器當作外設使用即可。?
4) DMA_BufferSize:設定待傳輸數據數目,初始化設定 DMA_CNDTR 寄存器的值。?
5) DMA_PeripheralInc:如果配置為 DMA_PeripheralInc_Enable,使能外設地址自動遞增功能,它設定 DMA_CCR 寄存器的 PINC 位的值;一般外設都是只有一個數據寄存器,所以一般不會使能該位。?
6) DMA_MemoryInc:如果配置為DMA_MemoryInc_Enable,使能存儲器地址自動遞增功能,它設定 DMA_CCR 寄存器的 MINC 位的值;我們自定義的存儲區一般都是存放多個數據的,所以要使能存儲器地址自動遞增功能。?
7) DMA_PeripheralDataSize:外設數據寬度,可選字節(8位)、半字(16位)和字(32位),它設定 DMA_CCR寄存器的 PSIZE[1:0]位的值。?
8) DMA_MemoryDataSize:存儲器數據寬度,可選字節(8 位)、半字(16 位)和字(32位),它設定 DMA_CCR 寄存器的 MSIZE[1:0]位的值。當外設和存儲器之間傳數據時,兩邊的數據寬度應該設置為一致大小。?
9) DMA_Mode:DMA 傳輸模式選擇,可選一次傳輸或者循環傳輸,它設定DMA_CCR 寄存器的 CIRC 位的值。例程我們的 ADC 采集是持續循環進行的,所以使用循環傳輸模式。?
10) DMA_Priority:軟件設置通道的優先級,有 4 個可選優先級分別為非常高、高、中和低,它設定 DMA_CCR 寄存器的 PL[1:0]位的值。DMA 通道優先級只有在多個 DMA 通道同時使用時才有意義,如果是單個通道,優先級可以隨便設置。?
11) DMA_M2M:存儲器到存儲器模式,使用存儲器到存儲器時用到,設定DMA_CCR 的位 14MEN2MEN 即可啟動存儲器到存儲器模式。


四、存儲器到存儲器的實驗?
先定義一個靜態的源數據,存放在內部Flash存儲器中,使用DMA傳輸,把源數據拷貝到目標地址上(內部SRAM),最后對比源數據和目標地址的數據,看看是否準確傳輸。?
1、思路要點?
1)使能DMA時鐘?
2)配置DMA數據參數?
3)使能DMA,進行傳輸?
4)等待傳輸完成,并對源數據和目標地址數據進行比較。?
2、DMA宏定義以及變量定義

1 // 當使用存儲器到存儲器模式時候,通道可以隨便選,沒有硬性的規定 2 #define DMA_CHANNEL DMA1_Channel6 3 #define DMA_CLOCK RCC_AHBPeriph_DMA1 4 5 // 傳輸完成標志 6 #define DMA_FLAG_TC DMA1_FLAG_TC6 7 8 // 要發送的數據大小 9 #define BUFFER_SIZE 32 10 11 /* 定義 aSRC_Const_Buffer 數組作為 DMA 傳輸數據源 12 * const 關鍵字將 aSRC_Const_Buffer 數組變量定義為常量類型 13 * 表示數據存儲在內部的 FLASH 中 14 */ 15 const uint32_t aSRC_Const_Buffer[BUFFER_SIZE]= 16 { 17 0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10, 18 0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20, 19 0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30, 20 0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40, 21 0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50, 22 0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60, 23 0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70, 24 0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80 25 }; 26 /* 定義 DMA 傳輸目標存儲器 27 * 存儲在內部的 SRAM 中 28 */ 29 uint32_t aDST_Buffer[BUFFER_SIZE];

aSRC_Const_Buffer[BUFFER_SIZE]定義用來存放源數據,并且使用了const關鍵字修飾,即常量類型,使得變量存儲在內部Flash空間上。

3、DMA數據配置

void DMA_Config(void) 2 { 3 DMA_InitTypeDef DMA_InitStructure; 4 5 // 開啟 DMA 時鐘 6 RCC_AHBPeriphClockCmd(DMA_CLOCK, ENABLE); 7 // 源數據地址 8 DMA_InitStructure.DMA_PeripheralBaseAddr = 9 (uint32_t)aSRC_Const_Buffer; 10 // 目標地址 11 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)aDST_Buffer; 12 // 方向:外設到存儲器(這里的外設是內部的 FLASH) 13 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 14 // 傳輸大小 15 DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE; 16 // 外設(內部的 FLASH)地址遞增 17 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; 18 // 內存地址遞增 19 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 20 // 外設數據單位 21 DMA_InitStructure.DMA_PeripheralDataSize = 22 DMA_PeripheralDataSize_Word; 23 // 內存數據單位 24 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; 25 // DMA 模式,一次或者循環模式 26 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ; 27 //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 28 // 優先級:高 29 DMA_InitStructure.DMA_Priority = DMA_Priority_High; 30 // 使能內存到內存的傳輸 31 DMA_InitStructure.DMA_M2M = DMA_M2M_Enable; 32 // 配置 DMA 通道 33 DMA_Init(DMA_CHANNEL, &DMA_InitStructure); 34 // 使能 DMA 35 DMA_Cmd(DMA_CHANNEL,ENABLE); 36 }

使用 DMA_InitTypeDef 結構體定義一個 DMA 初始化變量,這個結構體內容我們之前已經有詳細講解。?
調用 RCC_AHBPeriphClockCmd 函數開啟 DMA時鐘,使用 DMA控制器之前必須開啟對應的時鐘。?
源地址和目標地址使用之前定義的數組首地址,傳輸的數據量為宏 BUFFER_SIZE 決定,源和目標地址指針地址遞增,使用一次傳輸模式不能循環傳輸,因為只有一個 DMA通道,優先級隨便設置,最后調用 DMA_Init 函數完成 DMA 的初始化配置。?
DMA_ClearFlag函數用于清除DMA標志位,代碼用到傳輸完成標志位,使用之前先清除傳輸完成標志位以免產生不必要干擾。DMA_ClearFlag 函數需要 1 個形參,即事件標志位,可選有傳輸完成標志位、半傳輸標志位、FIFO 錯誤標志位、傳輸錯誤標志位等等,非常多,我們這里選擇傳輸完成標志位,由宏 DMA_FLAG_TC 定義。?
DMA_Cmd 函數用于啟動或者停止 DMA 數據傳輸,它接收兩個參數,第一個是 DMA通道,另外一個是開啟 ENABLE 或者停止 DISABLE。

4、存儲器數據對比

1 uint8_t Buffercmp(const uint32_t* pBuffer, 2 uint32_t* pBuffer1, uint16_t BufferLength) 3 { 4 /* 數據長度遞減 */ 5 while (BufferLength--) { 6 /* 判斷兩個數據源是否對應相等 */ 7 if (*pBuffer != *pBuffer1) { 8 /* 對應數據源不相等馬上退出函數,并返回 0 */ 9 return 0; 10 } 11 /* 遞增兩個數據源的地址指針 */ 12 pBuffer++; 13 pBuffer1++; 14 } 15 /* 完成判斷并且對應數據相對 */ 16 return 1; 17 }

判斷指定長度的兩個數據源是否完全相等,如果完全相等返回 1;只要其中一對數據不相等返回 0。它需要三個形參,前兩個是兩個數據源的地址,第三個是要比較數據長度。?
5、main函數

1 int main(void) 2 { 3 /* 定義存放比較結果變量 */ 4 uint8_t TransferStatus; 5 6 /* LED 端口初始化 */ 7 LED_GPIO_Config(); 8 9 /* 設置 RGB 彩色燈為紫色 */ 10 LED_PURPLE; 11 12 /* 簡單延時函數 */ 13 Delay(0xFFFFFF); 14 15 /* DMA 傳輸配置 */ 16 DMA_Config(); 17 18 /* 等待 DMA 傳輸完成 */ 19 while (DMA_GetFlagStatus(DMA_FLAG_TC)==RESET) 20 { 21 22 } 23 24 /* 比較源數據與傳輸后數據 */ 25 TransferStatus=Buffercmp(aSRC_Const_Buffer, aDST_Buffer, BUFFER_SIZE); 26 27 /* 判斷源數據與傳輸后數據比較結果*/ 28 if (TransferStatus==0) 29 { 30 /* 源數據與傳輸后數據不相等時 RGB 彩色燈顯示紅色 */ 31 LED_RED; 32 } 33 else 34 { 35 /* 源數據與傳輸后數據相等時 RGB 彩色燈顯示藍色 */ 36 LED_BLUE; 37 } 38 39 while (1) 40 { 41 } 42 }

首先定義一個變量用來保存存儲器數據比較結果。?
RGB 彩色燈用來指示程序進程,使用之前需要初始化它,LED_GPIO_Config 定義在bsp_led.c 文件中。開始設置 RGB 彩色燈為紫色,LED_PURPLE 是定義在 bsp_led.h 文件的一個宏定義。?
Delay函數只是一個簡單的延時函數。?
調用 DMA_Config 函數完成 DMA 數據流配置并啟動 DMA 數據傳輸。?
DMA_GetFlagStatus 函數獲取 DMA 事件標志位的當前狀態,這里獲取 DMA 數據傳輸完成這個標志位,使用循環持續等待直到該標志位被置位,即 DMA 傳輸完成這個事件發生,然后退出循環,運行之后程序。?
確定 DMA 傳輸完成之后就可以調用 Buffercmp 函數比較源數據與 DMA 傳輸后目標地址的數據是否一一對應。TransferStatus 保存比較結果,如果為 1 表示兩個數據源一一對應相等說明 DMA 傳輸成功;相反,如果為 0 表示兩個數據源數據存在不等情況,說明 DMA傳輸出錯。?
如果 DMA傳輸成功設置 RGB彩色燈為藍色,如果 DMA傳輸出錯設置 RGB彩色燈為紅色。

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的STM32系统学习——DMA(直接储存器访问)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。