You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FreeRTOS任务中如何等待两个DMA完成事件?xTaskNotify能否一行实现?

双DMA完成后的任务同步实现方案

用xTaskNotify实现(单等待逻辑)

完全可以通过xTaskNotify实现,核心思路是利用位掩码式通知来同步两个DMA完成事件:

  1. 为两个DMA分配独立的位标识(例如DMA1对应0x01,DMA2对应0x02)
  2. 在DMA完成回调(中断上下文)中,使用中断安全的通知API置位对应标识:
    // 全局或任务可见的处理任务句柄
    TaskHandle_t processingTaskHandle;
    
    // DMA1完成回调
    void HAL_DMA1_CompleteCallback(DMA_HandleTypeDef *hdma) {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        xTaskNotifyFromISR(processingTaskHandle, 0x01, eSetBits, &xHigherPriorityTaskWoken);
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
    
    // DMA2完成回调
    void HAL_DMA2_CompleteCallback(DMA_HandleTypeDef *hdma) {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        xTaskNotifyFromISR(processingTaskHandle, 0x02, eSetBits, &xHigherPriorityTaskWoken);
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
    
  3. 在数据处理任务中,用一行逻辑等待两个位都被置位:
    uint32_t notifiedBits;
    // 等待0x01和0x02位都被置位,完成后清除这两个位
    xTaskNotifyWait(0x00, 0x03, &notifiedBits, portMAX_DELAY);
    // 此时两个DMA均已完成,可开始处理ADC原始数据
    

其他可行方案

1. 事件组(更直观的多事件同步)

FreeRTOS事件组专为多事件等待场景设计,可读性更强:

// 全局事件组句柄
EventGroupHandle_t dmaEventGroup;

// 初始化事件组(任务创建前执行)
dmaEventGroup = xEventGroupCreate();

// DMA回调中设置事件位
void HAL_DMA1_CompleteCallback(DMA_HandleTypeDef *hdma) {
   BaseType_t xHigherPriorityTaskWoken = pdFALSE;
   xEventGroupSetBitsFromISR(dmaEventGroup, (1 << 0), &xHigherPriorityTaskWoken);
   portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void HAL_DMA2_CompleteCallback(DMA_HandleTypeDef *hdma) {
   BaseType_t xHigherPriorityTaskWoken = pdFALSE;
   xEventGroupSetBitsFromISR(dmaEventGroup, (1 << 1), &xHigherPriorityTaskWoken);
   portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

// 处理任务中等待两个事件触发
xEventGroupWaitBits(
    dmaEventGroup,
    (1 << 0) | (1 << 1),  // 等待的事件位掩码
    pdTRUE,               // 完成后清除事件位
    pdTRUE,               // 需所有事件位都置位才返回
    portMAX_DELAY         // 无限等待
);
// 两个DMA均完成,开始处理数据

2. 二值信号量

为每个DMA分配独立信号量,任务中依次获取两个信号量实现同步:

// 全局信号量句柄
SemaphoreHandle_t dma1Sem, dma2Sem;

// 初始化信号量(任务创建前执行)
dma1Sem = xSemaphoreCreateBinary();
dma2Sem = xSemaphoreCreateBinary();

// DMA回调中释放信号量
void HAL_DMA1_CompleteCallback(DMA_HandleTypeDef *hdma) {
   BaseType_t xHigherPriorityTaskWoken = pdFALSE;
   xSemaphoreGiveFromISR(dma1Sem, &xHigherPriorityTaskWoken);
   portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void HAL_DMA2_CompleteCallback(DMA_HandleTypeDef *hdma) {
   BaseType_t xHigherPriorityTaskWoken = pdFALSE;
   xSemaphoreGiveFromISR(dma2Sem, &xHigherPriorityTaskWoken);
   portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

// 处理任务中等待两个信号量
xSemaphoreTake(dma1Sem, portMAX_DELAY);
xSemaphoreTake(dma2Sem, portMAX_DELAY);
// 两个DMA均完成,开始处理数据

注意:所有中断上下文的FreeRTOS API调用,必须使用带FromISR后缀的版本,并根据返回值决定是否触发任务切换,避免中断阻塞。

内容的提问来源于stack exchange,提问作者Gokhan Sahin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 04:40:10