一、說明
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 使用率,這時就需要用到官方提供的兩個函式 vTaskList 和 vTaskGetRunTimeStats。使用者就可以通過這兩個函式獲得任務的執行情況。獲取了任務執行情況後,可以通過串列埠將其打印出來,當然,也可以通過任何其它方式將其顯示出來。
具體在 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
評論