以前單片機搬運數(shù)據(jù)(比如把串口收到的 100 個字節(jié)存進數(shù)組),必須由 CPU 親自動手:讀一個字節(jié)、存一個字節(jié)。搬磚的時候,CPU 沒法去算水表的流量,也沒法去管 4G 模塊。
DMA 就是一個‘專業(yè)的搬運工’。 你只要告訴它:‘從哪搬(源)、搬到哪(目的)、搬多少(數(shù)量)’,然后 CPU 就可以去喝咖啡了,搬運工作全交給 DMA 硬件電路自動完成。等搬完了,它會敲敲門告訴 CPU:‘老板,活干完了!(中斷)”。
階段一:CW32F030—DMA框圖


一共三件事:誰在干活?路怎么走?誰在發(fā)號施令?”
搬運工小隊:DMA 模塊 (Ch1 - Ch5)
在圖的最左側,你會看到一個大方框,里面排著 Ch1 到 Ch5。這就是我們提到的 5 條獨立“傳送帶”。 比如 Ch1 的優(yōu)先級最高。如果你有 5 件事同時發(fā)生,DMA 會先緊著 Ch1 的活干。對于我們的項目,我們會占用其中兩條來負責 SPI2 的收和發(fā)。
交通樞紐:Bus Matrix (總線矩陣)
圖中中心位置那個灰色的、帶有多個交叉點的長條,這就是總線矩陣。它是單片機里的“立交橋”。
注意圖中有兩條并行的總線:AHB Bus (CPU) 和 AHB Bus (DMA)。
“大家發(fā)現(xiàn)了嗎?CPU 和 DMA 各有一條路通往總線矩陣。這意味著:當 DMA 在把數(shù)據(jù)從 SPI 搬往 SRAM 的時候,CPU 可以走另外一條路去執(zhí)行別的指令,互不干擾! 這就是為什么用了 DMA 后,單片機會變快的原因——因為有兩個‘人’同時在干活?!?/p>
貨源地與目的地:外設與存儲器
看圖的最右側,那一排方塊就是數(shù)據(jù)要去的目的地。
AHB 設備:Flash(存程序)、SRAM(運行數(shù)據(jù))、GPIO(點燈/按鍵)。
APB 設備:通過“AHB to APB 橋接器”連接的各種傳感器接口。
避坑點:“同一個橋下的設備,CPU 永遠比 DMA 更有話語權?!?/strong> 如果兩個人都想訪問同一個橋下的東西,DMA 得先給 CPU 讓路。
誰在喊“開工”? (DMA Requests)
注意看圖左側那兩條細細的箭頭:
Software (軟件觸發(fā)):CPU 直接下令:“現(xiàn)在,立刻,把這段數(shù)據(jù)拷走!”
Hardware (硬件觸發(fā)):外設(比如 SPI、UART)發(fā)信號:“老板,我這兒攢夠 1 個字節(jié)了,快搬走吧!”
“對于我們的 SPI Flash 搬運,我們看的是下面的‘Hardware’箭頭。SPI2 會像敲門一樣給 DMA 發(fā)請求。”
階段三:邏輯分類(查閱 8.4 傳輸模式)

邏輯分類——掌握 DMA 的 “搬運套路”
開關 A:DMA_TRIGy.TYPE —— 誰在喊“開工”?
軟件觸發(fā) (TYPE=0):
話術:這就好比你親自給搬運工打電話:“喂,把這疊文件復印一下?!敝饕糜趦却娴絻却娴臄?shù)據(jù)拷貝。
硬件觸發(fā) (TYPE=1):
話術:這就好比你在流水線上裝了個感應器。SPI 接收到一個字節(jié),感應器就響一下,搬運工才動一下。
開關 B:DMA_CSRy.TRANS —— 搬運時的優(yōu)先級(重點?。?/p>
BULK 模式 (大批量傳輸, TRANS=0):
特點:霸道、一次性干完、不許插隊。
比喻:就像一輛滿載的渣土車沖上高速,誰也不讓,直到把貨卸完。
風險:如果搬運的數(shù)據(jù)量非常大(比如幾千個字節(jié)),DMA 會長時間占用總線,導致 CPU 沒法訪問內存,你的程序看起來就像“假死”了一樣。
BLOCK 模式 (塊傳輸, TRANS=1):
特點:禮貌、允許插隊、每搬一個就問一下。
比喻:就像一個禮貌的快遞員,每過一個路口(搬完一個數(shù)據(jù)塊)都會停下來看看有沒有救護車(高優(yōu)先級的 CPU 指令或 DMA 通道)要先過。如果有,他先讓路。
優(yōu)點:系統(tǒng)響應速度快,不會讓 CPU 閑著。
在我們的水表網(wǎng)關項目中,我們應該選擇 ‘硬件觸發(fā) BLOCK 傳輸模式’。
為什么?
因為我們需要配合 SPI2 的接收/發(fā)送信號(硬件觸發(fā))。
因為我們要跑 FreeRTOS。FreeRTOS 要求任務切換非??欤绻覀冇?BULK 模式一次性搬運幾百個字節(jié),可能會導致 FreeRTOS 的高優(yōu)先級任務被‘堵在路口’進不來。用 BLOCK 模式,能保證我們的 CPU 隨時能處理突發(fā)的 4G 通信或無線中斷。”
我們的 CW32 只有 8KB RAM,CPU 和 DMA 共享這條窄窄的內存通道。如果 DMA 用 BULK(無間隙) 模式死死占住總線,CPU 就沒法從 RAM 里讀取 FreeRTOS 的任務指令,你的系統(tǒng)就會出現(xiàn)微小的“卡頓”。而圖中的 BLOCK 模式,利用這些微小的間隙,讓 CPU 和 DMA 實現(xiàn)了真正的并行工作。

起跑:SOFTSRC 信號的“發(fā)令槍”
硬件表現(xiàn):看最上面那根線 DMA_TRIGy.SOFTSRC。當 CPU 在寄存器里把這一位寫為 1 時,電平瞬間拉高。
分析:這就是所謂的“軟件觸發(fā)”。不需要外設(如串口、SPI)給信號,CPU 說“開始”,DMA 立即起跑。
呼吸:傳輸間隙(The Breather)
這是 BLOCK 模式最核心的硬件特征:
硬件表現(xiàn):觀察“傳輸間隙”和“數(shù)據(jù)傳輸時隙”。你會發(fā)現(xiàn),DMA 并不是一鼓作氣把所有數(shù)據(jù)搬完的,它每搬運一個數(shù)據(jù)(比如從 SA 搬到 DA),就會停頓一下(傳輸間隙)。
為什么這么設計?“這就好比一個有禮貌的搬運工。他每搬一箱貨,都會在路口停半秒,看看有沒有救護車(CPU 發(fā)出的緊急指令)要過。如果有,他就讓路,等救護車走了再搬下一箱。這就是 BLOCK 模式比 BULK 模式‘講理’的地方?!?/p>
關聯(lián)硬件:這個“停頓”就是手冊里提到的仲裁機制。
算賬:地址與計數(shù)的“自動加減法”
看圖底部的三組波形,這是 DMA 的“核心算法”在硬件上的體現(xiàn):
計數(shù)器倒計時 (CNT):每經(jīng)過一個傳輸時隙,CNT 的值就從 3 變成 2,再變成 1。當變?yōu)?0 時,DMA 任務結束,自動停止。
地址自增 (SRCADDR / DSTADDR):
細節(jié)分析:圖中顯示地址從 SA變成了 SA+2,再變成 SA+4。
教學點:“大家注意這個 +2!這意味著我們現(xiàn)在搬運的數(shù)據(jù)寬度是 16 位(半字)。如果是 8 位(字節(jié))搬運,這里就是 +1;如果是 32 位(字)搬運,這里就是 +4。DMA 硬件會自動根據(jù)你的設置來計算下一個目的地在哪,完全不用你操心?!?/p>


信號驅動:從“發(fā)令槍”變成“敲門聲”
波形觀察:看第一行 硬件觸發(fā)請求信號。它不再是一個長電平,而是一個個短脈沖。
硬件分析:這些脈沖就是在 表 8-2 里選的那些“頻道”發(fā)出來的。
比喻:“比如你正在用 SPI 讀 Flash。SPI 硬件每收到一個字節(jié),就會‘敲一下門’(發(fā)一個脈沖信號)。DMA 聽到敲門聲,才動一下,搬一個字節(jié)。這就是所謂的硬件同步?!?/p>
一步一停:受控的傳輸間隙
波形觀察:注意看 傳輸間隙。在硬件觸發(fā)模式下,間隙的時間長短不由 DMA 決定,而是由外設決定。
要點:如果 SPI 跑得慢,兩個脈沖之間的距離就大,間隙就長;如果 SPI 跑得快,間隙就短。
對 FreeRTOS 的意義:由于存在這些間隙,CPU 始終有機會插手總線。即使你在搬運 500 個節(jié)點的大數(shù)據(jù),系統(tǒng)也不會因為 DMA 占線而導致任務切換卡頓。
經(jīng)典的 外設 -> 內存 地址配置
觀察最下面的 SA(源地址)和 DA(目的地址)波形,這是教科書級的配置案例:
源地址 (SA) 自動自增:
現(xiàn)象:圖中 DMA_SRCADDRy 隨傳輸進程從 SA 累加。
原理:我們要把 RAM 數(shù)組里準備好的數(shù)據(jù)包按順序取出來,所以地址必須自增。
目的地址 (DA) 保持不變:
現(xiàn)象:圖中 DMA_DSTADDRy 始終固定在 DA。
原理:數(shù)據(jù)被搬運到了外設的發(fā)送寄存器(如串口發(fā)送口)。外設寄存器地址是固定的,這就是所謂的“單點取貨口”。
軟件觸發(fā):通常用于“內存 -> 內存” (M2M)
對應的就是圖 8-2。
場景:把數(shù)組 A 的數(shù)據(jù)拷貝到數(shù)組 B。
邏輯:源頭是內存(自增),目的地也是內存(自增)。
結果:你看到 SA和 DA 都在同步增長(SA+1, DA+1...)。
硬件觸發(fā):通常用于“內存 -> 外設” (M2P) 或 “外設 ->內存” (P2M)
對應你看到的圖 8-5(發(fā)送場景)。
場景:把 RAM 里的數(shù)據(jù)包通過串口發(fā)出去。
邏輯:源頭是內存(自增),目的地是串口發(fā)送寄存器(固定)。
結果:你看到 SA 在增長,而 DA 像根橫線一樣死死不動。
三、 如果換成“硬件觸發(fā)讀取”,DA 也會加!
想象一下:如果你現(xiàn)在用 DMA 接收串口數(shù)據(jù)(P2M),情況就反過來了:
源地址 (SA):串口接收寄存器 固定(守株待兔)。
目的地址 (DA):RAM 接收數(shù)組 自增(按順序排隊)。
結論:在硬件觸發(fā)的接收模式下,DA 是會自增的。所以,地址動不動,完全取決于你搬運的目標是“一個點”還是“一排位置”。

階段四:進階技能(重點看 8.6 DMA 中斷)
大家想象一下,DMA 在后臺幫我們搬運 512 字節(jié)的水表數(shù)據(jù)。CPU 不可能一直盯著它看(輪詢),那樣太累了。 我們希望:DMA 搬完了,或者搬運出錯了,能主動‘敲敲 CPU 的門’(觸發(fā)中斷),告訴我們結果。這就是手冊 8.6 節(jié)講的內容。
標準動作:中斷的“三步走” (對照表 8-4)
很多初學者寫完中斷函數(shù)發(fā)現(xiàn)只進去了一次,程序就死機了。這是因為沒搞清楚表 8-4 里的 “SOP(標準作業(yè)程序)”:
第一步:開門 (使能)
在初始化代碼里,你需要把開關撥到 1:
想讓它搬完就報信?設置 TCIE = 1(Transfer Complete Interrupt Enable)。
想讓它出錯就報警?設置 TEIE = 1(Transfer Error Interrupt Enable)。
第二步:進屋 (中斷服務程序)
當信號觸發(fā),CPU 會自動跳進 DMA_IRQHandler(中斷函數(shù))。
第三步:打掃衛(wèi)生 (清除標志位) —— 極其關鍵!
看表 最右邊一列:“設置 DMA_ICR.TCy 為 0”。
“這就好比敲門。DMA 把門敲響了,如果你進屋處理完事情,不把那個門鈴關掉(清標志位),CPU 就會認為門一直在響,從而陷入死循環(huán),500 節(jié)點程序就卡死在這兒了!”
FreeRTOS 實戰(zhàn):如何讓 8KB RAM 飛起來?
在網(wǎng)關項目中,不需要在中斷函數(shù)里寫復雜的邏輯。用 “二值信號量 (Binary Semaphore)”。
實戰(zhàn)邏輯:
任務 A (讀水表):配置好 DMA,開啟中斷,然后調用 xSemaphoreTake(xSem_DMA, portMAX_DELAY)。此時任務 A 進入阻塞(睡眠)狀態(tài),完全不占 CPU。
DMA 搬運:硬件自動搬運,CPU 在跑別的任務(比如 4G 通訊)。
DMA 中斷:搬完了,進入 DMA_IRQHandler。
釋放信號量:在中斷里清除標志位,執(zhí)行 xSemaphoreGiveFromISR(xSem_DMA)。
喚醒:任務 A 瞬間醒來,處理數(shù)據(jù)。
初始狀態(tài):xSemaphoreCreateBinary 創(chuàng)建出來的信號量默認就是 0。所以任務執(zhí)行到 xSemaphoreTake 時肯定會卡住,這正是我們想要的——讓它等中斷。
FromISR 的重要性:在中斷里嚴禁使用xSemaphoreGive。必須帶 FromISR,否則會導致系統(tǒng)內核崩潰。
portYIELD_FROM_ISR:這一行非常關鍵。如果沒有它,雖然信號量給了,但系統(tǒng)可能要等到下一個“時鐘滴答(Tick)”才會切換任務。加上它,任務 A 就能“秒醒”。
#include "FreeRTOS.h" #include "task.h" #include "semphr.h" #include "cw32f030_dma.h" #include "cw32f030_uart.h" // 1. 定義信號量句柄 SemaphoreHandle_t xSem_DMA_Complete = NULL; // 模擬數(shù)據(jù)緩沖區(qū) uint8_t MeterDataBuffer[64]; // ========================================== // 任務 A:水表數(shù)據(jù)處理任務 // ========================================== void Task_WaterMeter(void *pvParameters) { // 創(chuàng)建二值信號量(初始為 0,即“沒票”) xSem_DMA_Complete = xSemaphoreCreateBinary(); for(;;) { // --- 第一步:配置并啟動 DMA --- // 假設這里配置 DMA 從 SPI (PAN3031) 搬運數(shù)據(jù)到 MeterDataBuffer // DMA_Cmd(DMA_CH1, ENABLE); // --- 第二步:阻塞等待信號量 --- // portMAX_DELAY 表示一直等,直到 DMA 中斷把信號量交出來 // 此時任務進入“阻塞態(tài)”,CPU 會自動去跑 4G 任務,完全不浪費電力 if(xSemaphoreTake(xSem_DMA_Complete, portMAX_DELAY) == pdPASS) { // --- 第五步:任務喚醒,處理數(shù)據(jù) --- // 當代碼運行到這里,說明 DMA 已經(jīng)搬完了! printf("DMA 搬運完成,開始解析水表數(shù)據(jù)...n"); // 處理 MeterDataBuffer... } } } // ========================================== // DMA 中斷服務函數(shù) (硬件自動觸發(fā)) // ========================================== void DMA_CH1_IRQHandler(void) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; // --- 第三步:檢查并清除標志位 --- if (DMA_GetITStatus(DMA_IT_TC1)) { DMA_ClearITPendingBit(DMA_IT_TC1); // 必須手動清零,否則會死循環(huán) // --- 第四步:釋放信號量喚醒任務 --- // 注意:中斷里必須使用 FromISR 后綴的函數(shù) xSemaphoreGiveFromISR(xSem_DMA_Complete, &xHigherPriorityTaskWoken); /*當你在中斷里調用 xSemaphoreGiveFromISR 時, FreeRTOS 內核會做一件重要的事情:檢查被喚醒的任務(任務 A)的優(yōu)先級。 它的邏輯非常簡單:“如果標志位是 TRUE,就手動觸發(fā)一次任務調度(Context Switch)?!? 如果沒有這一行代碼,會發(fā)生什么? 中斷結束,CPU 返回剛才被中斷的任務繼續(xù)跑。 任務 A 雖然醒了(處于就緒態(tài)),但必須等到下一個“系統(tǒng)時鐘滴答(Tick)”或者當前任務主動放棄 CPU 時,內核才會發(fā)現(xiàn)任務 A 優(yōu)先級更高并進行切換。 這會帶來 毫秒級 的延遲,對于高速通訊來說可能導致數(shù)據(jù)溢出 // 如果喚醒的任務優(yōu)先級更高,立即進行一次“任務切換” // 這樣任務 A 能在中斷結束的一瞬間就開始干活,沒有延遲*/ portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } // ========================================== // 任務 B:4G 通訊任務 (模擬 CPU 忙碌) // ========================================== void Task_4G_Comm(void *pvParameters) { for(;;) { // 這里的邏輯在任務 A 睡覺時依然在運行 // 比如不停地查詢 4G 模塊狀態(tài)、心跳包等 printf("4G 任務正在運行,不影響水表讀取...n"); vTaskDelay(pdMS_TO_TICKS(1000)); } } int main(void) { // 基礎硬件初始化... // 創(chuàng)建任務 xTaskCreate(Task_WaterMeter, "Meter", 256, NULL, 3, NULL); // 優(yōu)先級高 xTaskCreate(Task_4G_Comm, "4G", 256, NULL, 2, NULL); // 優(yōu)先級中 vTaskStartScheduler(); // 啟動調度器 while(1); }
| 特性 | 二值信號量 (Binary) | 計數(shù)型信號量 (Counting) |
| 數(shù)值范圍 | 0 或 1 | 0 到 最大值 (用戶設定) |
| 核心功能 | 同步 (Synchronization) | 資源管理 (Resource Management) |
| 通俗理解 | “一個通知”:要么來了,要么沒來 | “一堆門票”:還剩幾張,被領了幾張 |
| 典型關系 | 1 對 1 | 1 對 多(或 N 次事件) |
二值信號量:最強“同步鬧鐘”
正如 DMA 實戰(zhàn)邏輯里寫的,它最大的作用是“等一個信號”。
適用場合:單路硬件外設完成、單一事件觸發(fā)。
網(wǎng)關項目舉例: 你的 4G 模塊發(fā)送。任務 A 調用 AT+CIPSEND 后就 xSemaphoreTake 睡死。當串口 DMA 真正搬運完最后一個字符并收到 4G 模塊的 SEND OK 后,中斷給出一個信號量。任務 A 瞬間醒來確認結果。
特點:任務只關心“發(fā)沒發(fā)完”,不關心發(fā)了多少次。
計數(shù)型信號量:高效“資源管家”
場景:假設你的網(wǎng)關有 3 個串口(UART1, 2, 3) 都可以用來上報數(shù)據(jù),但你只想同時開啟 2 個以節(jié)省功耗。
用法:創(chuàng)建一個最大值為 2 的計數(shù)信號量。
任務 1 想發(fā)數(shù)據(jù):Take 掉一個(剩 1)。
任務 2 想發(fā)數(shù)據(jù):Take 掉一個(剩 0)。
任務 3 想發(fā)數(shù)據(jù):發(fā)現(xiàn)沒票了,在門口排隊(阻塞)。
任務 1 發(fā)完:Give 回一張票(剩 1),任務 3 立即拿票進場。
還有一個隱藏選手:互斥量 (Mutex)
互斥量 (Mutex):帶有“優(yōu)先級繼承”機制。
適用場合:保護共享資源(比如 500 個節(jié)點共用的那個 WaterPulseCount 全局大變量)。
區(qū)別:二值信號量通常由“外設給,任務拿”;互斥量則是“任務 A 拿,任務 A 釋放”。
階段五:實戰(zhàn)落地(查閱 8.7 & 8.8 寄存器列表)

一、 核心配置:決定“從哪搬、搬多少”
這三個寄存器是所有 DMA 傳輸?shù)幕僖粋€都跑不起來。
| 寄存器名稱 | 教學重點 | 為什么重要 |
| DMA_SRCADDRy | 源地址:貨在哪里? | 告訴 DMA 數(shù)據(jù)的起始物理地址。 |
| DMA_DSTADDRy | 目的地址:往哪搬? | 告訴 DMA 數(shù)據(jù)存放在哪里。 |
| DMA_CNTy | 傳輸數(shù)量:搬多少次? | 重點提醒:它是個“倒計時器”,每搬一個,值減 1,減到 0 就停。 |

二、DMA_CSRy (控制及狀態(tài)寄存器) —— 全場最核心
這是 DMA 通道的“大腦”。重點介紹其中的這幾個位:
EN (位 0):總開關。配完所有參數(shù),最后再點火。
SIZE (位 7:6):你是搬 8 位的字節(jié)、還是 32 位的字?(對應你的水表數(shù)據(jù)結構)。
SINC / DSTINC (位 4 / 5):地址要不要自增?(回憶我們之前分析的:外設不加,內存加)。
TRANS (位 3):選擇 BLOCK 還是 BULK 模式。

三、DMA_TRIGy (觸發(fā)源控制寄存器) —— 全場最核心
TYPE (位 0):你是要“軟件點火”還是“硬件敲門”?
HARDSRC (位 7:2):也就是那張 表 8-2 里的頻道號。比如要用 SPI2 搬運,這里就得填入對應的編碼。



張表非常規(guī)律,從位 0 到位 17,其實就是 5 組相同的信號。每一路通道(Channel)都配有兩個“燈”:
燈 A:TC (Transfer Complete) —— 傳輸完成標志
位地址:位 0, 4, 8, 12, 16(分別對應通道 1, 2, 3, 4, 5)。
含義:這是“綠燈”。當 TC = 1 時,表示這一批次的數(shù)據(jù)(你在 CNT 寄存器里設定的數(shù)量)已經(jīng)全部安全送達目的地。
實戰(zhàn)邏輯:在你的 500 節(jié)點項目中,當讀取 Flash 的 DMA 完成時,你會看到這個位變 1。
燈 B:TE (Transfer Error) —— 傳輸錯誤標志
位地址:位 1, 5, 9, 13, 17(分別對應通道 1, 2, 3, 4, 5)。
含義:這是“紅燈”。正常情況下它應該是 0。如果變成 1,說明出事了!
報錯原因:通常是地址指錯了(越界)或者總線訪問沖突。如果看到這個位亮了,就要去檢查 SRCADDR 和 DSTADDR 有沒有寫對。
| 通道編號 | 成功看這里 (TC) | 失敗看這里 (TE) |
| 通道 1 | 位 0 | 位 1 |
| 通道 2 | 位 4 | 位 5 |
| 通道 3 | 位 8 | 位 9 |
| 通道 4 | 位 12 | 位 13 |
| 通道 5 | 位 16 | 位 17 |
大家看,這寄存器就像一排指示燈。如果你用的是通道 2(CH2)來傳串口數(shù)據(jù),你就盯著第 4 位看。一旦第 4 位變成了 1,就說明你的數(shù)據(jù)已經(jīng)躺在內存里等著你處理了!
注意
DMA_ISR 是“只讀”的。
如果你在中斷服務程序里發(fā)現(xiàn)了 TC1 = 1,處理完業(yè)務后,你必須去 DMA_ICR(清除寄存器) 對應的位寫一個 0。
后果警告:如果你不跑去 DMA_ICR 清除這個標志,DMA_ISR 里的那個 1 就會一直亮著。單片機會認為“怎么還沒處理完?”,然后瘋狂地重復進入中斷,直到你的程序死機
為什么我們要學 DMA_ISR?因為在 FreeRTOS 里,我們不希望 CPU 浪費時間去等。我們讓任務去‘睡覺’(掛起),等 DMA 搬完磚,硬件會自動點亮 DMA_ISR 里的 TC 燈,觸發(fā)中斷。中斷里看一眼這個燈,確定沒問題了,再發(fā)個信號量把任務叫醒。這種‘事畢報信’的機制,才是單片機在 8KB RAM 下還能高效運行的秘密
在中斷服務函數(shù)(ISR)中干的事:
動作:快進快出。
職責 1:清除硬件中斷標志位(滅燈)。
職責 2:釋放信號量或發(fā)送任務通知(報信)。
職責 3:如果喚醒的任務優(yōu)先級更高,觸發(fā)任務切換(上下文切換)。
在任務(Task)中干的事:
動作:等待信號量(睡覺)。
職責 1:拿到信號量后,處理真正耗時的業(yè)務邏輯(如解析數(shù)據(jù)包、存入 Flash、計算校驗和)。
職責 2:處理完后重新配置下一輪的 DMA。
四、DMA_ICR中斷標志清除寄存器 (Interrupt Clear Register)
寄存器全稱:中斷標志清除寄存器 (Interrupt Clear Register)
它的核心作用:當 CPU 處理完 DMA 的中斷任務后,必須通過這個寄存器告訴硬件:“我已經(jīng)知道了,你可以把報告撤下去了?!?/p>
物理聯(lián)系:它和 DMA_ISR 是一一對應的。ISR 負責告狀,ICR 負責撤訴。
權限密碼:為什么是 R1W0?
這張表里有一個非常獨特的權限說明:R1W0。
官方解釋:
R1 (Read 1):無論當前中斷是否發(fā)生,你用代碼去讀這個寄存器,它吐給你的數(shù)據(jù)全是 1(即 0xFFFFFFFF)。
W0: 清除通道標志;W1: 無功能。
大白話翻譯:這是一個“寫 0 觸發(fā)”的機關。
如果你想清除通道 1 的完成標志(TC1),你得往位 0 寫一個數(shù)字 0。
如果你往這里寫 1,硬件會當沒看見,什么都不會發(fā)生。
提醒:這和很多單片機(如 STM32)“寫 1 清零”的習慣正好相反。

審核編輯 黃宇
-
無線抄表
+關注
關注
0文章
41瀏覽量
17437 -
CW32
+關注
關注
1文章
326瀏覽量
1971
發(fā)布評論請先 登錄
【項目展示】基于CW32的遙控循跡小車
【CW32無線抄表項目】W25Q+CW32程序示例
CW32 MCU有哪些系列?
【CW32無線抄表項目】W25Q_CW32_DMA簡介
評論