之前和大家分享过串口使用DMA传输的例子,今天和大家分享一下,使用DMA把数据缓冲区从flash中传输到SRAM中。
一:程序编写流程:
1.1:程序开始运行时,调用 HAL_Init() 函数来重置所有外围设备,
1.2 初始化 Flash 接口和系统,
1.3 调用SystemClock_Config() 配置CPU主频为 48 MHz 运行。
1.4 初始化DMA的初始化
1.5 编写DMA发送的函数
二:首先在cube中开始DMA1的通道
如上图所示,软件配置时候,只需要配置DMA1的通道1的发送功能,并开始DMA的中断功能。
DMA控制函数编写流程:
DMA1_Channel1 配置为将存储在 Flash 存储器中的 32 字数据缓冲区的内容传输到 RAM 中声明的接收缓冲区。
传输的开始由软件触发。DMA1_Channel1 已启用内存到内存传输。源地址和目标地址递增也已启用。通过设置 DMA1_Channel1 的 channel enable bit 来开始传输。在传输结束时,会生成一个 Transfer Complete 中断,因为它已启用,并且回调函数被调用。
三:软件代码编写:
3.1 代码DMA的初始化函数:
static void MX_DMA_Init(void) { /* DMA controller clock enable */ __HAL_RCC_DMA1_CLK_ENABLE(); /* Configure DMA request hdma_memtomem_dma1_channel1 on DMA1_Channel1 */ hdma_memtomem_dma1_channel1.Instance = DMA1_Channel1; hdma_memtomem_dma1_channel1.Init.Request = DMA_REQUEST_MEM2MEM; hdma_memtomem_dma1_channel1.Init.Direction = DMA_MEMORY_TO_MEMORY; hdma_memtomem_dma1_channel1.Init.PeriphInc = DMA_PINC_ENABLE; hdma_memtomem_dma1_channel1.Init.MemInc = DMA_MINC_ENABLE; hdma_memtomem_dma1_channel1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hdma_memtomem_dma1_channel1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; hdma_memtomem_dma1_channel1.Init.Mode = DMA_NORMAL; hdma_memtomem_dma1_channel1.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_memtomem_dma1_channel1) != HAL_OK) { Error_Handler( ); } /* DMA interrupt init */ /* DMA1_Channel1_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); }
3.2 需要DMA传输的字节如下所示:
static const uint32_t aSRC_Const_Buffer[BUFFER_SIZE] = { 0x01020304, 0x05060708, 0x090A0B0C, 0x0D0E0F10, 0x11121314, 0x15161718, 0x191A1B1C, 0x1D1E1F20, 0x21222324, 0x25262728, 0x292A2B2C, 0x2D2E2F30, 0x31323334, 0x35363738, 0x393A3B3C, 0x3D3E3F40, 0x41424344, 0x45464748, 0x494A4B4C, 0x4D4E4F50, 0x51525354, 0x55565758, 0x595A5B5C, 0x5D5E5F60, 0x61626364, 0x65666768, 0x696A6B6C, 0x6D6E6F70, 0x71727374, 0x75767778, 0x797A7B7C, 0x7D7E7F80 }; static uint32_t aDST_Buffer[BUFFER_SIZE];
传输代码如下:
/* Select Callbacks functions called after Transfer complete and Transfer error */ HAL_DMA_RegisterCallback(&hdma_memtomem_dma1_channel1, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete); HAL_DMA_RegisterCallback(&hdma_memtomem_dma1_channel1, HAL_DMA_XFER_ERROR_CB_ID, TransferError); /* Configure the source, destination and buffer size DMA fields and Start DMA Channel/Stream transfer */ /* Enable All the DMA interrupts */ if (HAL_DMA_Start_IT(&hdma_memtomem_dma1_channel1, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, BUFFER_SIZE) != HAL_OK) { /* Transfer Error */ Error_Handler(); }
代码测试截图如下所示:
可以看到执行好上述代码后,DMA将数据缓冲区从flash中传输到SRAM中
避坑经验:
1:可以通过修改文件 main.h 中的 defines 值来为 DMA 传输示例选择不同的通道。
2:使用 HAL_Delay() 时必须小心,此函数根据 SysTick ISR 中递增的变量提供准确的延迟(以毫秒为单位)。这意味着,如果 HAL_Delay() 是从外围 ISR 进程调用的,则 SysTick 中断必须具有比外围中断更高的优先级(数值上更低)。否则,调用方 ISR 进程将被阻止。要更改 SysTick 中断优先级,您必须使用 HAL_NVIC_SetPriority() 函数。
3:应用程序需要确保 SysTick 时基始终设置为 1 毫秒,才能执行正确的 HAL 操作。