STM32L496+CMSIS RTOS2下ADC采集任务及队列异常问题求助
问题分析与解决方案
一、核心问题根源
- 任务优先级倒挂:
main_task优先级(osPriorityAboveNormal3)高于acquisition_task(osPriorityAboveNormal2),系统启动后main_task会被优先调度,可能在acquisition_task尚未进入队列等待状态时就启动ADC采集,导致中断数据无人消费,队列快速溢出。 - 代码语法错误:
main_task中memset(msg, 0x00, sizeof(msg))为非法调用,memset要求第一个参数为指针,该错误会破坏栈内存,导致任务逻辑异常甚至无法进入阻塞状态。 - 消费调度不及时:12kHz高频ADC数据的消费任务优先级低于生产端依赖的调度逻辑,无法及时处理数据,引发队列堆积。
- 中断写入无容错:
HAL_ADC_ConvCpltCallback中osMessageQueuePut超时设为0,队列满时直接触发错误,且未处理溢出场景。 - 潜在内存非法访问:若
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
相关产品推荐
相关产品推荐

