浅谈STM32的DMA模块的使用
淺談STM32的DMA模塊的使用
轉(zhuǎn)自:http://blog.ednchina.com/jack_chang/123085/message.aspx
http://article.ednchina.com/Other/200806050734461.htm
By Jack Chang
????????????????? Thu Jun 5 2008? 18:30:49
E-mail:zhang-weihong@126.com QQ:179748613
前言:接觸MCU的編程已經(jīng)有幾年的歷史,剛開始是從PLC(C語言的)學(xué)習(xí)與應(yīng)用,后來有學(xué)習(xí)了8bits的AVR單片機(jī),對MCU有一定的了解;最近接觸了STM32的Chip,發(fā)現(xiàn)其優(yōu)點(diǎn)不只是單單宣傳的32bits的MCU的速度,而且在編程的風(fēng)格上也有了較大的變化(與我原有的編程習(xí)慣);特別是有一個(gè)與CPU并行運(yùn)行的模塊:DMA,對它印象深刻。現(xiàn)在就和大家一起討論學(xué)習(xí)這個(gè)Module,談?wù)勎以趯W(xué)習(xí)中一些感悟和大家一起分享;如有對DMA理解和應(yīng)用上的錯(cuò)誤和偏差,歡迎“拍磚”和提出更正,蝦米在此感謝大家了。哈哈!
什么是STM32的DMA?其全稱是:Direct Memory Access;根據(jù)ST公司提供的相關(guān)信息,DMA是STM32中一個(gè)獨(dú)立與Cortex-M3內(nèi)核的模塊,有點(diǎn)類似與ADC、PWM、TIMER等模塊;主要功能是通信“橋梁”的作用,可以將所有外設(shè)映射的寄存器“連接”起來,這樣就可以高速問各寄存器,其傳輸不受CPU的支配,傳輸還是雙向的;例如,從“表面”上看,它可以將flash中的數(shù)據(jù)與儲存器中變量建立通訊,還可以將一外設(shè)的積存器或緩沖器與另外設(shè)的寄存器或緩沖器建立雙向通訊,有點(diǎn)像把外設(shè)硬件之間用“導(dǎo)線”連接在一起了。其間的通訊不占CPU資源,訪問速度高,對于實(shí)時(shí)性強(qiáng)的應(yīng)用將是一個(gè)很好的選擇;當(dāng)然,對于實(shí)時(shí)性非常強(qiáng)的,建議還是采用專用的DSP芯片。
過程:怎樣啟用DMA?首先,眾所周知的是初始化,任何設(shè)備啟用前都要對其進(jìn)行初始化,要對模塊初始化,還要先了解該模塊相應(yīng)的結(jié)構(gòu)及其函數(shù),以便正確的設(shè)置;由于DMA較為復(fù)雜,我就只談?wù)凞MA的基本結(jié)構(gòu)和和常用函數(shù),這些都是ST公司提供在庫函數(shù)中的。
1、 下面代碼是一個(gè)標(biāo)準(zhǔn)DMA設(shè)置,當(dāng)然實(shí)際應(yīng)用中可根據(jù)實(shí)際情況進(jìn)行裁減:
DMA_DeInit(DMA_Channel1);
上面這句是給DMA配置通道,根據(jù)ST提供的資料,STM3210Fx中DMA包含7個(gè)通道(CH1~CH7),也就是說可以為外設(shè)或memory提供7座“橋梁”(請?jiān)试S我使用橋梁一詞,我覺得更容易理解,哈哈,別“拍磚”呀!);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
上面語句中的DMA_InitStructure是一個(gè)DMA結(jié)構(gòu)體,在庫中有聲明了,當(dāng)然使用時(shí)就要先定義了;DMA_PeripheralBaseAddr是該結(jié)構(gòu)體中一個(gè)數(shù)據(jù)成員,給DMA一個(gè)起始地址,好比是一個(gè)buffer起始地址,數(shù)據(jù)流程是:外設(shè)寄存器à DMA_PeripheralBaseAddàmemory中變量空間(或flash中數(shù)據(jù)空間等),ADC1_DR_Address是我定義的一個(gè)地址變量;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_ConvertedValue;
上面這句很顯然是DMA要連接在Memory中變量的地址,ADC_ConvertedValue是我自己在memory中定義的一個(gè)變量;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
上面的這句是設(shè)置DMA的傳輸方向,就如前面我所說的,DMA可以雙向傳輸,也可以單向傳輸,這里設(shè)置的是單向傳輸,如果需要雙向傳輸:把DMA_DIR_PeripheralSRC改成DMA_DIR_PeripheralDST即可。
DMA_InitStructure.DMA_BufferSize = 2;
上面的這句是設(shè)置DMA在傳輸時(shí)緩沖區(qū)的長度,前面有定義過了buffer的起始地址:ADC1_DR_Address ,為了安全性和可靠性,一般需要給buffer定義一個(gè)儲存片區(qū),這個(gè)參數(shù)的單位有三種類型:Byte、HalfWord、word,我設(shè)置的2個(gè)half-word(見下面的設(shè)置);32位的MCU中1個(gè)half-word占16 bits。
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
上面的這句是設(shè)置DMA的外設(shè)遞增模式,如果DMA選用的通道(CHx)有多個(gè)外設(shè)連接,需要使用外設(shè)遞增模式:DMA_PeripheralInc_Enable;我的例子里DMA只與ADC1建立了聯(lián)系,所以選用DMA_PeripheralInc_Disable
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
上面的這句是設(shè)置DMA的內(nèi)存遞增模式,DMA訪問多個(gè)內(nèi)存參數(shù)時(shí),需要使用DMA_MemoryInc_Enable,當(dāng)DMA只訪問一個(gè)內(nèi)存參數(shù)時(shí),可設(shè)置成:DMA_MemoryInc_Disable。
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
上面的這句是設(shè)置DMA在訪問時(shí)每次操作的數(shù)據(jù)長度。有三種數(shù)據(jù)長度類型,前面已經(jīng)講過了,這里不在敘述。
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
與上面雷同。在此不再說明。
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
上面的這句是設(shè)置DMA的傳輸模式:連續(xù)不斷的循環(huán)模式,若只想訪問一次后就不要訪問了(或按指令操作來反問,也就是想要它訪問的時(shí)候就訪問,不要它訪問的時(shí)候就停止),可以設(shè)置成通用模式:DMA_Mode_Normal
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
上面的這句是設(shè)置DMA的優(yōu)先級別:可以分為4級:VeryHigh,High,Medium,Low.
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
上面的這句是設(shè)置DMA的2個(gè)memory中的變量互相訪問的
DMA_Init(DMA_Channel1,&DMA_InitStructure);
前面那些都是對DMA結(jié)構(gòu)體成員的設(shè)置,在次再統(tǒng)一對DMA整個(gè)模塊做一次初始化,使得DMA各成員與上面的參數(shù)一致。
/*DMA Enable*/
DMA_Cmd(DMA_Channel1,ENABLE);
哈哈哈!這一句我想我就不羅嗦了,大家一看就明白。
至此,整個(gè)DMA總算設(shè)置好了,但是,DMA通道又是怎樣與外設(shè)聯(lián)系在一起的呢?哈哈,這也是我當(dāng)初最想知道的一個(gè)事情,別急!容我想喝口茶~~~~~~哈哈哈!
要使DMA與外設(shè)建立有效連接,這不是DMA自身的事情,是各個(gè)外設(shè)的事情,每個(gè)外設(shè)都有 一個(gè)xxx_DMACmd(XXXx,Enable )函數(shù),如果使DMA與ADC建立有效聯(lián)系,就使用ADC_DMACmd(ADC1,Enable); (這里我啟用了ADC中的ADC1模塊)。
下面就以我的一個(gè)實(shí)例來和大家一起學(xué)習(xí)。這個(gè)實(shí)例仿真是成功的,我使用的是IAR Embedded Workbench IDE(v4.42) 和Manley Mini-kit評估板+ST-Link II來調(diào)試,是一個(gè)USART+ADC+DMA的例子。
首先,按照相關(guān)的資料提示,建立好項(xiàng)目路徑、拷貝庫文件和相關(guān)必要的文件,并建立一個(gè)新工程;還有就是設(shè)置好IAR IDE的相關(guān)設(shè)置。一切準(zhǔn)備就緒后就開始修改相關(guān)的文檔:
conf.h文檔的修改是根據(jù)應(yīng)用中有啟用的相關(guān)功能Module。如下圖:
ADC模塊的啟用設(shè)置:
DMA模塊的啟用設(shè)置:
USART模塊啟用的設(shè)置:
其他的如flash、GPIO、RCC、NVIC、HSE等就不一一舉例,因?yàn)檫@些幾乎每個(gè)工程都要用到。
再回頭看看我的main.c文檔,
下圖是相關(guān)的私有定義
USART的配制如下(9600,8, N,1):
DMA的配置如下:
ADC的配置如下圖(采用了2路A/D多通道的ADC模式):
給各個(gè)模塊配置的時(shí)鐘使能如下圖;在此想羅嗦一句就是在這個(gè)位置的設(shè)置我沒有給DMA配置時(shí)鐘,造成DMA功能無法正常使用,也就是前面所有說的與我原先的編程風(fēng)格有較大的變化的原因,想說一句:在項(xiàng)目中所使用的所有功能模塊都要在此配置時(shí)鐘才能正常工作。
GPIO的配置
如果有開中斷子程序,請?jiān)谠贜VIC中配置,還可以定義每個(gè)中斷子程序的優(yōu)先級別,由于我的工程沒有用到,在此就不羅嗦了。
我項(xiàng)目應(yīng)用到的文件目錄如下圖:
我的項(xiàng)目仿真結(jié)果如下;PA0與GND間接了一個(gè)1.5V的干電池,其結(jié)果是如中ADC_ConvertedValue[0]的值;PA1懸空,未接模擬信號。
我的硬件仿真平臺如下2圖:紅色的是我AVR mega16L Mini開發(fā)板,主要是利用了其中的POWER和RS232
用PC端USART數(shù)據(jù)采集結(jié)果:(圖中的顯示是我將ADC轉(zhuǎn)換后的值給字符串化了)
ST-link II仿真窗口的測試結(jié)果與USART采集到的數(shù)據(jù)結(jié)果差異說明:由于Manley 的stme32 Mini-kit評估板套件無法給ADC和USART同時(shí)組合仿真,我是分別分開仿真和USART數(shù)據(jù)傳輸?shù)?#xff0c;所以出現(xiàn)差異。
心得: 1、這次學(xué)習(xí)STM32的MCU,最大的心得是改變我原有的編程思維,原來學(xué)習(xí)AVR的時(shí)候,文件庫需要自己寫,屬于底層操作,如要自己寫直接操作各外設(shè)的寄存器,復(fù)雜的還需要自己寫設(shè)置函數(shù),對底層要有非常的清楚的認(rèn)識,編寫的代碼的工作量也比較大;稍有不慎,容易把寄存器弄錯(cuò);調(diào)試也會花費(fèi)較大的時(shí)間。而STM32的編程風(fēng)格給我一個(gè)全新的視角(哈哈!別拍磚,雖然屬菜鳥級別,但比較容易接受新的東西),感覺只要按其提供的資料建立起工程的基本構(gòu)架,很多都是ST公司提供封裝好的接口(類似windows的API),直接調(diào)用接口和做少許修改就可以完成你想要的工程結(jié)果。
2、 清晰的工程構(gòu)架:ST提供一些工程案例的基本構(gòu)架,只要熟悉這些構(gòu)架,對構(gòu)架做一些適當(dāng)?shù)男薷?#xff0c;你將很輕松的完成你的任務(wù),開發(fā)周期也可以縮短很多。請記住:牢記工程構(gòu)架;
3、 哈哈!不想羅嗦的是STM32的速度和豐富的外設(shè)。(再羅嗦可能會被成批的磚頭拍死,哈哈哈哈!)
4、 更有信心用STM32做其他更復(fù)雜一些的項(xiàng)目。祝大家好運(yùn)!(別拍磚頭呀!哈哈!)
轉(zhuǎn)載于:https://www.cnblogs.com/hnrainll/archive/2011/01/18/1937891.html
總結(jié)
以上是生活随笔為你收集整理的浅谈STM32的DMA模块的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JAVA基础之理解JNI原理
- 下一篇: String,StringBuffer和