ESP32使用FreeRTOS串口接收任务时添加vTaskDelay触发LoadProhibited错误求助
ESP32使用FreeRTOS串口接收任务时添加vTaskDelay触发LoadProhibited错误求助
看起来你遇到的这个问题挺典型的,LoadProhibited错误本质是代码尝试访问了无效的内存地址(从错误信息里的EXCVADDR: 0xffffffff也能看出来,这个地址完全是无效的)。结合你说的「加vTaskDelay就崩,不加就正常」的现象,咱们一步步拆解问题:
问题根源分析
你的串口任务里用self = static_cast<ICBluetoothController*>(pvParameters)拿到了类实例的指针,然后循环访问self->_serial。问题就出在这个self指针上:
当你加上vTaskDelay让任务挂起时,你的ICBluetoothController实例可能已经被销毁了,导致self变成了野指针。
为什么不加vTaskDelay的时候没问题?因为不加延迟的话,这个任务会一直霸占CPU循环运行,其他代码根本没机会执行销毁实例的操作;但一旦加了vTaskDelay,任务会挂起20ms,系统会调度其他任务/代码运行,如果这时候你的ICBluetoothController对象被析构了(比如你在主线程里创建了局部实例,函数执行完就自动销毁了),等串口任务从延迟中恢复过来,再去访问self->_serial.available()时,就会去访问一块已经被释放的无效内存,直接触发LoadProhibited崩溃。
解决建议
给你几个可行的方案:
- 确保类实例的生命周期覆盖任务全程:把
ICBluetoothController的实例改成全局变量,或者用new动态分配(程序运行期间不要调用delete销毁它)。 - 同步任务与实例的生命周期:如果需要销毁实例,一定要先通过
vTaskDelete删除对应的串口任务,再销毁实例;任务的启动要在实例完全初始化完成之后。 - 修复队列发送的潜在问题:你现在用
xQueueSend(self->_rx_queue, &payload, portMAX_DELAY)把payload的地址发送到队列里,这是个隐患!payload是任务函数里的局部栈变量,当其他任务从队列取出这个地址时,payload的内容可能已经被后续的串口接收操作覆盖了。正确的做法是:- 创建队列时指定每个项的大小为128字节(和
payload数组长度一致); - 发送时直接传
payload(而不是&payload),让FreeRTOS把数组内容复制到队列中。
- 创建队列时指定每个项的大小为128字节(和
你可以先试试把ICBluetoothController的实例改成全局的,再加上vTaskDelay,应该就能解决崩溃问题了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

