91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

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

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

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

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

恩智浦MCU加油站 ? 來源:未知 ? 2023-12-21 08:55 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

DMA是直接存儲(chǔ)器訪問(DirectMemory Access)的縮寫。在MCU芯片中,DMA是除CPU之外,最常見的總線主設(shè)備。作為總線主設(shè)備,DMA控制器可以輸出地址和控制信號(hào)到總線上,主動(dòng)地發(fā)起和控制數(shù)據(jù)傳輸過程,它能夠按照程序的配置,在兩個(gè)從設(shè)備之間傳輸數(shù)據(jù)。例如在存儲(chǔ)器和I2C模塊之間傳輸數(shù)據(jù),實(shí)現(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è)備才能主動(dòng)發(fā)起數(shù)據(jù)的傳輸操作。

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

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

圖2.DMA傳輸示意圖

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

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

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

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

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

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

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

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

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

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

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

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

系列

通道數(shù)目

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

LPC80xLPC81x

0

0

LPC82x

18

9

LPC83x

18

8

LPC84x

25

13

1.3.1DMA寄存器一覽

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

寄存器組

寄存器名稱

功能

說明

通用寄存器組

CTL

DMA控制器寄存器

只有一個(gè)控制位,使能DMA控制器

INTSTAT

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

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

SRAMBASE

傳輸描述符地址寄存器

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

通道控制寄存器組

ENABLESET0

通道使能寄存器

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

ENABLECLR0

通道失能寄存器

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

ACTIVE0

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

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

BUSY0

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

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

通道中斷寄存器組

ERRINT0

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

每個(gè)通道占用一位。表示是否有錯(cuò)誤中斷

INTENSET0

中斷使能寄存器

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

INTENCLR0

中斷失能寄存器

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

INTA0

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

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

INTB0

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

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

傳輸控制寄存器

SETVALID0

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

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

SETTRIG0

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

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

ABORT0

通道中止傳輸寄存器

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

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

寄存器名稱

功能

說明

CFG

通道配置寄存器

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

CTLSTAT

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

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

XFERCFG

通道傳輸配置寄存器

用于配置通道的各個(gè)配置選項(xiàng)

1.3.2 DMA傳輸描述符

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

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

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

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

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

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

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

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

每個(gè)通道對(duì)應(yīng)的DMA請(qǐng)求源如下表所示:

wKgZomWDjhSAXLVrAACL8bMrNOk751.pngwKgZomWDjhSAd-bfAABMlOrT-KY420.png

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

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

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

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

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

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

每次DMA傳輸(即圖2示意中的每一次讀寫)的時(shí)機(jī),則由DMA請(qǐng)求信號(hào)決定。

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

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

表中的DMA傳輸請(qǐng)求信號(hào)以USARTTXRDY為例:

組合模式

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

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

操作模式說

0

0

0

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

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

1

0

1

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

2

1

0

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

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

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

3

1

1

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

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

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

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

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

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

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

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

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

wKgZomWDjhWAZvIUAAHyUtsnSG0901.png

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

每個(gè)通道的外設(shè)請(qǐng)求來源是固定的,見表1。例如對(duì)應(yīng)SPI0的發(fā)送就緒信號(hào)(TXRDY)DMA通道,在LPC82x/83x中是通道7,在LPC84x中是通道11HWTRIGEN:使能硬件觸發(fā)。硬件觸發(fā)信號(hào)源由DMA_ITRIG_INMUXn寄存器選擇,1.3.4節(jié)。0 – 使能硬件觸發(fā);1 – 不使能硬件觸發(fā)。TRIGPOL:觸發(fā)極性。TRIGTYPE:觸發(fā)類型。TRIGPOLTRIGTYPE共同決定如何使用觸發(fā)信號(hào),組合關(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:成組傳輸中每組的長度。這個(gè)域的內(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ù)源地址。

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

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

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

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

wKgZomWDjhWAX_oHAAIeMtFOje4522.png

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

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

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

注意:使用軟件觸發(fā)時(shí),在TRIGBURST=0時(shí),不得使用電平觸發(fā)。CLRTRIG:當(dāng)前描述符的傳輸結(jié)束后,是否清除觸發(fā)條件。0 – 不清除。如果RELOAD=1,則下一個(gè)描述符的觸發(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在硬件上沒有差別,用戶可以用這兩個(gè)中斷(標(biāo)志)區(qū)別是哪個(gè)描述符的傳輸完成了,尤其是在乒乓結(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é)對(duì)齊的。SRCINC:表示每次傳輸一個(gè)數(shù)據(jù)后,源地址的增量變化。0 – 地址無變化。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1.7若干DMA傳輸例程

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

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

typedef struct {

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

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

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

uint32_t next; // 鏈接到下一個(gè)描述符

} DMA_CHDESC_T;

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

ALIGN(512) DMA_CHDESC_T Chan_Desc_Table[];

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

結(jié)構(gòu)體DMA_RELOADDESC_T適用于其它描述符。所有描述符必須位于16字節(jié)對(duì)齊的內(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; // 鏈接到下一個(gè)描述符

} DMA_RELOADDESC_T;

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

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

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

wKgZomWDjhWAQg70AAAtAqdSbxI093.png下面是初始化DMA控制器,并啟動(dòng)DMA的函數(shù)。代碼片段1.使用DMA在內(nèi)存中拷貝一個(gè)數(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í)設(shè)置為無效
12                0 << DMA_XFERCFG_RELOAD   | // 沒有下一個(gè)描述符
13                1 << DMA_XFERCFG_SWTRIG   | // 軟件觸發(fā)
14                1 << DMA_XFERCFG_CLRTRIG  | // 傳輸結(jié)束時(shí)清除觸發(fā)標(biāo)志
15                1 << DMA_XFERCFG_SETINTA  | // 傳輸結(jié)束時(shí)設(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  }

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

#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ù)組,這個(gè)數(shù)組的起始地址必須是512字節(jié)對(duì)齊的。

ALIGN(512) DMA_CHDESC_T Chan_Desc_Table[1];

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

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

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

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

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

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

代碼片段2.使用DMA拷貝一個(gè)數(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)完成。在實(shí)際的項(xiàng)目中,用戶程序可以替換上述21~23行的代碼,執(zhí)行其它的一些操作。

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

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

首先還是DMA的初始化函數(shù),這個(gè)函數(shù)與前面的數(shù)據(jù)塊搬運(yùn)初始化基本一致,指示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è)請(qǐng)求
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í)設(shè)置為無效
16                0 << DMA_XFERCFG_RELOAD   | // 沒有下一個(gè)描述符
17                0 << DMA_XFERCFG_SWTRIG   | // 沒有軟件觸發(fā)
18                1 << DMA_XFERCFG_CLRTRIG  | // 傳輸結(jié)束時(shí)清除觸發(fā)標(biāo)志
19                1 << DMA_XFERCFG_SETINTA  | // 傳輸結(jié)束時(shí)設(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不同的地方。還有一個(gè)明顯的不同是,此處所有涉及到DMA通道號(hào)時(shí),都換成了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í)鐘的分頻系數(shù)
10      LPC_SYSCON->UARTFRGMULT = 4; 
11      LPC_SYSCON->UARTFRGDIV = 255; 
12      LPC_USART0->BRG = 16 - 1;
13  
14      // 8個(gè)數(shù)據(jù)位,無校驗(yàn)位,1個(gè)停止位,沒有硬件流控,異步模式
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é)的重點(diǎn)。代碼片段3的第11~13行,配置DMA通道為硬件觸發(fā)信號(hào)的下降沿觸發(fā),下面是初始化PINTINT,使用USER_KEY產(chǎn)生觸發(fā)信號(hào),和對(duì)應(yīng)的中斷程序。代碼片段5.初始化按鍵產(chǎn)生DMA硬件觸發(fā)信號(hào)

01  #define PINTSEL0 0       // 定義引腳中斷0的編號(hào)
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對(duì)應(yīng)的引腳為輸入
15      LPC_SYSCON->PINTSEL[PINTSEL0] = KEY_USER; // USER_KEY對(duì)應(yīng)對(duì)應(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  }

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

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

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

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

圖中的時(shí)間點(diǎn)④是觸發(fā)DMA傳輸?shù)臅r(shí)間,這個(gè)時(shí)間點(diǎn)與代碼片段507行的執(zhí)行相對(duì)應(yīng)。如果清除上升沿中斷的動(dòng)作被推遲,則DMA傳輸?shù)臅r(shí)間也會(huì)被推遲,所以用戶要盡快地響應(yīng)PINTINT中斷并清除中斷標(biāo)志,以實(shí)現(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  }

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

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

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

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

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

wKgZomWDjhWAIf71AAGIuEduoic486.png圖6.DMA執(zhí)行USART0的成組發(fā)送例程的描述符鏈另外,例程中安排了以成組(Burst)方式發(fā)送每個(gè)字符串,即每次觸發(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!
";         // 鏈頭對(duì)應(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è)請(qǐng)求
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)個(gè)數(shù)據(jù)
16  
17      xfercfg = 0 << DMA_XFERCFG_CFGVALID | // 暫時(shí)設(shè)置為無效
18                1 << DMA_XFERCFG_RELOAD   | // 有下一個(gè)描述符
19                0 << DMA_XFERCFG_SWTRIG   | // 沒有軟件觸發(fā)
20                1 << DMA_XFERCFG_CLRTRIG  | // 傳輸結(jié)束時(shí)清除觸發(fā)標(biāo)志
21                1 << DMA_XFERCFG_SETINTA  | // 傳輸結(jié)束時(shí)設(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è)置的兩個(gè)中斷INTAINTB的內(nèi)部機(jī)制完全一致,分為兩個(gè)中斷源只是為了讓用戶區(qū)分對(duì)應(yīng)的描述符,用戶可以自由安排。本例中設(shè)置描述符A執(zhí)行結(jié)束后會(huì)產(chǎn)生中斷A,描述符B執(zhí)行結(jié)束后會(huì)產(chǎn)生中斷B,因此相比前一個(gè)例程中斷處理程序也多了出來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í)行完一個(gè)描述符后,就會(huì)相應(yīng)地產(chǎn)生一個(gè)中斷(INTAINTB),用戶可以自行在代碼片段8的第0509行安插代碼在適當(dāng)?shù)臅r(shí)候結(jié)束整個(gè)描述符鏈的DMA傳輸,例如當(dāng)循環(huán)次數(shù)滿足一定要求時(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í)行這個(gè)例程后,每按一次按鍵DMA會(huì)發(fā)送8個(gè)字符,在串口助手上有如下顯示:

wKgZomWDjhWAQFD2AAIY--ljgGc244.png

END

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

wKgZomWDjhWAF7paAABCdkRE230661.jpg ? ? ?

NXP客棧


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

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

恩智浦MCU加油站


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

wKgZomWDjhaAAHlMAAATNlPH08Y038.jpg ?

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


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

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


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

    關(guān)注

    147

    文章

    18929

    瀏覽量

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

    關(guān)注

    14

    文章

    6095

    瀏覽量

    147645

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

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

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

掃碼添加小助手

加入工程師交流群

    評(píng)論

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

    【「Altium Designer 25 電路設(shè)計(jì)精進(jìn)實(shí)踐」閱讀體驗(yàn)】+第九章實(shí)例- what?這不就是官方的SAM V71開發(fā)板嗎?

    本書最后一的實(shí)例, SAM V71開發(fā)板翻遍了本書,也沒找到書中有關(guān)該實(shí)例的資源文件? 去機(jī)工電氣,機(jī)工電子的官網(wǎng),公眾號(hào)找了一遍,也沒找到半點(diǎn)信息。 再來仔細(xì)看下這一的內(nèi)容 好像就是介紹了下
    發(fā)表于 02-14 16:55

    【「Altium Designer 25 電路設(shè)計(jì)精進(jìn)實(shí)踐」閱讀體驗(yàn)】+本書概覽與內(nèi)容特點(diǎn)介紹

    的參考。第七介紹了元器件庫的維護(hù)與管理,維護(hù)自己的庫有利于高效的設(shè)計(jì),減少出錯(cuò)。 實(shí)踐部分第八 介紹了多板系統(tǒng)和線束設(shè)計(jì)實(shí)例第九章 介紹了SAM V71開發(fā)板的實(shí)例,可以參考這個(gè)動(dòng)手做一個(gè)自己的開發(fā)板
    發(fā)表于 02-14 15:56

    【「Altium Designer 25 電路設(shè)計(jì)精進(jìn)實(shí)踐」閱讀體驗(yàn)】+讀后感

    、封裝庫了,相當(dāng)于的子單元,是構(gòu)建的基石。 第八、九章節(jié)是為我們實(shí)例操作了兩個(gè)例程,讓我們更好的了解軟件,項(xiàng)目中怎么做。 但是第九章標(biāo)題有點(diǎn)誤導(dǎo)了我,寫的仿真開發(fā)板 我第一眼以為是使用AD軟件怎么仿真
    發(fā)表于 02-14 11:38

    抒微智能Surertech受邀參展?第九屆世界無人機(jī)大會(huì)(深圳)

    抒微智能Surertech受邀參展?第九屆世界無人機(jī)大會(huì)(深圳)
    的頭像 發(fā)表于 02-03 11:40 ?341次閱讀
    抒微智能Surertech受邀參展?<b class='flag-5'>第九</b>屆世界無人機(jī)大會(huì)(深圳)

    CW32F030 RAM存儲(chǔ)器的介紹

    時(shí)鐘頻率進(jìn)行訪問 ?支持奇偶校驗(yàn)功能 3 RAM 存儲(chǔ)器操作 用戶可執(zhí)行的 RAM 存儲(chǔ)器操作包括:讀操作、寫操作。 對(duì) RAM 的讀寫操作支持 8bit、16bit 和 32bit 三種
    發(fā)表于 01-12 06:33

    LPC800系列MCU:低功耗與高性能的完美結(jié)合

    LPC800系列MCU:低功耗與高性能的完美結(jié)合 在電子工程師的日常工作中,選擇合適的微控制(MCU)對(duì)于項(xiàng)目的成功至關(guān)重要。今天,我們就來詳細(xì)探討一下NXP的LPC800系列MCU,看看它有
    的頭像 發(fā)表于 12-24 16:40 ?293次閱讀

    CW32 DMA的主要特性

    CW32F030 支持直接內(nèi)存訪問DMA),無需 CPU 干預(yù),即可實(shí)現(xiàn)外設(shè)和存儲(chǔ)器之間、外設(shè)和外設(shè)之間、存儲(chǔ)器
    發(fā)表于 12-16 07:14

    CW32L052 DMA直接內(nèi)存訪問介紹

    傳輸,如FLASH存儲(chǔ)器、UART串口、TIM定時(shí)、ADC數(shù)模轉(zhuǎn)換等被配置為DMA通道的觸發(fā)源時(shí), 可以產(chǎn)生DMA請(qǐng)求(
    發(fā)表于 12-12 07:21

    15屆藍(lán)橋杯嵌入式省賽客觀題及參考答案

    1,DMA控制是什么()。A:一個(gè)獨(dú)立的外設(shè)B:一個(gè)與MCU并行工作的處理C:一個(gè)調(diào)節(jié)系統(tǒng)時(shí)鐘的模塊D:一個(gè)處理中斷和事件的單元【解析】DMA
    的頭像 發(fā)表于 12-02 21:07 ?482次閱讀
    15屆藍(lán)橋杯嵌入式省賽客觀題及參考答案

    芯源的直接內(nèi)存訪問DMA)技術(shù)介紹

    芯片內(nèi)置 DMA 控制,4 條獨(dú)立通道,外設(shè)和存儲(chǔ)器之間、外設(shè)和外設(shè)之間、存儲(chǔ)器存儲(chǔ)器之間的高速數(shù) 據(jù)傳輸。 每個(gè)
    發(fā)表于 11-12 07:40

    芯源的片上存儲(chǔ)器介紹

    片上FLASH 閃存由兩部分物理區(qū)域組成:主FLASH 存儲(chǔ)器和啟動(dòng)程序存儲(chǔ)器。 ●● 主 FLASH 存儲(chǔ)器,共 64KB,地址空間為 0x0000 0000 - 0x0000 FFFF。該區(qū)
    發(fā)表于 11-12 07:34

    第九屆集創(chuàng)賽全國總決賽“紫光同創(chuàng)杯”圓滿落幕

    近日,第九屆全國大學(xué)生集成電路創(chuàng)新創(chuàng)業(yè)大賽(簡稱“第九屆集創(chuàng)賽”)全國總決賽在上海臨港圓滿落幕。第九屆集創(chuàng)賽覆蓋集成電路全產(chǎn)業(yè)鏈,報(bào)名隊(duì)伍超過7400支,參賽師生逾20000人,參與高校500余家,賽事規(guī)模和影響力再創(chuàng)新高!
    的頭像 發(fā)表于 09-04 15:20 ?1862次閱讀

    鎧俠第九代 BiCS FLASH? 512Gb TLC 存儲(chǔ)器開始送樣

    融合現(xiàn)有存儲(chǔ)單元與先進(jìn)的 CMOS 技術(shù),實(shí)現(xiàn)投資效益最大化 ? 全球存儲(chǔ)解決方案領(lǐng)導(dǎo)者鎧俠宣布,其采用第九代 BiCS FLASH? 3D 閃存技術(shù)的 512Gb TLC存儲(chǔ)器已開始
    發(fā)表于 07-28 15:30 ?720次閱讀

    第九章 W55MH32 HTTP Server示例

    本文介紹了在 W55MH32?芯片上實(shí)現(xiàn) HTTP Server?功能,并通過瀏覽修改其網(wǎng)絡(luò)地址信息的方法。闡述了 HTTP?協(xié)議的概念、特點(diǎn)、應(yīng)用場景、工作流程、請(qǐng)求方法、響應(yīng)內(nèi)容,以及 Web?頁面構(gòu)成和交互方式。展示了在W55MH32上實(shí)現(xiàn)的過程。
    的頭像 發(fā)表于 07-24 09:35 ?1130次閱讀
    <b class='flag-5'>第九章</b> W55MH32 HTTP Server示例

    第十五 DMA

    本章介紹DMA直接存儲(chǔ)器存?。淇稍诓徽加肅PU的情況下搬數(shù)據(jù),支持多種傳輸方向,含控制、通道等配置及相關(guān)實(shí)驗(yàn)代碼。
    的頭像 發(fā)表于 06-14 16:32 ?1431次閱讀
    第十五<b class='flag-5'>章</b> <b class='flag-5'>DMA</b>