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

STM32L496+CMSIS RTOS2下ADC采集任务及队列异常问题求助

问题分析与解决方案

一、核心问题根源

  1. 任务优先级倒挂:main_task优先级(osPriorityAboveNormal3)高于acquisition_task(osPriorityAboveNormal2),系统启动后main_task会被优先调度,可能在acquisition_task尚未进入队列等待状态时就启动ADC采集,导致中断数据无人消费,队列快速溢出。
  2. 代码语法错误:main_task中memset(msg, 0x00, sizeof(msg))为非法调用,memset要求第一个参数为指针,该错误会破坏栈内存,导致任务逻辑异常甚至无法进入阻塞状态。
  3. 消费调度不及时:12kHz高频ADC数据的消费任务优先级低于生产端依赖的调度逻辑,无法及时处理数据,引发队列堆积。
  4. 中断写入无容错:HAL_ADC_ConvCpltCallback中osMessageQueuePut超时设为0,队列满时直接触发错误,且未处理溢出场景。
  5. 潜在内存非法访问:若message_t的buff成员为未初始化指针,memcpy会写入非法内存,导致系统崩溃。

具体修复步骤

1. 修复语法错误

将main_task中的非法memset调用改为:

memset(&msg, 0x00, sizeof(msg));

2. 调整任务优先级,保障消费调度

将acquisition_task优先级提升至不低于main_task,确保高频数据能被及时处理:

const osThreadAttr_t acq_thread_attr = {
    .stack_size = 1024U,
    .priority = osPriorityAboveNormal3, // 与main_task同级或更高
};

3. 同步ADC启动与消费任务就绪状态

通过信号量确保acquisition_task进入等待状态后再启动ADC,避免数据无人消费:

  • 新增信号量定义:
osSemaphoreId_t acq_ready_sem = NULL;
  • 在acquisition_task_init中创建信号量:
acq_ready_sem = osSemaphoreNew(1, 0, NULL);
  • 修改acquisition_task,就绪后释放信号量:
void acquisition_task(void *argument)
{
    message_t msg;
    osStatus_t status;
    // 通知main_task:消费任务已就绪
    osSemaphoreRelease(acq_ready_sem);
    while(1)
    {
        status = osMessageQueueGet(acquisition_queue_id, &msg, NULL, osWaitForever);
        if (status != osOK)
        {
            // 错误处理逻辑
        }
        // 新增:ADC数据处理逻辑
    }
}
  • 修改main_task,等待信号量后再启动ADC:
if(swt_state == SWITCH_ON)
{
    // 等待消费任务就绪
    osSemaphoreAcquire(acq_ready_sem, osWaitForever);
    msg.type = START_ADC_CAPTURE;
    status = osMessageQueuePut(main_queue_id, &msg, 0U, 0U);
    if (status != osOK)
    {
        // 错误处理逻辑
    }
}

4. 优化中断队列写入逻辑

确保message_t的buff为有效内存,并增加队列满时的容错处理:

  • 确认message_t定义(示例):
#define ADC_SAMPLE_COUNT 10 // 根据实际DMA采集长度调整
typedef struct {
    uint8_t type;
    uint16_t buff[ADC_SAMPLE_COUNT]; // 使用数组而非未初始化指针
} message_t;
  • 中断中调整写入逻辑:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    osStatus_t status;
    message_t msg;

    memcpy(msg.buff, l_buff, sizeof(msg.buff)); // 使用sizeof避免越界
    msg.type = ADC_DATA;

    status = osMessageQueuePut(acquisition_queue_id, &msg, 0U, 0U);
    if (status != osOK)
    {
        // 队列满时的容错:比如记录错误计数器
        static uint32_t overflow_count = 0;
        overflow_count++;
    }
}

5. 合理设置队列大小

根据系统最大调度延迟计算最小队列容量:比如12kHz频率下,若最大调度延迟为1ms,队列至少需要容纳12个消息,建议设置为20~30以留足缓冲空间。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 09:45:41