Fork me on GitHub
0%

Debug笔记-2

  1. Freertos 使用udisk功能从PC向板子拷贝数据,拷贝三次之后,速度降到0随后失败?

    板子连接串口,通过串口发现板子已经跑飞,进一步通过ra和epc寄存器定位在vPortSuppressTickAndSleep函数。

    阅读汇编指令及dump寄存器的结果发现,出现了除0错误,但是如果按照正常指令顺序执行的话,分母位置是常数。进一步定位原因在于关中断之后,又使用了进入临界区的函数导致的。将进入临界区的函数注释掉正常。

  2. 主机ping开发板系统跑飞?

    解决思路

    • 将LWIP的Debug功能打开,查看是否有报错显示

    • 根据跑飞的ra epc等寄存器值,根据汇编定位到相关函数,最终确定是在ip4_input中

    • 通过打印的方式确定是payload的地址为空导致的跑飞,但是函数入口处该地址非空。由于pbuf这个结构体是外部申请并传参进来的,所以猜测可能是由于多线程同步关系没有设置好,导致一个线程释放了该指针而另外一个线程仍需要使用。

    解决方案:将内存池的方式改成PBUF_RAM的方式正常

  3. Linux在TF卡上创建一个文件,将TF卡拔出分别在Windows和Linux机器上看文件创建时间,发现不一致?

    • Windows把系统硬件时间当作本地时间(local time),即操作系统中显示的时间跟BIOS中显示的时间是一样的。

    • Linux/Unix/Mac把硬件时间当作UTC,操作系统中显示的时间是硬件时间经过换算得来的,比如说北京时间是GMT+8,则系统中显示时间是硬件时间+8。

  4. FreeRTOS系统调度进入tickless低功耗模式的时候系统crash?

    在RTOS系统中,处理器大量的时间处在IDLE线程中,这个时间可以考虑进入低功耗模式。FreeRTOS特地提供了一个解决方法–Tickless模式,当处理器进入空闲任务以后就关闭系统节拍中断(滴答定时器中断),只有当其他中断发生或者其他任务需要处理的时候处理器才会被低功耗模式中唤醒。

    在标准RTOS中port.c文件用于实现和平台相关的函数,对于低功耗可以在文件中实现 vPortSuppressTicksAndSleep 函数。具体的步骤包括:

    • 关中断

    • 判断是否可以进入低功耗状态。是否有任务需要被相应、休眠时间过小等条件直接返回

    • 设置滴答定时器。保存滴答定时器的值,并根据函数的参数(期待休眠的时间)设置定时器

    • 进入低功耗状态。在进入wait之前需要保存系统状态,其中包括prefetch、刷cache、sync等操作。出现本次的carsh的原因也在此,以下代码是改进的方法。

    • wait

    • 退出低功耗状态。当中断到来或者定时器时间到,退出wait状态

    • 恢复状态。计算上一段IDLE状态的时间,并把这一段时间加到wait之前的滴答定时器的值上,同时重新进行任务调度

    • 开中断

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 这一段代码的作用是将label处的代码预取的cache中
    #define Index_Prefetch_I (0x1C)
    #define cache_prefetch(label) \
    do{ \
    ┆ unsigned long addr,size,end; \
    ┆ addr = (unsigned long)(&&label) & ~(32 - 1); \ // 地址对齐
    ┆ size = 32 * 6; /* load 128 cachelines */ \
    ┆ end = addr + size; \
    for (; addr < end; addr += 32) { \
    ┆ ┆ __asm__ volatile ( \
    ┆ ┆ ┆ ┆ ".set push\n" \ // 保存当前汇编状态
    ┆ ┆ ┆ ┆ ".set mips32\n\t" \ // 切换到MIPS32模式
    ┆ ┆ ┆ ┆ " cache %0, 0(%1)\n\t" \ // 执行cache命令(%0是下面的参数)
    ┆ ┆ ┆ ┆ ".set mips32\n\t" \
    ┆ ┆ ┆ ┆ ".set pop\n" \ // 恢复之前保存的汇编状态
    ┆ ┆ ┆ ┆ : \ // 输出
    ┆ ┆ ┆ ┆ : "I" (Index_Prefetch_I), "r"(addr)); \ // 输入
    ┆ } \
    } while(0)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 调用上述预取的代码片段
    cache_prefetch(IDLE_PROGRAM);
    IDLE_PROGRAM:
    __asm__ __volatile__ (
    ┆ ┆ " .set push \n" // 保存当前汇编状态,
    ┆ ┆ " .set mips32 \n" // 切换到MIPS32模式
    ┆ ┆ " sync \n" // 执行同步操作,确保内存的一致性
    ┆ ┆ " lw $0, 0(%0) \n" // 从地址 0xa0000000 处加载一个字到寄存器 $0
    ┆ ┆ " wait \n" // 置于低功耗模式,等待中断
    ┆ ┆ " nop \n" // 空操作
    ┆ ┆ " nop \n"
    ┆ ┆ " nop \n"
    ┆ ┆ " .set pop \n" // 恢复之前保存的汇编状态
    ┆ ┆ :: "r" (0xa0000000) // 输入参数
    ┆ ┆ );
  5. 基于第4个问题扩展cache汇编指令的使用方法?

    1
    cache op, offset(base)
    • op:缓存操作码,指定具体的缓存操作(Prefetch、Invalidata、WriteBack)操作码的数值需要具体的结构体系决定
    • offset(base):内存地址,base 是寄存器,offset 是偏移量
  6. LWIP内存池和非内存池的配置选项

    image

参考文章