在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

FreeRTOS優化與錯誤排查方法有哪些

汽車電子技術 ? 來源:物聯網IoT開發 ? 作者:杰杰 ? 2023-02-14 09:59 ? 次閱讀

寫在前面

主要是為剛接觸 FreeRTOS 的用戶指出那些新手通常容易遇到的問題。這里把最主要的篇幅放在棧溢出以及棧溢出檢測上,因為棧相關的問題是初學者遇到最多的問題。

printf-stdarg.c

當調用 C 標準庫 的函數時,棧空間使用量可能會急劇上升,特別是 IO 與字符串處理函數,比如 sprintf()、printf()等。在 FreeRTOS 源碼包中有一個名為 printf-stdarg.c 的文件。這個文件實現了一個棧效率優化版的小型 sprintf()、printf(),可以用來代替標準 C 庫函數版本。在大多數情況下,這樣做可以使得調用 sprintf()及相關函數的任務對棧空間的需求量小很多。

可能很多人都不知道freertos中有這樣子的一個文件,它放在第三方資料中,路徑為“ FreeRTOSv9.0.0\\FreeRTOS-Plus\\Demo\\FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC ”,我們發布工程的時候就無需依賴 C 標準庫 ,這樣子就能減少棧的使用,能優化不少空間。

該文件源碼(部分):

1static int print( char **out, const char *format, va_list args )
 2{
 3    register int width, pad;
 4    register int pc = 0;
 5    char scr[2];
 6
 7    for (; *format != 0; ++format) {
 8        if (*format == '%') {
 9            ++format;
10            width = pad = 0;
11            if (*format == '\\0') break;
12            if (*format == '%') goto out;
13            if (*format == '-') {
14                ++format;
15                pad = PAD_RIGHT;
16            }
17            while (*format == '0') {
18                ++format;
19                pad |= PAD_ZERO;
20            }
21            for ( ; *format >= '0' && *format <= '9'; ++format) {
22                width *= 10;
23                width += *format - '0';
24            }
25            if( *format == 's' ) {
26                register char *s = (char *)va_arg( args, int );
27                pc += prints (out, s?s:"(null)", width, pad);
28                continue;
29            }
30            if( *format == 'd' || *format == 'i' ) {
31                pc += printi (out, va_arg( args, int ), 10, 1, width, pad, 'a');
32                continue;
33            }
34            if( *format == 'x' ) {
35                pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'a');
36                continue;
37            }
38            if( *format == 'X' ) {
39                pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'A');
40                continue;
41            }
42            if( *format == 'u' ) {
43                pc += printi (out, va_arg( args, int ), 10, 0, width, pad, 'a');
44                continue;
45            }
46            if( *format == 'c' ) {
47                /* char are converted to int then pushed on the stack */
48                scr[0] = (char)va_arg( args, int );
49                scr[1] = '\\0';
50                pc += prints (out, scr, width, pad);
51                continue;
52            }
53        }
54        else {
55        out:
56            printchar (out, *format);
57            ++pc;
58        }
59    }
60    if (out) **out = '\\0';
61    va_end( args );
62    return pc;
63}
64
65int printf(const char *format, ...)
66{
67    va_list args;
68
69    va_start( args, format );
70    return print( 0, format, args );
71}
72
73int sprintf(char *out, const char *format, ...)
74{
75    va_list args;
76
77    va_start( args, format );
78    return print( &out, format, args );
79}
80
81
82int snprintf( char *buf, unsigned int count, const char *format, ... )
83{
84    va_list args;
85
86    ( void ) count;
87
88    va_start( args, format );
89    return print( &buf, format, args );
90}

使用的例子與 C 標準庫基本一樣:

1int main(void)
 2{
 3    char *ptr = "Hello world!";
 4    char *np = 0;
 5    int i = 5;
 6    unsigned int bs = sizeof(int)*8;
 7    int mi;
 8    char buf[80];
 9
10    mi = (1 << (bs-1)) + 1;
11    printf("%s\\n", ptr);
12    printf("printf test\\n");
13    printf("%s is null pointer\\n", np);
14    printf("%d = 5\\n", i);
15    printf("%d = - max int\\n", mi);
16    printf("char %c = 'a'\\n", 'a');
17    printf("hex %x = ff\\n", 0xff);
18    printf("hex %02x = 00\\n", 0);
19    printf("signed %d = unsigned %u = hex %x\\n", -3, -3, -3);
20    printf("%d %s(s)%", 0, "message");
21    printf("\\n");
22    printf("%d %s(s) with %%\\n", 0, "message");
23    sprintf(buf, "justif: \\"%-10s\"\\n", "left"); printf("%s", buf);
24    sprintf(buf, "justif: \"%10s\"\\n", "right"); printf("%s", buf);
25    sprintf(buf, " 3: %04d zero padded\\n", 3); printf("%s", buf);
26    sprintf(buf, " 3: %-4d left justif.\\n", 3); printf("%s", buf);
27    sprintf(buf, " 3: %4d right justif.\\n", 3); printf("%s", buf);
28    sprintf(buf, "-3: %04d zero padded\\n", -3); printf("%s", buf);
29    sprintf(buf, "-3: %-4d left justif.\\n", -3); printf("%s", buf);
30    sprintf(buf, "-3: %4d right justif.\\n", -3); printf("%s", buf);
31
32    return 0;
33}

棧計算

每個任務都獨立維護自己的棧空間, 任務棧空間總量在任務創建時進行設定。uxTaskGetStackHighWaterMark()主要用來查詢指定任務的運行歷史中, 其棧空間還差多少就要溢出。這個值被稱為棧空間的 High Water Mark

函數原型:

1UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask )

想要使用它,需要將對應的宏定義打開:INCLUDE_uxTaskGetStackHighWaterMark

函數描述:

參數 說明
xTask 被查詢任務的句柄如果傳入 NULL 句柄,則任務查詢的是自身棧空間的高水線
返回值 任務棧空間的實際使用量會隨著任務執行和中斷處理過程上下浮動。uxTaskGetStackHighWaterMark()返回從任務啟動執行開始的運行歷史中,棧空間具有的最小剩余量。這個值即是棧空間使用達到最深時的剩下的未使用的棧空間。這個值越是接近 0,則這個任務就越是離棧溢出不遠。

如果不知道怎么計算任務棧大小,就使用這個函數進行統計一下,然后將任務運行時最大的棧空間作為任務棧空間的80%大小即可。即假設統計得到的任務棧大小為常量 A ,那么在創建線程的時候需要 X 大小的空間,那么 X * 80% = A ,算到的 X 作為任務棧大小就差不多了。

運行時棧檢測

FreeRTOS 包含兩種運行時棧檢測機制,由 FreeRTOSConfig.h 中的配置常量configCHECK_FOR_STACK_OVERFLOW 進行控制。這兩種方式都會增加上下切換開銷。

棧溢出鉤子函數(或稱回調函數)由內核在檢測到棧溢出時調用。要使用棧溢出鉤子函數,需要進行以下配置:

  • 在 FreeRTOSConfig.h 中把 configCHECK_FOR_STACK_OVERFLOW 設為 1 或者 2
  • 提供鉤子函數的具體實現,采用下面所示的函數名和函數原型。
1void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed portCHAR *pcTaskName );

補充說明:

  • 棧溢出鉤子函數只是為了使跟蹤調試棧空間錯誤更容易,而無法在棧溢出時對其進行恢復。函數的入口參數傳入了任務句柄和任務名,但任務名很可能在溢出時已經遭到破壞。
  • 棧溢出鉤子函數還可以在中斷的上下文中進行調用
  • 某些微控制器在檢測到內存訪問錯誤時會產生錯誤異常,很可能在內核調用棧溢出鉤子函數之前就觸發了錯誤異常中斷。

方法1

configCHECK_FOR_STACK_OVERFLOW 設置為 1 時選用方法 1

任務被交換出去的時候,該任務的整個上下文被保存到它自己的棧空間中。這時任務棧的使用應當達到了一個峰值。當 configCHECK_FOR_STACK_OVERFLOW 設為1 時,內核會在任務上下文保存后檢查棧指針是否還指向有效棧空間。一旦檢測到棧指針的指向已經超出任務棧的有效范圍,棧溢出鉤子函數就會被調用。

方法 1 具有較快的執行速度,但棧溢出有可能發生在兩次上下文保存之間,這種情況不會被檢測到,因為這種檢測方式僅在任務切換中檢測。

方法2

configCHECK_FOR_STACK_OVERFLOW 設為 2 就可以選用方法 2 。方法 2在方法 1 的基礎上進行了一些補充。

當創建任務時,任務棧空間中就預置了一個標記。方法 2 會檢查任務棧的最后 20個字節的數據,查看預置在這里的標記數據是否被覆蓋。如果最后 20 個字節的標記數據與預設值不同,則棧溢出鉤子函數就會被調用。

方法 2 沒有方法 1 的執行速度快,但測試僅僅 20 個字節相對來說也是很快的。這種方法應該可以檢測到任何時候發生的棧溢出,雖然理論上還是有可能漏掉一些情況,但這些情況幾乎是不可能發生的。

其它常見錯誤

在一個 Demo 應用程序中增加了一個簡單的任務,導致應用程序崩潰

可能的情況:

  1. 任務創建時需要在內存堆中分配空間。許多 Demo 應用程序定義的堆空間大小只夠用于創建 Demo 任務——所以當任務創建完成后,就沒有足夠的剩余空間來增加其它的 任務,隊列或信號

  2. 空閑任務是在 vTaskStartScheduler()調用中自動創建的。如果由于內存不足而無法創建空閑任務,vTaskStartScheduler()會直接返回。所以一般在調用 vTaskStartScheduler()后加上一條空循環for(;;) / while(1)可以使這種錯誤更加容易調試。

    如果要添加更多的任務,可以增加內存堆空間大小(修改配置文件),或是刪掉一些已存在的 Demo任務。

在中斷中調用一個 API 函數,導致應用程序崩潰

需要做的第一件事是檢查中斷是否導致了棧溢出。

然后檢查API接口是否正確 ,除了具有后綴為FromISR函數名的 API 函數,千萬不要在中斷服務程序中調用其它 API 函數。

除此之外,還需要注意中斷的優先級:

FreeRTOSConfig.h文件中可以配置系統可管理的最高中斷優先級數值,宏定義configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY是用于配置basepri寄存器的,當basepri設置為某個值的時候,會讓系統不響應比該優先級低的中斷,而優先級比之更高的中斷則不受影響。就是說當這個宏定義配置為5的時候,中斷優先級數值在0、1、2、3、4的這些中斷是不受FreeRTOS管理的,不可被屏蔽, 同時也不能調用FreeRTOS中的API函數接口 ,而中斷優先級在5到15的這些中斷是受到系統管理,可以被屏蔽的,也可以調用FreeRTOS中的API函數接口。

臨界區無法正確嵌套

除了 taskENTER_CRITICA()和 taskEXIT_CRITICAL(),千萬不要在其它地方修改控制器的中斷使能位或優先級標志。這兩個宏維護了一個嵌套深度計數,所以只有當所有的嵌套調用都退出后計數值才會為 0,也才會使能中斷。

在調度器啟動前應用程序就崩潰了

這個問題我也會遇到,如果一個中斷會產生上下文切換,則這個中斷不能在調度器啟動之前使能。這同樣適用于那些需要讀寫隊列或信號量的中斷。在調度器啟動之前,不能進行上下文切換。

還有一些 API 函數不能在調度器啟動之前調用。在調用 vTaskStartScheduler()之前,最好是限定只使用創建任務,隊列和信號量的 API 函數。

比如有一些初始化需要中斷的,或者在初始化完成的時候回產生一個中斷,這些驅動的初始化最好放在一個任務中進行,我是這樣子處理的,在main函數中創建一個任務,在任務中進行bsp初始化,然后再創建消息隊列、信號量、互斥量、事件以及任務等操作。

在調度器掛起時調用 API 函數,導致應用程序崩潰

調用 vTaskSuspendAll()使得調度器掛起,而喚醒調度器調用 xTaskResumeAll()。千萬不要在調度器掛起時調用其它 API 函數。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 函數
    +關注

    關注

    3

    文章

    4332

    瀏覽量

    62643
  • FreeRTOS
    +關注

    關注

    12

    文章

    484

    瀏覽量

    62193
  • 棧空間
    +關注

    關注

    0

    文章

    5

    瀏覽量

    5456
收藏 人收藏

    評論

    相關推薦

    使用匯編知識排查疑難問題的方法

    那么,本篇文章,我將再介紹一個使用匯編知識排查疑難問題的方法,希望對大家有所幫助。
    發表于 07-27 10:31 ?677次閱讀

    利用符號模擬技術優化錯誤診斷方法

    優化基于區域模型錯誤診斷過程的方法。該方法首先使用基于區域模型錯誤診斷方法中電路劃分
    發表于 07-05 08:05

    電子書:STM32-FREERTOS快速學習知識解密

    ——應用場景3STM32單片機中,FreeRTOS RAM使用情況及優化方法4FreeRTOS中列表和列表項插入函數分析5FreeRTOS+
    發表于 05-09 14:30

    STM32 FreeRTOS RAM 使用情況及優化方法實用資料分享~

    的一般方法,并給出在 FreeRTOS優化 RAM 使用的方法,也由衷的期望讀者在使用其他 RTOS 時,可以通過相似的思路來解決問題。Free
    發表于 01-26 14:10

    什么方法可以查看FreeRTOS任務的運行狀態呢

    什么方法可以查看FreeRTOS任務的運行狀態呢?怎樣去查看FreeRTOS任務的運行狀態呢?
    發表于 11-02 07:59

    CH579無規律進入hardfault錯誤如何排查

    CH579 程序運行時,偶爾進入 hardfault 錯誤 ,沒有什么規律,如何排查?謝謝
    發表于 07-26 07:24

    GPIO無法觸發中斷常規排查方法哪些?

    1、電源域是否打開 2、IOMUX是否設置對 3、是否配置了中斷方式,外部電平是否滿足條件 4、是否為輸入狀態 備注:這次分享的是,我們做展銳平臺GPIO排查方法,不同平臺、不同版本、不同項目都會
    發表于 11-24 16:11

    建立一個方法和套路來對 Load 高問題排查

    講解 Linux Load 高如何排查的話題屬于老生常談了,但多數文章只是聚焦了幾個點,缺少整體排查思路的介紹。所謂 “授人以魚不如授人以漁"。本文試圖建立一個方法和套路,來幫助讀者對 Load 高問題
    的頭像 發表于 12-28 14:18 ?5479次閱讀
    建立一個<b class='flag-5'>方法</b>和套路來對 Load 高問題<b class='flag-5'>排查</b>

    FreeRTOS中的API函數功能分析及調用方法

    FreeRTOS中的API函數功能分析及調用方法說明。
    發表于 03-26 11:50 ?33次下載

    單片機硬錯誤排查方法

    HardFault 錯誤調試定位方法1、首先更改 startup.s 的啟動文件,把里面的 HardFault_Handler 代碼段換成下面的代碼:HardFault_Handler
    發表于 12-16 16:54 ?0次下載
    單片機硬<b class='flag-5'>錯誤</b><b class='flag-5'>排查</b><b class='flag-5'>方法</b>

    科普系列:CAN總線錯誤幀及排查方法簡介

    作者|蒹葭小編|吃不飽CAN幀多種格式,錯誤幀作為CAN幀中獨特的一種,了解其作用,類型與產生原因,對于進行測試以及開發有很大的幫助,本文將對錯誤幀的相關基礎知識以及后續的分析排查
    的頭像 發表于 02-23 15:11 ?3157次閱讀
    科普系列:CAN總線<b class='flag-5'>錯誤</b>幀及<b class='flag-5'>排查</b><b class='flag-5'>方法</b>簡介

    雅馬哈YS/YSM系列貼片機故障排查方法

    雅馬哈YS/YSM系列貼片機故障排查方法
    的頭像 發表于 09-13 10:05 ?3528次閱讀
    雅馬哈YS/YSM系列貼片機故障<b class='flag-5'>排查</b><b class='flag-5'>方法</b>

    常見的電源適配器故障及排查方法哪些?

    常見的電源適配器故障及排查方法哪些? 電源適配器故障是使用電子設備時經常遇到的問題之一。合理排查和解決電源適配器故障是確保電子設備正常運行的重要步驟。本文將詳細介紹常見的電源適配器故
    的頭像 發表于 11-24 14:08 ?7786次閱讀

    腳本錯誤scripterror怎么解決

    分析和排查。以下是一些常見的解決腳本錯誤方法: 檢查語法錯誤: 仔細檢查腳本中的代碼,看是否拼寫錯誤
    的頭像 發表于 11-26 14:46 ?8640次閱讀

    如何用示波器排查CAN的各種錯誤幀呢?

    如何用示波器排查CAN的各種錯誤幀呢? 導言: 控制器局域網絡(Controller Area Network,CAN)是一種常用的現場總線通信協議,廣泛應用于汽車電子系統、工業自動化等領域。然而
    的頭像 發表于 12-07 11:09 ?1212次閱讀
    主站蜘蛛池模板: baoyu777永久免费视频| 手机看片日韩永久福利盒子| 国产二三区| 成人在线色视频| 亚欧美色| 最近最新视频中文字幕4| 欧美乱乱| 女人精69xxxxxx| 中文在线 | 中文| 久久在线播放| 性色成人网| 日韩午夜在线视频不卡片| 欧美人与动欧交视频| 久久大伊人| 男人透女人超爽视频免费| 天堂网2021天堂手机版丶| 男女交性视频免费播放| 中国业余老太性视频| 亚洲激情五月| 三级电影在线观看视频| 久久国产精品久久久久久久久久| www.色噜噜| 免费在线黄色网址| 欧美ol丝袜高跟秘书在线观看| 日本一级成人毛片免费观看| 一级毛片子| 青草青青产国视频在线| 四虎国产精品永久在线播放| 欧美高清在线播放| 成 人 色综合| 男人天堂资源站| toyota东热综合网| 一级@片| 日本成人免费观看| 2021av网站| 四虎国产一区二区三区| 久色99| 天天碰视频| 午夜影院7cdy| 在线免费视频你懂的| 欧美一级视频高清片|