一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

STM32F1的DMA使用

科技綠洲 ? 來(lái)源:?jiǎn)纹瑱C(jī)與嵌入式 ? 作者:?jiǎn)纹瑱C(jī)與嵌入式 ? 2023-06-22 10:23 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

在前面我們提到過(guò) DMA,這一章我們就來(lái)學(xué)習(xí) STM32F1 的DMA 使

用。要實(shí)現(xiàn)的功能是:通過(guò) K_UP 按鍵控制 DMA 串口 1 數(shù)據(jù)的傳送,在傳送過(guò)程中讓 D2 指示燈不斷閃爍,直到數(shù)據(jù)傳送完成。D1 指示燈閃爍提示系統(tǒng)正常運(yùn)行。學(xué)習(xí)時(shí)可以參考《STM32F10x 中文參考手冊(cè)》-10 DMA 控制器(DMA)章節(jié)。

DMA 簡(jiǎn)介

DMA,全稱是 Direct Memory Access,中文意思為直接存儲(chǔ)器訪問(wèn)。DMA 可用于實(shí)現(xiàn)外設(shè)與存儲(chǔ)器之間或者存儲(chǔ)器與存儲(chǔ)器之間數(shù)據(jù)傳輸?shù)母咝?。之所以稱為高效, 是因?yàn)?DMA 傳輸數(shù)據(jù)移動(dòng)過(guò)程無(wú)需 CPU 直接操作, 這樣節(jié)省的 CPU 資源就可供其它操作使用。從硬件層面來(lái)理解,DMA 就好像是 RAM 與 I/O 設(shè)備間數(shù)據(jù)傳輸?shù)耐罚?外設(shè)與存儲(chǔ)器之間或者存儲(chǔ)器與存儲(chǔ)器之間可以直接在這條通路上進(jìn)行數(shù)據(jù)傳輸。這里說(shuō)的外設(shè)一般指外設(shè)的數(shù)據(jù)寄存器, 比如 ADC、SPI、I2C、DCMI等外設(shè)的數(shù)據(jù)寄存器, 存儲(chǔ)器一般是指片內(nèi) SRAM、 外部存儲(chǔ)器、 片內(nèi) Flash等。

STM32F1 最多有 2 個(gè) DMA 控制器 ( DMA2 僅存在大容量產(chǎn)品中) ,DMA17 個(gè)通道。DMA25 個(gè)通道。每個(gè)通道專門用來(lái)管理來(lái)自于一個(gè)或多個(gè)外設(shè)對(duì)存儲(chǔ)器訪問(wèn)的請(qǐng)求。還有一個(gè)仲裁器來(lái)協(xié)調(diào)各個(gè) DMA 請(qǐng)求的優(yōu)先權(quán)。

STM32F1 的 DMA 有以下主要特性:

● 12 個(gè)獨(dú)立的可配置的通道(請(qǐng)求):DMA1 有 7 個(gè)通道, DMA2 有 5 個(gè)通

● 每個(gè)通道都直接連接專用的硬件 DMA 請(qǐng)求,每個(gè)通道都同樣支持軟件觸

發(fā)。這些功能通過(guò)軟件來(lái)配置。

● 在同一個(gè) DMA 模塊上, 多個(gè)請(qǐng)求間的優(yōu)先權(quán)可以通過(guò)軟件編程設(shè)置(共有

四級(jí):很高、高、中等和低),優(yōu)先權(quán)設(shè)置相等時(shí)由硬件決定(請(qǐng)求 0 優(yōu)先于請(qǐng)求1,依此類推) 。

● 獨(dú)立數(shù)據(jù)源和目標(biāo)數(shù)據(jù)區(qū)的傳輸寬度(字節(jié)、半字、全字),模擬打包和拆包的過(guò)程。源和目標(biāo)地址必須按數(shù)據(jù)傳輸寬度對(duì)齊。

● 支持循環(huán)的緩沖器管理

● 每個(gè)通道都有 3 個(gè)事件標(biāo)志(DMA 半傳輸、 DMA 傳輸完成和 DMA 傳輸出錯(cuò)),這3 個(gè)事件標(biāo)志邏輯或成為一個(gè)單獨(dú)的中斷請(qǐng)求。

● 存儲(chǔ)器和存儲(chǔ)器間的傳輸

● 外設(shè)和存儲(chǔ)器、存儲(chǔ)器和外設(shè)之間的傳輸

● 閃存、 SRAM、外設(shè)的 SRAM、 APB1、 APB2 和 AHB 外設(shè)均可作為訪問(wèn)的源和目標(biāo)。

● 可編程的數(shù)據(jù)傳輸數(shù)目:最大為 65535

DMA 結(jié)構(gòu)框圖

DMA 控制器獨(dú)立于內(nèi)核,屬于一個(gè)單獨(dú)的外設(shè),結(jié)構(gòu)比較簡(jiǎn)單,從編程的角度來(lái)看,我們只需掌握結(jié)構(gòu)框圖中的三部分內(nèi)容即可。如圖所示(大家也可以查看《STM32F10x中文參考手冊(cè)》-10 DMA 控制器(DMA)章節(jié)內(nèi)容)。

圖片

我們把 DMA 結(jié)構(gòu)框圖分成3個(gè)子模塊,按照順序依次進(jìn)行簡(jiǎn)單介紹。

(1)標(biāo)號(hào) 1:DMA 請(qǐng)求

如果外設(shè)要想通過(guò) DMA 來(lái)傳輸數(shù)據(jù), 必須先給 DMA 控制器發(fā)送 DMA 請(qǐng)求,DMA 收到請(qǐng)求信號(hào)之后, 控制器會(huì)給外設(shè)一個(gè)應(yīng)答信號(hào), 當(dāng)外設(shè)應(yīng)答后且 DMA 控制器收到應(yīng)答信號(hào)之后,就會(huì)啟動(dòng) DMA 的傳輸,直到傳輸完畢。

根據(jù)前面介紹我們知道,DMA 含有 DMA1 和 DMA2 兩個(gè)控制器,其中 DMA1 含有 7個(gè)通道,DMA2 含有 5 個(gè)通道,不同的 DMA 控制器的通道對(duì)應(yīng)著不同的外設(shè)請(qǐng)求。

從DMA 請(qǐng)求映射圖中可以知道各通道所對(duì)應(yīng)的外設(shè)請(qǐng)求,如圖分別是DMA1和DMA2請(qǐng)求映射圖:

圖片

圖片

DMA2 請(qǐng)求通道中 ADC3、 SDIO 和 TIM8 的 DMA 請(qǐng)求只在大容量產(chǎn)品中存在,這個(gè)在具體項(xiàng)目時(shí)要注意。

(2)標(biāo)號(hào) 2:DAM 通道

DMA 具有 12 個(gè)獨(dú)立可編程的通道,其中 DMA17 個(gè)通道, DMA25個(gè)通道,每個(gè)通道對(duì)應(yīng)不同的外設(shè)的 DMA 請(qǐng)求。雖然每個(gè)通道可以接收多個(gè)外設(shè)的請(qǐng)求,但是同一時(shí)間只能接收一個(gè),不能同時(shí)接收多個(gè)。

(3)標(biāo)號(hào) 3:仲裁器

當(dāng)發(fā)生多個(gè) DMA 通道請(qǐng)求時(shí),就意味著有先后響應(yīng)處理的順序問(wèn)題,這個(gè)就由仲裁器也管理。仲裁器管理 DMA 通道請(qǐng)求分為兩個(gè)階段。第一階段屬于軟件階段,可以在 DMA_CCRx 寄存器中設(shè)置,有 4 個(gè)等級(jí):非常高、高、中和低四個(gè)優(yōu)先級(jí)。第二階段屬于硬件階段,如果兩個(gè)或以上的 DMA 通道請(qǐng)求設(shè)置的優(yōu)先級(jí)一樣,則他們優(yōu)先級(jí)取決于通道編號(hào),編號(hào)越低優(yōu)先權(quán)越高,比如通道 0高于通道 1。在大容量產(chǎn)品和互聯(lián)型產(chǎn)品中,DMA1 控制器擁有高于 DMA2 控制器的優(yōu)先級(jí)。

DMA 數(shù)據(jù)配置

使用 DMA, 最核心就是配置要傳輸?shù)臄?shù)據(jù), 包括數(shù)據(jù)從哪里來(lái), 要到哪里去,傳輸?shù)臄?shù)據(jù)的單位是什么,要傳多少數(shù)據(jù),是一次傳輸還是循環(huán)傳輸?shù)取?

(1)從哪里來(lái)到哪里去

我們知道 DMA 傳輸數(shù)據(jù)的方向有三個(gè):從外設(shè)到存儲(chǔ)器,從存儲(chǔ)器到外設(shè),從存儲(chǔ)器到存儲(chǔ)器。具體的方向 DMA_CCR 位 4 DIR 配置:0 表示從外設(shè)到存儲(chǔ)器, 1 表示從存儲(chǔ)器到外設(shè)。這里面涉及到的外設(shè)地址由 DMA_CPAR 配置,存儲(chǔ)器地址由 DMA_CMAR配置。

外設(shè)到存儲(chǔ)器

當(dāng)我們使用從外設(shè)到存儲(chǔ)器傳輸時(shí),以 ADC 采集為例。DMA 外設(shè)寄存器的地址對(duì)應(yīng)的就是 ADC 數(shù)據(jù)寄存器的地址,DMA 存儲(chǔ)器的地址就是我們自定義的變量(用來(lái)接收存儲(chǔ) AD 采集的數(shù)據(jù))的地址。方向我們?cè)O(shè)置外設(shè)為源地址。

存儲(chǔ)器到外設(shè)

當(dāng)我們使用從存儲(chǔ)器到外設(shè)傳輸時(shí), 以串口向電腦端發(fā)送數(shù)據(jù)為例。DMA 外設(shè)寄存器的地址對(duì)應(yīng)的就是串口數(shù)據(jù)寄存器的地址, DMA 存儲(chǔ)器的地址就是我們自定義的變量(相當(dāng)于一個(gè)緩沖區(qū),用來(lái)存儲(chǔ)通過(guò)串口發(fā)送到電腦的數(shù)據(jù))的地址。方向我們?cè)O(shè)置外設(shè)為目標(biāo)地址。

存儲(chǔ)器到存儲(chǔ)器

當(dāng)我們使用從存儲(chǔ)器到存儲(chǔ)器傳輸時(shí),以內(nèi)部 FLASH 向內(nèi)部 SRAM 復(fù)制數(shù)據(jù)為例。DMA 外設(shè)寄存器的地址對(duì)應(yīng)的就是內(nèi)部 FLASH(我們這里把內(nèi)部 FALSH當(dāng)作一個(gè)外設(shè)來(lái)看)的地址, DMA 存儲(chǔ)器的地址就是我們自定義的變量(相當(dāng)于一個(gè)緩沖區(qū),用來(lái)存儲(chǔ)來(lái)自內(nèi)部 FLASH 的數(shù)據(jù))的地址。方向我們?cè)O(shè)置外設(shè)(即內(nèi)部 FLASH)為源地址。跟上面兩個(gè)不一樣的是,這里需要把 DMA_CCR 位14:MEM2MEM:存儲(chǔ)器到存儲(chǔ)器模式配置為 1,啟動(dòng) M2M 模式。

(2)要傳多少,單位是什么

當(dāng)我們配置好數(shù)據(jù)要從哪里來(lái)到哪里去之后, 我們還需要知道我們要傳輸?shù)臄?shù)據(jù)是多少,數(shù)據(jù)的單位是什么。

以串口向電腦發(fā)送數(shù)據(jù)為例,我們可以一次性給電腦發(fā)送很多數(shù)據(jù),具體多少由 DMA_CNDTR 配置,這是一個(gè) 32 位的寄存器,一次最多只能傳輸 65535 個(gè)數(shù)據(jù)。

要想數(shù)據(jù)傳輸正確,源和目標(biāo)地址存儲(chǔ)的數(shù)據(jù)寬度還必須一致,串口數(shù)據(jù)寄存器是 8 位的,所以我們定義的要發(fā)送的數(shù)據(jù)也必須是 8 位。外設(shè)的數(shù)據(jù)寬度由 DMA_CCR 的 PSIZE[1:0]配置,可以是 8/16/32 位,存儲(chǔ)器的數(shù)據(jù)寬度由DMA_CCR 的 MSIZE[1:0]配置,可以是 8/16/32 位。

在 DMA 控制器的控制下,數(shù)據(jù)要想有條不紊的從一個(gè)地方搬到另外一個(gè)地方,還必須正確設(shè)置兩邊數(shù)據(jù)指針的增量模式。外設(shè)的地址指針由 DMA_CCRx 的PINC 配置,存儲(chǔ)器的地址指針由 MINC 配置。以串口向電腦發(fā)送數(shù)據(jù)為例,要發(fā)送的數(shù)據(jù)很多,每發(fā)送完一個(gè),那么存儲(chǔ)器的地址指針就應(yīng)該加 1,而串口數(shù)據(jù)寄存器只有一個(gè),那么外設(shè)的地址指針就固定不變。具體的數(shù)據(jù)指針的增量模式由實(shí)際情況決定。

(3)什么時(shí)候傳輸完成

數(shù)據(jù)什么時(shí)候傳輸完成,我們可以通過(guò)查詢標(biāo)志位或者通過(guò)中斷的方式來(lái)判斷。每個(gè) DMA 通道在 DMA 傳輸過(guò)半、傳輸完成和傳輸錯(cuò)誤時(shí)都會(huì)有相應(yīng)的標(biāo)志位,如果使能了該類型的中斷后,則會(huì)產(chǎn)生中斷。有關(guān)各個(gè)標(biāo)志位的詳細(xì)描述請(qǐng)參考 DMA 中斷狀態(tài)寄存器DMA_ISR 的詳細(xì)描述。

傳輸完成還分兩種模式,是一次傳輸還是循環(huán)傳輸,一次傳輸很好理解,即傳輸一次之后就停止,要想再傳輸?shù)脑?,必須關(guān)斷 DMA 使能后再重新配置后才能繼續(xù)傳輸循環(huán)傳輸則是一次傳輸完成之后又恢復(fù)第一次傳輸時(shí)的配置循環(huán)傳輸,不斷的重復(fù)具體的由 DMA_CCR 寄存器的 CIRC 循環(huán)模式位控制。

DMA 配置步驟

接下來(lái)我們介紹下如何使用庫(kù)函數(shù)對(duì) DMA 進(jìn)行配置。這個(gè)也是在編寫程序中必須要了解的。具體步驟如下:(DMA 相關(guān)庫(kù)函數(shù)在 stm32f10x_dma.c 和stm32f10x_dma.h 文件中)

(1)使能 DMA 控制器(DMA1 或 DMA2)時(shí)鐘

要使能 DMA 時(shí)鐘,需通過(guò)AHB1ENR 寄存器來(lái)控制,使能 DMA時(shí)鐘庫(kù)函數(shù)為:
void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState
NewState);

例如使能 DMA1 時(shí)鐘,函數(shù)如下:

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

(2)初始化 DMA 通道,包括配置通道、外設(shè)和內(nèi)存地址、傳輸數(shù)據(jù)量等要使用 DMA,必須對(duì)其相關(guān)參數(shù)進(jìn)行設(shè)置,包括通道選擇、外設(shè)和內(nèi)存地址、

通道優(yōu)先級(jí)、傳輸數(shù)據(jù)量的配置等。該部分設(shè)置通過(guò) DMA 初始化函數(shù) DMA_Init完成的:

void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx,DMA_InitTypeDef*
DMA_InitStruct);
函數(shù)中第一個(gè)參數(shù)是用來(lái)確定 DMA 通道,參數(shù)范圍為:
DMA1_Channel_0~DMA1_Channel_7(DMA2 是DMA2_Channel_0-DMA2_Channel_5)
第二個(gè)參數(shù)是一個(gè)結(jié)構(gòu)體指針變量,結(jié)構(gòu)體類型是 DMA_InitTypeDef,其內(nèi)包含了 DMA 相關(guān)參數(shù)的設(shè)置。下面我們簡(jiǎn)單介紹下它的成員:
typedef struct
{
uint32_t DMA_PeripheralBaseAddr; // 外設(shè)地址
uint32_t DMA_MemoryBaseAddr; // 存儲(chǔ)器地址
uint32_t DMA_DIR; // 傳輸方向
uint32_t DMA_BufferSize; // 傳輸數(shù)目
uint32_t DMA_PeripheralInc; // 外設(shè)地址增量模式
uint32_t DMA_MemoryInc; // 存儲(chǔ)器地址增量模式
uint32_t DMA_PeripheralDataSize; // 外設(shè)數(shù)據(jù)寬度
uint32_t DMA_MemoryDataSize; // 存儲(chǔ)器數(shù)據(jù)寬度
uint32_t DMA_Mode; // 模式選擇
uint32_t DMA_Priority; // 通道優(yōu)先級(jí)
uint32_t DMA_M2M; // 存儲(chǔ)器到存儲(chǔ)器模式
} DMA_InitTypeDef;
DMA_PeripheralBaseAddr:外設(shè)地址,通過(guò) DMA_CPAR 寄存器設(shè)置,一般設(shè)置為外設(shè)的數(shù)據(jù)寄存器地址,比如要進(jìn)行串口 DMA 傳輸,那么外設(shè)基地址為串口接受發(fā)送數(shù)據(jù)存儲(chǔ)器 USART1- >DR 的地址,表示方法為&USART1- >DR。如果是存儲(chǔ)器到存儲(chǔ)器模式則設(shè)置為其中一個(gè)存儲(chǔ)區(qū)地址。

DMA_Memory0BaseAddr:存儲(chǔ)器地址,通過(guò) DMA_CMAR 寄存器設(shè)置,一般設(shè)置為我們自定義存儲(chǔ)區(qū)的首地址,即我們存放 DMA 傳輸數(shù)據(jù)的內(nèi)存地址。比如我們定義一個(gè) u32 類型數(shù)組,將數(shù)組首地址(直接使用數(shù)組名即可)賦值給DMA_Memory0BaseAddr,在DMA傳輸?shù)臅r(shí)候就可以把數(shù)組內(nèi)的數(shù)據(jù)發(fā)送或接收。

DMA_DIR:數(shù)據(jù)傳輸方向選擇,可選擇外設(shè)到存儲(chǔ)器、存儲(chǔ)器到外設(shè)以及存

儲(chǔ)器到存儲(chǔ)器。通過(guò)設(shè)定 DMA_CCR 寄存器的 DIR[1:0]位的值決定。比如本章實(shí)驗(yàn)是從內(nèi)存讀取數(shù)據(jù)發(fā)送到串口,所以數(shù)據(jù)傳輸方向?yàn)榇鎯?chǔ)器到外設(shè),配置為DMA_DIR_MemoryToPeripheral。

DMA_BufferSize:用來(lái)設(shè)置一次傳輸數(shù)據(jù)的大小,通過(guò) DMA_CNDTR 寄存器設(shè)置。

DMA_PeripheralInc:用來(lái)設(shè)置外設(shè)地址是遞增還是不變,通過(guò) DMA_CCR寄存器的 PINC 位設(shè)置,如果設(shè)置為遞增,那么下一次傳輸?shù)臅r(shí)候地址加 1。通常外 設(shè) 只 有 一 個(gè) 數(shù) 據(jù) 寄 存 器 , 所 以 一 般 不 會(huì) 使 能 該 位 , 即 配 置 為DMA_PeripheralInc_Disable。

DMA_MemoryInc:用來(lái)設(shè)置內(nèi)存地址是否遞增,通過(guò) DMA_CCR 寄存器的MINC位設(shè)置。我們自定義的存儲(chǔ)區(qū)一般都是存放多個(gè)數(shù)據(jù)的,所以需要使能存儲(chǔ)器地址自動(dòng)遞增功能,即配置為 DMA_MemoryInc_Enable。

DMA_PeripheralDataSize:外設(shè)數(shù)據(jù)寬度選擇,可以為字節(jié)(8 位)、半字

(16位)、字(32 位),通過(guò) DMA_CCR 寄存器的 PSIZE[1:0]位設(shè)置。例如本實(shí)驗(yàn)數(shù)據(jù)是按照 8 位字節(jié)傳輸,所以配置為DMA_PeripheralDataSize_Byte。

DMA_MemoryDataSize:存儲(chǔ)器數(shù)據(jù)寬度選擇,可以為字節(jié)(8 位)、半字(16位)、字(32 位),通過(guò) DMA_CCR 寄存器的 MSIZE[1:0]位設(shè)置。本章實(shí)驗(yàn)同樣設(shè)置為 8 位字節(jié)傳輸,這個(gè)要和我們定義的數(shù)組對(duì)應(yīng),所以配置為DMA_MemoryDataSize_Byte。

DMA_Mode:DMA 傳輸模式選擇, 可選擇一次傳輸或者循環(huán)傳輸, 通過(guò)DMA_CCR寄存器的 CIRC 位來(lái)設(shè)定。比如我們要從內(nèi)存 (存儲(chǔ)器) 中傳輸 64 個(gè)字節(jié)到串口,如果設(shè)置為循環(huán)傳輸,那么它會(huì)在 64 個(gè)字節(jié)傳輸完成之后繼續(xù)從內(nèi)存的第一個(gè)地址傳輸,如此循環(huán)。這里我們?cè)O(shè)置為一次傳輸完成之后不循環(huán)。所以設(shè)置值為DMA_Mode_Normal。

DMA_Priority:用來(lái)設(shè)置 DMA 通道的優(yōu)先級(jí),有低,中,高,超高四種級(jí)別,可通過(guò) DMA_CCR 寄存器的PL[1:0]位來(lái)設(shè)定。DMA 優(yōu)先級(jí)只有在多個(gè) DMA 通道同時(shí)使用時(shí)才有意義,本章實(shí)驗(yàn)我們只使用了一個(gè) DMA 通道,所以可以任意設(shè)置DMA 優(yōu)先級(jí),這里我們就設(shè)置為中等優(yōu)先級(jí),配置參數(shù)為DMA_Priority_Medium。

DMA_Priority:用來(lái)設(shè)置 DMA 通道的優(yōu)先級(jí),有低,中,高,超高四種級(jí)別,可通過(guò) DMA_CCR 寄存器的PL[1:0]位來(lái)設(shè)定。DMA 優(yōu)先級(jí)只有在多個(gè) DMA 通道同時(shí)使用時(shí)才有意義,本章實(shí)驗(yàn)我們只使用了一個(gè) DMA 通道,所以可以任意設(shè)置DMA 優(yōu)先級(jí),這里我們就設(shè)置為中等優(yōu)先級(jí),配置參數(shù)為DMA_Priority_Medium。

DMA_M2M:用來(lái)設(shè)置存儲(chǔ)器到存儲(chǔ)器模式,使用存儲(chǔ)器到存儲(chǔ)器時(shí)用到,設(shè)定 DMA_CCR 的位 14 MEN2MEN 即可啟動(dòng)存儲(chǔ)器到存儲(chǔ)器模式。

了解結(jié)構(gòu)體成員功能后,就可以進(jìn)行配置,本實(shí)驗(yàn)配置代碼如下:
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMA外設(shè)地址
DMA_InitStructure.DMA_MemoryBaseAddr = mar;//DMA 存儲(chǔ)器0地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//存儲(chǔ)器到外
設(shè)模式
DMA_InitStructure.DMA_BufferSize = ndtr;//數(shù)據(jù)傳輸量
DMA_InitStructure.DMA_PeripheralInc =
DMA_PeripheralInc_Disable;//外設(shè)非增量模式
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存儲(chǔ)器
增量模式
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_Byte;//外設(shè)數(shù)據(jù)長(zhǎng)度:8 位
DMA_InitStructure.DMA_MemoryDataSize =
DMA_MemoryDataSize_Byte;//存儲(chǔ)器數(shù)據(jù)長(zhǎng)度:8 位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等優(yōu)先
級(jí)
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA 通道 x 沒(méi)有

設(shè)置為內(nèi)存到內(nèi)存?zhèn)鬏?/p>

DMA_Init(DMAy_Channelx, &DMA_InitStructure);//初始化DMA

(3)使能外設(shè) DMA功能(DMA 請(qǐng)求映射圖對(duì)應(yīng)的外設(shè))

配置好 DMA 后,我們就需要使能外設(shè) DMA 功能,例如我們要使能串口的DMA發(fā)送功能,調(diào)用的庫(kù)函數(shù)為:
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //使能串口 1 的 DMA發(fā)送
如果是要使能串口DMA接受, 那么第二個(gè)參數(shù)修改為USART_DMAReq_Rx即可。

如果是其他的外設(shè)需開啟DMA功能, 只需要在對(duì)應(yīng)的標(biāo)準(zhǔn)外設(shè)庫(kù)函數(shù)中查找到對(duì)應(yīng)的外設(shè) DMA 使能函數(shù)。

(4)開啟 DMA 的通道傳輸

初始化 DMA 后,要使用DMA還必須開啟它,開啟 DMA 通道傳輸?shù)膸?kù)函數(shù)為:
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalStateNewState);
第一個(gè)參數(shù)為外設(shè)所對(duì)應(yīng)的 DMA 通道,例如本章使用的是 USART1_TXDMA請(qǐng)求,因此它對(duì)應(yīng)的是 DMA1_Channel4,可通過(guò)前面DMA 請(qǐng)求映射圖選擇。第二個(gè)參數(shù)相信不說(shuō)也知道,就是使能或失能。

本實(shí)驗(yàn)使能 DMA1_Channel4函數(shù)為:
DMA_Cmd(DMA1_Channel4,ENABLE);

(5)查詢 DMA 傳輸狀態(tài)

通過(guò)以上 4 步設(shè)置,我們就可以啟動(dòng)一次 DMA 傳輸了。但是在 DMA 傳輸過(guò)程中,我們還需要查詢 DMA傳輸通道的狀態(tài),使用的庫(kù)函數(shù)是:
FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);
例如我們要查詢 DMA1通道4 傳輸是否完成,方法是:
DMA_GetFlagStatus(DMA1_FLAG_TC4);
標(biāo)準(zhǔn)庫(kù)中,還提供了獲取當(dāng)前剩余數(shù)據(jù)量大小的函數(shù):
uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef*DMAy_Channelx);
例如我們要獲取 DMA1通道4 還有多少個(gè)數(shù)據(jù)沒(méi)有傳輸,方法是:
DMA_GetCurrDataCounter(DMA1_Channel4);
同樣,標(biāo)準(zhǔn)庫(kù)中還提供了設(shè)置傳輸數(shù)據(jù)量大小的函數(shù):
void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx,uint16_t DataNumber);
將以上幾步全部配置好后,我們就可以使用 DMA 來(lái)傳輸對(duì)應(yīng)外設(shè)的數(shù)據(jù)了。

硬件設(shè)計(jì)

本實(shí)驗(yàn)使用到硬件資源如下:

(1)D1 和 D2 指示燈

(2)K_UP 按鍵

(3)串口 1

(4)DMA

D1和 D2 指示燈、K_UP 按鍵、串口 1 電路在前面章節(jié)都介紹過(guò),這里就不多說(shuō),至于 DMA 它屬于 STM32F1 芯片內(nèi)部的資源,只要通過(guò)軟件配置好 DMA即可使用。D1指示燈用來(lái)提示系統(tǒng)運(yùn)行狀態(tài),K_UP 按鍵用來(lái)控制 DMA發(fā)送,每按一次K_UP鍵,DMA 就將內(nèi)存(自定義的一個(gè)數(shù)組)內(nèi)數(shù)據(jù)發(fā)送 USART1,并通過(guò)串口 1將發(fā)送的內(nèi)容打印出來(lái),在 DMA 數(shù)據(jù)傳輸?shù)倪^(guò)程中讓 D2 指示燈不斷閃爍,直到數(shù)據(jù)傳輸完成。D2 指示燈閃爍表示 CPU在執(zhí)行其他的任務(wù),說(shuō)明 DMA 傳輸是不需要占用 CPU 的。

所要實(shí)現(xiàn)的功能是:通過(guò) K_UP 按鍵控制 DMA 串口 1 數(shù)據(jù)的傳送,在傳送過(guò)程中讓 D2 指示燈不斷閃爍,直到數(shù)據(jù)傳送完成。D1 指示燈閃爍提示系統(tǒng)正常運(yùn)行。程序框架如下:

(1)初始化 USART1_TX對(duì)應(yīng)的 DMA 通道相關(guān)參數(shù)

(2)編寫主函數(shù)

前面介紹 DMA 配置步驟時(shí), 就已經(jīng)講解如何初始化 DMA。下面我們打開 “DMA實(shí)驗(yàn)” 工程, 在 APP 工程組中可以看到添加了dma.c文件(里面包含了 DMA 驅(qū)動(dòng)程序),在 StdPeriph_Driver 工程組中添加了stm32f10x_dma.c 庫(kù)文件。DMA 操作的庫(kù)函數(shù)都放在 stm32f10x_dma.c 和stm32f10x_dma.h 文件中,所以使用到 DMA 就必須加入 stm32f10x_dma.c文件,同時(shí)還要包含對(duì)應(yīng)的頭文件路徑。

這里我們分析幾個(gè)重要函數(shù),其他部分程序大家可以打開工程查看。

DMA 初始化函數(shù)

要使用 DMA,我們必須先對(duì)它進(jìn)行配置。初始化代碼如下:
/****************************************************************
* 函 數(shù) 名 : DMAx_Init
* 函數(shù)功能 : DMA 初始化函數(shù)
* 輸 入 :
DMAy_Channelx:DMA 通 道 選 擇 ,@ref DMA_channel
DMA_Channel_0~DMA_Channel_7
par:外設(shè)地址
mar:存儲(chǔ)器地址
ndtr:數(shù)據(jù)傳輸量
* 輸 出 : 無(wú)
*****************************************************************/
void DMAx_Init(DMA_Channel_TypeDef* DMAy_Channelx,u32 par,u32
mar,u16 ndtr)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//DMA1時(shí)鐘使能
//DMA_DeInit(DMAy_Channelx);
/* 配置 DMA */
DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMA外設(shè)地址
DMA_InitStructure.DMA_MemoryBaseAddr = mar;//DMA 存儲(chǔ)器0地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//存儲(chǔ)器到外設(shè)模式
DMA_InitStructure.DMA_BufferSize = ndtr;//數(shù)據(jù)傳輸量
DMA_InitStructure.DMA_PeripheralInc =
DMA_PeripheralInc_Disable;//外設(shè)非增量模式
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存儲(chǔ)器增量模式
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_Byte;//外設(shè)數(shù)據(jù)長(zhǎng)度:8 位
DMA_InitStructure.DMA_MemoryDataSize =DMA_MemoryDataSize_Byte;//存儲(chǔ)器數(shù)據(jù)長(zhǎng)度:8 位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等優(yōu)先級(jí)
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA 通道 x 沒(méi)有設(shè)置為內(nèi)存到內(nèi)存?zhèn)鬏?DMA_Init(DMAy_Channelx, &DMA_InitStructure);//初始化DMA
}
DMAx_Init()函數(shù)中,首先使能 DMA1 時(shí)鐘,然后初始化 DMA 各參數(shù),即配置 DMA_InitStructure結(jié)構(gòu)體,初始化 DMA 通道,這一過(guò)程在前面步驟介紹中已經(jīng)提了。

通道的選擇有函數(shù)參數(shù)DMAy_Channelx傳遞進(jìn)來(lái), 函數(shù)中還有另外3個(gè)形參,par 傳遞的是外設(shè)地址,mar傳遞的是存儲(chǔ)器(內(nèi)存)地址,ndtr傳遞的是DMA數(shù)據(jù)傳輸量。這樣做的好處是方便大家修改。

開啟 DMA 傳輸函數(shù)

配置好 DMA 后,我們需要開啟它,代碼如下:
/****************************************************************
* 函 數(shù) 名 : DMAx_Enable
* 函數(shù)功能 : 開啟一次 DMA 傳輸
* 輸 入 : DMAy_Channelx:DMA 通道選擇,@ref DMA_channel
DMA_Channel_0~DMA_Channel_7
ndtr:數(shù)據(jù)傳輸量
* 輸 出 : 無(wú)
*****************************************************************/
void DMAx_Enable(DMA_Channel_TypeDef *DMAy_Channelx,u16 ndtr)
{
DMA_Cmd(DMAy_Channelx, DISABLE); //關(guān)閉
DMA 傳輸
DMA_SetCurrDataCounter(DMAy_Channelx,ndtr); //數(shù)據(jù)傳輸量
DMA_Cmd(DMAy_Channelx, ENABLE); //開啟DMA傳輸
}
此函數(shù)功能很簡(jiǎn)單,首先失能 DMA 傳輸通道,然后設(shè)置傳輸?shù)臄?shù)據(jù)量大小,最后使能 DMA 傳輸通道。函數(shù)帶有形參 DMAy_Channelx 和 ndtr,用于方便選擇對(duì)應(yīng)外設(shè)的通道和數(shù)據(jù)量。

主函數(shù)

編寫好 DMA 的初始化和使能函數(shù)后, 接下來(lái)就可以編寫主函數(shù)了, 代碼如下:
/****************************************************************
* 函 數(shù) 名 : main
* 函數(shù)功能 : 主函數(shù)
* 輸 入 : 無(wú)
* 輸 出 : 無(wú)
*****************************************************************/
int main()
{
u8 i=0;
u8 key;
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中斷優(yōu)先級(jí)分組 分2 組
LED_Init();
USART1_Init(9600);
KEY_Init();
DMAx_Init(DMA1_Channel4,(u32)&USART1- >DR,(u32)send_buf,send_buf_len);
Send_Data(send_buf);
while(1)
{
key=KEY_Scan(0);
if(key==KEY_UP)
{
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //使能串口 1的DMA 發(fā)送
DMAx_Enable(DMA1_Channel4,send_buf_len); //開始一次DMA 傳輸!
//等待 DMA傳輸完成,此時(shí)我們來(lái)做另外一些事
//實(shí)際應(yīng)用中,傳輸數(shù)據(jù)期間,可以執(zhí)行另外的任務(wù)
while(1)
{
if(DMA_GetFlagStatus(DMA1_FLAG_TC4)!=0)//判斷通道 4傳輸完成
{
DMA_ClearFlag(DMA1_FLAG_TC4);
break;
}
led2=!led2;
delay_ms(300);
}
}
i++;
if(i%20==0)
{
led1=!led1;
}
delay_ms(10);
}
}
主函數(shù)實(shí)現(xiàn)的功能很簡(jiǎn)單,首先調(diào)用之前編寫好的硬件初始化函數(shù),包括SysTick系統(tǒng)時(shí)鐘, 中斷分組, LED初始化等。然后調(diào)用我們前面編寫的DMAx_Init函數(shù),由于 USART1_TX 是在 DMA1 的通道 4 中,所以通道選擇為 DMA1_Channel4。

外設(shè)地址傳遞的是&USART1- >DR,因?yàn)?USART1 用來(lái)接收數(shù)據(jù)的寄存器是USART1- >DR,加上一個(gè)&就轉(zhuǎn)換成地址了。存儲(chǔ)器地址為send_buf(數(shù)組名就是數(shù)組的地址) , 這個(gè)是我們自定義的一個(gè)u8類型數(shù)組, 數(shù)組大小為send_buf_len,這個(gè)也是我們定義的一個(gè)宏,值為 5000。然后調(diào)用Send_Data 函數(shù),此函數(shù)功能是將數(shù)組 send_buf 內(nèi)所有成員全部賦值為字符 5,代碼如下:
#define send_buf_len 5000
u8 send_buf[send_buf_len];
void Send_Data(u8 *p)
{
u16 i;
for(i=0;i< send_buf_len;i++)
{
*p='5';
p++;
}
}
最后進(jìn)入 while 循環(huán),調(diào)用KEY_Scan 函數(shù),不斷檢測(cè) K_UP按鍵是否按下,如果 K_UP 按鍵按下,啟動(dòng)一次 USART_TX 的 DMA 傳輸,在傳輸?shù)倪^(guò)程中讓 CPU控制 D2指示燈閃爍,直到 DMA 數(shù)據(jù)傳輸完成。D1 指示燈間隔200ms 閃爍,提示系統(tǒng)正常運(yùn)行。

將工程程序編譯后下載到開發(fā)板內(nèi),可以看到 D1 指示燈不斷閃爍,表示程序正常運(yùn)行。當(dāng) K_UP 按鍵按下,DMA 開始將內(nèi)存數(shù)組內(nèi)的數(shù)據(jù)傳輸?shù)酱?span id="vusqeur"    class="hljs-number">1 上,同時(shí)傳輸過(guò)程中,D2 指示燈閃爍,直到傳輸完成。如果想在串口調(diào)試助手上看到傳輸信息,可以打開“串口調(diào)試助手”,首先勾選下標(biāo)號(hào) 1 DTR 框,然后再取消勾選。這是因?yàn)榇舜谥謫?dòng)時(shí)會(huì)把系統(tǒng)復(fù)位住,通過(guò) DTR 狀態(tài)切換下即可。然后設(shè)置好波特率等參數(shù)后,串口助手上即會(huì)收到串口發(fā)送過(guò)來(lái)的信息。(串口助手上先勾選下標(biāo)號(hào)1 DTR 框,然后再取

消勾選)如圖所示:

圖片

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4381

    瀏覽量

    64890
  • dma
    dma
    +關(guān)注

    關(guān)注

    3

    文章

    576

    瀏覽量

    103254
  • stm32f1
    +關(guān)注

    關(guān)注

    1

    文章

    60

    瀏覽量

    12526
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    STM32實(shí)例教程-DMA實(shí)驗(yàn)

    在前面我們提到過(guò) DMA,這一章我們就來(lái)學(xué)習(xí) STM32F1DMA 使用。要實(shí)現(xiàn)的功能是:通過(guò) K_UP 按鍵控制 DMA 串口 1 數(shù)
    發(fā)表于 05-24 09:20 ?1595次閱讀
    <b class='flag-5'>STM32</b>實(shí)例教程-<b class='flag-5'>DMA</b>實(shí)驗(yàn)

    求各位大神看一下哪里出錯(cuò)了 我想把發(fā)送的數(shù)據(jù)顯示在lcd上 可是下載以后lcd直接熄滅了

    ];//·¢?íêy?Y?o3???const u8 TEXT_TO_SEND[]={"ALIENTEK WarShip STM32F1 DMA ′??úêμ?é"}; int main(void
    發(fā)表于 10-09 21:50

    請(qǐng)問(wèn)有STM32F1 DMA傳輸?shù)腎2C通信例程嗎?

    求一個(gè)STM32F1 DMA傳輸?shù)腎2C通信例程
    發(fā)表于 02-18 06:32

    STM32F4與STM32F1使用串口DMA有何區(qū)別呢

    STM32的串口DMA有哪些特性呢?STM32F4與STM32F1使用串口DMA有何區(qū)別呢?
    發(fā)表于 12-06 06:51

    如何利用STM32F1DMA來(lái)實(shí)現(xiàn)串口數(shù)據(jù)傳送

    本章介紹STM32F1DMA。在本章中,我們將利用STM32F1DMA來(lái)實(shí)現(xiàn)串口數(shù)據(jù)傳送,并在TFTLCD模塊上顯示當(dāng)前的傳送進(jìn)度。當(dāng)CPU初始化這個(gè)傳輸動(dòng)作,傳輸動(dòng)作本身是由
    發(fā)表于 02-08 07:36

    關(guān)于stm32f1中的ADC和DMA理解

    怎樣去校準(zhǔn)stm32f1中的ADC呢?怎樣去理解stm32f1中的ADC和DMA呢?
    發(fā)表于 02-21 06:05

    STM32F2直接存儲(chǔ)器訪問(wèn)DMA

    /unpack? 突發(fā)傳輸模式? 通用DMA傳輸過(guò)程? 循環(huán)模式和雙緩沖模式(STM32F2新增)? 流控(STM32F2新增)? 事件、中斷和錯(cuò)誤管理? DMA stream配置流程
    發(fā)表于 09-13 07:02

    STM32F1的ADC2如何使用DMA功能 USART過(guò)載錯(cuò)誤Overrun error

    STM32F1的ADC2如何使用DMA功能,USART過(guò)載錯(cuò)誤Overrun error
    的頭像 發(fā)表于 03-14 14:42 ?8767次閱讀
    <b class='flag-5'>STM32F1</b>的ADC2如何使用<b class='flag-5'>DMA</b>功能 USART過(guò)載錯(cuò)誤Overrun error

    STM32F1 _DMA_USART

    STM32F1_DMA_USART
    的頭像 發(fā)表于 04-08 10:23 ?5221次閱讀
    <b class='flag-5'>STM32F1</b> _<b class='flag-5'>DMA</b>_USART

    STM32F1系列芯片中文參考手冊(cè)

    STM32F1系列芯片中文參考手冊(cè)(嵌入式開發(fā)培訓(xùn)教程)-STM32F1系列芯片的中文用戶手冊(cè)
    發(fā)表于 07-30 09:32 ?218次下載
    <b class='flag-5'>STM32F1</b>系列芯片中文參考手冊(cè)

    STM32F1F4的區(qū)別

    STM32F1F4的區(qū)別
    發(fā)表于 12-04 13:51 ?24次下載
    <b class='flag-5'>STM32F1</b>和<b class='flag-5'>F</b>4的區(qū)別

    STM32F1開發(fā)指南筆記32----DMA

    本章介紹STM32F1DMA。在本章中,我們將利用STM32F1DMA來(lái)實(shí)現(xiàn)串口數(shù)據(jù)傳送,并在TFTLCD模塊上顯示當(dāng)前的傳送進(jìn)度。當(dāng)CPU初始化這個(gè)傳輸動(dòng)作,傳輸動(dòng)作本身是由
    發(fā)表于 12-04 19:21 ?20次下載
    <b class='flag-5'>STM32F1</b>開發(fā)指南筆記32----<b class='flag-5'>DMA</b>

    STM32F1 ADC和DMA的簡(jiǎn)單理解

    本文主要講解stm32f1中ADC和DMA的使用,在學(xué)習(xí)中參考了多篇文章,感謝前輩的付出。STM32F10X ADC多通道讀取小教程(包含DMA)_JameScottX的博客-CSDN
    發(fā)表于 12-27 19:09 ?35次下載
    <b class='flag-5'>STM32F1</b> ADC和<b class='flag-5'>DMA</b>的簡(jiǎn)單理解

    STM32F1DMA提高串口速度

    STM32F1DMA,提高串口速度
    發(fā)表于 09-26 16:11 ?5次下載

    AN4904_從STM32F1STM32F4的軟件移植

    AN4904_從STM32F1STM32F4的軟件移植
    發(fā)表于 11-21 17:06 ?5次下載
    AN4904_從<b class='flag-5'>STM32F1</b>到<b class='flag-5'>STM32F</b>4的軟件移植