欧美性猛交xxxx免费看_牛牛在线视频国产免费_天堂草原电视剧在线观看免费_国产粉嫩高清在线观看_国产欧美日本亚洲精品一5区

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

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

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

LPC800前生今世-第九章 直接存儲器訪問 (DMA)

恩智浦MCU加油站 ? 來源:未知 ? 2023-12-21 08:55 ? 次閱讀

DMA是直接存儲器訪問(DirectMemory Access)的縮寫。在MCU芯片中,DMA是除CPU之外,最常見的總線主設(shè)備。作為總線主設(shè)備,DMA控制器可以輸出地址和控制信號到總線上,主動地發(fā)起和控制數(shù)據(jù)傳輸過程,它能夠按照程序的配置,在兩個從設(shè)備之間傳輸數(shù)據(jù)。例如在存儲器和I2C模塊之間傳輸數(shù)據(jù),實現(xiàn)I2C數(shù)據(jù)的發(fā)送或接收,或從ADC讀出數(shù)據(jù)再傳送到USART進(jìn)行發(fā)送。

下圖是LPC82x的部分框圖,圖中醒目標(biāo)出了總線主設(shè)備,和DMA控制器。wKgZomWDjhOAIhgaAAF_2DFruUQ412.png? ? ? ? ? ? ? ? ? ?? ??圖1.LPC82x結(jié)構(gòu)框圖(部分)LPC82x的所有片內(nèi)外設(shè)中,只有DMA控制器是總線主設(shè)備,其它都是總線從設(shè)備,只有主設(shè)備才能主動發(fā)起數(shù)據(jù)的傳輸操作。

DMA的優(yōu)勢是,可以在CPU最少的干預(yù)下,高效地執(zhí)行數(shù)據(jù)塊的傳輸,節(jié)省CPU的時間,同時可以在CPU執(zhí)行內(nèi)部操作而不訪問總線時,更高效地利用總線的時間。

1.1DMA控制器的一些基本操作在介紹LPC800DMA控制器之前,先通過這個傳輸示意圖,回顧一下通用DMA控制器必須具備的基本操作。wKgZomWDjhSAfUdoAAEaJ-B3HnA548.png

圖2.DMA傳輸示意圖

產(chǎn)生數(shù)據(jù)傳輸?shù)脑吹刂泛湍繕?biāo)地址:DMA控制器在接到傳輸請求后,在內(nèi)部總線上產(chǎn)生源數(shù)據(jù)地址SA,讀出要傳輸?shù)臄?shù)據(jù),然后再產(chǎn)生存放數(shù)據(jù)的目標(biāo)地址DA,將數(shù)據(jù)寫入指定的地方。

控制每次傳輸后地址的變化:可以控制每次DMA傳輸是涉及到一個連續(xù)的地址區(qū)域還是單個獨立的地址。每次讀寫的源地址和目標(biāo)地址分別改變或不改變,也可以同步地改變。

控制傳輸?shù)臄?shù)據(jù)長度:軟件需要指定每次DMA傳輸?shù)臄?shù)據(jù)數(shù)量n。

指定傳輸?shù)臄?shù)據(jù)寬度:軟件需要指定每次DMA讀寫的數(shù)據(jù)寬度,一般是以內(nèi)部數(shù)據(jù)總線的寬度為限。對于32MCU,可以是1個字節(jié)、2個字節(jié)(半字)4個字節(jié)()。

控制傳輸數(shù)據(jù)的節(jié)奏,即傳輸數(shù)據(jù)的時機(jī):每次DMA讀寫都需要在有傳輸請求時才會執(zhí)行。傳輸請求可以來自于數(shù)據(jù)源設(shè)備,例如ADC轉(zhuǎn)換結(jié)束;傳輸請求也可以來自于數(shù)據(jù)目標(biāo)設(shè)備,例如SPI的發(fā)送就緒。因此每兩次傳輸請求的間隔可以不一致。DMA的傳輸請求也可以由DMA控制器內(nèi)部產(chǎn)生,用于內(nèi)存中數(shù)據(jù)塊的傳送。

狀態(tài)查詢和中斷控制:DMA控制器的狀態(tài)和中斷可以是多種多樣,通常有傳輸開始、傳輸結(jié)束、傳輸錯誤等。

LPC800DMA控制器實現(xiàn)了上述所有的基本控制功能,而且還有不少自己的特色,下面一一介紹。

1.2DMA傳輸與CPU指令的執(zhí)行不管是CPU還是DMA控制器,都要通過同一條總線訪問存儲器和各種片內(nèi)外設(shè),進(jìn)行數(shù)據(jù)傳輸。CPU的基本操作就是取指、譯碼、運算、執(zhí)行的過程,取指操作需要占用總線,執(zhí)行階段的讀數(shù)據(jù)或?qū)憯?shù)據(jù)操作也需要占用總線。DMA控制器可以充分地利用CPU不占用總線的時間,在總線上傳輸數(shù)據(jù)。

如果在同一個時間,CPUDMA控制器都需要占用總線,這種情況下需要有仲裁機(jī)制,協(xié)調(diào)兩個總線主設(shè)備的動作。

如果在總線已經(jīng)被某個主設(shè)備(例如CPU)占用的時候,另一個主設(shè)備(例如DMA控制器)就會稍作等待,待總線空閑時,再開始數(shù)據(jù)傳輸。

從以上描述可以看出,DMA可以在不需CPU干預(yù)的情況下,利用CPU不占用總線的空閑時間進(jìn)行數(shù)據(jù)傳輸。這樣不但提高了總線的利用率,還減輕了CPU搬運數(shù)據(jù)的負(fù)擔(dān),提高了系統(tǒng)的并行性,能夠?qū)崿F(xiàn)更復(fù)雜的控制要求,或降低整體的功耗。

1.3LPC800DMA控制器LPC800DMA控制器具有如下特性:多個通道,每個通道唯一地連接到一個片內(nèi)外設(shè)的輸入或輸出請求,例如USARTSPII2C通信外設(shè)。▲DMA傳輸可以由片內(nèi)或片外事件觸發(fā),每個DMA通道都可以有多個觸發(fā)輸入源,每次傳輸只能選擇一個觸發(fā)源。可以指定每個DMA通道的優(yōu)先級,當(dāng)通道之間的傳輸需求發(fā)生沖突時,高優(yōu)先級通道先進(jìn)行傳輸。傳輸描述符機(jī)制,通過多個傳輸描述符互聯(lián),可以實現(xiàn)鏈?zhǔn)降?/span>DMA傳輸控制。每次(每個傳輸描述符)最多可以傳輸1024個字(1024x4=4096字節(jié))。地址增量的多種選項,允許靈活的數(shù)據(jù)包處理。LPC800各系列的DMA配置如下:

系列

通道數(shù)目

觸發(fā)輸入源數(shù)目

LPC80x、LPC81x

0

0

LPC82x

18

9

LPC83x

18

8

LPC84x

25

13

1.3.1DMA寄存器一覽

DMA控制器有15個寄存器,涉及到所有通道,可以分為四組。

寄存器組

寄存器名稱

功能

說明

通用寄存器組

CTL

DMA控制器寄存器

只有一個控制位,使能DMA控制器

INTSTAT

中斷狀態(tài)寄存器

標(biāo)志是否有掛起的中斷

SRAMBASE

傳輸描述符地址寄存器

所有通道第一個傳輸描述符的存放地址(必須512字節(jié)對齊)

通道控制寄存器組

ENABLESET0

通道使能寄存器

每個通道占用一位。表示是否使能對應(yīng)通道

ENABLECLR0

通道失能寄存器

每個通道占用一位。表示是否失能對應(yīng)通道

ACTIVE0

通道激活狀態(tài)寄存器

每個通道占用一位。表示對應(yīng)通道是否加載了傳輸描述符

BUSY0

通道忙狀態(tài)寄存器

每個通道占用一位。表示對應(yīng)通道是否正在搬運數(shù)據(jù)

通道中斷寄存器組

ERRINT0

錯誤中斷狀態(tài)寄存器

每個通道占用一位。表示是否有錯誤中斷

INTENSET0

中斷使能寄存器

每個通道占用一位。表示是否使能對應(yīng)通道的中斷

INTENCLR0

中斷失能寄存器

每個通道占用一位。表示是否失能對應(yīng)通道的中斷

INTA0

中斷A狀態(tài)寄存器

每個通道占用一位。表示是否有中斷A

INTB0

中斷B狀態(tài)寄存器

每個通道占用一位。表示是否有中斷B

傳輸控制寄存器

SETVALID0

設(shè)置“有效”控制位寄存器

每個通道占用一位。用于設(shè)置描述符的“有效”控制位

SETTRIG0

設(shè)置“觸發(fā)”控制位寄存器

每個通道占用一位。用于觸發(fā)對應(yīng)的通道傳輸

ABORT0

通道中止傳輸寄存器

每個通道占用一位。用于中止對應(yīng)的通道傳輸

每個DMA通道還分別有下表中的三個寄存器,用于配置各個通道的參數(shù),將在1.4節(jié)詳細(xì)介紹。

寄存器名稱

功能

說明

CFG

通道配置寄存器

用于配置通道的使能、觸發(fā)、成組傳輸(Burst)和優(yōu)先級的選項

CTLSTAT

通道控制狀態(tài)寄存器

用于標(biāo)示通道的有效和觸發(fā)狀態(tài)

XFERCFG

通道傳輸配置寄存器

用于配置通道的各個配置選項

1.3.2 DMA傳輸描述符

除了上述寄存器外,LPC800DMA控制器通過位于內(nèi)存中的傳輸描述符,控制每次的DMA傳輸。每個傳輸描述符有4個字(32/),內(nèi)容如下:wKgZomWDjhSAcHgNAAAfGz12R-s782.png多個傳輸描述符可以構(gòu)成一個連續(xù)的鏈條或循環(huán)鏈,鏈條中的每一個描述符對應(yīng)一次DMA傳輸。傳輸?shù)臄?shù)據(jù)數(shù)量、數(shù)據(jù)寬度以及地址變化的方式等,由XFERCFG寄存器的內(nèi)容指定。

每次DMA傳輸開始前,DMA控制器都要把一個完整的描述符讀入,傳輸描述符中偏移地址為0x0的字會被傳送到XFERCFG寄存器中,用于控制各項傳輸參數(shù)。一個鏈條的第一次傳輸參數(shù),需要由軟件直接寫入到XFERCFG寄存器,因此鏈條中的第一個描述符的第一個字為保留位。在傳輸開始時,DMA控制器會把傳輸區(qū)的地址讀入內(nèi)部寄存器中。

使用描述符的鏈接特性,可以方便地實現(xiàn)多種數(shù)據(jù)傳輸控制。

例如需要使用SPI驅(qū)動一個LCD屏幕產(chǎn)生動畫效果時,可以配置為下圖所示的乒乓結(jié)構(gòu)的DMA描述符鏈條,CPU只需要不斷地生成顯示圖片,由DMA控制器平行地進(jìn)行圖片數(shù)據(jù)至LCD屏幕的傳送。

wKgZomWDjhSAQY9AAAFL7cj531c211.png? ? ? ? ? ? ? ? ? ??圖3.乒乓結(jié)構(gòu)的DMA描述符鏈

這里使用了三個傳輸描述符。第一個描述符(鏈頭)指示將緩沖區(qū)A的數(shù)據(jù)傳輸?shù)?/span>SPI的發(fā)送寄存器,后面兩個描述符分別指示緩沖區(qū)B和緩沖區(qū)A的數(shù)據(jù),輪流傳輸?shù)?/span>SPI的發(fā)送寄存器。CPU只需要在對應(yīng)的緩沖區(qū)準(zhǔn)備好數(shù)據(jù),再設(shè)置對應(yīng)的描述符為“有效”,接下來DMA控制器就會直接把數(shù)據(jù)傳送到SPI模塊進(jìn)行發(fā)送。

1.3.3 DMA傳輸通道每個通信外設(shè)的發(fā)送傳輸可以產(chǎn)生DMA請求,接收傳輸也可以產(chǎn)生DMA請求。

LPC800DMA控制器非常簡單,每個片內(nèi)外設(shè)產(chǎn)生的DMA傳輸請求信號,唯一地連接到一個固定的DMA通道。即如果把片內(nèi)外設(shè)作為DMA傳輸?shù)脑椿蚰繕?biāo),并且希望由該外設(shè)來控制傳輸?shù)墓?jié)奏(通過DMA傳輸請求信號),則必須使用對應(yīng)的通道。如果能夠使用其它的方法(例如時鐘觸發(fā)等),保證外設(shè)不會發(fā)生數(shù)據(jù)溢出的情況,則可以使用任意通道,但這種用法不能最優(yōu)地利用帶寬時間,除非需要特殊的時序控制,一般不建議使用。

每個通道對應(yīng)的DMA請求源如下表所示:

wKgZomWDjhSAXLVrAACL8bMrNOk751.pngwKgZomWDjhSAd-bfAABMlOrT-KY420.png

表1.DMA通道與DMA請求源的對應(yīng)表

1.3.4 DMA觸發(fā)源的選擇

DMA控制器之外,有一個DMA觸發(fā)輸入 (DMA TRIGMUX)模塊,每個DMA通道都在這個模塊中有一個對應(yīng)的多選一選擇器,由DMA_ITRIG_INMUXn寄存器控制(n對應(yīng)表1的通道號),用戶可以在多種信號中選擇一個作為DMA的觸發(fā)信號。下表列出了所有可能的選項:wKgZomWDjhSAL5FoAACCKcBc_X4128.png表2.DMA觸發(fā)選項(1):在LPC82x/83x中,n取值0~17;在LPC84x中,n取值0~24。

*:每一個DMA通道都輸出一個觸發(fā)信號,所有通道輸出的觸發(fā)信號都連接到兩個多選一的選擇器:DMA_INMUX_INMUX0DMA_INMUX_INMUX1,這兩個多選一選擇器的輸出可以作為另一個DMA通道的觸發(fā)源選項之一。這個配置允許多個DMA通道的協(xié)同操作。

wKgZomWDjhSAFyZlAAFhs4hBuhg801.png? ? ? ? ? ? ? ? ? ? ? ?圖4.DMA觸發(fā)輸入框圖

上圖為某個DMA通道的觸發(fā)輸入模塊框圖,每個通道都有一個這樣相同的電路用于選擇它的觸發(fā)輸入。 1.4 DMA傳輸?shù)恼埱?、觸發(fā)與生成傳輸概念每個通道的DMA觸發(fā)信號相當(dāng)于這個通道的總開關(guān),只有打開這個總開關(guān),才能夠進(jìn)行隨后的DMA傳輸操作。

每次DMA傳輸(即圖2示意中的每一次讀寫)的時機(jī),則由DMA請求信號決定。

成組傳輸(Burst)是指在一次觸發(fā)之后,按照指定的次數(shù)進(jìn)行一組數(shù)據(jù)的傳輸,這組數(shù)據(jù)傳輸完成后,需要另一次的觸發(fā)條件才能進(jìn)行下一組的數(shù)據(jù)傳輸。

成組傳輸控制和DMA傳輸請求控制組合為四種操作模式,他們與觸發(fā)信號的關(guān)系如下表所示。

表中的DMA傳輸請求信號以USARTTXRDY為例:

組合模式

使能成組傳輸(TRIGBURST,見1.5.1節(jié))

使能外設(shè)請求(PERIPHREQEN,見1.5.1節(jié))

操作模式說

0

0

0

觸發(fā)信號用于啟動完整的DMA傳輸過程,只需一個觸發(fā)信號即可完成所有數(shù)據(jù)傳輸。

DMA將以最快的速度,連續(xù)不斷地傳送數(shù)據(jù),直到完成所有數(shù)據(jù)。

1

0

1

每個DMA傳輸請求(TXRDY),只能傳輸一個數(shù)據(jù)。

2

1

0

每個觸發(fā)信號啟動一組DMA傳輸,每組傳送BURSTPOWER(1.5.1節(jié))個數(shù)據(jù)。因此總共需要(XFERCOUNT/BURSTPOWER)組的傳輸(即需要相同數(shù)目的觸發(fā)信號),才能完成所有數(shù)據(jù)。

XFERCOUNT位于XFERCFG寄存器(1.5.2節(jié))

DMA將以最快的速度,連續(xù)不斷地傳送數(shù)據(jù),直到完成所有數(shù)據(jù)。

3

1

1

每個DMA傳輸請求(TXRDY),只能傳輸一個數(shù)據(jù)。

表3.成組傳輸和外設(shè)請求與觸發(fā)信號的關(guān)系表

表中的組合模式0適合于從存儲器至存儲器的數(shù)據(jù)塊拷貝;組合模式1適合于常用的通信模塊的數(shù)據(jù)發(fā)送和接收。

組合模式2、3則視具體的應(yīng)用情況,由用戶自由發(fā)揮。例如,要在USART上發(fā)送若干個固定長度的數(shù)據(jù)包,而發(fā)送每個數(shù)據(jù)包的時間需要由定時器來決定,則可以使用上述的組合模式3,設(shè)置BURSTPOWER為數(shù)據(jù)包的長度,設(shè)置SCT定時器產(chǎn)生觸發(fā)信號(見表2SCT_DMA0/1)

拿自動步槍做一個形象的比喻,成組的概念相當(dāng)于子彈夾,外設(shè)請求相當(dāng)于扳機(jī),觸發(fā)相當(dāng)于擊發(fā)保險,一次DMA傳輸中需要打出一箱子彈。那么每種組合模式有如下對應(yīng):組合模式0:打開擊發(fā)保險后,不需其它動作,整箱子彈即全部射出。組合模式1:打開擊發(fā)保險后,每扣動一次扳機(jī),射出一發(fā)子彈,直到打完整箱子彈。組合模式2:打開擊發(fā)保險后,不需其它動作,一個彈夾中的子彈即全部射出。然后再次打開擊發(fā)保險,即射出另一個彈夾中的全部子彈。重復(fù)上述操作直到整箱子彈打光。組合模式3:打開擊發(fā)保險后,每扣動一次扳機(jī),射出一個彈夾中的一顆子彈,重復(fù)直到這個彈夾中的子彈打光,擊發(fā)保險自動關(guān)閉。然后須再次打開擊發(fā)保險,再一次次地扣動扳機(jī),逐個射出另一個彈夾中的所有子彈,擊發(fā)保險再次自動關(guān)閉。重復(fù)上述過程直到打完整箱子彈。

這里有一個要求,即XFERCOUNT必須能被BURSTPOWER整除,即一箱子彈的數(shù)目,必須是一個彈夾能容納子彈個數(shù)的倍數(shù)。

1.5 DMA通道參數(shù)寄存器

1.3.1節(jié)中列出的寄存器,用于控制整個DMA控制器,以及控制每個通道的使能、中斷和觸發(fā)等狀態(tài)。每個通道的具體工作模式,由下述三個寄存器來描述。

1.5.1DMA通道配置寄存器(CFG)

wKgZomWDjhWAZvIUAAHyUtsnSG0901.png

各個控制域的說明如下:▲PERIPHREQEN:使能外設(shè)請求。0 – 使能外設(shè)請求;1 – 不使能外設(shè)請求。

每個通道的外設(shè)請求來源是固定的,見表1。例如對應(yīng)SPI0的發(fā)送就緒信號(TXRDY)DMA通道,在LPC82x/83x中是通道7,在LPC84x中是通道11。HWTRIGEN:使能硬件觸發(fā)。硬件觸發(fā)信號源由DMA_ITRIG_INMUXn寄存器選擇,1.3.4節(jié)。0 – 使能硬件觸發(fā);1 – 不使能硬件觸發(fā)。TRIGPOL:觸發(fā)極性。TRIGTYPE:觸發(fā)類型。TRIGPOLTRIGTYPE共同決定如何使用觸發(fā)信號,組合關(guān)系如下表。

TRIGTYPE

TRIGPOL

說明

0

0

下降沿觸發(fā)

0

1

上升沿觸發(fā)

1

0

低電平觸發(fā)

1

1

高電平觸發(fā)

TRIGBURST:觸發(fā)成組傳輸。

0 – 觸發(fā)之后不按組傳輸(或可理解為所有數(shù)據(jù)為一組)1 - 觸發(fā)之后執(zhí)行成組傳輸。BURSTPOWER:成組傳輸中每組的長度。這個域的內(nèi)容為2的冪次數(shù)值,取值為0~10,表示每組長度為1(20)、2(21)4(22) 、8(23)、……、1024(210)不支持0~10之外的數(shù)值。

注意:XFERCOUNT必須是BURSTPOWER的倍數(shù)。

SRCBURSTWRAP:成組傳輸中每組傳輸結(jié)束后,是否需要恢復(fù)傳輸?shù)脑吹刂贰?/span>0 – 不恢復(fù)源地址;1 – 恢復(fù)源地址。

這個控制項適合于重復(fù)地讀出相同的數(shù)據(jù)塊,或相同的一組寄存器。DSTBURSTWRAP:成組傳輸中每組傳輸結(jié)束后,是否需要恢復(fù)傳輸?shù)哪繕?biāo)地址。0 – 不恢復(fù)目標(biāo)地址;1 – 恢復(fù)目標(biāo)地址。

這個控制項適合于重復(fù)地寫入相同的存儲區(qū),例如重復(fù)地讀出一組傳感器的數(shù)值,軟件只關(guān)心即時的數(shù)值,而不關(guān)心數(shù)值變化的過程。CHPRIORITY:設(shè)置本通道的優(yōu)先級。在多個通道同時請求獲得總線進(jìn)行傳輸時,優(yōu)先級高的通道先得到總線的使用權(quán)限。

0 – 最高優(yōu)先級;7 – 最低優(yōu)先級。

1.5.2 DMA通道傳輸配置寄存器(XFERCFG)

wKgZomWDjhWAX_oHAAIeMtFOje4522.png

該寄存器的內(nèi)容給出了當(dāng)前DMA傳輸?shù)母黜梾?shù)。一個傳輸描述符指定的一次傳輸結(jié)束后,DMA控制器會自動地讀入鏈條中的下一個描述符,描述符的第一個字的內(nèi)容會加載到XFERCFG寄存器,見1.3.2節(jié)的說明。

XFERCFG各個控制域的說明如下:CFGVALID:表示所對應(yīng)的描述符是否有效。0 – 描述符無效;1 – 描述符有效。RELOAD:當(dāng)前描述符所指定的傳輸完成后,是否需要讀入下一個描述符。0 – 不讀入下一個描述符;1 – 讀入下一個描述符,允許描述符的鏈接操作。SWTRIG:軟件觸發(fā)。0 – 需要由HWTRIGEN、TRIGPOLTRIGTYPE指定通道的觸發(fā)條件。

1 – 設(shè)置此位表示該通道的觸發(fā)條件立即滿足。

注意:使用軟件觸發(fā)時,在TRIGBURST=0時,不得使用電平觸發(fā)。CLRTRIG:當(dāng)前描述符的傳輸結(jié)束后,是否清除觸發(fā)條件。0 – 不清除。如果RELOAD=1,則下一個描述符的觸發(fā)條件滿足。

1 – 清除。當(dāng)前描述符指示的傳輸結(jié)束后,清除觸發(fā)條件。

注意:只有軟件觸發(fā)條件和邊沿觸發(fā)條件可以被清除,而電平觸發(fā)條件不能被清除。SETINTA:當(dāng)前描述符的傳輸結(jié)束后,是否產(chǎn)生中斷標(biāo)志INTA0 – 不產(chǎn)生中斷標(biāo)志;1 – 產(chǎn)生中斷標(biāo)志。▲SETINTB:當(dāng)前描述符的傳輸結(jié)束后,是否產(chǎn)生中斷標(biāo)志INTB。0 – 不產(chǎn)生中斷標(biāo)志;1 – 產(chǎn)生中斷標(biāo)志。

INTAINTB在硬件上沒有差別,用戶可以用這兩個中斷(標(biāo)志)區(qū)別是哪個描述符的傳輸完成了,尤其是在乒乓結(jié)構(gòu)的傳輸中。WIDTH:表示每次DMA傳輸?shù)臄?shù)據(jù)寬度。源地址的讀和目標(biāo)地址的寫,使用相同的數(shù)據(jù)寬度。0 – 8位數(shù)據(jù)傳輸;1 – 16位數(shù)據(jù)傳輸;2 – 32位數(shù)據(jù)傳輸;3 – 保留組合,不得使用。

注意:如果要求的數(shù)據(jù)寬度是16位或32位,則傳輸?shù)牡刂芬脖仨毞謩e是2字節(jié)或4字節(jié)對齊的。SRCINC:表示每次傳輸一個數(shù)據(jù)后,源地址的增量變化。0 – 地址無變化。

1 – 地址按數(shù)據(jù)寬度+1,指向數(shù)據(jù)區(qū)中的下一個數(shù)據(jù)。

2 – 地址按數(shù)據(jù)寬度+2。

3 – 地址按數(shù)據(jù)寬度+4DSTINC:表示每次傳輸一個數(shù)據(jù)后,目標(biāo)地址的增量變化。該域的取值含義與SRCINC一樣。

SRCINCDSTINC取值為0,最常見的應(yīng)用場景是面對外設(shè)寄存器的讀寫,例如傳送一個數(shù)據(jù)塊至SPI0TXDAT,或從USARTRXDAT讀出一組數(shù)據(jù)至存儲區(qū)。

SRCINCDSTINC取值為1,最常見的應(yīng)用場景對一個連續(xù)的存儲區(qū)的讀寫。

SRCINCDSTINC取值為23時,一個應(yīng)用案例是,當(dāng)WIDTH=0(8位數(shù)據(jù))時,希望傳輸一組數(shù)據(jù)字或半字中的某個字節(jié),而不管其它字節(jié)。▲XFERCOUNT:傳輸?shù)臄?shù)據(jù)總數(shù),寄存器中填入(總數(shù)-1)。該域有10位,即最大傳輸數(shù)據(jù)數(shù)目為1024。

傳輸?shù)淖止?jié)總數(shù)為:(XFERCOUNT + 1) *WIDTH

注意1:在DMA傳輸過程中,DMA控制器會遞減該數(shù)值,因此不能在傳輸過程中或傳輸結(jié)束后,讀出該域而得知預(yù)設(shè)的傳輸數(shù)目。

注意2:如果設(shè)置了TRIGBURST =1,則XFERCOUNT必須是BURSTPOWER的倍數(shù)。

1.5.3DMA通道控制和狀態(tài)寄存器(CTLSTAT)wKgZomWDjhWAHK8VAABpkAN0DLo503.png這個寄存器只有兩個標(biāo)志位,用戶可以檢查這些標(biāo)志位,獲知當(dāng)前DMA控制器的部分運行狀態(tài)。▲VALIDPENDING:延遲的有效位。見0的說明。▲TRIG:觸發(fā)標(biāo)志。該位表示是否有觸發(fā)條件。設(shè)置觸發(fā)條件有多種途徑:通道傳輸配置寄存器(XFERCFG)SWTRIG控制位。設(shè)置觸發(fā)控制寄存器(SETTRIG0) ,該寄存器可以同時設(shè)置一個或多個通道的觸發(fā)條件。■DMA觸發(fā)輸入模塊選定的硬件觸發(fā)信號,滿足TRIGPOLTRIGTYPE時。清除觸發(fā)條件也有多種途徑:當(dāng)CLRTRIG=1時,描述符指定的傳輸結(jié)束時,清除觸發(fā)條件。

當(dāng)失能DMA控制器時,見CTRL寄存器。

1.6描述符有效位的延遲設(shè)置機(jī)制通道傳輸配置寄存器(XFERCFG)CFGVALID位,指定該描述符是否有效。當(dāng)一個有效的描述符被讀入DMA控制器后,當(dāng)CTLSTAT寄存器的TRIG標(biāo)志被設(shè)置后,DMA傳輸就會立即開始,這是最理想的情況。

通常的情況是,當(dāng)準(zhǔn)備好一個描述符A,尤其是使用描述符鏈時,描述符A所對應(yīng)的存儲區(qū)的數(shù)據(jù)可能還沒有準(zhǔn)備好,循環(huán)的乒乓結(jié)構(gòu)就是一個很好的例子。這種情況下,就需要先設(shè)置描述符ACFGVALID=0,待數(shù)據(jù)區(qū)準(zhǔn)備好后再設(shè)置它為有效。這樣延遲設(shè)置描述符有效,是通過SETVALID0寄存器來完成。

SETVALID0寄存器的每一位對應(yīng)一個DMA通道,第n位寫’1’表示延遲設(shè)置通道n的描述符有效。

使用SETVALID0寄存器實現(xiàn)延遲設(shè)置描述符有效,是為了避免設(shè)置錯誤。設(shè)想一下,當(dāng)DMA控制器已經(jīng)在運行鏈上的某個描述符B時,軟件無法知道另一個描述符A是否已經(jīng)被讀入DMA控制器。如果它還未被讀入DMA控制器,則可以直接操作描述符A所在的存儲區(qū);如果它已經(jīng)被讀入DMA控制器,則應(yīng)該操作XFERCFG寄存器。

SETVALID0寄存器就是為了正確地設(shè)置描述符的有效位。

經(jīng)過以上介紹可以看到,如果當(dāng)前加載到DMA控制器的描述符是有效的,設(shè)置SETVALID0寄存器表示延遲設(shè)置鏈中下一個描述符為有效,此時CTLSTAT寄存器的VALIDPENDING為‘1’,標(biāo)示這種狀態(tài);當(dāng)下一個描述符被讀入DMA控制器時,經(jīng)延遲的設(shè)置描述符有效的操作才最終完成,此時VALIDPENDING位被清除。如果當(dāng)前加載到DMA控制器的描述符是無效的,設(shè)置SETVALID0寄存器表示改變當(dāng)前這個描述符為有效,不需經(jīng)過延遲,操作立即生效。

使用這種延遲機(jī)制,軟件可以從容地先準(zhǔn)備好描述符鏈,然后再按部就班地準(zhǔn)備好數(shù)據(jù)區(qū),逐步推進(jìn)數(shù)據(jù)傳輸進(jìn)程,而不必費周折查詢等待DMA控制器的狀態(tài)。

1.7若干DMA傳輸例程

本節(jié)的幾個例程,分別展示幾種DMA的常見用法。所有例程都會用到這樣幾個結(jié)構(gòu)體。

結(jié)構(gòu)體DMA_CHDESC_T是所有通道的描述符鏈中的第一個描述符。

typedef struct {

uint32_t notused; // 第一個描述符的這個位置是保留位

uint32_t source; // DMA傳輸源數(shù)據(jù)區(qū)的末地址

uint32_t dest; // DMA傳輸目標(biāo)數(shù)據(jù)區(qū)的末地址

uint32_t next; // 鏈接到下一個描述符

} DMA_CHDESC_T;

所有通道的第一個描述符,需要按順序放在一個DMA_CHDESC_T數(shù)組中,而且這個數(shù)組的開始地址必須是512字節(jié)對齊的內(nèi)存地址:

ALIGN(512) DMA_CHDESC_T Chan_Desc_Table[];

每個通道的第一個描述符,必須放在這個數(shù)組中與通道編號對應(yīng)的單元中。例如USART1_RX_DMA通道的第一個描述符需要放在數(shù)組的第2個單元中(見表1)。

結(jié)構(gòu)體DMA_RELOADDESC_T適用于其它描述符。所有描述符必須位于16字節(jié)對齊的內(nèi)存地址。

typedef struct {

uint32_t xfercfg; // 描述符的傳輸配置寄存器

uint32_t source; // DMA傳輸源數(shù)據(jù)區(qū)的末地址

uint32_t dest; // DMA傳輸目標(biāo)數(shù)據(jù)區(qū)的末地址

uint32_t next; // 鏈接到下一個描述符

} DMA_RELOADDESC_T;

1.7.1DMA執(zhí)行內(nèi)存中的數(shù)據(jù)塊拷貝

使用DMA的最簡單應(yīng)用就是在內(nèi)存中拷貝一個數(shù)據(jù)塊,這是一個非常有效率的搬移數(shù)據(jù)塊的方法,尤其是數(shù)據(jù)量比較大時,CPU可以同時執(zhí)行更多的操作。DMA拷貝數(shù)據(jù)塊不涉及到任何外設(shè)請求,使用軟件觸發(fā),所以也不涉及到任何硬件的觸發(fā)。

本例程先用隨機(jī)數(shù)初始化數(shù)組Buffer1[ ],然后用DMABuffer1[ ]傳送數(shù)據(jù)至Buffer2[ ]。數(shù)組定義如下:

wKgZomWDjhWAQg70AAAtAqdSbxI093.png下面是初始化DMA控制器,并啟動DMA的函數(shù)。代碼片段1.使用DMA在內(nèi)存中拷貝一個數(shù)據(jù)塊

01  void DMA_M2M_Init(uint32_t *buf1, uint32_t *buf2, uint32_t length)
02  {   uint32_t ch_cfg_val, xfercount, xfercfg; 
03  
04      LPC_SYSCON->SYSAHBCLKCTRL |= DMA;
05      LPC_DMA->CTRL = 0;
06  
07      LPC_DMA->SRAMBASE = (uint32_t)(&Chan_Desc_Table); 
08  
09      xfercount = length - 1; 
10  ch_cfg_val = 0; 
11      xfercfg = 0 << DMA_XFERCFG_CFGVALID | // 暫時設(shè)置為無效
12                0 << DMA_XFERCFG_RELOAD   | // 沒有下一個描述符
13                1 << DMA_XFERCFG_SWTRIG   | // 軟件觸發(fā)
14                1 << DMA_XFERCFG_CLRTRIG  | // 傳輸結(jié)束時清除觸發(fā)標(biāo)志
15                1 << DMA_XFERCFG_SETINTA  | // 傳輸結(jié)束時設(shè)置INTA中斷
16                0 << DMA_XFERCFG_SETINTB  |
17                2 << DMA_XFERCFG_WIDTH    | // 數(shù)據(jù)寬度為32位
18                1 << DMA_XFERCFG_SRCINC   | // 每次傳輸后源地址遞增
19                1 << DMA_XFERCFG_DSTINC   | // 每次傳輸后目標(biāo)地址遞增
20                xfercount << DMA_XFERCFG_XFERCOUNT; // 傳輸長度
21      LPC_DMA->CHANNEL[CH_USART0_RX].CFG = ch_cfg_val; 
22      LPC_DMA->CHANNEL[CH_USART0_RX].XFERCFG = xfercfg; 
23  
24      Chan_Desc_Table[CH_USART0_RX].source = (uint32_t)(&buf1[xfercount]);
25      Chan_Desc_Table[CH_USART0_RX].dest   = (uint32_t)(&buf2[xfercount]);
26      Chan_Desc_Table[CH_USART0_RX].next   = (uint32_t)0L; 
27  
28      LPC_DMA->INTENSET0 =  1 << CH_USART0_RX; 
29      LPC_DMA->ENABLESET0 = 1 << CH_USART0_RX; 
30  
31      LPC_DMA->CTRL = 1; 
32  
33      LPC_DMA->SETVALID0 = 1 << CH_USART0_RX; 
34  //  LPC_DMA->SETTRIG0  = 1 << CH_USART0_RX;
35  }

在這個例程中,用到了宏定義CH_USART0_RX,這是對應(yīng)USART0接收方向的DMA通道號(見表1),在頭文件中定義了所有的通道號:

#define CH_USART0_RX 0 // USART0接收就緒

#define CH_USART0_TX 1 // USART0發(fā)送就緒

#define CH_USART1_RX 2 // USART1接收就緒

#define CH_USART1_TX 3 // USART1發(fā)送就緒

......

......

Chan_Desc_Table所有通道的描述符鏈頭構(gòu)成的數(shù)組,這個數(shù)組的起始地址必須是512字節(jié)對齊的。

ALIGN(512) DMA_CHDESC_T Chan_Desc_Table[1];

在本例程中,由于使用的是通道0,而沒有使用其它通道,所以在數(shù)組中只配置了一個單元。

原則上,這個數(shù)組中對應(yīng)不使用的通道的描述符單元,可以挪做其它用途。

在這個例程里,配置好所有的寄存器和描述符,并且使能了整個DMA控制器后,在第33行配置了對應(yīng)的傳輸符為有效,該語句執(zhí)行后DMA傳輸立即開始了。

如果第13行沒有配置XFERCFG的“軟件觸發(fā)”位,執(zhí)行第33行后DMA通道還需要等待觸發(fā)信號才能開始傳輸,第34行就是由軟件發(fā)出DMA觸發(fā)信號的另一種途徑。

由上面的介紹可以看出,可以有多種方式,靈活地安排啟動DMA傳輸?shù)臅r機(jī)和方法,讓用戶可以更加有效地安排自己的應(yīng)用流程。

下面是這個例程的主函數(shù)和中斷處理程序。

代碼片段2.使用DMA拷貝一個數(shù)據(jù)塊的中斷函數(shù)和主函數(shù)

01  uint8_t DMA_IntA_Flag;
02  void DMA_IRQHandler(void) // DMA中斷處理程序
03  {
04      if (LPC_DMA->INTA0 & (1 << CH_USART0_RX)) {
05          LPC_DMA->INTA0 = 1 << CH_USART0_RX;
06          DMA_IntA_Flag = 1;
07      }
08      if (LPC_DMA->ERRINT0 & (1 << CH_USART0_RX)) 
09          LPC_DMA->ERRINT0 = 1 << CH_USART0_RX;
10  }
11  
12  void main()
13  {   uint32_t pp;
14      for (pp = 0; pp < BUF_SIZE; pp++)
15          Buffer1[pp] = rand();
16  
17      DMA_IntA_Flag = 0; 
18      DMA_M2M_Init(Buffer1, Buffer2, BUF_SIZE); 
19  
20      NVIC_EnableIRQ(DMA_IRQn); 
21      do {
22          __WFI();
23      } while (DMA_IntA_Flag == 0); 
24  
25      while (1);
26  }

DMA傳輸結(jié)束后產(chǎn)生中斷,在中斷函數(shù)中將軟件標(biāo)志置’1’,主函數(shù)可以知道DMA傳輸是否已經(jīng)完成。在實際的項目中,用戶程序可以替換上述21~23行的代碼,執(zhí)行其它的一些操作。

1.7.2DMA執(zhí)行USART0的連續(xù)發(fā)送(硬件觸發(fā))

下面這個例程是使用DMA通過USART0發(fā)送一個字符串,需要配置使用USART0的發(fā)送請求,并采用開發(fā)板上的USER_KEY產(chǎn)生硬件觸發(fā),即按下按鍵后才送出所有數(shù)據(jù),用戶可以在PC端的虛擬串口上看到送出的字符串。

首先還是DMA的初始化函數(shù),這個函數(shù)與前面的數(shù)據(jù)塊搬運初始化基本一致,指示CFGXFERCFG寄存器的內(nèi)容有所變化。

代碼片段3. DMA通過USART0發(fā)送字符串01 void DMA_UART_Send(uint8_t *buf, uint32_t length)

02  {   uint32_t ch_cfg_val, xfercount, xfercfg; 
03  
04      LPC_SYSCON->SYSAHBCLKCTRL |= DMA;
05      LPC_DMA->CTRL = 0;
06  
07      LPC_DMA->SRAMBASE = (uint32_t)(&Chan_Desc_Table); 
08  
09      xfercount = length - 1; 
10  ch_cfg_val = 1 << DMA_CFG_PERIPHREQEN | // 外設(shè)請求
11                   1 << DMA_CFG_HWTRIGEN |  // 硬件觸發(fā)
12                   0 << DMA_CFG_TRIGTYPE |  // 邊沿觸發(fā)
13                   0 << DMA_CFG_TRIGPOL;    // 下降沿觸發(fā)
14  
15      xfercfg = 0 << DMA_XFERCFG_CFGVALID | // 暫時設(shè)置為無效
16                0 << DMA_XFERCFG_RELOAD   | // 沒有下一個描述符
17                0 << DMA_XFERCFG_SWTRIG   | // 沒有軟件觸發(fā)
18                1 << DMA_XFERCFG_CLRTRIG  | // 傳輸結(jié)束時清除觸發(fā)標(biāo)志
19                1 << DMA_XFERCFG_SETINTA  | // 傳輸結(jié)束時設(shè)置INTA中斷
20                0 << DMA_XFERCFG_SETINTB  |
21                0 << DMA_XFERCFG_WIDTH    | // 數(shù)據(jù)寬度為8位
22                1 << DMA_XFERCFG_SRCINC   | // 每次傳輸后源地址遞增
23                0 << DMA_XFERCFG_DSTINC   | // 每次傳輸后目標(biāo)地址不遞增
24                xfercount << DMA_XFERCFG_XFERCOUNT; // 傳輸長度
25      LPC_DMA->CHANNEL[CH_USART0_TX].CFG = ch_cfg_val; 
26      LPC_DMA->CHANNEL[CH_USART0_TX].XFERCFG = xfercfg; 
27  
28      Chan_Desc_Table[CH_USART0_TX].source = (uint32_t)(&buf[xfercount]);
29      Chan_Desc_Table[CH_USART0_TX].dest   = (uint32_t)(&LPC_USART0->TXDAT);
30      Chan_Desc_Table[CH_USART0_TX].next   = (uint32_t)0L; 
31  
32      LPC_DMA->INTENSET0 =  1 << CH_USART0_TX; 
33      LPC_DMA->ENABLESET0 = 1 << CH_USART0_TX; 
34  
35      LPC_DMA->CTRL = 1; 
36  
37      LPC_DMA->SETVALID0 = 1 << CH_USART0_TX; 
38  }

上述代碼里用橙色標(biāo)注出與代碼片段1不同的地方。還有一個明顯的不同是,此處所有涉及到DMA通道號時,都換成了CH_USART0_TX。

USART0的初始化部分與USART章節(jié)的代碼完全一致,現(xiàn)抄錄如下。

代碼片段4.基本UART收發(fā)例程的USART0初始化

00  void USART0_init() {
01      LPC_SYSCON->SYSAHBCLKCTRL |= (UART0 | SWM); 
02  
03      LPC_SYSCON->PRESETCTRL &= (UART0_RST_N); 
04      LPC_SYSCON->PRESETCTRL |= ~(UART0_RST_N);
05  
06      ConfigSWM(U0_TXD, P0_4); 
07      ConfigSWM(U0_RXD, P0_0);
08  
09      LPC_SYSCON->UARTCLKDIV = LPC_SYSCON->SYSAHBCLKDIV; // 設(shè)置USART時鐘的分頻系數(shù)
10      LPC_SYSCON->UARTFRGMULT = 4; 
11      LPC_SYSCON->UARTFRGDIV = 255; 
12      LPC_USART0->BRG = 16 - 1;
13  
14      // 8個數(shù)據(jù)位,無校驗位,1個停止位,沒有硬件流控,異步模式
15      LPC_USART0->CFG = DATA_LENG_8 | PARITY_NONE | STOP_BIT_1; 
16  
17      LPC_USART0->CTL = 0;
18  
19      LPC_USART0->STAT = 0xFFFF; 
20  
21      LPC_USART0->INTENSET = RXRDY; 
22      NVIC_EnableIRQ(UART0_IRQn);
23  }

接下來是本節(jié)的重點。代碼片段3的第11~13行,配置DMA通道為硬件觸發(fā)信號的下降沿觸發(fā),下面是初始化PINTINT,使用USER_KEY產(chǎn)生觸發(fā)信號,和對應(yīng)的中斷程序。代碼片段5.初始化按鍵產(chǎn)生DMA硬件觸發(fā)信號

01  #define PINTSEL0 0       // 定義引腳中斷0的編號
02  #define KEY_USER P0_1    // 定義按鍵USER_KEY的引腳
03  
04  void PININT0_IRQHandler(void)
05  {
06      if (LPC_PIN_INT->RISE & (1<
07          LPC_PIN_INT->RISE = 1<// 清除上升沿中斷標(biāo)志
08      if (LPC_PIN_INT->FALL & (1<
09          LPC_PIN_INT->FALL = 1<// 清除下降沿中斷標(biāo)志
10  }
11  
12  void PINT_Init_Key_User()
13  {
14      LPC_GPIO_PORT->DIRCLR0 = 1 << KEY_USER;   // 配置USER_KEY對應(yīng)的引腳為輸入
15      LPC_SYSCON->PINTSEL[PINTSEL0] = KEY_USER; // USER_KEY對應(yīng)對應(yīng)到引腳中斷0(PINTSEL0)
16      LPC_PIN_INT->ISEL = 0 << PINTSEL0;        // 配置引腳中斷0(PINTSEL0)為邊沿觸發(fā)
17      LPC_PIN_INT->IENR = 1 << PINTSEL0;        // 配置引腳中斷0(PINTSEL0)是上升沿觸發(fā)
18      LPC_PIN_INT->IENF = 0 << PINTSEL0;        // 配置引腳中斷0(PINTSEL0)不是下降沿觸發(fā)
19      LPC_PIN_INT->IST = 0xFF;                  // 清除所有可能的引腳中斷標(biāo)志
20      NVIC_EnableIRQ(PININT0_IRQn);             // 使能引腳中斷
21  }

上述代碼是對PINTINT的初始化,它配置USER_KEY對應(yīng)的引腳產(chǎn)生一個中斷信號,確切地說是按鍵按下再抬起時的上升沿將產(chǎn)生中斷。04行的中斷處理程序中,只是簡單地清除可能的上升沿或下降沿中斷標(biāo)志。

這里要澄清兩個概念,一個是引腳中斷的觸發(fā)信號,另一個是DMA的觸發(fā)信號。前者是引腳上的信號,用于產(chǎn)生中斷;后者是芯片內(nèi)部的中斷標(biāo)志對應(yīng)的信號,用于觸發(fā)DMA傳輸。兩個信號分別有上升沿和下降沿的選項,但兩者是不等價的,本例程中引腳中斷選擇的是上升沿,而DMA觸發(fā)信號選擇的是下降沿。

下圖顯示出了這兩個信號之間的關(guān)系:

wKgZomWDjhWAP2UqAADYuOAcS-w277.png? ? ? ? ? ? ? ? ? ? ??圖5.引腳中斷與DMA觸發(fā)信號的關(guān)系圖

圖中的時間點④是觸發(fā)DMA傳輸?shù)臅r間,這個時間點與代碼片段507行的執(zhí)行相對應(yīng)。如果清除上升沿中斷的動作被推遲,則DMA傳輸?shù)臅r間也會被推遲,所以用戶要盡快地響應(yīng)PINTINT中斷并清除中斷標(biāo)志,以實現(xiàn)快速高效傳輸。

下面是主函數(shù)代碼,主函數(shù)中調(diào)用了前面介紹過的DMA、USARTPINTINT函數(shù)。

代碼片段6.硬件觸發(fā)DMA傳輸UART發(fā)送數(shù)據(jù)例程

01  const unsigned char Hello[] = "Hello DMA World!
"; // 待發(fā)送的數(shù)據(jù)串
02  void main()
03  {
04      USART0_init();      // 初始化USART0
05  
06      DMA_IntA_Flag = 0;  // 清除DMA中斷標(biāo)記
07  
08      DMA_UART_Send((uint8_t *)Hello, sizeof(Hello)-1); // 初始化DMA控制器
09  
10      LPC_DMATRIGMUX->DMA_ITRIG_INMUX1 = 0x05; 
11      PINT_Init_Key_User();
12  
13      NVIC_EnableIRQ(DMA_IRQn); 
14      do {
15          __WFI();
16      }
17      while (DMA_IntA_Flag == 0);
18  
19      while (1);
20  }

這個主函數(shù)與前面那個例程(見代碼片段2)的主要區(qū)別,就是第1011行配置DMA觸發(fā)源和對觸發(fā)源(引腳中斷0)的初始化。

這里需要注意的是第10行配置DMA觸發(fā)源,一定要在使能DMA時鐘之后執(zhí)行。本例程中,DMA的時鐘是在DMA_UART_Send()中設(shè)置的,見代碼片段3

1.7.3DMA執(zhí)行USART0的成組發(fā)送

這個例程是在上一個例程的基礎(chǔ)上,增加了使用乒乓鏈接的描述符,同時設(shè)置成組傳輸。

下圖所示為本例程中乒乓鏈接的描述符鏈。鏈頭描述符指向一個開始字符串Hello,并鏈接到描述符B。描述符A指向一個字符串A,描述符B指向另一個字符串B。傳輸執(zhí)行的效果是,先發(fā)送Hello,然后循環(huán)發(fā)送SpingBàSpingAàSpingB......

wKgZomWDjhWAIf71AAGIuEduoic486.png圖6.DMA執(zhí)行USART0的成組發(fā)送例程的描述符鏈另外,例程中安排了以成組(Burst)方式發(fā)送每個字符串,即每次觸發(fā)只發(fā)送BURSTPOWER指定長度的數(shù)據(jù),見1.5.1的說明。

和上節(jié)一樣,例程中的觸發(fā)源也是與USER_KEY相連的引腳中斷0。

本例程用到下述變量。

  ALIGN(512) DMA_CHDESC_T Chan_Desc_Table[2]; // 所有通道描述符鏈頭數(shù)組
  ALIGN(16) DMA_RELOADDESC_T Descriptor_A;    // 描述符A
  ALIGN(16) DMA_RELOADDESC_T Descriptor_B;    // 描述符B
  
  uint8_t DMA_IntA_Flag;    // 中斷A軟件標(biāo)志
  uint8_t DMA_IntB_Flag;    // 中斷B軟件標(biāo)志
                          // 1234----1234----1234----1234----
  const uint8_t Hello[] =   ">> Hello my DMA world!
";         // 鏈頭對應(yīng)的字符串
  const uint8_t StringA[] = ">> Hello dear StringA.
 ";        // 描述符A的字符串
  const uint8_t StringB[] = "<< Hello I am saying String B.
"; // 描述符B的字符串

下面是DMA初始化的代碼代碼片段7.執(zhí)行USART0的成組發(fā)送例程的DMA初始化代碼

01  void DMA_UART_PingPong_Send(uint8_t *buf, uint32_t length)
02  {   uint32_t ch_cfg_val, xfercount, xfercfg; 
03  
04      LPC_SYSCON->SYSAHBCLKCTRL |= DMA;
05      LPC_DMA->CTRL = 0;
06  
07      LPC_DMA->SRAMBASE = (uint32_t)(&Chan_Desc_Table); 
08  
09      xfercount = length - 1; 
10  ch_cfg_val = 1 << DMA_CFG_PERIPHREQEN |   // 外設(shè)請求
11                   1 << DMA_CFG_HWTRIGEN |  // 硬件觸發(fā)
12                   0 << DMA_CFG_TRIGTYPE |  // 邊沿觸發(fā)
13                   0 << DMA_CFG_TRIGPOL |   // 下降沿觸發(fā)
14                   1 << DMA_CFG_TRIGBURST | // 成組傳輸模式
15                   3 << DMA_CFG_BURSTPOWER; // 每組為8(23)個數(shù)據(jù)
16  
17      xfercfg = 0 << DMA_XFERCFG_CFGVALID | // 暫時設(shè)置為無效
18                1 << DMA_XFERCFG_RELOAD   | // 有下一個描述符
19                0 << DMA_XFERCFG_SWTRIG   | // 沒有軟件觸發(fā)
20                1 << DMA_XFERCFG_CLRTRIG  | // 傳輸結(jié)束時清除觸發(fā)標(biāo)志
21                1 << DMA_XFERCFG_SETINTA  | // 傳輸結(jié)束時設(shè)置INTA中斷
22                0 << DMA_XFERCFG_SETINTB  |
23                0 << DMA_XFERCFG_WIDTH    | // 數(shù)據(jù)寬度為8位
24                1 << DMA_XFERCFG_SRCINC   | // 每次傳輸后源地址遞增
25                0 << DMA_XFERCFG_DSTINC   | // 每次傳輸后目標(biāo)地址不遞增
26                xfercount << DMA_XFERCFG_XFERCOUNT; // 傳輸長度
27      LPC_DMA->CHANNEL[CH_USART0_TX].CFG = ch_cfg_val; 
28      LPC_DMA->CHANNEL[CH_USART0_TX].XFERCFG = xfercfg; 
29  
30      Chan_Desc_Table[CH_USART0_TX].source = (uint32_t)(&buf[xfercount]);
31      Chan_Desc_Table[CH_USART0_TX].dest   = (uint32_t)(&LPC_USART0->TXDAT);
32      Chan_Desc_Table[CH_USART0_TX].next   = (uint32_t)& Descriptor_B; 
33  
34      xfercount = sizeof(StringB)- 2; // 去掉字符串結(jié)尾的字符’’
35      Descriptor_B.xfercfg = 1 << DMA_XFERCFG_CFGVALID |
36                             1 << DMA_XFERCFG_RELOAD   |
37                             1 << DMA_XFERCFG_CLRTRIG  |
38                             1 << DMA_XFERCFG_SETINTB  |
39                             1 << DMA_XFERCFG_SRCINC   |
40                             xfercount << DMA_XFERCFG_XFERCOUNT;
41      Descriptor_B.source = (uint32_t)(&StringB[xfercount]);
42      Descriptor_B.dest = (uint32_t)(&LPC_USART0->TXDAT);
43      Descriptor_B.next = (uint32_t)&Descriptor_A;
44  
45      xfercount = sizeof(StringA)- 2; // 去掉字符串結(jié)尾的字符’’ 
46      Descriptor_A.xfercfg = 1 << DMA_XFERCFG_CFGVALID |
47                             1 << DMA_XFERCFG_RELOAD   |
48                             1 << DMA_XFERCFG_CLRTRIG  |
49                             1 << DMA_XFERCFG_SETINTA  |
50                             1 << DMA_XFERCFG_SRCINC   |
51                             xfercount << DMA_XFERCFG_XFERCOUNT;
52      Descriptor_A.source = (uint32_t)(&StringA[xfercount]);
53      Descriptor_A.dest = (uint32_t)(&LPC_USART0->TXDAT);
54      Descriptor_A.next = (uint32_t)&Descriptor_B;
55  
56      LPC_DMA->INTENSET0 =  1 << CH_USART0_TX; 
57      LPC_DMA->ENABLESET0 = 1 << CH_USART0_TX; 
58  
59      LPC_DMA->CTRL = 1; 
60  
61      LPC_DMA->SETVALID0 = 1 << CH_USART0_TX; 
62  }

DMA控制器中設(shè)置的兩個中斷INTAINTB的內(nèi)部機(jī)制完全一致,分為兩個中斷源只是為了讓用戶區(qū)分對應(yīng)的描述符,用戶可以自由安排。本例中設(shè)置描述符A執(zhí)行結(jié)束后會產(chǎn)生中斷A,描述符B執(zhí)行結(jié)束后會產(chǎn)生中斷B,因此相比前一個例程中斷處理程序也多了出來INTB的代碼。

代碼片段8.執(zhí)行USART0的成組發(fā)送例程中斷處理程序
01  void DMA_IRQHandler(void)
02  {
03      if (LPC_DMA->INTA0 & (1 << CH_USART0_TX)) {
04          LPC_DMA->INTA0 = 1 << CH_USART0_TX;
05          DMA_IntA_Flag++;
06      }
07      if (LPC_DMA->INTB0 & (1 << CH_USART0_TX)) {
08          LPC_DMA->INTB0 = 1 << CH_USART0_TX; 
09          DMA_IntB_Flag++;
10      }
11      if (LPC_DMA->ERRINT0 & (1 << CH_USART0_TX))
12          LPC_DMA->ERRINT0 = 1 << CH_USART0_TX;
13  }

每次執(zhí)行完一個描述符后,就會相應(yīng)地產(chǎn)生一個中斷(INTAINTB),用戶可以自行在代碼片段8的第0509行安插代碼在適當(dāng)?shù)臅r候結(jié)束整個描述符鏈的DMA傳輸,例如當(dāng)循環(huán)次數(shù)滿足一定要求時。

代碼片段9.執(zhí)行USART0的成組發(fā)送例程的主函數(shù)

01  void main()
02  {
03      USART0_init();      // 初始化USART0
04  
05      DMA_IntA_Flag = DMA_IntB_Flag = 0;  // 清除DMA中斷標(biāo)記
06  
07      DMA_UART_PingPong_Send((uint8_t *)Hello, sizeof(Hello)-1); // 初始化DMA控制器
08  
09      LPC_DMATRIGMUX->DMA_ITRIG_INMUX1 = 0x05; 
10      PINT_Init_Key_User();
11  
12      NVIC_EnableIRQ(DMA_IRQn); 
13      while (1)
14          __WFI();
15  }

主函數(shù)和前面的代碼片段6基本一致。執(zhí)行這個例程后,每按一次按鍵DMA會發(fā)送8個字符,在串口助手上有如下顯示:

wKgZomWDjhWAQFD2AAIY--ljgGc244.png

END

更多恩智浦AI-IoT市場和產(chǎn)品信息,邀您同時關(guān)注“NXP客棧”微信公眾號

wKgZomWDjhWAF7paAABCdkRE230661.jpg ? ? ?

NXP客棧


恩智浦致力于打造安全的連接和基礎(chǔ)設(shè)施解決方案,為智慧生活保駕護(hù)航。

長按二維碼,關(guān)注我們

恩智浦MCU加油站


這是由恩智浦官方運營的公眾號,著重為您推薦恩智浦MCU的產(chǎn)品信息、開發(fā)技巧、教程文檔、培訓(xùn)課程等內(nèi)容。

wKgZomWDjhaAAHlMAAATNlPH08Y038.jpg ?

長按二維碼,關(guān)注我們


原文標(biāo)題:LPC800前生今世-第九章 直接存儲器訪問 (DMA)

文章出處:【微信公眾號:恩智浦MCU加油站】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。


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

    關(guān)注

    146

    文章

    17362

    瀏覽量

    352851
  • 恩智浦
    +關(guān)注

    關(guān)注

    14

    文章

    5886

    瀏覽量

    108479

原文標(biāo)題:LPC800前生今世-第九章 直接存儲器訪問 (DMA)

文章出處:【微信號:NXP_SMART_HARDWARE,微信公眾號:恩智浦MCU加油站】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    九章云極DataCanvas公司與云南聯(lián)通簽署合作協(xié)議

    近日,九章云極DataCanvas公司與中國聯(lián)合網(wǎng)絡(luò)通信有限公司云南省分公司(以下簡稱云南聯(lián)通)在昆明正式簽署《中國聯(lián)通兩亞“國際”智算中心聯(lián)合運營協(xié)議》,標(biāo)志著雙方將共同推進(jìn)建設(shè)云南省首個千P級
    的頭像 發(fā)表于 10-30 16:08 ?368次閱讀
    <b class='flag-5'>九章</b>云極DataCanvas公司與云南聯(lián)通簽署合作協(xié)議

    揚(yáng)帆出海!九章云極DataCanvas公司驚艷亮相迪拜GITEX Global 2024

    近日,第44屆GITEXGLOBAL展會(GITEXGLOBAL2024)及全球領(lǐng)先的創(chuàng)業(yè)與投資盛會ExpandNorthStar2024在迪拜盛大啟幕。九章云極DataCanvas公司驚艷亮相盛會
    的頭像 發(fā)表于 10-18 17:08 ?329次閱讀
    揚(yáng)帆出海!<b class='flag-5'>九章</b>云極DataCanvas公司驚艷亮相迪拜GITEX Global 2024

    內(nèi)存儲器主要用來存儲什么

    的主要功能 數(shù)據(jù)存儲 :內(nèi)存儲器用于存儲CPU需要直接訪問的數(shù)據(jù),這些數(shù)據(jù)可能是程序代碼、用戶輸入的數(shù)據(jù)、計算過程中的中間結(jié)果等。 指令存儲
    的頭像 發(fā)表于 10-14 09:55 ?1220次閱讀

    內(nèi)存儲器分為隨機(jī)存儲器和什么

    內(nèi)存儲器是計算機(jī)系統(tǒng)中用于臨時存儲數(shù)據(jù)和程序的關(guān)鍵部件,它直接影響到計算機(jī)的運行速度和性能。內(nèi)存儲器主要分為兩大類:隨機(jī)存儲器(RAM,Ra
    的頭像 發(fā)表于 10-14 09:54 ?1622次閱讀

    存儲器訪問速度最快的是什么

    在探討存儲器訪問速度最快的是哪一種時,我們首先需要了解計算機(jī)存儲系統(tǒng)的層次結(jié)構(gòu)以及各類存儲器的特性和功能。計算機(jī)存儲系統(tǒng)通常包括多個層次的
    的頭像 發(fā)表于 10-12 17:01 ?2456次閱讀

    九章云極DataCanvas公司「算力包」產(chǎn)品璀璨亮相2024中國算力大會!

    九章云極DataCanvas公司技術(shù)專家向與會者詳細(xì)介紹算力包的產(chǎn)品能力和創(chuàng)新模式,收獲行業(yè)伙伴的高度認(rèn)可。算力作為AI時代的數(shù)字能源,將在行業(yè)應(yīng)用和技術(shù)創(chuàng)新互相驅(qū)動下,邁入“算力普惠”的終極生態(tài),AI應(yīng)用也將迎來爆發(fā)式的繁榮。
    的頭像 發(fā)表于 09-29 14:44 ?837次閱讀
    <b class='flag-5'>九章</b>云極DataCanvas公司「算力包」產(chǎn)品璀璨亮相2024中國算力大會!

    《DNK210使用指南 -CanMV版 V1.0》第九章 打印輸出實驗

    第九章 打印輸出實驗 本章節(jié)為實驗篇的第一,將通過打印輸出實驗為后續(xù)實驗中的交互打下基礎(chǔ)。通過本章的學(xué)習(xí),讀者將學(xué)習(xí)到CanMV中print()函數(shù)的使用。本章分為如下幾個小節(jié):9.1 打印輸出
    發(fā)表于 09-28 14:51

    九章云極DataCanvas算力包正式發(fā)布

    在數(shù)字化轉(zhuǎn)型的浪潮中,九章云極DataCanvas再次引領(lǐng)創(chuàng)新,正式推出全新算力產(chǎn)品——“算力包”。這一創(chuàng)新力作,以用戶為核心,顛覆傳統(tǒng)算力服務(wù)模式,采用“按需購買、即買即用”的靈活方式,讓算力資源觸手可及。
    的頭像 發(fā)表于 09-26 14:58 ?470次閱讀

    智算筑基,九章云極DataCanvas公司閃耀2024年服貿(mào)會

    9月12日,2024年中國國際服務(wù)貿(mào)易交易會在北京隆重開幕,九章云極DataCanvas公司攜AI智算產(chǎn)品系列深度參展本屆服貿(mào)會,為觀眾奉上技術(shù)與應(yīng)用深度融合的參展盛宴。
    的頭像 發(fā)表于 09-14 16:02 ?439次閱讀
    智算筑基,<b class='flag-5'>九章</b>云極DataCanvas公司閃耀2024年服貿(mào)會

    第九章-PID整定方法 STM32PID驅(qū)動編碼 STM32PID控制電機(jī)轉(zhuǎn)速

    控制、PID循跡、PID跟隨、遙控、避障、PID角度控制、視覺控制、電磁循跡、RTOS等功能。 ?# 第九章-PID整定方法 ## 9.1-調(diào)整合適的采樣周期和PID調(diào)參方法 正如
    的頭像 發(fā)表于 08-21 16:37 ?1267次閱讀
    <b class='flag-5'>第九章</b>-PID整定方法 STM32PID驅(qū)動編碼<b class='flag-5'>器</b> STM32PID控制電機(jī)轉(zhuǎn)速

    九章云極DataCanvas公司入選北京市通用人工智能產(chǎn)業(yè)創(chuàng)新伙伴計劃

    作為北京市標(biāo)桿人工智能企業(yè),九章云極DataCanvas公司將持續(xù)發(fā)揮產(chǎn)業(yè)優(yōu)勢,繼續(xù)堅持將自主創(chuàng)新的AI技術(shù)注入產(chǎn)業(yè),以大模型應(yīng)用為終極服務(wù)目標(biāo),通過包括大模型在內(nèi)的人工智能基礎(chǔ)軟件,為政府和行業(yè)用戶提供國際領(lǐng)先的AI服務(wù),加速數(shù)字經(jīng)濟(jì)跨越發(fā)展!
    的頭像 發(fā)表于 07-03 15:41 ?382次閱讀
    <b class='flag-5'>九章</b>云極DataCanvas公司入選北京市通用人工智能產(chǎn)業(yè)創(chuàng)新伙伴計劃

    九章云極DataCanvas公司強(qiáng)勢入選IDC生成式AI圖譜7大核心板塊

    九章云極DataCanvas公司把握既有前沿技術(shù)和服務(wù)經(jīng)驗,將AI軟件以核心操作系統(tǒng)的形式深度融入智算中心體系,同時積極與上下游生態(tài)伙伴合作在全國范圍布局智算中心建設(shè)和運營。
    的頭像 發(fā)表于 06-29 10:39 ?383次閱讀
    <b class='flag-5'>九章</b>云極DataCanvas公司強(qiáng)勢入選IDC生成式AI圖譜7大核心板塊

    STM32F103DMA模塊存儲器存儲器可以實現(xiàn)循環(huán)嗎?

    STM32F103 參考手冊中循環(huán)模式部分描述:DMA模塊存儲器存儲器不能與循環(huán)模式同時使用。但是經(jīng)過實際測試,是可以實現(xiàn)循環(huán)的,請問怎么理解這句話呢?
    發(fā)表于 04-02 06:23

    請問DMA控制可以減輕CPU負(fù)擔(dān)嗎?

    直接存儲器訪問 ( DMA )控制,可以在內(nèi)存和/或外設(shè)之間傳輸數(shù)據(jù),而不需要 CPU 參與每次傳輸。合理利用
    的頭像 發(fā)表于 03-28 09:41 ?810次閱讀
    請問<b class='flag-5'>DMA</b>控制<b class='flag-5'>器</b>可以減輕CPU負(fù)擔(dān)嗎?

    淺談存儲器層次結(jié)構(gòu)

    通過多級存儲器的設(shè)計,存儲器層次結(jié)構(gòu)能夠在存儲容量和訪問速度之間找到一個平衡點。高速緩存存儲器和主存儲器
    發(fā)表于 02-19 13:54 ?917次閱讀
    淺談<b class='flag-5'>存儲器</b>層次結(jié)構(gòu)