【阿福的隨筆】NXP i.MXRT 系列之淺談 嵌入的 OS 使用方式(下)

一、說明

NXP i.MXRT 通常都有嵌入的 OS,一般來說都是 RTOS 的 Free RTOS

FreeRTOS 是一種免費可使用  即時作業系統,但它比較精簡,沒有控制週邊,比較像是即時的分時多工的程序,但若是出現錯誤又要如何除錯呢? 有時出錯是就是直接 Hard Fault 又該怎辦呢? 這裡來簡單說一下如何簡易的除錯

 

以下是 FreeRTOS 的下載點

FreeRTOS V10.0.0

下載點 : https://sourceforge.net/projects/freertos/files/FreeRTOS/V10.0.0/FreeRTOSv10.0.0.zip/download

Amazon FreeRTOS

下載點 : https://github.com/aws/amazon-freertos


二、FreeRTOS 如何簡易除錯

這裡的除錯方法主要是如何獲取任務的執行情況,通過獲取的任務資訊,可以進一步的配置和優化工程。很多時候,我們需要了解任務的執行狀態,任務棧的使用情況以及各個任務的 CPU 使用率,這時就需要用到官方提供的兩個函式 vTaskListvTaskGetRunTimeStats。使用者就可以通過這兩個函式獲得任務的執行情況。獲取了任務執行情況後,可以通過串列埠將其打印出來,當然,也可以通過任何其它方式將其顯示出來。

 

具體在 FreeRTOS 的工程中如何做才可以實現任務資訊獲取呢? 

需要用到官方提供的兩個函式 vTaskList 和 vTaskGetRunTimeStats。
需要在 FreeRTOSConfig.h 文件中使能如下巨集定義:

configGENERATE_RUN_TIME_STATS

configUSE_TRACE_FACILITY

configUSE_STATS_FORMATTING_FUNCTIONS

 

使用按鍵的 TASK 或 其它可控的 TASK 來加入需列印的程式。

unsigned char ucBuffer[300];

//     任務名       任務狀態    優先級       棧     任務序號
printf("Name           State     Priority      Stack   Num\r\n");
 

vTaskList((char *)&ucBuffer);

printf("%s\r\n", ucBuffer);

printf("\r\nTask           Abs Time           % Time\r\n"); //任務名 執行計數 使用率

vTaskGetRunTimeStats((char *)&ucBuffer);

printf("%s\r\n", ucBuffer);

 

如果還是一直 Hard fault ,那該怎麼 debug 呢?

那麼可以加上一段小程式來查看

// 在 Keil ARM 的 .s 的修改方式

// Assembly wrapper for Keil_ MDK, ARM_ Compilation tool chain

// (including DS-5_ Professional and RealView_ Development Suite)

// -------------------------------------------------------------------------

// Hard Fault handler wrapper in assembly

// It extracts the location of stack frame and passes it to handler

// in C as a pointer. We also extract the LR value as second parameter.

__asm void HardFault_Handler(void)

{

TST LR, #4

ITE EQ

MRSEQ R0, MSP

MRSNE R0, PSP

MOV R1, LR

B __cpp(HardFault_Handler_C)

}

// 在 gcc ( MCUXpresso ) 的 組語 的修改方式

For users of gcc, you can create a separate assembly file to do the same thing:

/* Assembly file for gcc */

.text

.syntax unified

.thumb

.type HardFault_Handler, %function

.global HardFault_Handler

.global HardFault_Handler_c

HardFault_Handler:

tst lr, #4

ite eq

mrseq r0, msp /* stacking was using MSP */

mrseq r0, psp /* stacking was using PSP */

mov r1, lr /* second parameter */

ldr r2,=HardFault_Handler_c

bx r2

.end



// 在 IAR ARM 的 .s 的修改方式

 

// And for users of IAR Embedded Workbench (many thanks for various Cortex_- M

// users for porting the example to IAR and posting it to the Internet):

// Assembly wrapper for IAR Embedded Workbench

// -------------------------------------------------------------------------

// Hard Fault handler wrapper in assembly

// It extracts the location of stack frame and passes it to handler

// in C as a pointer. We also extract the LR value as second parameter.

void HardFault_Handler(void)

{

    __asm("TST LR, #4");

    __ASM("ITE EQ");

    __ASM("MRSEQ R0, MSP");

    __ASM("MRSNE R0, PSP");

    __ASM("MOV R1, LR");

    __ASM("B HardFault_Handler_C");

}

 

// 接下來只要再將要看的 register 放在 HardFault_Handler_C 內就可以了。若是 hardfault 在 UART initial 之前,

// 無法使用 printf ,則可改寫成放入固定且不同位址的memory 中

 

The second part of the HardFault handler is coded in C; it displays the fault status

registers, fault address register, and the contents in the stack frame:

// Second part of the HardFault handler in C

void HardFault_Handler_C(unsigned long * hardfault_args, unsigned int lr_value)

{

    unsigned long stacked_r0;

    unsigned long stacked_r1;

    unsigned long stacked_r2;

    unsigned long stacked_r3;

 

    unsigned long stacked_r12;

    unsigned long stacked_lr;

    unsigned long stacked_pc;

    unsigned long stacked_psr;

    unsigned long cfsr;

    unsigned long bus_fault_address;

    unsigned long memmanage_fault_address;

    bus_fault_address = SCB->BFAR;

    memmanage_fault_address = SCB->MMFAR;

    cfsr = SCB->CFSR;

    stacked_r0 = ((unsigned long) hardfault_args[0]);

    stacked_r1 = ((unsigned long) hardfault_args[1]);

    stacked_r2 = ((unsigned long) hardfault_args[2]);

    stacked_r3 = ((unsigned long) hardfault_args[3]);

    stacked_r12 = ((unsigned long) hardfault_args[4]);

    stacked_lr = ((unsigned long) hardfault_args[5]);

    stacked_pc = ((unsigned long) hardfault_args[6]);

    stacked_psr = ((unsigned long) hardfault_args[7]);

    printf ("[HardFault]\n");

    printf ("- Stack frame:\n");

    printf (" R0 = %x\n", stacked_r0);

    printf (" R1 = %x\n", stacked_r1);

    printf (" R2 = %x\n", stacked_r2);

    printf (" R3 = %x\n", stacked_r3);

    printf (" R12 = %x\n", stacked_r12);

    printf (" LR = %x\n", stacked_lr);

    printf (" PC = %x\n", stacked_pc);

    printf (" PSR = %x\n", stacked_psr);

    printf ("- FSR/FAR:\n");

    printf (" CFSR = %x\n", cfsr);

    printf (" HFSR = %x\n", SCB->HFSR);

    printf (" DFSR = %x\n", SCB->DFSR);

    printf (" AFSR = %x\n", SCB->AFSR);

    if (cfsr & 0x0080)
        printf (" MMFAR = %x\n",memmanage_fault_address);

    if (cfsr & 0x8000)
        printf (" BFAR = %x\n", bus_fault_address);

    printf ("- Misc\n");

    printf (" LR/EXC_RETURN= %x\n", lr_value);

    while(1); // endless loop

}

 

之後可先知道是哪一類型的 hard fault ,並且以PC 和 stack 的內容,來推斷問題的原因。

三、參考資料

https://zh.wikipedia.org/wiki/FreeRTOS

http://wiki.csie.ncku.edu.tw/embedded/freertos

The Definitive Guide to ARM® Cortex®-M3 and Cortex®-M4 Processors

★博文內容均由個人提供,與平台無關,如有違法或侵權,請與網站管理員聯繫。

★文明上網,請理性發言。內容一周內被舉報5次,發文人進小黑屋喔~

評論