直接存儲器訪問(DMA)控制器執(zhí)行數(shù)據(jù)傳輸任務,并從ADuCM4050微控制器單元(MCU)卸載這些任務。DMA 在外設和存儲器之間提供高速數(shù)據(jù)傳輸。DMA 無需任何 CPU 操作即可快速移動數(shù)據(jù),從而使 CPU 資源可用于其他操作。
本應用筆記介紹如何使用ADuCM4050微控制器的DMA功能。本應用筆記還提供了對DMA控制器進行編程所需的編程步驟、DMA圖和DMA代碼片段。
DMA 控制器特性
DMA 控制器支持以下功能:
27 個獨立的 DMA 通道
每個 DMA 通道的兩個可編程優(yōu)先級
每個優(yōu)先級都使用由 DMA 通道號確定的固定優(yōu)先級進行仲裁
每個 DMA 通道都可以訪問主通道和/或備用通道控制數(shù)據(jù)結構
支持以下傳輸類型:
內(nèi)存到內(nèi)存
內(nèi)存到外設
內(nèi)存外設
支持以下 DMA 循環(huán)類型:
基本
自動請求
乒乓球
分散聚集
支持多種 DMA 傳輸數(shù)據(jù)寬度(8 位、16 位和 32 位)
每個 DMA 通道都可以具有獨立的源和目標遞增和遞減控制
DMA
DMA 通道
DMA 有 27 個通道,每個通道專用于管理來自外設的內(nèi)存訪問請求。
表 1 顯示了 DMA 通道分配。
通道節(jié)點 | 外設 |
0 | SPI2 傳輸 |
1 | SPI2 接收 |
2 | 運動0A |
3 | 運動0B |
4 | SPI0 傳輸 |
5 | SPI0 接收 |
6 | SPI1 傳輸 |
7 | SPI1 接收 |
8 | UART0 傳輸 |
9 | UART0 接收 |
10 | 我2C 從機傳輸 |
11 | 我2C 從接收 |
12 | 我2C 主控 |
13 | 密碼學 |
14 | 密碼學輸出 |
15 | 閃光 |
16 到 23 | 軟件 DMA |
24 | 模數(shù)轉(zhuǎn)換器 (ADC) 接收 |
25 | UART1 傳輸 |
26 | UART1 接收 |
DMA系統(tǒng)框圖
圖 1 顯示了 DMA 系統(tǒng)框圖。
圖1.DMA 系統(tǒng)框圖
DMA 如何工作?
DMA 根據(jù) DMA 控制器中提供的信息在內(nèi)存和外設之間傳輸數(shù)據(jù)。當生成 DMA 請求(通過軟件 DMA 請求或外設 DMA 請求)時,DMA 控制器從相應的通道控制數(shù)據(jù)結構中收集信息并執(zhí)行所需的傳輸。
DMA 控制器
DMA 控制器是執(zhí)行傳輸?shù)?DMA 塊的主要部分。控制器從通道控制數(shù)據(jù)結構中獲取傳輸信息,并在收到DMA傳輸請求后執(zhí)行事務。
通道控制數(shù)據(jù)結構
每個通道都有兩個控制數(shù)據(jù)結構:主通道和備用通道。必須聲明一個與存儲器分開的空間,其中包含每個通道的主數(shù)據(jù)和備用數(shù)據(jù)結構,具體取決于應用復雜性。此內(nèi)存空間是 DMA 控制器獲取有關傳輸?shù)男畔⒌奈恢谩?/p>
主數(shù)據(jù)結構和備用數(shù)據(jù)結構以及數(shù)據(jù)庫指針
主數(shù)據(jù)結構和備用數(shù)據(jù)結構包含所有 DMA 通道的 DMA 描述符。這些數(shù)據(jù)結構在 RAM 區(qū)域中聲明,每個通道描述符有 16 個字節(jié)。數(shù)據(jù)庫指針包含這些描述符的起始地址,這是 DMA 控制器了解特定通道的描述符信息拾取位置的方式。收到傳輸請求時,DMA 控制器讀取基指針,遍歷到通道的指定描述符,并按照描述符指定的方式執(zhí)行傳輸。如果描述符信息在另一個內(nèi)存空間中定義,請在啟用 DMA 控制器之前將描述符信息移動到通道數(shù)據(jù)結構內(nèi)存空間。備用數(shù)據(jù)結構基指針是一個只讀寄存器,當主描述符基指針更改時,其值會自動調(diào)整。
16 字節(jié) DMA 描述符由所有 DMA 事務信息組成。在啟用 DMA 控制器之前,必須將描述符復制到特定的通道控制數(shù)據(jù)結構,因為 DMA 從通道控制數(shù)據(jù)結構中獲取有關傳輸?shù)男畔?。?2 顯示了 DMA 描述符通道的元素。
名字 | 描述 | 大小(字節(jié)) |
SRC_END_PTR | 源數(shù)據(jù)的結束地址 | 4 |
DST_END_PTR | 目標數(shù)據(jù)的結束地址 | 4 |
CHL_CFG | 提供 DMA 傳輸?shù)目刂菩畔?/strong> | 4 |
保留 | 保留 | 4 |
DMA 編程模型
DMA 設置的一般編程順序如下:
設置用于數(shù)據(jù)傳輸?shù)?DMA 描述符。
設置 DMA 基指針。
啟用所需的 DMA 通道。
在 DMA 配置寄存器 (DMA_CFG) 中啟用 DMA 控制器。
在 DMA 通道軟件請求寄存器 (DMA_SWREQ) 中生成軟件 DMA 請求,或啟用生成 DMA 控制器中斷的外設。
有關每種模式的 DMA 設置的特定信息,請參閱 DMA 模式部分。
數(shù)字對象模式
自動請求 (ARQ) 模式和基本模式
ARQ 和基本模式是所有模式中最基本的,由單個描述符傳輸組成。ARQ 模式用于內(nèi)存到內(nèi)存的傳輸,基本模式用于內(nèi)存到外設或外設到內(nèi)存的傳輸。
在這兩種模式下,DMA描述符可以先構建,然后移動到通道數(shù)據(jù)結構中,也可以直接寫入通道數(shù)據(jù)結構。
這些模式的編程順序如下:
填充 DMA 描述符并將其移動到通道數(shù)據(jù)結構或直接寫入通道數(shù)據(jù)結構。
將主控制數(shù)據(jù)庫 (PCD) 指針指向通道控制數(shù)據(jù)結構的基。
清除特定 DMA 通道的通道請求掩碼。
啟用 DMA 的請求源中斷和 DMA 完成中斷(可選)。
啟用相應的 DMA 通道。
通過將DMA_CFG寄存器設置為 1 來啟用 DMA 控制器。
生成軟件 DMA 請求 (ARQ DMA) 或等待生成外圍 DMA 請求(基本 DMA)。
ARQ 和基本模式一次最多允許 1024 次傳輸,并且每次傳輸后必須重新啟用 DMA 控制器。
基本模式的時序圖如圖 2 所示,除步驟 7 外,與 ARQ 模式相同。
圖2.基本模式序列圖
示例代碼:RAM 的兩個數(shù)據(jù)塊內(nèi)的內(nèi)存到內(nèi)存 ARQ 傳輸
此示例演示如何在內(nèi)存塊之間執(zhí)行 DMA ARQ 傳輸。此示例使用通道 16 DMA(軟件 DMA)描述符,并將數(shù)據(jù)從 srcPtr[] 復制到 destPtr[]。
/* Build the channel descriptor */
ChannelDesc[16].srcEndPtr =(unsigned int) &srcPtr[61];
ChannelDesc[16].destEndPtr =(unsigned int) &destPtr[61];
ChannelDesc[16].ctrlCfg.src_inc = 0;
ChannelDesc[16].ctrlCfg.dst_inc = 0;
ChannelDesc[16].ctrlCfg.src_size = 0;
ChannelDesc[16].ctrlCfg.n_minus_1 = 61u;
ChannelDesc[16].ctrlCfg.r_power = 0;
ChannelDesc[16].ctrlCfg.cycle_ctrl = 2u;
/* give the address of the built channel descriptor to the DMA controller */
*pREG_DMA0_PDBPTR = (unsigned int) &ChannelDesc[0];
/* Enable the DMA channel 16 */
*pREG_DMA0_EN_SET = (1u << 16u);
/* Enable the peripherals to create DMA requests on channel 16 */
*pREG_DMA0_RMSK_CLR = (1u << 16u);
/* enable the DMA controller */
*pREG_DMA0_CFG = 1u;
/* Generate a software DMA request on channel 16 */
*pREG_DMA0_SWREQ = (1u << 16u);
示例代碼:使用 UART 進行內(nèi)存到外設基本模式數(shù)據(jù)傳輸
此示例演示如何在內(nèi)存塊和外設緩沖區(qū)寄存器之間執(zhí)行基本硬件請求傳輸。該示例使用通道 8 DMA(UART0 發(fā)送),并將數(shù)據(jù)從 srcPts[] 發(fā)送到通用異步接收器發(fā)射器 (UART) 終端。
/* Build the channel descriptor */
ChannelDesc[8].srcEndPtr =(unsigned int) &srcPtr[61];
ChannelDesc[8].destEndPtr =(unsigned int)pREG_UART0_TX;
ChannelDesc[8].ctrlCfg.src_inc = 0;
ChannelDesc[8].ctrlCfg.dst_inc = 3;
ChannelDesc[8].ctrlCfg.src_size = 0;
ChannelDesc[8].ctrlCfg.n_minus_1 = 61u;
ChannelDesc[8].ctrlCfg.r_power = 0;
ChannelDesc[8].ctrlCfg.cycle_ctrl = 1u;
/* enable the DMA controller */
*pREG_DMA0_CFG = 1u;
/* give the address of the built channel descriptor to the DMA controller */
*pREG_DMA0_PDBPTR = (unsigned int) &ChannelDesc[0];
/* Enable the peripherals to create DMA requests on channel 8 */
*pREG_DMA0_RMSK_CLR = (1u << 8u);
/* Enable the DMA channel 8 */
*pREG_DMA0_EN_SET = (1u << 8u);
/* Configure DMA Channel 8 to use primary data structure */
*pREG_DMA0_ALT_CLR = (1u << 8u);
/* pin mux for UART 0 */
*((volatile uint32_t *)REG_GPIO0_CFG) |= UART0_TX_PORTP0_MUX | UART0_RX_PORTP0_MUX ;
/* UART 0 configuration */
/* baud rate = 9600*/
*pREG_UART0_DIV = 0x1C;
*pREG_UART0_FBR = (0x1<
*pREG_UART0_LCR2 = (0x3<
/* parity , stop */
*pREG_UART0_LCR = (0x3<
/* Enable DMA request from UART0 to DMA controller */
*pREG_UART0_IEN |=(1u << 4u);
內(nèi)存分散收集和外設分散收集模式
內(nèi)存分散收集模式是重復 ARQ 模式,外設分散收集模式是重復的基本模式,其中兩種分散收集模式都設置并同時觸發(fā)多個 DMA 描述符。當同時執(zhí)行大型傳輸時,此模式很有用。
此模式涉及設置所有描述符,并將描述符逐個移動到發(fā)生 DMA 事務的備用通道數(shù)據(jù)結構中。描述符從內(nèi)存到備用通道描述符 (ACD) 的這種移動由主 DMA 執(zhí)行。因此,特定 DMA 通道的主描述符填充了以下信息:源端是聲明的描述符的結尾,目標是備用通道描述符、字大小和仲裁大小,增量設置為 4。由于仲裁設置為 4,因此 DMA 控制器執(zhí)行主描述符字大小的四次傳輸(即一個描述符移動到備用描述符),然后轉(zhuǎn)移到備用描述符,在那里執(zhí)行實際數(shù)據(jù)傳輸,然后移回主控制器。循環(huán)一直持續(xù)到循環(huán)達到基本模式 DMA 描述符。DMA 完成中斷在描述符的每次傳輸完成后生成。
散點收集模式的編程順序如下:
使用有關在基本模式下使用最后一個 DMA 描述符執(zhí)行的傳輸?shù)男畔⒍x DMA 描述符(如果需要 DMA 事務終止)。
使用將聲明的 DMA 描述符移動到仲裁為 4 的備用通道數(shù)據(jù)結構的詳細信息填充主通道數(shù)據(jù)結構。
將 PCD 指針指向通道描述符的基座。
清除特定 DMA 通道的通道請求掩碼。
啟用 DMA 的請求源中斷和 DMA 完成中斷(可選)。
啟用相應的 DMA 通道。
通過將DMA_CFG寄存器設置為 1 來啟用 DMA 控制器。
生成軟件 DMA 請求(內(nèi)存散射收集 DMA 模式)或等待生成外設 DMA 請求(外設散射收集 DMA 模式)。
散點收集的序列圖如圖 3 所示。
圖3.散點收集模式序列圖
示例代碼:內(nèi)存到內(nèi)存分散收集軟件請求 RAM 的兩個數(shù)據(jù)塊內(nèi)的數(shù)據(jù)傳輸
此示例演示如何在內(nèi)存塊之間執(zhí)行 DMA 分散收集傳輸。此示例使用 DMA 通道 16(軟件 DMA)描述符,將數(shù)據(jù)從 srcPtr1[] 復制到 destPtr1[],將 srcPtr2[] 復制到 destPtr2[],將 srcPtr3[] 復制到 destPtr3[]。
/* Build the scatter gather descriptor 1 to copy srcPtr1[] to destPtr1[]*/ ScatterGatherDesc[0].srcEndPtr =(unsigned int) &srcPtr1[9];
ScatterGatherDesc[0].destEndPtr =(unsigned int)&destPtr1[9];
ScatterGatherDesc[0].ctrlCfg.src_inc = 0;
ScatterGatherDesc[0].ctrlCfg.dst_inc = 0;
ScatterGatherDesc[0].ctrlCfg.src_size = 0;
ScatterGatherDesc[0].ctrlCfg.n_minus_1 = 9u;
ScatterGatherDesc[0].ctrlCfg.r_power = 0;
ScatterGatherDesc[0].ctrlCfg.cycle_ctrl = 5u;
/* alternate memory to memory scatter gather */
/* Build the scatter gather descriptor 2 to copy srcPtr2[] to destPtr2[]*/
ScatterGatherDesc[1].srcEndPtr =(unsigned int) &srcPtr2[9];
ScatterGatherDesc[1].destEndPtr =(unsigned int)&destPtr2[9];
ScatterGatherDesc[1].ctrlCfg.src_inc = 0;
ScatterGatherDesc[1].ctrlCfg.dst_inc = 0;
ScatterGatherDesc[1].ctrlCfg.src_size = 0;
ScatterGatherDesc[1].ctrlCfg.n_minus_1 = 9u;
ScatterGatherDesc[1].ctrlCfg.r_power = 0;
ScatterGatherDesc[1].ctrlCfg.cycle_ctrl = 5u;
/* alternate memory to memory scatter gather */
/* Build the scatter gather descriptor 3 to copy srcPtr3[] to destPtr3[]*/
ScatterGatherDesc[2].srcEndPtr =(unsigned int) &srcPtr3[9];
ScatterGatherDesc[2].destEndPtr =(unsigned int)&destPtr3[9];
ScatterGatherDesc[2].ctrlCfg.src_inc = 0;
ScatterGatherDesc[2].ctrlCfg.dst_inc = 0;
ScatterGatherDesc[2].ctrlCfg.src_size = 0;
ScatterGatherDesc[2].ctrlCfg.n_minus_1 = 9u;
ScatterGatherDesc[2].ctrlCfg.r_power = 0;
ScatterGatherDesc[2].ctrlCfg.cycle_ctrl = 2u;
/* the last descriptor has to be ARQ to stop the DMA */
/* enable the DMA controller */
*pREG_DMA0_CFG = 1u;
/* Enable the DMA channel 16 */
*pREG_DMA0_EN_SET = (1u << 16u);
/* Enable the peripherals to create DMA requests on channel 16 */
*pREG_DMA0_RMSK_CLR = (1u << 16u);
/* give the address of the built channel descriptor to the DMA controller */
*pREG_DMA0_PDBPTR = (unsigned int) &ChannelDesc[0];
/* Locate the Alternate channel descriptor for channel 16 in memory */
pChannelDescAlternate =(ADI_DMA_DESC*)((*pREG_DMA0_ADBPTR) + (16 * 16));
uint8_t* ptypIntScatterGatherDesc =(uint8_t*)pScatterGatherDesc;
uint8_t* ptypIntChannelDescAlternate =(uint8_t*)pChannelDescAlternate;
/* Build the primary channel descriptor to move ScatterGatherDesc to ChannelDescAlternate*/
ChannelDesc[16].srcEndPtr =(unsigned int)((ptypIntScatterGatherDesc + 11*4)+3);
ChannelDesc[16].destEndPtr =(unsigned int)((ptypIntChannelDescAlternate + 3*4)+3);
ChannelDesc[16].ctrlCfg.src_inc = 2;
ChannelDesc[16].ctrlCfg.dst_inc = 2;
ChannelDesc[16].ctrlCfg.src_size = 2;
ChannelDesc[16].ctrlCfg.n_minus_1 = 11u;
ChannelDesc[16].ctrlCfg.r_power = 2;
ChannelDesc[16].ctrlCfg.cycle_ctrl = 4u;
/* Generate a software DMA request on channel 16 */
*pREG_DMA0_SWREQ = (1u << 16u);
乒乓球模式
乒乓模式對于連續(xù)傳輸數(shù)據(jù)非常有用,在傳輸過程中沒有任何中斷。在此模式下,DMA 控制器在主描述符和備用描述符之間切換,直到控制器命中基本模式描述符。
最初,主數(shù)據(jù)結構和備用數(shù)據(jù)結構都填充了 DMA 描述符信息。傳輸從主數(shù)據(jù)結構開始。傳輸完成后,DMA 控制器會立即選取備用數(shù)據(jù)結構并開始下一個事務,而不會延遲切換。備用傳輸完成后,傳輸將返回到主數(shù)據(jù)結構,并且循環(huán)繼續(xù),直到遇到基本模式描述符。
確保當主數(shù)據(jù)結構完成且備用數(shù)據(jù)結構正在傳輸時,在備用數(shù)據(jù)結構完成傳輸之前重置主數(shù)據(jù)結構,反之亦然,重置備用數(shù)據(jù)結構。
如前所述,當數(shù)據(jù)結構完成事務時,除非更新源字段和目標字段,否則只有 N ? 1 字段和循環(huán)控制字段會重置。
乒乓球模式的編程順序如下:
使用有關在基本模式下使用最后一個 DMA 描述符執(zhí)行的傳輸?shù)男畔⒍x所有 DMA 描述符(如果需要 DMA 事務終止)。
將填充的主描述符和備用描述符復制到主數(shù)據(jù)結構和備用數(shù)據(jù)結構。
將 PCD 指針指向主通道描述符的基座。
清除特定通道的通道請求掩碼。
啟用 DMA 的請求源中斷和 DMA 完成中斷。
啟用相應的 DMA 通道。
通過將DMA_CFG寄存器設置為 1 來啟用 DMA 控制器。
生成軟件 DMA 請求(如果是軟件乒乓 DMA 請求)或等待外圍 DMA 請求生成。
在DMA_DONE中斷例程中,創(chuàng)建一個標志,指示哪個主傳輸或備用傳輸已完成。因此,在特定傳輸完成后,重置通道的主描述符或備用描述符中的相應字段。
乒乓球模式的時序圖如圖 4 所示。
圖4.乒乓球模式時序圖
示例代碼:使用UART進行內(nèi)存乒乓球數(shù)據(jù)傳輸?shù)膬?nèi)存外圍設備
此示例演示如何執(zhí)行從內(nèi)存塊到外設緩沖區(qū)寄存器的乒乓硬件請求傳輸。該示例使用通道 9 DMA (UART0 Rx),ping 和 pong 交替將從 UART 接收的數(shù)據(jù)分別存儲到 srcPtr[] 和 destPtr[] 中。當從 UART 收到五個字符時,ping 將切換到 pong,反之亦然。然后,收到的五個字符通過UART發(fā)送出去。
/* Build the primary channel descriptor */
ChannelDesc[9].srcEndPtr =(unsigned int) pREG_UART0_RX;
ChannelDesc[9].destEndPtr =(unsigned int)&srcPtr[4];
ChannelDesc[9].ctrlCfg.src_inc = 3;
ChannelDesc[9].ctrlCfg.dst_inc = 0;
ChannelDesc[9].ctrlCfg.src_size = 0;
ChannelDesc[9].ctrlCfg.n_minus_1 = 4u;
ChannelDesc[9].ctrlCfg.r_power = 0;
ChannelDesc[9].ctrlCfg.cycle_ctrl = 3u;
/* enable the DMA controller */
*pREG_DMA0_CFG = 1u;
/* Enable the DMA channel 9 */
*pREG_DMA0_EN_SET = (1u << 9u);
/* Enable the peripherals to create DMA requests on channel 9 */
*pREG_DMA0_RMSK_CLR = (1u << 9u);
/* give the address of the built channel descriptor to the DMA controller */
*pREG_DMA0_PDBPTR = (unsigned int) &ChannelDesc[0];
/* Locate the Alternate channel descriptor for channel 9 in memory */
ChannelDescAlternate =(ADI_DMA_DESC*)((*pREG_DMA0_ADBPTR) + (16 * 9));
/* Build the Alternate channel descriptor */
ChannelDescAlternate->srcEndPtr =(unsigned int)pREG_UART0_RX;
ChannelDescAlternate->destEndPtr =(unsigned int)&destPtr[4];
ChannelDescAlternate->ctrlCfg.src_inc = 3;
ChannelDescAlternate->ctrlCfg.dst_inc = 0;
ChannelDescAlternate->ctrlCfg.src_size = 0;
ChannelDescAlternate->ctrlCfg.n_minus_1 = 4u;
ChannelDescAlternate->ctrlCfg.r_power = 0;
ChannelDescAlternate->ctrlCfg.cycle_ctrl = 3u;
/* Enable the DMA channel 9 interrupt in NVIC */
NVIC_EnableIRQ(DMA0_CH9_DONE_IRQn);
/* pin mux for UART 0 */
*((volatile uint32_t *)REG_GPIO0_CFG) |= UART0_TX_PORTP0_MUX | UART0_RX_PORTP0_MUX ;
/* UART 0 configuration */
/* baud rate = 9600*/
*pREG_UART0_DIV = 0x1C;
*pREG_UART0_FBR = (0x1<
審核編輯:郭婷
-
控制器
+關注
關注
112文章
16332瀏覽量
177806 -
存儲器
+關注
關注
38文章
7484瀏覽量
163762 -
cpu
+關注
關注
68文章
10854瀏覽量
211578
發(fā)布評論請先 登錄
相關推薦
評論