FreeRTOS中使用DMA
时间: 2025-01-01 11:26:47 浏览: 10
### 实现 FreeRTOS 下的 DMA 使用
在 FreeRTOS 中实现 DMA 的关键是确保任务间的同步以及正确配置中断优先级。当 FreeRTOS 运行时,如果遇到像 STM32H743XI 这样的设备上 UART 的 DMA 中断无法正常工作的情况,通常是因为抢占式内核的任务调度机制影响到了低级别的硬件中断处理。
为了使 FreeRTOS 和 DMA 协同工作,在初始化阶段应调整 NVIC (Nested Vectored Interrupt Controller) 设置来保证 DMA 请求可以被及时响应[^1]:
```c
// 调整DMA通道和UART中断优先级, 确保它们高于其他非关键ISR
HAL_NVIC_SetPriority(DMA_STREAM_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA_STREAM_IRQn);
HAL_NVIC_SetPriority(UART_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(UART_IRQn);
```
接着定义用于控制 DMA 操作的任务,并设置适当的任务堆栈大小与优先级以防止饥饿现象发生。对于需要频繁触发的数据传输操作来说,较高的任务优先级可能是必要的。
创建一个回调函数用来通知 FreeRTOS 当前有新的数据通过 DMA 接收到并准备好了:
```c
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
BaseType_t xHigherPriorityTaskWoken;
// 唤醒等待接收完成事件的任务
xSemaphoreGiveFromISR(xUARTRxMutex,&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
```
最后编写实际负责读取或写入数据到外设寄存器中的任务逻辑部分。这里展示的是一个简单的例子,其中包含了启动 DMA 收发过程的方法调用:
```c
static void vStartDMATransfer(void const *argument)
{
while(1){
/* 阻塞直到获得互斥锁 */
if(pdTRUE == xSemaphoreTake(xUARTRxMutex,portMAX_DELAY)){
// 开始一次新的DMA接收循环
HAL_UART_Receive_DMA(&huart6, aRxBuffer, RXBUFFERSIZE);
// 执行一些额外的工作...
// 发送完成后释放互斥锁
xSemaphoreGive(xUARTRxMutex);
}
// 让出CPU给更高优先级的任务
taskYIELD();
}
}
/* 创建上述任务 */
xTaskCreate(vStartDMATransfer,"DMA Transfer",configMINIMAL_STACK_SIZE,NULL,tskIDLE_PRIORITY+1,NULL );
```
以上代码片段展示了如何利用 FreeRTOS 提供的功能——特别是信号量(semaphore),实现了安全可靠的 DMA 数据交换流程。这种方式不仅解决了原始问题中提到的现象,同时也提高了整个应用程序架构的设计质量[^2]。
阅读全文