前言
????????本篇博客主要學習了解DMA的工作原理和部分寄存器解析,針對ADC多通道來對代碼部分,應用部分作詳細講解,掌握代碼編程原理。本篇博客大部分是自己收集和整理,如有侵權請聯系我刪除。
本次博客開發板使用的是正點原子精英版,芯片是STM32F103ZET6,需要資料可以@我拿取。
交流群:717237739
本博客內容原創,創作不易,轉載請注明
————————————————
一 . DMA的基本介紹
- DMA(Direct Memory Access)直接存儲器存取
- DMA可以提供外設和存儲器或者存儲器和存儲器之間的高速數據傳輸,無須CPU干預,節省了CPU的資源
- DMA傳輸將數據從一個地址空間復制到另一個地址空間。當CPU初始化這個傳輸動作,傳輸動作本身是由DMA控制器來實現和完成的。
- DMA傳輸方式無需CPU直接控制傳輸,也沒有中斷處理方式那樣保留現場和恢復現場過程,通過硬件為RAM和IO設備開辟一條直接傳輸數據的通道,使得CPU的效率大大提高。
作用:為CPU減負。
因此:轉移數據(尤其是轉移大量數據)是可以不需要CPU參與。比如希望外設A的數據拷貝到外設B,只要給兩種外設提供一條數據通路,直接讓數據由A拷貝到B 不經過CPU的處理,
二 . DMA的特性
- 12個獨立的可配置的通道(請求):DMA1有7個通道,DMA2有5個通道
- 每個通道都直接連接專用的硬件DMA請求,每個通道都同樣支持軟件觸發。這些功能通過軟件來配置。
- 在同一個DMA模塊上,多個請求間的優先權可以通過軟件編程設置(共有四級:很高、高、中等和低),優先權設置相等時由硬件決定(請求0優先于請求1,依此類推) 。
? ? ? ? 在相等的優先級下,DMA1通道2的優先級是 大于 DMA1通道4,通道越低優先級越高。
- 獨立數據源和目標數據區的?傳輸寬度(字節、半字、全字)?,模擬打包和拆包的過程。源和目標地址必須按數據傳輸寬度對齊。
- 支持循環的緩沖器管理
- 每個通道都有3個事件標志(DMA半傳輸、DMA傳輸完成和DMA傳輸出錯),這3個事件標志
- 邏輯或成為一個單獨的中斷請求。
- 存儲器和存儲器間的傳輸
- 外設和存儲器、存儲器和外設之間的傳輸
- 閃存、SRAM、外設的SRAM、APB1、APB2和AHB外設均可作為訪問的源和目標。
- 可編程的數據傳輸數目:最大為65535
三. 存儲器映像
四 . DMA功能框圖?
1.功能描述
?2.DMA仲裁器
3.DMA通道?
1.DMA1 控制器?
2.DMA 1 各通道一覽:
3.DMA 2 控制器
4.DMA 2 各通道一覽:
5.DMA傳輸方式
????????DMA的作用就是實現數據的直接傳輸,而去掉了傳統數據傳輸需要CPU寄存器參與的環節,主要涉及四種情況的數據傳輸,但本質上是一樣的,都是從內存的某一區域傳輸到內存的另一區域(外設的數據寄存器本質上就是內存的一個存儲單元)。四種情況的數據傳輸如下:
- 外設到內存
- 內存到外設
- 內存到內存
- 外設到外設
6 .DMA傳輸參數
??我們知道,數據傳輸,首先需要的是
1 數據的源地址
2 數據傳輸位置的目標地址
3 傳遞數據多少的數據傳輸量
4 進行多少次傳輸的傳輸模式 DMA所需要的核心參數
????????當用戶將參數設置好,主要涉及源地址、目標地址、傳輸數據量這三個,DMA控制器就會啟動數據傳輸,當剩余傳輸數據量為0時 達到傳輸終點,結束DMA傳輸 ,當然,DMA 還有循環傳輸模式 當到達傳輸終點時會重新啟動DMA傳輸。
也就是說只要剩余傳輸數據量不是0,而且DMA是啟動狀態,那么就會發生數據傳輸。
6.?stm32中DMA的circle和normal模式的區別
?
在STM32系列微控制器上,DMA(Direct Memory Access,直接內存訪問)是一種用于高效數據傳輸的重要功能。DMA的Circle(循環)模式和Normal(普通)模式是兩種常見的DMA傳輸模式,它們在數據傳輸方面有一些區別。
Circle(循環)模式:
- 在Circle模式下,DMA傳輸可以循環執行,即在完成一次傳輸后會自動重新開始下一次傳輸,形成一個循環。這種模式適用于需要連續、循環傳輸數據的場景。
- 在循環模式下,DMA傳輸會持續不斷地從源地址讀取數據,并將數據寫入目標地址,直到達到設定的傳輸長度或觸發停止條件。
- 循環模式下的DMA傳輸通常用于周期性的數據傳輸,如音頻、視頻流等連續數據流的傳輸。
Normal(普通)模式:
- 在Normal模式下,DMA傳輸只會執行一次,傳輸完畢后就會停止。這種模式適用于單次數據傳輸的場景。
- 在普通模式下,DMA傳輸會從源地址讀取數據,并將數據寫入目標地址,直到達到設定的傳輸長度或觸發停止條件,然后傳輸停止。
- 普通模式下的DMA傳輸適用于需要一次性傳輸數據的情況,如初始化數據、配置信息等。
需要注意的是,循環模式和普通模式都可以設置傳輸長度、源地址和目標地址等參數,區別主要在于傳輸的執行方式和傳輸結束后是否重新開始。
在使用DMA時,需要根據具體的應用需求選擇適合的模式。
如果需要連續、循環傳輸數據,可以選擇循環模式;
如果只需進行單次傳輸,可以選擇普通模式。
同時,還需要注意設置適當的傳輸長度和停止條件,以確保傳輸的準確性和可靠性。
?
五 . DMA 的配置和應用
1.DMA運作過程圖解:
下面看有與沒有DMA的情況下,ADC采集的數據是怎樣存放到SRAM中的?
沒有DMA
1.如果沒有DMA,CPU傳輸數據還要以內核作為中轉站,比如要將ADC采集的數據轉移到到SRAM中,這個過程是這樣的:
內核通過DCode經過總線矩陣協調,從獲取AHB存儲的外設ADC采集的數據,
然后內核再通過DCode經過總線矩陣協調把數據存放到內存SRAM中。
?
參考博客鏈接:https://blog.csdn.net/as480133937/article/details/104927922
2.DMA數據流(僅存在于STM32F4 /M4 內核上)了解即可
在設置了DMA的通道之后,還要選擇通道對應外設的數據流
3.指針增量
存儲器到存儲器:源和目標的指針都需要設置為增量模式
存儲器到外設: 存儲器地址設置為增量模式,外設地址設置為非增量模式。
4.通道配置過程:
0 .開啟DMA時鐘
1. 在DMA_CPARx寄存器中設置外設寄存器的地址。發生外設數據傳輸請求時,這個地址將
是數據傳輸的源或目標。
2. 在DMA_CMARx寄存器中設置數據存儲器的地址。發生外設數據傳輸請求時,傳輸的數
據將從這個地址讀出或寫入這個地址。
3. 在DMA_CNDTRx寄存器中設置要傳輸的數據量。在每個數據傳輸后,這個數值遞減。
4. 在DMA_CCRx寄存器的PL[1:0]位中設置通道的優先級。
5. 在DMA_CCRx寄存器中設置數據傳輸的方向、循環模式、外設和存儲器的增量模式、外
設和存儲器的數據寬度。?---CCRX寄存器
6. 設置DMA_CCRx寄存器的ENABLE位,啟動該通道。
5 .DMA中斷
?每個DMA通道都可以在DMA傳輸過半、傳輸完成和傳輸錯誤時產生中斷。為應用的靈活性考慮,通過設置寄存器的不同位來打開這些中斷。
?六. DMA配置過程
這個部分我們結合ADC來進行講解使用:
DMA配置參數包括:通道地址、優先級、數據傳輸方向、存儲器/外設數據寬度、存儲器/外設地址是否增量、循環模式、數據傳輸量。
?ADC+DMA多通道框圖:
ADC詳解在另一個博客:ADC 講解
配置初始化代碼:
#include "stm32f10x.h" // Device headeruint16_t AD_Value[4];void AD_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//開啟對應通道ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在獨立模式ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //數據右對齊ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//轉換由軟件而不是外部觸發啟動ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模數轉換工作在循環轉換模式ADC_InitStructure.ADC_ScanConvMode = ENABLE; //模數轉換工作在多通道模式ADC_InitStructure.ADC_NbrOfChannel = 4; //順序進行規則轉換的ADC通道的數目ADC_Init(ADC1, &ADC_InitStructure); //根據ADC_InitStruct中指定的參數初始化外設ADCx的寄存器 DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; // ADC- DMA外設基地址DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //半字傳輸,數據寬度為16位DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外設地址不自增DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value; //存儲器數據存儲地址 數組DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //半字傳輸,數據寬度為16位DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存儲器內存地址寄存器遞增DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //數據傳輸方向,從外設讀取發送到存儲器DMA_InitStructure.DMA_BufferSize = 4; //掃描通道:4個DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循環模式DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x沒有設置為內存到內存傳輸DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x擁有中優先級 DMA_Init(DMA1_Channel1, &DMA_InitStructure);DMA_Cmd(DMA1_Channel1, ENABLE); //使能DMAADC_DMACmd(ADC1, ENABLE); //使能ADC_DMA傳輸ADC_Cmd(ADC1, ENABLE); //使能ADCADC_ResetCalibration(ADC1); //使能復位校準 while (ADC_GetResetCalibrationStatus(ADC1) == SET); //等待復位校準結束ADC_StartCalibration(ADC1); //開啟AD校準while (ADC_GetCalibrationStatus(ADC1) == SET); //等待校準結束ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的軟件轉換啟動功能
}
?庫函數講解,摘自群友的筆記:
?
總結:
? ? ? DMA的使用并不復雜,搞清楚數據的方向,還是是否自增就行了,多使用多實踐,大家如果對我的博客有疑問或者錯誤,可以@我修改,大家相互交流。
交流群:717237739
如果覺得有用點贊關注收藏三連,多謝支持
? 點贊收藏關注博主,不定期分享單片機知識,互相學習交流。
————————————————