STM32—DMA存儲器到外設(shè)

DMA簡介

DMA(Direct Memory Access)——直接存儲器存取,就像其名稱一樣,DMA的主要作用是搬數(shù)據(jù),DMA可以把數(shù)據(jù)從存儲器搬到外設(shè)铃在、從外設(shè)搬到存儲器、從存儲器搬到存儲器碍遍。DMA的特殊之處就是搬運(yùn)數(shù)據(jù)==不需要占用CPU==,DMA控制器包含了DMA1和DMA2阳液,其中DMA1由7個通道怕敬,DMA2有5個通道。

DMA框圖

了解外設(shè)先要理解其工作框圖:

在這里插入圖片描述

功能框圖主要分為三部分:
1.DMA請求
外設(shè)如果想要通過DMA傳輸數(shù)據(jù)帘皿,必先給DMA控制器發(fā)送DMA請求东跪,DMA收到請求信號之后會傳回給外設(shè)一個應(yīng)答信號,當(dāng)外設(shè)應(yīng)答后且DMA控制器收到應(yīng)答信號后鹰溜,就會啟動DMA的傳輸虽填,直至傳輸完畢。但DMA有2個DMA控制器曹动,15條通道斋日,不同的通道對應(yīng)著不同的外設(shè)請求,所以必須對通道和外設(shè)請求進(jìn)行一一對口墓陈,各個通道對應(yīng)的外設(shè)如下:
在這里插入圖片描述

2.通道
要注意的是DMA共有12個獨(dú)立可編程的通道恶守,DMA1有7個第献、DMA2有5個,每個通道對應(yīng)著不同的外設(shè)的請求兔港,但同一時間只能接收一個庸毫。
3.仲裁器
當(dāng)多個通道同時請求時,就要處理先后響應(yīng)的問題衫樊,就像中斷里的優(yōu)先級分組一樣飒赃。仲裁器管理DMA通道請求時主要依據(jù)倆點(diǎn):
第一判斷:在DMA_CCRx 寄存器中設(shè)置有 4 個等級:非常高、高科侈、中和低载佳,先根據(jù)此優(yōu)先級判斷響應(yīng)的先后,如果優(yōu)先級都一樣兑徘,進(jìn)行第二判斷刚盈。
第二判斷:比較通道的編號,編號越低優(yōu)先權(quán)越高挂脑。

DMA傳輸數(shù)據(jù)分析

使用DMA藕漱,核心技術(shù)就是配置數(shù)據(jù)的傳輸崭闲,主要分為三點(diǎn):
==1.傳輸?shù)姆较?br> 2.傳輸?shù)臄?shù)量
3.傳輸?shù)哪J?=

1.傳輸?shù)姆较?/h3>

DMA有三種數(shù)據(jù)傳輸方向:
一:存儲器——>外設(shè)
當(dāng)我們使用從存儲器到外設(shè)傳輸時刁俭,以串口向電腦端發(fā)送數(shù)據(jù)為例牍戚。 DMA 外設(shè)寄存器的地址對應(yīng)的就是串口數(shù)據(jù)寄存器的地址, DMA 存儲器的地址就是我們自定義的變量(相當(dāng)于一個緩沖區(qū)宪哩,用來存儲通過串口發(fā)送到電腦的數(shù)據(jù))的地址锁孟。方向我們設(shè)置外設(shè)為目
標(biāo)地址茁瘦。
二:外設(shè)——>存儲器
當(dāng)我們使用從外設(shè)到存儲器傳輸時甜熔,以 ADC 采集為例纺非。 DMA 外設(shè)寄存器的地址對應(yīng)的就是 ADC 數(shù)據(jù)寄存器的地址赘方, DMA 存儲器的地址就是我們自定義的變量(用來接收存儲 AD 采集的數(shù)據(jù))的地址窄陡。方向我們設(shè)置外設(shè)為源地址跳夭。
三:存儲器——>存儲器
當(dāng)我們使用從存儲器到存儲器傳輸時币叹,以內(nèi)部 FLASH 向內(nèi)部 SRAM 復(fù)制數(shù)據(jù)為例颈抚。DMA 外設(shè)寄存器的地址對應(yīng)的就是內(nèi)部 FLASH(我們這里把內(nèi)部 FALSH 當(dāng)作一個外設(shè)來看)的地址贩汉, DMA 存儲器的地址就是我們自定義的變量(相當(dāng)于一個緩沖區(qū)锚赤,用來存儲來自內(nèi)部 FLASH 的數(shù)據(jù))的地址线脚。方向我們設(shè)置外設(shè)(即內(nèi)部 FLASH)為源地址浑侥。跟上面兩個不一樣的是,這里需要把 DMA_CCR 位 14: MEM2MEM:存儲器到存儲器模式配
置為 1蠢莺,啟動 M2M 模式。

2.傳輸?shù)臄?shù)量

以串口向電腦發(fā)送數(shù)據(jù)為例考蕾,我們可以一次性給電腦發(fā)送很多數(shù)據(jù)肖卧,具體多少由==DMA_CNDTR== 配置掸鹅,這是一個 32 位的寄存器,一次最多只能傳輸 65535 個數(shù)據(jù)荷鼠。而且源和目標(biāo)的數(shù)據(jù)寬度必須一致榔幸,數(shù)據(jù)寬度可以設(shè)置為8/16/32位削咆。
除此之外拨齐,還要設(shè)置源和目標(biāo)倆邊==數(shù)據(jù)指針的增量模式== ,即傳輸完一個數(shù)據(jù)后數(shù)據(jù)指針的移動模式厦滤,是加一馁害?還是不變蹂匹?以串口向電腦發(fā)送數(shù)據(jù)為例限寞,要發(fā)送的數(shù)據(jù)很多履植,每發(fā)送完一個玫霎,那么存儲器的地址指針就應(yīng)該加 1庶近,而串口數(shù)據(jù)寄存器只有一個,那么外設(shè)的地址指針就固定不變反番。

3.傳輸?shù)哪J?/h3>

數(shù)據(jù)傳輸?shù)那闆r可以通過查詢標(biāo)志位或者通過中斷來鑒別篙贸,每個DMA通道在DMA傳輸過半爵川、傳輸完成雁芙、傳輸錯誤時都會有相應(yīng)的標(biāo)志位兔甘,如果使能相關(guān)的中斷后還會產(chǎn)生中斷洞焙。一次數(shù)據(jù)傳輸完成后還分倆種模式:是一次傳輸還是循環(huán)傳輸澡匪。
一次傳輸: 傳輸一次后就停止褒链,要想再傳的話甸鸟,必須關(guān)閉DMA使能后重新配置后方能繼續(xù)傳輸兵迅。
循環(huán)傳輸: 一次傳輸完成后又恢復(fù)第一次傳輸時的配置循環(huán)傳輸抢韭,不斷重復(fù)。

代碼部分

編程要點(diǎn):
1.配置USART通信功能
2.設(shè)置DMA工作參數(shù)
3.使能DMA

DMA初始化結(jié)構(gòu)體

固件庫編程中對一個外設(shè)的操作主要通過配置外設(shè)的初始化結(jié)構(gòu)體來完成恍箭,雖然最終操作的是寄存器刻恭,但相比較寄存器,還是采用庫函數(shù)比較方便扯夭。

 typedef struct
 {
 uint32_t DMA_PeripheralBaseAddr; // 外設(shè)地址
 uint32_t DMA_MemoryBaseAddr; // 存儲器地址
 uint32_t DMA_DIR; // 傳輸方向
 uint32_t DMA_BufferSize; // 傳輸數(shù)目
 uint32_t DMA_PeripheralInc; // 外設(shè)地址增量模式
 uint32_t DMA_MemoryInc; // 存儲器地址增量模式
 uint32_t DMA_PeripheralDataSize; // 外設(shè)數(shù)據(jù)寬度
 uint32_t DMA_MemoryDataSize; // 存儲器數(shù)據(jù)寬度
 uint32_t DMA_Mode; // 模式選擇
 uint32_t DMA_Priority; // 通道優(yōu)先級
 uint32_t DMA_M2M; // 存儲器到存儲器模式
 } DMA_InitTypeDef;

下面利用《零死角玩轉(zhuǎn) STM32F103》的話介紹一下結(jié)構(gòu)體成員:
==1.DMA_PeripheralBaseAddr==:外設(shè)地址鳍贾,設(shè)定 DMA_CPAR 寄存器的值;一般設(shè)置為外設(shè)的數(shù)據(jù)寄存器地址交洗,如果是存儲器到存儲器模式則設(shè)置為其中一個存儲器地址贾漏。

== 2.DMA_Memory0BaseAddr == : 存儲器地址,設(shè)定 DMA_CMAR 寄存器值藕筋;一般設(shè)置為我們自定義存儲區(qū)的首地址。零死角玩轉(zhuǎn) STM32F103—MINI

==3.DMA_DIR==:傳輸方向選擇,可選外設(shè)到存儲器隐圾、存儲器到外設(shè)。它設(shè)定
DMA_CCR 寄存器的 DIR[1:0]位的值。這里并沒有存儲器到存儲器的方向選擇,
當(dāng)使用存儲器到存儲器時,只需要把其中一個存儲器當(dāng)作外設(shè)使用即可。

==4. DMA_BufferSize==:設(shè)定待傳輸數(shù)據(jù)數(shù)目,初始化設(shè)定 DMA_CNDTR 寄存器的值。

==5. DMA_PeripheralInc==:如果配置為 DMA_PeripheralInc_Enable,使能外設(shè)地址自動遞增功能,它設(shè)定 DMA_CCR 寄存器的 PINC 位的值;一般外設(shè)都是只有一個數(shù)據(jù)寄存器,所以一般不會使能該位。

==6. DMA_MemoryInc==:如果配置為 DMA_MemoryInc_Enable,使能存儲器地址自動遞增功能,它設(shè)定 DMA_CCR 寄存器的 MINC 位的值;我們自定義的存儲區(qū)一般都是存放多個數(shù)據(jù)的,所以要使能存儲器地址自動遞增功能。

==7.DMA_PeripheralDataSize==:外設(shè)數(shù)據(jù)寬度哥捕,可選字節(jié)(8 位)凫佛、半字(16 位)和字(32位),它設(shè)定 DMA_CCR 寄存器的 PSIZE[1:0]位的值瓮栗。

==8. DMA_MemoryDataSize==:存儲器數(shù)據(jù)寬度,可選字節(jié)(8 位)以蕴、半字(16 位)和字(32位),它設(shè)定 DMA_CCR 寄存器的 MSIZE[1:0]位的值。當(dāng)外設(shè)和存儲器之間傳數(shù)據(jù)時搞疗,兩邊的數(shù)據(jù)寬度應(yīng)該設(shè)置為一致大小泄隔。

==9. DMA_Mode==: DMA 傳輸模式選擇暖呕,可選一次傳輸或者循環(huán)傳輸湾揽,它設(shè)定
DMA_CCR 寄存器的 CIRC 位的值。例程我們的 ADC 采集是持續(xù)循環(huán)進(jìn)行的葱淳,所
以使用循環(huán)傳輸模式钝腺。

==10.DMA_Priority==:軟件設(shè)置通道的優(yōu)先級毫目,有 4 個可選優(yōu)先級分別為非常高、高、中和低掂名,它設(shè)定 DMA_CCR 寄存器的 PL[1:0]位的值。 DMA 通道優(yōu)先級只有在多個 DMA 通道同時使用時才有意義雳窟,如果是單個通道尊浪,優(yōu)先級可以隨便設(shè)置。

==11. DMA_M2M == :存 儲器 到存 儲器 模式 封救,使 用存儲 器到 存儲 器時 用到拇涤, 設(shè)定DMA_CCR 的位 14 MEN2MEN 即可啟動存儲器到存儲器模式。

USART配置函數(shù)

此代碼結(jié)合串口通信章節(jié)內(nèi)容理解更佳誉结,此處不多于講解鹅士。USART配置詳解

void DEBUG_UART_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    
    /* 第一步:初始化GPIO */
        // 打開串口GPIO的時鐘
    DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
        // 將USART Tx的GPIO配置為推挽復(fù)用模式
    GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  // 將USART Rx的GPIO配置為浮空輸入模式
    GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);   
    
    /* 第二步:配置串口的初始化結(jié)構(gòu)體 */
        // 打開串口外設(shè)的時鐘
    DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
    // 配置串口的工作參數(shù)
    // 配置波特率
    USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
    // 配置 針數(shù)據(jù)字長
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    // 配置停止位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    // 配置校驗位
    USART_InitStructure.USART_Parity = USART_Parity_No ;
    // 配置硬件流控制
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    // 配置工作模式,收發(fā)一起
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    // 完成串口的初始化配置
    USART_Init(DEBUG_USARTx, &USART_InitStructure);

    /* 第三步:使能串口 */  
        // 使能串口
    USART_Cmd(DEBUG_USARTx, ENABLE);    
}

DMA配置函數(shù)

此函數(shù)主要是打開==DMA外設(shè)時鐘惩坑、配置DMA初始化結(jié)構(gòu)體掉盅、使能DMA通道==

// 串口對應(yīng)的DMA請求通道
#define  USART_TX_DMA_CHANNEL     DMA1_Channel4
// 外設(shè)寄存器地址也拜,USART1的數(shù)據(jù)寄存器地址(數(shù)據(jù)寄存器包含USART將發(fā)送或接收的數(shù)據(jù))
#define  USART_DR_ADDRESS        (USART1_BASE+0x04)
// 一次發(fā)送的數(shù)據(jù)量
#define  SENDBUFF_SIZE            5000

uint8_t SendBuff[SENDBUFF_SIZE];
/* 定義的數(shù)組就存儲在存儲器SRAM中 */


void USARTx_DMA_Config(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
       // 設(shè)置DMA源地址:串口數(shù)據(jù)寄存器地址*/
       DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;
        // 內(nèi)存地址(要傳輸?shù)淖兞康闹羔?
        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
        // 方向:從內(nèi)存到外設(shè)    
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
        // 傳輸大小 
        DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
        // 外設(shè)地址不增       
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        // 內(nèi)存地址自增
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        // 外設(shè)數(shù)據(jù)單位   
        DMA_InitStructure.DMA_PeripheralDataSize =  DMA_PeripheralDataSize_Byte;
        // 內(nèi)存數(shù)據(jù)單位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;  
        // DMA模式,一次或者循環(huán)模式
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
        //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;   
        // 優(yōu)先級:中    
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; 
        // 禁止內(nèi)存到內(nèi)存的傳輸
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        // 配置DMA通道         
        DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure);     
        // 使能DMA
        DMA_Cmd (USART_TX_DMA_CHANNEL,ENABLE);
}

主函數(shù)

int main(void)
{
    uint32_t i;
    
    
    DEBUG_UART_Config();    
    USARTx_DMA_Config();
    
      /*填充將要發(fā)送的數(shù)據(jù)*/
  for(i=0;i<SENDBUFF_SIZE;i++)
  {
    SendBuff[i]  = 'P';    
  }
   /* USART1向DMA發(fā)出請求 */
    USART_DMACmd(DEBUG_USARTx, USART_DMAReq_Tx, ENABLE);

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末趾痘,一起剝皮案震驚了整個濱河市慢哈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌永票,老刑警劉巖卵贱,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異侣集,居然都是意外死亡艰赞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岳链,“玉大人浮还,你說我怎么就攤上這事∠侍模” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長斋泄。 經(jīng)常有香客問我,道長镐牺,這世上最難降的妖魔是什么炫掐? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮睬涧,結(jié)果婚禮上募胃,老公的妹妹穿的比我還像新娘。我一直安慰自己畦浓,他們只是感情好痹束,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著讶请,像睡著了一般祷嘶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上夺溢,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天论巍,我揣著相機(jī)與錄音,去河邊找鬼风响。 笑死嘉汰,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的钞诡。 我是一名探鬼主播郑现,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼湃崩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了接箫?” 一聲冷哼從身側(cè)響起攒读,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎辛友,沒想到半個月后薄扁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡废累,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年邓梅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邑滨。...
    茶點(diǎn)故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡日缨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掖看,到底是詐尸還是另有隱情匣距,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布哎壳,位于F島的核電站毅待,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏归榕。R本人自食惡果不足惜尸红,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望刹泄。 院中可真熱鬧外里,春花似錦、人聲如沸循签。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽县匠。三九已至风科,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乞旦,已是汗流浹背贼穆。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留兰粉,地道東北人故痊。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像玖姑,于是被迫代替她去往敵國和親愕秫。 傳聞我的和親對象是個殘疾皇子慨菱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容

  • # STM32之串口DMA接收不定長數(shù)據(jù) ## 引言 在使用stm32或者其他單片機(jī)的時候,會經(jīng)常使用到串口通訊戴甩,...
    杰杰T_T閱讀 532評論 0 0
  • 姓名:周崇杰 學(xué)號:16140120059 專業(yè):機(jī)械設(shè)計制造及其自動化 轉(zhuǎn)載自:http://blog.csd...
    CJbaby閱讀 3,484評論 0 3
  • 姓名:周崇杰 學(xué)號:16140120059 專業(yè):機(jī)械設(shè)計制造及其自動化 轉(zhuǎn)載自:http://blog.csd...
    CJbaby閱讀 4,699評論 0 5
  • ???本文主要介紹嵌入式系統(tǒng)的一些基礎(chǔ)知識符喝,希望對各位有幫助。 嵌入式系統(tǒng)基礎(chǔ) 1甜孤、嵌入式系統(tǒng)的定義 (1)定義:...
    OpenJetson閱讀 3,297評論 0 13
  • 簡介與特征 DMA:直接存儲器入口 高速運(yùn)輸协饲,無需CPU干預(yù)外設(shè)與存儲器存儲器之間 兩個DMADMA1:7通道DM...
    吳松乾閱讀 2,515評論 0 1