FreeRTOS--疑難雜症

来源:http://www.cnblogs.com/LinTeX9527/archive/2017/12/13/8031565.html
-Advertisement-
Play Games

花了3個晚上,把這個章節看完,受益匪淺。 1. 最有用的應該是與中斷相關的錯誤,優先排查中斷優先順序設置。 2. 堆棧溢出檢查,可能用到,一般先把堆棧設置的足夠大,只要沒有溢出就是好事,溢出了,掌握了棧溢出鉤子函數排錯很方便。 3. 相關的問題應該儘量不會出現,畢竟只要需要列印調試信息的情況下才使用, ...


花了3個晚上,把這個章節看完,受益匪淺。

  1. 最有用的應該是與中斷相關的錯誤,優先排查中斷優先順序設置。
  2. 堆棧溢出檢查,可能用到,一般先把堆棧設置的足夠大,只要沒有溢出就是好事,溢出了,掌握了棧溢出鉤子函數排錯很方便。
  3. printf()相關的問題應該儘量不會出現,畢竟只要需要列印調試信息的情況下才使用,而且嵌入式系統一般都是用串口重定向的。
    講真,嵌入式中printf()真的挺煩的,嚴重影響性能,我的開發案例中發現,串口列印會影響板子的 power save性能,這是實測到的。

此章節涉及新手最常遇見的3種問題:

  1. 錯誤的中斷優先順序設置
  2. 棧溢出
  3. 不恰當的使用printf()

使用configASSERT()能夠顯著地提高生產效率,它能夠捕獲、識別多種類型的錯誤。強烈建議在開發或者調試中開啟巨集configASSERT()

中斷優先順序

註意:這是頭號需要技術支持的問題,在大多數的移植版本中通過定義configASSERT()就能夠立刻捕獲這個錯誤。

如果FreeRTOS移植版本支持中斷嵌套,並且中斷服務程式使用了FreeRTOS API,那麼必須把中斷優先順序設置為configMAX_SYSCALL_INTERRUPT_PRIORITY或者低一點。沒有這麼設置將會導致臨界區失效,反過來就會導致間歇性的錯誤。

當FreeRTOS運行在以下處理器上需要特別註意:

  • 中斷優先順序使用可能的最高優先順序,這就是ARM Cortex 處理器上的情形,還有一些其他的。在這些處理器上,調用FreeRTOS API 的中斷的優先順序不能留置未初始化。
  • 優先順序數值越高表示邏輯上優先順序越低,這可能與直覺相反,因此可能導致混淆。同樣這可能在某些ARM Cortex處理器上,可能還有其他的。
  • 例如,在某個處理器上一個中斷的優先順序為5,正在運行,但是能夠被一個優先順序為4的中斷打斷。因此,如果configMAX_SYSCALL_INTERRUPT_PRIORITY設置為5,那麼任何其他的使用FreeRTOS API的中斷的優先順序必須設置為5甚至更高。在這種情形下優先順序為5或者6的是有效的,但是優先順序為3的中斷是無效的。
  • 不同的庫實現期待中斷優先順序用不同的方式指定。此外尤其是針對ARM Cortex處理器相關的庫,它們的中斷優先順序在寫入硬體寄存器之前是經過位移的。某些庫可能自己進行位移操作,然而其他的庫期待中斷優先順序在傳給庫函數之前已經進行了位移操作。
  • 同樣架構上的不同的實現,實現的是中斷優先順序的比特位不同。例如同樣的Cortex-M處理器某一個廠商可能實現了3個優先順序比特位,但是另一個廠商實現了4個優先順序比特位。
  • 定義一個中斷優先順序的比特位被分成兩個部分,一部分定義搶占的級別,另外的比特位定義子優先順序。確保所有的比特位都是指定搶占的優先順序,而子優先順序不使用。

在某些移植版本中configMAX_SYSCALL_INTERRUPT_PRIORITY有一個別名configMAX_API_CALL_INTERRUPT_PRIORITY

棧溢出

棧溢出是第二個經常尋求技術支持的問題。FreeRTOS提供了幾個特性來輔助捕獲和調試和棧相關的問題。

API函數uxTaskGetStackHighWaterMark()

每個任務都在維護自己的棧,棧的總大小在創建任務的時候就指定了。函數uxTaskGetStackHighWaterMark()就是用來查詢分配給這個任務的棧接近棧溢出的程度。返回值稱為棧的高水位線

UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );

任務使用棧的多少,隨著任務的運行和中斷的處理時而增加時而減少。uxTaskGetStackHighWaterMark()返回自任務開始運行以來剩餘可用的棧空間的最小值。它返回的是棧未使用的空間占最大值的比值。高水位越接近於0,那麼這個任務的棧就越快要溢出。

運行時棧檢查

FreeRTOS提供了兩種在運行時檢查棧的機制。都是由文件FreeRTOSConfig.h中的configCHECK_FOR_STACK_OVERFLOW來在編譯時進行控制的。兩種方法都會增加上下文切換的時間。

棧溢出鉤子函數(又稱為棧溢出回調函數)是一個由內核檢查到棧溢出時調用的函數。要使用棧溢出鉤子函數要滿足以下條件:

  1. 在文件FreeRTOSConfig.h中把configCHECK_FOR_STACK_OVERFLOW設置為1或者2
  2. 實現以下鉤子函數,使用完全一樣的函數名字和原型:
void vApplicationStackOverflowHook( TaskHandle_t *pxTask, signed char *pcTaskName);

棧溢出鉤子函數會讓捕獲和調試棧錯誤更加的簡單,但是發生棧溢出錯誤時是沒有辦法恢復的。此函數把發生棧溢出的任務的句柄和名字傳遞進去。

棧溢出鉤子函數會在一個中斷的上下文中進行調用。

某些微控制器在檢測到一個錯誤的記憶體訪問時會產生一個錯誤異常,這個錯誤異常的觸發會使得內核根本就沒有機會調用棧溢出鉤子函數。

運行時棧檢查--方法1

當進行如下設置是會選擇方法1.

#define configCHECK_FOR_STACK_OVERFLOW 1

每當一個任務被切換出去時它的整個的執行上下文都會被保存到它自己的棧中。很有可能這就是棧使用率達到最大值的時候。當使用方法1是,當任務的上下文被保存之後內核回去檢查棧指針是否在棧可用空間內。如果發現棧指針已經超出了可用的範圍那麼就會調用棧溢出鉤子函數。

方法1執行速度快,但是在發生上下文切換時有可能會錯過棧溢出。

運行時棧檢查--方法2

進行如下設置後才會選擇方法2.

#define configCHECK_FOR_STACK_OVERFLOW 2

除了方法1中的行為,方法2還會執行其他的檢查。

創建任務時它的棧會被一個已知的樣本填充。任務2檢查棧空間的最後20個位元組,驗證這個已知的樣本是否已經被覆蓋。如果這20個位元組的值與預期值不一樣那麼就會調用棧溢出鉤子函數。

方法2不如方法1快,當時相對來講還是快,畢竟只是測試20個位元組。很有可能方法2會捕獲到所有的棧溢出,但是有可能(幾乎不可能)某些棧溢出還是漏掉了。

不恰當地使用printf()sprintf()

不恰當地只用printf()是一種常見的錯誤源,並且沒有意識到這種錯誤,通常應用開發者會增加更多的printf()來輔助調試,結果就是加重了問題。

許多交叉編譯器廠商會提供一種適合在小型嵌入式系統中使用的printf()的實現。即便在這種情形下,printf()的實現可能並不是線程安全的,幾乎可以肯定不適合在中斷服務程式中使用,並且取決於輸出被重定向到哪裡,會占用相當長的一段執行時間。。

如果小型嵌入式系統的printf()的實現不可用,並且使用了通用的printf()的實現,那麼就需要特別註意了:

  • 僅僅增加了一個對printf()或者sprintf()的調用就會急劇的增加應用執行文件的體積;
  • 如果使用了heap_3以外的存儲空間方案,printf()sprintf()調用了malloc(),這個是無效的。
  • printf()sprintf()可能會申請一個幾倍於通常情況的棧空間。

Printf-stdarg.c

許多的FreeRTOS示例工程了使用了一個printf-stdarg.c的文件,它提供了一個極小的、棧使用率非常高效的能夠取代標準庫函數版本的sprintf()實現。在大多數情形下,使得任務每次調用sprintf()或者相關的函數卻分配更少的棧空間。

printf-stdarg.c提供了一種機制把printf()輸出重定向,一個位元組一個位元組的輸出,雖然慢,但是卻極大地減少了棧空間的占用。

註意:並不是所有的FreeRTOS下載副本中文件printf-stdarg.c都實現了snprintf()函數。沒有實現snprintf()的副本直接忽略緩衝區大小參數,它們是直接映射到sprintf()函數。

printf-stdarg.c是開源的,但是是第三方擁有的,因此它的授權和FreeRTOS是分開的。它的授權條款在文件的首部。

其他的常見錯誤

癥狀:添加一個簡單任務到常式中卻導致了常式掛掉

創建任務需要從堆中分配記憶體。許多示例工程的棧空間僅僅能夠容納常式任務,因此在創建了常式任務後,沒有足夠的堆空間留給其他更多的任務,隊列,事件組,信號量。

空閑任務,又或許是FreeRTOS的守護進程,在調用vTaskStartScheduler()時是自動創建的。只有當堆空間不足以創建這些任務時vTaskStartScheduler()才會返回。在調用vTaskStartScheduler()之後添加一個for(;;);會讓這個問題更容易排錯。

要想添加更多的任務,要麼擴大堆空間,要麼減少已經存在的例子任務。

癥狀:中斷中使用API導致應用掛掉

在中斷服務程式中不要使用API,除非API名字是以FromISR()結尾。特別地,在中斷中不要創建一個臨界區,除非使用中斷安全的巨集。

在支持中斷嵌套的FreeRTOS移植版本中,如果中斷優先順序高於configMAX_SYSCALL_INTERRUPT_PRIORITY就不要在其中使用 API 函數。

癥狀:有時應用程式在中斷服務函數中掛掉

首先要檢查中斷是否產生了棧溢出。有的移植版本中只檢查任務的棧溢出,並沒有檢查中斷是否棧溢出。

中斷的定義和使用方式隨著移植版本和編譯器的不同而不同。因此,其次要檢查語法,巨集定義,調用規則在中斷服務程式中的使用是否與移植文檔中的完全一致,是否與常式中的完全一致。

如果應用運行在數值越低的優先順序表示邏輯上越高的優先順序的處理器上,那麼需要確保分配給中斷的優先順序要考慮到這種情況,因為它看起來是違反直覺的。

如果應用運行在把中斷優先順序預設設置為最大可能的優先順序的處理器上,需要確保每個中斷的優先順序沒有留置為預設值。

癥狀:調度器嘗試啟動第一個任務時掛掉

確保設置了FreeRTOS的中斷句柄。參考FreeRTOS移植文檔,還有示常式序。

某些處理器必須在調度器啟動之前處於特權模式。最簡單的實現方法是在C語言main()之前的啟動代碼中就把處理器置於特權模式。

癥狀: 中斷被異常地禁止了,又或者臨界區沒有正確地嵌套

如果在調度器啟動之前就調用了FreeRTOS API函數那麼中斷就會被蓄意地禁止,直到第一個任務啟動之後才會重新使能。這樣做是為了保護系統不掛掉,原因在於初始化過程中中斷嘗試調用FreeRTOS API函數,然而調度器還沒有啟動,它可能處於一個不一致的狀態。

除了調用taskENTER_CRITICAL()taskEXIT_CRITICAL()函數之外不要使用任何其它的方法來更改微處理器的中斷使能位和優先順序標誌。這兩個巨集會統計中斷嵌套深度確保當中斷嵌套深度為0時中斷又使能。需要知悉某些庫函數可能在內部使能和禁止中斷。

癥狀:遠在調度器啟動之前應用就掛掉了

有可能發生上下文切換的中斷是禁止在調度器啟動之前就開始執行的。同樣的規則適用於嘗試發送或者接收FreeRTOS對象(例如隊列和信號量)的任何中斷服務程式。上下文切換必須在調度器啟動之後才能發生。

很多API函數必須在調度器啟動之後才能調用。最好是在調用vTaskStartScheduler()之後將API的使用限制在創建諸如任務,隊列和信號量上,而不是使用這些對象。

癥狀: 在調度器掛起時又或者是臨界區內部調用API函數會導致應用程式掛掉

調用函數vTaskSuspendAll()會掛起調度器,調用函數xTaskResumeAll()會恢復調度器。

調用函數taskENTER_CRITICAL()會進入臨界區,調用函數taskEXIT_CRITICAL()會退出臨界區。

在調度器掛起時或者臨界區內永遠不要調用API函數。

聲明

歡迎轉載,請註明出處和作者,同時保留聲明。
作者:LinTeX9527
出處:http://www.cnblogs.com/LinTeX9527/p/8031565.html
本博客的文章如無特殊說明,均為原創,轉載請註明出處。如未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 演示產品源碼下載地址:http://www.jinhusns.com ...
  • 來源:http://blog.csdn.net/xinglun88/article/details/19987719 第一步:下載並安裝PDMReader,資源網站: http://www.pdmreader.com/ 第二步:打開PDMReader,新建項目:test; 第三步:在項目test點擊 ...
  • 本節將分析 代碼,確定是如何一步一步到我們註冊的中間件,並介紹幾種Configure的方式。 源代碼參考.NET Core 2.0.0 "WebHost" "Kestrel" "HttpAbstractions" 目錄 Server.StartAsync Server IHttpApplicatio ...
  • linux第三天學習1.putty介紹和使用2.硬連接和符號連接3.sudo的使用4.job的使用5.磁碟分區使用6.主機名查看和修改7.配置主機名和IP地址的映射8.關機重啟命令9.命令嵌套10.創建用戶11.Linux環境變數相關問題許可權 r //100 = 4 //文件:讀取內容 //文件夾: ...
  • PHPWord是用純PHP提供了一組類寫入和從不同的文檔格式的文件閱讀庫。PHPWord的當前版本支持微軟的Office Open XML(OOXML或處理OpenXML),用於Office應用程式OASIS開放文檔格式(OpenDocument格式或ODF)和富文本格式(RTF)。 ...
  • 1 .首先登錄搜狗輸入法Linux官網https://pinyin.sogou.com/linux/?r=pinyin,下載64bit輸入法安裝包。2.打開終端,輸入命令先安裝一個叫Gdebi輔助工具,命令如下:正常情況下終端會提醒你按(Y/N)來決定是否真的安裝,我們輸入“Y”,然後按回車鍵繼續。 ...
  • //先要理解這四個概念,這是一個提交代碼的流動軌跡:1.工作區(編輯器)-經過add到2- 2.暫存區 (緩存)- 經過commit3-3.本地倉庫 (本地項目)-經過 push4-4.遠程倉庫 (線上項目 ) //拉取遠程(這裡預設擁有項目許可權)$ git clone <項目地址> //拉取遠程分 ...
  • 一、解壓文件到當前目錄 命令:tar -zxvf mysql....tar.gz 二、移動解壓完成的文件夾到目標目錄並更名mysql 命令:mv mysql-版本號 /usr/local/mysql 添加系統mysql組和mysql用戶 添加系統mysql組 sudo groupadd mysql ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...