# STM32 DMA ###### tags: `STM32` * 本篇只解說原理,不解說DMA程式上使用方式 * DMA就是不佔用CPU執行序,將『資料傳輸』的控制權交給 DMA 控制器,讓資料在週邊 (Peripherals) 與記憶體 (SRAM) 之間直接流動。 * 本篇解說 * STM32L0 and STM32L4方塊圖,STM32F系列也可以參考如下方塊圖 * STM32G4系列就沒有分 DMA1 和 DMA2,G4是規劃一個DMA區域讓User自行分配 ## DMA 原理 * Cortex-M 內核和 DMA1 控制器都與其他 MCU 周邊設備交互通過一系列Bus。如果仍然不清楚,重要的是要注意flash和SRAM暫儲器是 MCU 內核之外的元件,因此它們需要相互交互其他通過總線互連。 * Cortex-M 內核和 DMA1 控制器都是主機。這意味著他們是唯一的可以在總線上啟動事務的單元。但是,必須規範對總線的訪問這樣他們就不能同時訪問同一個從外圍設備。 * BusMatrix 管理 Cortex-M 內核與 DMA1 之間的訪問仲裁控制器。仲裁使用循環算法來控制對總線的訪問。這BusMatrix 由兩個主機(CPU、DMA)和四個從機(flash、SRAM、AHB1 帶有 AHB 到高級外部總線 (APB) 橋接器和 AHB2)。 BusMatrix 也允許在它們之間自動互連多個外部設備。 * 系統總線將 Cortex-M 內核連接到 BusMatrix。 * DMA 總線將 DMA 的高級高性能總線 (AHB) 主接口連接到 BusMatrix。 * AHB 到 APB 橋接器提供了 AHB 和 APB 總線之間的完全同步連接,其中連接了大多數周邊設備 ## 為什麼說 DMA 「不佔用 CPU 執行緒」 * CPU 從週邊(例如 I2C 或 UART)讀取一個 Byte。 * CPU 將這個 Byte 寫入 SRAM 的某個位置。 * 這段時間 CPU 沒辦法處理其他邏輯運算。 ### 有了 DMA (Direct Memory Access) 之後 * CPU 只需要花幾微秒告訴 DMA:「幫我把 UART 收到的 100 個 Byte 搬到 SRAM 的 0x20000000 位置,搬完再叫我。」 * 指令下達後,CPU 立即去做其他數學運算或邏輯判斷。 * DMA 與 CPU 會分時或同時共享系統總線 (Bus) 來存取 SRAM。 ### DMA應用場景 1. 指令型傳輸 (CMD: UART, I2C, SPI, CAN) * 這類通訊非常適合 DMA,主要原因不在於「資料量」,而在於**「非同步等待」**。 * 優勢:當你發送一個長字串(如 AT Command)或讀取感測器時,如果不使用 DMA,CPU 必須在每個 Byte 傳輸完成後被中斷一次。 * 實務感觸:使用 DMA 後,你可以實現「背景傳輸」。 * 範例:發送 100 Bytes 的 UART Log,CPU 只需要花 1 條指令啟動 DMA,然後就可以去跑更重要的 PID 演算法,完全不需要理會這 100 次的發送中斷。 2. ADC 傳輸的場景分析 1. 多通道 (6~12組以上):非常有感 * 當通道數變多時,若使用傳統的「中斷觸發(Interrupt)」或「輪詢(Polling)」: * 中斷地獄:每轉換完一個通道就進一次中斷,CPU 會花大量的時間在進出中斷(Context Switch),導致主程式效率低落。 * DMA 的做法:設定 ADC 進入 掃描模式 (Scan Mode),結合 DMA。ADC 會自動轉換完通道 1 到通道 12,並由 DMA 依序填入 SRAM 中的陣列。 * 結果:CPU 只需要在「整組 12 個通道都轉完」時看一眼結果就好。 2. 少量通道 (1~2組):感觸不明顯 * 原因:如果只有一兩個數值,且取樣頻率不高,CPU 順手讀一下暫存器(Register)的時間極短,配置 DMA 的程式碼複雜度反而更高。 * 修正觀點:即使通道少,如果「取樣頻率極高」(例如音訊處理,每秒取樣 48,000 次),DMA 依然是必須的。因為高頻率的中斷會讓 CPU 沒時間處理其他邏輯。 ## STM32 L0 and STM32 L4 ### M0 ![](https://i.imgur.com/IHLALn7.png) ### M4 ![](https://i.imgur.com/qMtkyvu.png) * I-bus * 該bus將 Cortex®-M4 內核的指令總線連接到 BusMatrix。 * I-bus使用該總線來獲取指令。 * 該總線的目標是包含代碼的存儲器(Flash memory、內部 SRAM 或通過 FMC 或 OCTOSPI 的外部存儲器)。 * D-bus * 該bus將 Cortex®-M4 內核的數據總線連接到 BusMatrix。 * 這D-bus由內核用於文字加載和調試訪問。 * 該總線的目標是包含代碼的存儲器(Flash memory、內部 SRAM 或通過 FMC 或 OCTOSPI 的外部存儲器)。 * S-bus * 該bus將 Cortex®-M4 內核的系統總線連接到 BusMatrix。 * 這s-bus是內核用於訪問位於外部設備或 SRAM 區域中的數據。 * 本次的目標總線是內部 SRAM,AHB1 外設包括 APB1 和 APB2外設、AHB2 外設和外部存儲器通過 OCTOSPI 或 FMC。 * SRAM2 也可通過該總線訪問以允許與 SRAM1 和 SRAM3 的連續映射。 * DMA總線 * 該總線將 DMA 的 AHB 主接口連接到 BusMatrix。 * 總線是 SRAM1、SRAM2 和 SRAM3,AHB1 外設包括 APB1 和APB2 外設、AHB2 外設和通過 OCTOSPI 的外部存儲器或FMC。 * DMA2D-bus 總線 * 該總線將 DMA2D 的 AHB 主接口連接到 BusMatrix。 * 的目標該總線是通過 OCTOSPI 的 SRAM1、SRAM2 和 SRAM3 以及外部存儲器或FMC。 ## STM32 G4 DMA搭配方式 ```= void Init_DMA1_CH1(void) { // ADC12 -> DMA1_CH1 _DMA1_CCR1.bit.DIR = 0; // Read data from peripheral _DMA1_CCR1.bit.CIRC = 1; // circular mode enabled _DMA1_CCR1.bit.MINC = 1; // memory increment mode enabled _DMA1_CCR1.bit.PINC = 0; // peripheral increment mode disabled _DMA1_CCR1.bit.PSIZE = 2; // Set peripheral size to 32-bits _DMA1_CCR1.bit.MSIZE = 2; // Set memory size to 32-bits _DMA1_CCR1.bit.PL = 3; //priority = very high _DMA1_CCR1.bit.TCIE = 1; // Enable DMA TC ISR _DMA1_CNDTR1.bit.NDT = 7; // Number of data need to be transfer _DMA1_CPAR1.bit.PA = (unsigned long)&_ADC12_CDR.all; // address of _ADC12_CDR.all or (0x5000030C) _DMA1_CMAR1.bit.MA = (unsigned long)&adc12RawData; _DMAMUX1_C0CR.bit.DMAREQ_ID = 5; // Set ADC12 as the DMA request source _DMA1_CCR1.bit.EN = 1; } ``` ```= void Init_DMA1_CH2(void) { // ADC345 -> DMA1_CH2 _DMA1_CCR2.bit.DIR = 0; // Read data from peripheral _DMA1_CCR2.bit.CIRC = 1; // circular mode enabled _DMA1_CCR2.bit.MINC = 1; // memory increment mode enabled _DMA1_CCR2.bit.PINC = 0; // peripheral increment mode disabled _DMA1_CCR2.bit.PSIZE = 2; // Set peripheral size to 32-bits _DMA1_CCR2.bit.MSIZE = 2; // Set memory size to 32-bits _DMA1_CCR2.bit.PL = 1; // priority = Med _DMA1_CCR2.bit.TCIE = 0; // Disable DMA TC ISR _DMA1_CNDTR2.bit.NDT = 8; // Number of data need to be transfer _DMA1_CPAR2.bit.PA = (unsigned long)&_ADC345_CDR.all; // address of _ADC345_CDR.all or (0x5000070C) _DMA1_CMAR2.bit.MA = (unsigned long)&adc345RawData; _DMAMUX1_C1CR.bit.DMAREQ_ID = 37; // Set ADC345 as the DMA request source _DMA1_CCR2.bit.EN = 1; } ``` * M4 ![](https://i.imgur.com/89WVnyO.png) ## STM32 DMA Datasheet ### STM32 L0 DMA * [Using the STM32F0/F1/F3/Gx/Lx Series DMA controller](https://www.st.com/resource/en/application_note/cd00160362-using-the-stm32f0f1f3gxlx-series-dma-controller-stmicroelectronics.pdf) ### STM32 F2 F4 F7 DMA * [Using the STM32F2, STM32F4 and STM32F7 Series DMA controller](https://www.st.com/resource/en/application_note/dm00046011-using-the-stm32f2-stm32f4-and-stm32f7-series-dma-controller-stmicroelectronics.pdf) ## Reference * [ARM的BUS Matrix的作用](https://blog.csdn.net/m0_49540263/article/details/111675882) * [CortexM3与CortexM0的bus matrix](https://blog.csdn.net/qq_34686440/article/details/116561517?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163600662716780264061646%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=163600662716780264061646&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-116561517.first_rank_v2_pc_rank_v29&utm_term=BUS+Matrix+M0) * [【STM32】 DMA原理,步骤超细详解,一文看懂DMA](https://blog.csdn.net/as480133937/article/details/104927922)