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

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

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

3天內不再提示

【freeRTOS開發筆記】xTaskCreate接口不返回

嵌入式物聯網開發 ? 來源:嵌入式物聯網開發 ? 作者:嵌入式物聯網開發 ? 2022-07-11 09:18 ? 次閱讀

1 前言

最近博主在做一些適配freeRTOS的項目,簡單來說就是從別的RTOS平臺遷移到freeRTOS平臺。 由于之前的代碼都是可用的,憑經驗我們認為只需要將OSAL的接口重新封裝一下,理論上上層的邏輯應該問題不大;但是我們沒想到的卻是在OSAL層適配的時候,遇到了一些之前沒有考慮到的問題。

2 遇到的問題

簡單描述一下,我所遇到的問題;這個問題主要的體現就是在創建任務xTaskCreate的接口調用上,freeRTOS的接口原型為:

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
                            const char * const pcName,     /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                            const configSTACK_DEPTH_TYPE usStackDepth,
                            void * const pvParameters,
                            UBaseType_t uxPriority,
                            TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION;

我在一個任務里面調用該接口去創建一個新的任務,然后我發現新建的任務跑起來了,但是我發起創建的任務卻不往下跑了。初步觀察,就是xTaskCreate接口沒有返回出來。

3 問題分析

3.1 初略分析

考慮到我的操作場景是在從別的RTOS平臺遷移代碼到freeRTOS平臺,所以第一感覺會是OSAL層封裝是不是有問題? 于是把任務創建相關的OSAL接口重新捋了一遍,包括每個參數的傳參轉換是否正確,都做了一個遍,確認封裝是沒有問題的。 之前我們做代碼調試的時候,留了一手,就是在xTaskCreate內部創建任務的時候,會把任務相關的一些信息打印出來,以便觀察。

                    /* Allocate space for the TCB. */
                    pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of TCB_t is always a pointer to the task's stack. */

                    if( pxNewTCB != NULL )
                    {
                        /* Store the stack location in the TCB. */
                        pxNewTCB->pxStack = pxStack;
                        kprintf("[THD]%s:[tcb]%x [stack]%x-%x:%d:%d\r\n", pcName, 
                        pxNewTCB, pxStack,
                        (size_t)pxStack + ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ), 
                        ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) )
                        , uxPriority);
                    }
                    else
                    {
                        /* The stack cannot be used as the TCB was not created.  Free
                         * it again. */
                        vPortFreeStack( pxStack );
                    }

所以這個調試信息,讓我發現了端倪,我在調用創建任務卡死不返回的地方,發現了如下log:

[THD]cli:[tcb]41a360 [stack]419758-41a358:3072:60

任務優先級為60?好像freeRTOS不支持這么高數值的優先級? 到這里,初步懷疑是任務優先級數值的問題導致的。

3.2 深究源碼

于是一步步去深究freerTOS的源碼,這就是開源代碼的好處啊! 捋了一下代碼調用的關鍵路徑:

xTaskCreate ->
prvInitialiseNewTask ->
prvAddNewTaskToReadyList ->

其中在prvInitialiseNewTask中有以下代碼片段:

/* This is used as an array index so must ensure it's not too large. */
    configASSERT( uxPriority < configMAX_PRIORITIES );
    if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
    {
        uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    pxNewTCB->uxPriority = uxPriority;

這段代碼主要是對任務優先級數值的檢查和處理,這里可以看到它會跟configMAX_PRIORITIES進行比較,比如我的環境下,這個值是10,它是在freeRTOSConfig.h里面定義的。 從這段代碼可以知道,應用層傳入的60優先級實際被修改成9了;在freeRTOS里面,這是最高優先級了。

/* Task */
#define configMAX_PRIORITIES                        ( 10 )

在freeRTOS里面,這個值可以定義大一些,但是需要多消耗一些RAM。

然后在prvAddNewTaskToReadyList中有以下代碼片段:

    if( xSchedulerRunning != pdFALSE )
    {
        /* If the created task is of a higher priority than the current task
         * then it should run now. */
        if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )
        {
            taskYIELD_IF_USING_PREEMPTION();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

這里尤其注意第2個if語句,如果創建的新任務優先級更高,那么就立即執行它:

#define portYIELD()                    __asm ( "SWI 0" )

#ifndef portYIELD_WITHIN_API
    #define portYIELD_WITHIN_API    portYIELD
#endif

#if ( configUSE_PREEMPTION == 0 )

/* If the cooperative scheduler is being used then a yield should not be
 * performed just because a higher priority task has been woken. */
    #define taskYIELD_IF_USING_PREEMPTION()
#else
    #define taskYIELD_IF_USING_PREEMPTION()    portYIELD_WITHIN_API()
#endif

在我的平臺,直接就跑到SWI0了,及產生一個軟中斷,隨后就立即發生任務調度了。 那么這個時候,這個低優先級的任務(調用了xTaskCreate的任務)感覺就沒法往下執行了,因為log都不打了!

3.3 代碼驗證

其實通過debug信息,我只需要在xTaskCreate的入口和出口加上調試信息就可以知道到底退沒退出,但是我無法驗證是否真的是:高優先級的任務創建低優先級的任務可以退出,而低優先級的任務創建高優先級的任務無法退出。 于是我寫了以下代碼做個簡單驗證:

#include "task.h"

TaskHandle_t calling_task;
TaskHandle_t lower_task;
TaskHandle_t higher_task;

void create_lower_task(void *data)
{
    TaskStatus_t TaskStatus;

    vTaskGetInfo( lower_task,
                   &TaskStatus,
                   0,
                   eInvalid);
    while(1) {
        task_debug("%s:%d >>> prio: %d\r\n", __func__, __LINE__, TaskStatus.uxCurrentPriority);
        vTaskDelay(1000);
    }
}

void create_higher_task(void *data)
{
    TaskStatus_t TaskStatus;

    vTaskGetInfo( higher_task,
                   &TaskStatus,
                   0,
                   eInvalid);

    while(1) {
        task_debug("%s:%d >>> prio: %d\r\n", __func__, __LINE__, TaskStatus.uxCurrentPriority);
        vTaskDelay(1000);
    }
}

void create_calling_task(void *data)
{
    int ret;
    int lower_prio = 3;
    int higher_prio = 60; //final set to prio 9
    TaskStatus_t TaskStatus;

    (void)higher_prio;

    vTaskGetInfo( lower_task,
                   &TaskStatus,
                   0,
                   eInvalid);

    task_debug("%s:%d >>> prio: %d\r\n", __func__, __LINE__, TaskStatus.uxCurrentPriority);
    ret = xTaskCreate(create_lower_task, "test-2", 256, NULL, lower_prio, 
        (TaskHandle_t * const )&lower_task);
    if (ret != pdPASS) {
        task_debug("Error: Failed to create test task: %d\r\n", ret);
    }
    task_debug("%s:%d >>>\r\n", __func__, __LINE__);
#if 1
    task_debug("%s:%d >>>\r\n", __func__, __LINE__);
    ret = xTaskCreate(create_higher_task, "test-3", 256, NULL, higher_prio, 
        (TaskHandle_t * const )&higher_task);
    if (ret != pdPASS) {
        task_debug("Error: Failed to create test task: %d\r\n", ret);
    }
    task_debug("%s:%d >>>\r\n", __func__, __LINE__);
#endif

    while(1) {
        task_debug("%s:%d >>> prio: %d\r\n", __func__, __LINE__, TaskStatus.uxCurrentPriority);
        vTaskDelay(1000);
    }
}

void freertos_task_priority_test(void)
{
    int ret;
    int cur_prio = 4;

    {
        TaskStatus_t TaskStatus;

        vTaskGetInfo( xTaskGetHandle( "extended_app" ),
                   &TaskStatus,
                   0,
                   eInvalid);
        task_debug("%s:%d >>> prio: %d\r\n", __func__, __LINE__, TaskStatus.uxCurrentPriority);
    }

    task_debug("%s:%d >>>\r\n", __func__, __LINE__);
    ret = xTaskCreate(create_calling_task, "test-1", 256, NULL, cur_prio, 
        (TaskHandle_t * const )&calling_task);
    if (ret != pdPASS) {
        cli_printf("Error: Failed to create test task: %d\r\n", ret);
    }
    task_debug("%s:%d >>>\r\n", __func__, __LINE__);
}

#endif

結果代碼一跑,卻超出了我之前的預想:

freertos_task_priority_test:793 >>> prio: 4
freertos_task_priority_test:796 >>>
[THD]test-1:[tcb]419b68 [stack]419760-419b60:1024:4
freercreate_calling_task:758tos_task_priority_test: >>> prio: 4
[THD]test802 >>>
[THD]cli:[tcb]-2:[tcb]41a1e8 [stack]4419bd8 [stack]41a258-4119de0-41a1e0:1024:3
creae58:3072:60
ate_calling_task:764 >>>
create_calling_task:766 >>>
[THD]test-3:[tcb]419c48 [stack]41ae60-41b260:1024:60
create_higher_task:739 >>> prio: 9
create_calling_task:772 >>>
create_calling_task:776 >>> prio: 4
create_lower_task:724 >>> prio: 3

create_higher_task:739 >>> prio: 9
create_calling_task:776 >>> prio: 4
create_lower_task:724 >>> prio: 3
create_higher_task:739 >>> prio: 9
create_calling_task:776 >>> prio: 4
create_lower_task:724 >>> prio: 3
create_higher_task:739 >>> prio: 9
create_calling_task:776 >>> prio: 4
create_lower_task:724 >>> prio: 3
create_higher_task:739 >>> prio: 9
create_calling_task:776 >>> prio: 4
create_lower_task:724 >>> prio: 3
create_higher_task:739 >>> prio: 9
create_calling_task:776 >>> prio: 4
create_lower_task:724 >>> prio: 3
create_higher_task:739 >>> prio: 9
create_calling_task:776 >>> prio: 4
create_lower_task:724 >>> prio: 3
create_higher_task:739 >>> prio: 9
create_calling_task:776 >>> prio: 4
create_lower_task:724 >>> prio: 3

簡單來說,就是xTaskCreate壓根就沒有卡住啊? 一個任務優先級為4的任務,分別創建任務優先級為3和9的任務,都跑的好好的,并沒有發現xTaskCreate不返回的問題! 難道是我哪里想錯了?

3.4 進一步分析

通過上面的簡單代碼已經驗證了,我之前的猜想是不對的,但是我的確看到了在我的應用代碼里面出現了xTaskCreate卡死不返回的情況,還需要再細細分析下我新創建的這個任務,多半是問題出在它身上,因為我屏蔽了創建它,問題就沒有復現了。 為了說明問題,我把這個任務的執行代碼簡略了下:

void task_main(void *data)
{
    int32_t ret;

    char *msg = NULL;

    while (!task_cancel_check()) {
        if (task_get_input(g_cli->inbuf, &g_cli->bp) != 0) {
            /* do something */
        }
    }

    task_exit();
}

看到這偽代碼,也許你發現了點問題,這個while里面看樣子都是查詢下的代碼,并且沒有延時處理,如果這個任務的優先級是最高的,那么它將一直占用CPU,別的任務壓根無法被調度到。 回想我的代碼場景,傳入了一個優先級60,被減小到configMAX_PRIORITIES-1,即優先級為9;這個在freeRTOS里面可是最高優先級的任務了,所以才出現了xTaskCreate無法退出返回;因為這個時候除這個最高優先級的任務在跑外,其他任務都可能跑不起來了。

3.5 如何優化

明白了出現問題的原因,修改一來就很簡單了,這里提供兩個思路:

1) 把這個taskmain修改成一個合適的優先級,像這個不緊急的任務,建議設置成次優先級即可,即優先級數值為1; 2)在taskmain的while循環里面,加上適當的delay,比如vTaskDelay(1),讓其在合適的時間讓出CPU。

理論上,以上兩種方案都可以解決問題,但是肯定強烈推薦方式1,因為它才是解決根源的思路。

4 經驗總結

  • freeRTOS的優先級定義與別人不一樣,不要混淆!
  • 在freeRTOS里面創建任務,注意考量下優先級的問題,不能隨意定義優先級!
  • 高優先級的任務里面創建低優先級的任務是可以的;但是反過來,低優先級任務里面創建高優先級任務,也是可以的!
  • 編寫任務的執行函數,注意不要讓它死跑,如果沒有調用阻塞式的可以引起系統掛起的接口,適當使用vTaskDelay接口讓任務讓出CPU。

5 更多分享

歡迎關注我的github倉庫01workstation,日常分享一些開發筆記和項目實戰,歡迎指正問題。

同時也非常歡迎關注我的CSDN主頁和專欄:

【CSDN主頁:架構師李肯】

RT-Thread主頁:架構師李肯】

【C/C++語言編程專欄】

【GCC專欄】

【信息安全專欄】

【RT-Thread開發筆記】

【freeRTOS開發筆記】

有問題的話,可以跟我討論,知無不答,謝謝大家。

審核編輯:湯梓紅

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

    關注

    33

    文章

    8968

    瀏覽量

    153347
  • RTOS
    +關注

    關注

    24

    文章

    845

    瀏覽量

    120862
  • FreeRTOS
    +關注

    關注

    12

    文章

    492

    瀏覽量

    63909
收藏 人收藏

    評論

    相關推薦
    熱點推薦

    freeRTOS開發筆記】關注創建任務時傳入優先級數值問題

    freeRTOS開發筆記】關注創建任務時傳入的優先級數值問題
    的頭像 發表于 07-11 09:13 ?3040次閱讀
    【<b class='flag-5'>freeRTOS</b><b class='flag-5'>開發筆記</b>】關注創建任務時傳入優先級數值問題

    freeRTOS開發筆記】記一次坑爹的freeTOS升級

    freeRTOS開發筆記】記一次坑爹的freeTOS-v9.0.0升級到freeRTOS-v10.4.4
    的頭像 發表于 07-11 09:15 ?5183次閱讀
    【<b class='flag-5'>freeRTOS</b><b class='flag-5'>開發筆記</b>】記一次坑爹的freeTOS升級

    安卓開發筆記

    安卓開發筆記(中文)
    發表于 04-26 10:57

    基于STM32的USB程序開發筆記 匯總

    忙了一下午終于有時間整理了,基于STM32的USB程序開發筆記匯總,需要的親們點擊鏈接閱讀哈!{:4_95:}基于STM32的USB程序開發筆記(一)https://bbs.elecfans.com
    發表于 03-20 16:08

    Modbus庫開發筆記之十一:關于Modbus協議棧開發的說明

    們不就使用的最終結果負責。當然如果發現任何的不足,我們非常并歡迎大家將發現的問題告知我們,以便我們持續的改進之。本系列的全部分裝如下:Modbus庫開發筆記之一:實現功能的基本設計https
    發表于 08-27 20:32

    壇友經驗分享之STM32的USB程序開發筆記

    基于STM32的USB程序開發筆記(一)基于STM32的USB程序開發筆記(二)基于STM32的USB程序開發筆記(三)基于STM32的USB程序開發筆記(四)基于STM32的USB程
    發表于 09-04 17:42

    基于STM32的USB程序開發筆記

    基于STM32的USB程序開發筆記
    發表于 04-24 09:23

    Odrive開發筆記 精選資料推薦

    Odrive開發筆記文章目錄Odrive開發筆記接線配置進入校準測試用python來控制odrive電機控制介紹位置環速度環把從一開始做odrive驅動無刷電機的所有過程都記錄下來接線1. 首先
    發表于 09-02 07:33

    求大佬分享STM32CubeMX-HAL庫開發筆記

    求大佬分享STM32CubeMX-HAL庫開發筆記
    發表于 12-02 07:26

    求大佬分享CAN開發筆記

    求大佬分享CAN開發筆記
    發表于 02-07 06:16

    基于STM32的USB程序開發筆記

    基于STM32的USB程序開發筆記STM32 USB 源代碼及筆記下載.rar
    發表于 10-09 06:05

    STM32的USB程序開發筆記

    STM32的USB程序開發筆記
    發表于 09-29 14:55 ?27次下載
    STM32的USB程序<b class='flag-5'>開發筆記</b>

    基于LM3S網絡開發筆記3_多網頁開發

    基于LM3S網絡開發筆記3_多網頁開發
    發表于 10-11 08:52 ?4次下載
    基于LM3S網絡<b class='flag-5'>開發筆記</b>3_多網頁<b class='flag-5'>開發</b>

    基于LM3S網絡開發筆記1_開發平臺

    基于LM3S網絡開發筆記1_開發平臺
    發表于 10-11 08:57 ?4次下載
    基于LM3S網絡<b class='flag-5'>開發筆記</b>1_<b class='flag-5'>開發</b>平臺

    STM32G0開發筆記FreeRTOS和FreeModbus庫使用

    使用Platformio平臺的libopencm3開發框架來開發STM32G0,以下為FreeRTOS和FreeModbus庫使用。
    的頭像 發表于 01-16 14:44 ?6841次閱讀
    STM32G0<b class='flag-5'>開發筆記</b>:<b class='flag-5'>FreeRTOS</b>和FreeModbus庫使用
    主站蜘蛛池模板: 午夜一级精品免费毛片 | 成人在线视频网 | 天天综合网天天综合色不卡 | 热re66久久精品国产99热 | 手机看高清特黄a大片 | 青娱乐久草| 久久久久久国产精品免费 | 午夜爽爽 | 四虎在线精品免费高清在线 | 国产破苞合集 magnet | 久久久久久人精品免费费看 | 日韩精品亚洲一级在线观看 | 色多多污网站在线观看 | 2018天天操夜夜操 | 视频在线观看免费视频 | 综合7799亚洲伊人爱爱网 | 亚洲444444在线观看 | 天天做天天爱天天综合网2021 | 欧美一级高清片在线 | 一级片+国产 | 天天爽夜夜爽夜夜爽精品视频 | 亚洲综合情 | 日本一区二区视频 | 五月婷婷综合激情 | 乱人伦一区二区三区 | 亚洲国产综合久久精品 | 国产精品11页| 四级毛片在线播放 | 国产香蕉98碰碰久久人人 | 你懂得国产| 黄色在线播放网址 | 日日操夜夜骑 | 5060精品国产福利午夜 | 亚洲地址一地址二地址三 | 色啦啦影院 | 国产白白白在线永久播放 | 国产人成高清视频观看 | 热久久最新视频 | 国产大片黄在线观看 | 日本在线观看www | 香蕉久久影院 |