调试小记2

最近遇到一个很棘手的bug,值得记录一下。
这是在stm32f103vct6单片机上运行的ucos程序,我根据一些书上的描述移植的(很简单),使用标准库和usb驱动库,因为板卡的USART1没有直接的串口接口,所以使用usb与主机通信并调试。开发环境是eclipse,其实是用makefile+arm-none-eabi-gcc工具链编译的,集成得不好,就是写代码方便。
我创建了两个任务,大致代码如下:

OSTaskCreate(task_manager, NULL, (OS_STK*)&task_manager_stk[STK_SIZE], 20);
OSTaskCreate(task1, NULL, (OS_STK*)&task1_stk[STK_SIZE], 30);

void task_manager(void *pdata)
{
    printf("task_manager\n");
    while(!is_usb_buffer_empty());

    while(1){
           OSTimeDly(1000);
           printf("task delay 1s\n");
           while(!is_usb_buffer_empty());
    }
}

void task1()
{
     printf("task1\n");
     while(!is_usb_buffer_empty());
     while(1);
}


问题就出在task_manager延迟够1s,被唤醒时。systick时钟中断先调用OSTimeTick(),再调用OSIntExit,进行可能的任务切换。
OSIntExit会在临界区检查是否需要任务切换,需要则调用OSIntCtxSw()函数。OSIntCtxSw被实现如下:

 .thumb_func
OSCtxSw:
OSIntCtxSw:
 LDR  R0, =NVIC_SCB_ICSR
 LDR  R1, =NVIC_PENDSVSET
 STR  R1, [R0]
 BX  LR

这里的OSIntCtxSw和OSCtxSw功能一致,都是设置pendsv异常阻塞标志,实际的任务切换发生在PendSV_Handler中。

我开始是怀疑任务堆栈出了问题,在task_manager被换入和换出时打印了它的上下文,发现是相同的。
因为usb基本只能在中断情况下通信,而且它优先级又无法高过一些系统异常,所以即使我怀疑是产生了某些系统异常,也没办法用usb输出信息来验证。
这里其实可以用板卡上的led灯验证是进入了那个异常,但我选择了另一种方法,就是用led灯显示确定在哪里产生了异常。最大范围是从OSIntExit
到task_manager重新运行,采用二分法(悲剧的板卡上只有1个led灯)。
最后我终于确定,它竟然没有进入PendSV_Handler,也不是在调用OSIntCtxSw之前,那问题就集中在OSIntCtxSw这段仅有4条指令的代码上。

因为之前从task_manager切换到task1是正常的,所以OSCtxSw可以正常工作,但OSIntCtxSw却不行。我注意到OSCtxSw前面比OSIntCtxSw多了
一个.thumb_func,或许是它产生了影响。

我再回头去分别检查调用OSCtxSw和OSIntCtxSw的反汇编代码。
调用OSCtxSw的指令如下:
   bl  0x800f46a
调用OSIntCtxSw的指令如下:
   blx 0x800f46a

这显然是问题所在,bl指令不切换thumb2状态,但blx会切换,而且后面0x800f46a第0位为0,会尝试切换到arm状态,在cortex-m3上自然死定了。

所以问题浮出了水面,只需做出如下修改:

 .thumb_func
OSCtxSw:
        .thumb_func
OSIntCtxSw:
 LDR  R0, =NVIC_SCB_ICSR
 LDR  R1, =NVIC_PENDSVSET
 STR  R1, [R0]
 BX  LR


这个调试过程说起来简单,但中间也很艰辛。也只能怪自己学东西急躁,写代码时没完全搞清楚.thumb_func的问题就,调试时也没有第一时间冷静地去看代码。
这是首次在usb通信的情况下调试,还是比用串口时麻烦一些。在调试的时候,不停地鄙视自己落后的调试手段,不但连断点、单步什么的都没有,就是想输出些
东西都要受各种限制,真是吃了苦头。其实调试就是脑子中不断涌出各种猜想,动手去实验验证,获得反馈,又有新的猜想,再验证。这个bug虽然不算好找,但
场景简单,可稳定重现,即使在如此落后的调试手段下,也可以找出并修正。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值