在idle线程中进行低功耗配置的时候驱动使用了xQueueSemaphoreTake后死机

先说结论

空闲线程优先级问题

空闲线程的优先级是系统中最低的。如果在空闲线程中调用 xQueueSemaphoreTake 并设置了阻塞时间,可能会导致系统出现问题。

分析

当空闲线程阻塞在 xQueueSemaphoreTake 时,由于其优先级最低,没有其他高优先级任务可运行,系统可能会陷入无任务可调度的状态,从而触发断言。

排查:

发现进入休眠功能就死机。

查看callback。

结果死在SPI配置flash时进入deep sleep时,使用SPI通信,结果xQueueSemaph等待,出现问题呢。

当在 xQueueSemaphoreTake 函数中出现断言死机的情况,通常是由于违反了某些先决条件或者代码运行环境出现了异常。以下为你详细分析可能的原因及相应的解决办法。

可能的原因

1. 句柄无效

  • xQueueSemaphoreTake 函数的第一个参数是队列或者信号量的句柄。若传入的句柄无效(比如句柄为 NULL),就可能触发断言。这往往是因为在创建队列或信号量时失败,却仍使用了错误的句柄。
  • 示例代码

收起

c

QueueHandle_t xQueue;
// 创建队列失败,但仍使用无效句柄
xQueue = xQueueCreate( 10, sizeof( int ) );
if ( xQueue == NULL ) {
    // 这里没有正确处理创建失败的情况
}
xQueueSemaphoreTake( xQueue, portMAX_DELAY ); // 传入无效句柄可能导致断言死机
2. 中断上下文问题

  • xQueueSemaphoreTake 函数有两种形式:一种用于任务上下文,另一种用于中断上下文。若在中断服务程序(ISR)里调用了用于任务上下文的版本,就可能引发断言。
  • 示例代码

收起

c

void vMyISR( void )
{
    // 错误:在中断服务程序中调用任务上下文版本
    xQueueSemaphoreTake( xQueue, portMAX_DELAY ); 
}
3. 内核调度器状态问题

  • 若在调度器未启动之前调用 xQueueSemaphoreTake 函数,可能会触发断言。因为在调度器未启动时,任务调度和队列操作都无法正常工作。
  • 示例代码

收起

c

QueueHandle_t xQueue;
xQueue = xQueueCreate( 10, sizeof( int ) );
// 错误:在调度器启动之前调用
xQueueSemaphoreTake( xQueue, portMAX_DELAY ); 
vTaskStartScheduler();
4. 栈溢出或内存损坏

  • 栈溢出或者内存损坏可能会破坏队列或信号量的内部数据结构,从而导致 xQueueSemaphoreTake 函数在执行时触发断言。
  • 示例代码

收起

c

void vTaskFunction( void *pvParameters )
{
    char largeArray[10000]; // 可能导致栈溢出
    // 后续调用 xQueueSemaphoreTake 可能会因为栈溢出出现问题
    xQueueSemaphoreTake( xQueue, portMAX_DELAY ); 
}
解决办法
1. 检查句柄有效性

  • 在使用队列或信号量句柄之前,要确保其创建成功。
  • 示例代码

收起

c

QueueHandle_t xQueue;
xQueue = xQueueCreate( 10, sizeof( int ) );
if ( xQueue != NULL ) {
    xQueueSemaphoreTake( xQueue, portMAX_DELAY );
} else {
    // 处理创建失败的情况
}
2. 使用正确的函数版本

  • 在中断服务程序中,要使用专门为中断上下文设计的版本(通常函数名带有 FromISR 后缀)。
  • 示例代码

收起

c

void vMyISR( void )
{
    BaseType_t xHigherPriorityTaskWoken;
    xQueueSemaphoreTakeFromISR( xQueue, &xHigherPriorityTaskWoken );
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
3. 确保调度器已启动

  • 要在调度器启动之后再调用 xQueueSemaphoreTake 函数。
  • 示例代码

收起

c

QueueHandle_t xQueue;
xQueue = xQueueCreate( 10, sizeof( int ) );
vTaskStartScheduler();
// 在调度器启动之后调用
xQueueSemaphoreTake( xQueue, portMAX_DELAY ); 
4. 检查栈和内存使用情况

  • 要合理分配栈空间,避免栈溢出。同时,要检查代码中是否存在内存越界访问等问题。
  • 示例代码

收起

c

// 合理分配栈空间
#define TASK_STACK_SIZE 1024
void vTaskFunction( void *pvParameters )
{
    char smallArray[100]; // 避免栈溢出
    xQueueSemaphoreTake( xQueue, portMAX_DELAY ); 
}

xTaskCreate( vTaskFunction, "Task", TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );

通过上述的分析和解决办法,你应该能够找出并解决 xQueueSemaphoreTake 函数中断言死机的问题。

unsigned long 在stm32wb55系统中是多少字节

在 STM32WB55 系统中,unsigned long 数据类型通常是 4 字节。

具体解释

STM32WB55 是基于 ARM Cortex - M4 内核的微控制器,该内核采用 32 位架构。在大多数遵循标准 C 语言规范且基于 32 位架构的嵌入式系统中,unsigned long 被定义为 32 位(即 4 字节),其取值范围是 0 到 4294967295() 。

代码验证

你可以通过以下代码在 STM32WB55 开发环境(如 Keil、IAR 等)中进行验证:

收起

c

#include <stdio.h>

int main(void)
{
    // 使用 sizeof 操作符获取 unsigned long 类型的字节数
    size_t size = sizeof(unsigned long); 
    printf("The size of unsigned long is %zu bytes.\n", size);

    while (1)
    {
        // 主循环可以添加其他代码
    }
}

将上述代码编译并下载到 STM32WB55 开发板上运行,通过串口调试助手等工具查看输出结果,会显示 The size of unsigned long is 4 bytes. ,这表明 unsigned long 类型占 4 个字节。

不过,需要注意的是,虽然一般情况下是 4 字节,但 unsigned long 的大小实际上由编译器和目标平台共同决定。在某些特殊的编译器配置或者非标准环境下,其大小可能会有所不同。但在常见的基于 ARM Cortex - M4 的 STM32WB55 开发中,unsigned long 为 4 字节。

在freertos系统的idle线程里使用xQueueSemaphoreTake 断言死机是为什么

在 FreeRTOS 系统的空闲(Idle)线程里使用 xQueueSemaphoreTake 函数导致断言死机,通常有以下几个可能的原因:

1. 调度器状态问题

空闲线程是 FreeRTOS 调度器启动后自动创建的一个低优先级线程。如果在调度器还未完全启动或者正在关闭的过程中调用 xQueueSemaphoreTake,可能会触发断言。

分析

在调度器启动前,内核的一些数据结构和状态还未正确初始化,队列和信号量的操作可能无法正常工作。同样,在调度器关闭过程中,系统状态也不稳定,调用这些函数会引发错误。

示例错误代码

收起

c

// 错误示例:在调度器启动前调用相关操作
int main()
{
    QueueHandle_t xQueue = xQueueCreate(10, sizeof(int));
    // 这里调度器还未启动
    xQueueSemaphoreTake(xQueue, portMAX_DELAY); 
    vTaskStartScheduler();
    return 0;
}
解决办法

确保在调度器启动后再调用 xQueueSemaphoreTake,并且避免在调度器关闭过程中使用该函数。

2. 队列或信号量句柄无效

如果传入 xQueueSemaphoreTake 的队列或信号量句柄无效(例如为 NULL),会触发断言。

分析

无效句柄通常是由于队列或信号量创建失败,但后续代码仍然使用该句柄导致的。

示例错误代码

收起

c

QueueHandle_t xQueue;
xQueue = xQueueCreate(10, sizeof(int));
if (xQueue == NULL)
{
    // 未正确处理创建失败的情况
}
// 使用可能无效的句柄
xQueueSemaphoreTake(xQueue, portMAX_DELAY); 
解决办法

在使用队列或信号量句柄之前,先检查其是否有效。

收起

c

QueueHandle_t xQueue;
xQueue = xQueueCreate(10, sizeof(int));
if (xQueue != NULL)
{
    xQueueSemaphoreTake(xQueue, portMAX_DELAY);
}
else
{
    // 处理创建失败的情况,例如打印错误信息
}

3. 空闲线程优先级问题

空闲线程的优先级是系统中最低的。如果在空闲线程中调用 xQueueSemaphoreTake 并设置了阻塞时间,可能会导致系统出现问题。

分析

当空闲线程阻塞在 xQueueSemaphoreTake 时,由于其优先级最低,没有其他高优先级任务可运行,系统可能会陷入无任务可调度的状态,从而触发断言。

示例错误代码

收起

c

void vIdleHook(void)
{
    QueueHandle_t xQueue = xQueueCreate(10, sizeof(int));
    // 空闲线程阻塞等待
    xQueueSemaphoreTake(xQueue, portMAX_DELAY); 
}
解决办法

尽量避免在空闲线程中使用会阻塞的操作。如果确实需要等待队列或信号量,可以考虑在其他高优先级任务中进行。

4. 栈溢出问题

如果空闲线程的栈空间不足,在调用 xQueueSemaphoreTake 时可能会发生栈溢出,从而触发断言。

分析

栈溢出会破坏系统的内存结构,导致函数调用和数据存储出现错误。

解决办法

增加空闲线程的栈空间。在 FreeRTOS 配置文件中可以调整空闲线程的栈大小。例如:

收起

c

#define configMINIMAL_STACK_SIZE    256  // 增大栈大小

5. 中断上下文问题

如果在中断服务程序(ISR)中错误地调用了非 FromISR 版本的 xQueueSemaphoreTake 函数,也可能导致断言死机。虽然在空闲线程中一般不会直接出现这种情况,但如果存在中断嵌套等复杂情况,可能会引发错误。

分析

xQueueSemaphoreTake 有普通版本和 FromISR 版本,FromISR 版本是专门为中断上下文设计的,使用错误的版本会破坏系统状态。

解决办法

确保在中断服务程序中使用 xQueueSemaphoreTakeFromISR 函数。

收起

c

void vISRFunction(void)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xQueueSemaphoreTakeFromISR(xQueue, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

通过以上分析和解决办法,你可以逐步排查并解决在 FreeRTOS 空闲线程中使用 xQueueSemaphoreTake 导致断言死机的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值