首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

STM32 DMA 實戰 (一):SRAM ↔ Flash 高速資料搬移完整教學

     編輯:關於C

為什麼用 DMA?

  • 解放 CPU:資料搬移由硬體自動完成,CPU 可執行其他任務。
  • 高速:記憶體間直接傳輸,不經 CPU,頻率可達系統時脈。
  • 低延遲:無中斷開銷,適合大塊資料、週期性搬移。

DMA 傳輸模式

  1. 記憶體到記憶體 (Memory-to-Memory):SRAM ↔ SRAM、SRAM ↔ Flash。
  2. 外設到記憶體:如 UART 接收 → SRAM。
  3. 記憶體到外設:SRAM → UART 發送暫存器。

關鍵參數配置 (STM32F103VE)

參數本範例設定說明
通道DMA1 Channel 1支援 M2M 的通道
方向DMA_DIR_PeripheralSRCFlash (視為外設) → SRAM
資料寬度DMA_PeripheralDataSize_Word / DMA_MemoryDataSize_Word32-bit (4 bytes) 傳輸
位址增量啟用 DMA_PeripheralInc_Enable, DMA_MemoryInc_Enable源/目標位址自增
模式DMA_Mode_Normal單次傳輸,非循環
優先級DMA_Priority_High高優先級
M2MDMA_M2M_Enable啟用記憶體到記憶體
傳輸量BufferSize以「資料寬度單位」計數 (非位元組)

完整初始化程式碼

#define SRC_ADDR  ((uint32_t)SRC_Const_Buffer)  // Flash 位址 (const 資料)
#define DST_ADDR  ((uint32_t)DST_Buffer)        // SRAM 位址
#define BUF_WORDS 256                           // 256 個 32-bit 字 = 1 KB

void DMA_Init(void) {
    DMA_InitTypeDef dma;
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    DMA_DeInit(DMA1_Channel1);

    dma.DMA_PeripheralBaseAddr = SRC_ADDR;
    dma.DMA_MemoryBaseAddr     = DST_ADDR;
    dma.DMA_DIR                = DMA_DIR_PeripheralSRC;
    dma.DMA_BufferSize         = BUF_WORDS;
    dma.DMA_PeripheralInc      = DMA_PeripheralInc_Enable;
    dma.DMA_MemoryInc          = DMA_MemoryInc_Enable;
    dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
    dma.DMA_MemoryDataSize     = DMA_MemoryDataSize_Word;
    dma.DMA_Mode               = DMA_Mode_Normal;
    dma.DMA_Priority           = DMA_Priority_High;
    dma.DMA_M2M                = DMA_M2M_Enable;
    DMA_Init(DMA1_Channel1, &dma);

    DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); // 傳輸完成中斷
    DMA_Cmd(DMA1_Channel1, ENABLE);                 // 啟動
}

中斷服務常式 (ISR)

void DMA1_Channel1_IRQHandler(void) {
    if (DMA_GetITStatus(DMA1_IT_TC1)) {
        // 可選:檢查剩餘計數器 DMA_GetCurrDataCounter()
        DMA_ClearITPendingBit(DMA1_IT_GL1);
        // 設旗標通知主程式傳輸完成
        dma_done = 1;
    }
}

NVIC 優先級設定

void NVIC_Config(void) {
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 0 搶佔, 4 子優先級
    NVIC_InitTypeDef nvic = {
        .NVIC_IRQChannel = DMA1_Channel1_IRQn,
        .NVIC_IRQChannelPreemptionPriority = 0,
        .NVIC_IRQChannelSubPriority = 0,
        .NVIC_IRQChannelCmd = ENABLE
    };
    NVIC_Init(&nvic);
}

主程式輪詢等待

int main(void) {
    SystemInit();
    NVIC_Config();
    DMA_Init();
    while (!dma_done); // 簡單輪詢,實際專案建議用信號量/事件
    // 驗證資料...
    while (1);
}

關鍵觀察:變數儲存區

  • SRC_Const_Buffer 定義為 const uint32_t → 編譯器置於 Flash (0x0800xxxx)。
  • DST_Buffer 定義為 uint32_t (無 const) → 編譯器置於 SRAM (0x2000xxxx)。
  • DMA 實際搬移路徑:**Flash → SRAM**,驗證 M2M 模式下「外設」端可為 Flash。

常見坑點

  1. BufferSize 單位:是「資料寬度單位」,32-bit 模式下 256 代表 1024 位元組,非 256 位元組。
  2. Flash 讀取速度:若系統時脈 > 24 MHz 需開啟 Flash 等待週期 (FLASH_SetLatency),否則 DMA 讀取可能錯誤。
  3. 快取一致性:Cortex-M3 無資料快取,無需清理;M4/M7 有快取時需 SCB_CleanDCache/SCB_InvalidateDCache。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved