精华内容
下载资源
问答
  • FreeRTOS 创建任务失败原因

    千次阅读 2019-10-21 09:35:40
    我在移植开源库时里面的是 Heap_3 但是 我使用了 Heap_4的配置导致申请 任务堆栈空间失败创建 任务原因 /*Allocate space for the stack used by the task being created. */ pxStack = ( StackType_t * ) ...

    (我的环境是:
    我在移植开源库时里面的是 Heap_3 但是 我使用了 Heap_4的配置导致申请 任务堆栈空间失败

    创建 任务原因

    /*Allocate space for the stack used by the task being created. */
    pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
    

    在为任务堆栈分配空间时返回值为 0

    也就是分配的堆栈空间失败

    导致分配的原因呢
    那么就是 Heap管理机制 与设置的参数不一致,也就是FreeRTOSConfig.h 函数里面的相关配置

    (以下介绍来自https://blog.csdn.net/weixin_42385536/article/details/80639712)

    freeRTOS没有强制提供Heap管理机制,只是给出了几类推荐方案,用于支持RTOS所需存储空间的分配回收管理。

    Heap_1:使用栈管理heap,分配的存储空间在回收时,必须保证在其之后分配的存储空间都已经回收后才能进行,可使用该类分配方式,不建议进行存储空间的回收。

    Heap_2:使用链表管理heap,可能产生碎片,不建议使用

    Heap_3:使用标准C提供的malloc和free管理heap,

    Heap_4:使用链表管理heap,并且使用首次适配算法整理碎片,推荐使用

    Heap_5:与Heap_4基本一致,但是支持heap为多段不连续存储空间的集合

    展开全文
  • S32DS自带了Freertos的分析调试工具,打开后可以显示任务的状态,heap的使用大小。 然后结合debug与assert()发现了是其他两个任务并没有创建。 void my_assert(uint8_t condition,char* file_name,uint32_t line_no)...

    问题

    使用NXP的S32芯片开发,环境是S32DS 2018,创建了三个任务,最后发现只有一个任务在运行。

    找问题

    S32DS自带了Freertos的分析调试工具,打开后可以显示任务的状态,heap的使用大小。分析工具
    然后结合debug与assert()发现了是其他两个任务并没有创建。

    void my_assert(uint8_t condition,char* file_name,uint32_t line_no)
    {
      
      if(!condition)
      {
        printf( "\n[Debug]Assert failed: %s, line %u\n",file_name,line_no);
        abort();
      }
    }
    
    

    解决

    任务不能正常创建一般是heap分配不够的原因,于是去修改configTOTAL_HEAP_SIZE这个宏

    #define configTOTAL_HEAP_SIZE                    ( ( size_t ) 20480 )
    

    最后我给的20K,够用了,成功创建三个任务,heap使用率为55%。

    展开全文
  • FreeRTOS任务创建

    千次阅读 2017-09-10 18:43:17
    FreeRTOS 任务创建

    本文是《ALIENTEK STM32F429 FreeRTOS 开发教程》第八章学习笔记-1
    第一章笔记–FreeRTOS简介与源码下载
    第二章笔记–FreeRTOS在STM32F4上移植
    第三章笔记-FreeRTOS系统配置
    第四章笔记-FreeRTOS中断分析
    第四章笔记补充-FreeRTOS临界段代码
    第五章笔记-FreeRTOS任务基础
    第六章笔记-FreeRTOS任务API函数的使用
    第七章笔记-FreeRTOS列表和列表项

    任务创建

    1. 任务创建函数

    FreeRTOS使用函数xTaskCreate()和xTaskCreateStatic()分别动态和静态创建任务

    xTaskCreate()的源代码在tasks.c中:

    #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
        BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
                    const char * const pcName,
                    const uint16_t usStackDepth,
                    void * const pvParameters,
                    UBaseType_t uxPriority,
                    TaskHandle_t * const pxCreatedTask )
        {
            TCB_t *pxNewTCB;
            BaseType_t xReturn;
            #if( portSTACK_GROWTH > 0 )
            {
                pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
                if( pxNewTCB != NULL )
                {
                    pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); 
                    if( pxNewTCB->pxStack == NULL )
                    {
                        vPortFree( pxNewTCB );
                        pxNewTCB = NULL;
    
                    }
                        }
            }
            #else /* portSTACK_GROWTH */
            {
                StackType_t *pxStack;
                pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );
                if( pxStack != NULL )
                {
                    pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
                    if( pxNewTCB != NULL )
                    {
                        pxNewTCB->pxStack = pxStack;
                    }
                    else
                    {
                        vPortFree( pxStack );
                    }
                }
                else
                {
                    pxNewTCB = NULL;
                }
            }
            #endif /* portSTACK_GROWTH */
    
            if( pxNewTCB != NULL )
            {
                #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
                {
                    pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
                }
                #endif /* configSUPPORT_STATIC_ALLOCATION */
                prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
                prvAddNewTaskToReadyList( pxNewTCB );
                xReturn = pdPASS;
            }
            else
            {
                xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
            }
            return xReturn;
        }
    
    #endif /* configSUPPORT_DYNAMIC_ALLOCATION */

    if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ):可以看出使用此函数进行任务创建时必须将支持动态内存宏定为1

    if( portSTACK_GROWTH > 0 ):如果宏定义堆栈向上增长则执行接下来的代码,portSTACK_GROWTH在portmacro.h里有宏定义

    pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
    if( pxNewTCB != NULL )
                {
                    pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); 
                    if( pxNewTCB->pxStack == NULL )
                    {
                        vPortFree( pxNewTCB );
                        pxNewTCB = NULL;
    
                    }
                        }

    先使用函数pvPortMalloc()给任务控制块申请内存,如果成功的话,再给人物的任务堆栈申请内存,如果申请失败释放任务控制块内存

    #else /* portSTACK_GROWTH */
            {
                StackType_t *pxStack;
                pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );
                if( pxStack != NULL )
                {
                    pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
                    if( pxNewTCB != NULL )
                    {
                        pxNewTCB->pxStack = pxStack;
                    }
                    else
                    {
                        vPortFree( pxStack );
                    }
                }
                else
                {
                    pxNewTCB = NULL;
                }
            }
    #endif /* portSTACK_GROWTH */

    这段代码表示若向下增长堆栈时,先申请任务堆栈内存,再申请任务控制块内存

    pxNewTCB->ucStaticallyAllocated=tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB:标记任务堆栈和任务控制块是使用动态内存分配方法得到的

    prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL ):使用函数prvInitialiseNewTask()初始化任务,完成对任务控制块中各个字段的初始化工作

    prvAddNewTaskToReadyList( pxNewTCB ):将新创建的任务加入到就绪表中

    2. 任务初始化函数

    static void prvInitialiseNewTask(   
                        TaskFunction_t pxTaskCode,
                        const char * const pcName,
                        const uint32_t ulStackDepth,
                        void * const pvParameters,
                        UBaseType_t uxPriority,
                        TaskHandle_t * const pxCreatedTask,
                        TCB_t *pxNewTCB,
                        const MemoryRegion_t * const xRegions )

    任务初始化代码较多,只列出了函数定义,之后重点分析当中代码,源代码在tasks.c中

    参数:pxTaskCode:任务函数;pcName:任务名称;ulStackDepth:任务堆栈大小,从任务创建函数中强制转化成uint32_t格式传入任务初始化函数;pvParameters:传递给任务函数的参数,一直是NULL没看出作用;uxPriority:任务优先级;pxCreatedTask:任务句柄;pxNewTCB:任务控制块;xRegions:使用xTaskCreateRestricted()函数建立微处理器保护任务时传递的内存地址参数,普通人物建立时此参数为NULL

    #if( portUSING_MPU_WRAPPERS == 1 )
            /* Should the task be created in privileged mode? */
            BaseType_t xRunPrivileged;
            if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
            {
                xRunPrivileged = pdTRUE;
            }
            else
            {
                xRunPrivileged = pdFALSE;
            }
            uxPriority &= ~portPRIVILEGE_BIT;
        #endif /* portUSING_MPU_WRAPPERS == 1 */

    如果宏定义portUSING_MPU_WRAPPERS为1,判断该任务是否在特权模式下创建,给xRunPrivileged赋值,并赋值优先级大小,由于我们将portUSING_MPU_WRAPPERS宏定义为0,所以不编译这段代码

        #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
        {
            /* Fill the stack with a known value to assist debugging. */
            ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
        }
    #endif

    如果使能了堆栈溢出检测功能或者追踪可视化就使用一个定值tskSTACK_FILL_BYTE来填充任务堆栈,值为0xa5U

        #if( portSTACK_GROWTH < 0 )
        {
            pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
            pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); /*lint !e923 MISRA exception.  Avoiding casts between pointers and integers is not practical.  Size differences accounted for using portPOINTER_SIZE_TYPE type. */
    
            /* Check the alignment of the calculated top of stack is correct. */
            configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
        }
        #else /* portSTACK_GROWTH */
        {
            pxTopOfStack = pxNewTCB->pxStack;
    
            /* Check the alignment of the stack buffer is correct. */
            configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
    
            /* The other extreme of the stack space is required if stack checking is
            performed. */
            pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
        }
        #endif /* portSTACK_GROWTH */

    使用条件编译,在向上堆栈和向下堆栈不同时计算堆栈栈顶pxTopOfStack

        for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
        {
            pxNewTCB->pcTaskName[ x ] = pcName[ x ];
    
            /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
            configMAX_TASK_NAME_LEN characters just in case the memory after the
            string is not accessible (extremely unlikely). */
            if( pcName[ x ] == 0x00 )
            {
                break;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }

    保存任务的任务名

    pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = ‘\0’:在任务名数组添加字符串结束符’\0’

        if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
        {
            uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

    判断任务优先级是否大于预先定义的最大优先级configMAX_PRIORITIES宏,若大于则将任务优先级设置为configMAX_PRIORITIES-1

    pxNewTCB->uxPriority = uxPriority:将得到的uxPriority值赋给任务控制块的优先级(即初始化任务控制块的优先级)

        #if ( configUSE_MUTEXES == 1 )
        {
            pxNewTCB->uxBasePriority = uxPriority;
            pxNewTCB->uxMutexesHeld = 0;
        }
        #endif /* configUSE_MUTEXES */

    如果宏定义configUSE_MUTEXES为1,即使用了互斥信号量,这里初始化相应变量

    vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
    vListInitialiseItem( &( pxNewTCB->xEventListItem ) );

    这里初始化列表项xStateListItem和xEventListItem,任务控制块结构体中有两个列表项,对其做初始化操作

    listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
    listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority );
    listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
    
    #define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )  ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
    #define listSET_LIST_ITEM_VALUE( pxListItem, xValue )   ( ( pxListItem )->xItemValue = ( xValue ) )

    这里设置了列表项xStateListItem和xEventListItem属于当前任务控制块,即设置两个列表项的成员变量pvOwner为新创建的任务的任务控制块;并且设置了列表项xEventListItem的变量xItemValue为configMAX_PRIORITIES-uxPriority,意味着xItemValue的值越大优先级越小(列表插入按照xItemValue的值升序排列)

    #if ( portCRITICAL_NESTING_IN_TCB == 1 )
    {
        pxNewTCB->uxCriticalNesting = ( UBaseType_t ) 0U;
    }
    #endif /* portCRITICAL_NESTING_IN_TCB */
    #if ( configUSE_APPLICATION_TASK_TAG == 1 )
    {
        pxNewTCB->pxTaskTag = NULL;
    }
    #endif /* configUSE_APPLICATION_TASK_TAG */
    #if ( configGENERATE_RUN_TIME_STATS == 1 )
    {
        pxNewTCB->ulRunTimeCounter = 0UL;
    }
    #endif /* configGENERATE_RUN_TIME_STATS */

    分别条件编译,portCRITICAL_NESTING_IN_TCB:临界区嵌套宏定义;configUSE_APPLICATION_TASK_TAG:任务标签功能;configGENERATE_RUN_TIME_STATS:时间统计功能;若使能这些功能宏定义,则给任务控制块的相关变量初始化赋值

    #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
        {
        for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ )
        {
            pxNewTCB->pvThreadLocalStoragePointers[ x ] = NULL;
        }
        }
    #endif

    如果使能了宏configNUM_THREAD_LOCAL_STORAGE_POINTERS为1,初始化线程本地存储指针

    #if ( configUSE_TASK_NOTIFICATIONS == 1 )
        {
            pxNewTCB->ulNotifiedValue = 0;
            pxNewTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
        }
    #endif
    
    #if ( configUSE_NEWLIB_REENTRANT == 1 )
        {
            /* Initialise this task's Newlib reent structure. */
            _REENT_INIT_PTR( ( &( pxNewTCB->xNewLib_reent ) ) );
        }
    #endif
    
    #if( INCLUDE_xTaskAbortDelay == 1 )
        {
            pxNewTCB->ucDelayAborted = pdFALSE;
        }
    #endif

    条件编译,configUSE_TASK_NOTIFICATIONS:使能任务通知功能(默认开启);configUSE_NEWLIB_REENTRANT:使能NEWLIB;INCLUDE_xTaskAbortDelay:使能函数INCLUDE_xTaskAbortDelay();如果使能了相应功能,则给任务控制块的相关变量初始化赋值

    #if( portUSING_MPU_WRAPPERS == 1 )
        {
            pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
        }
    #else /* portUSING_MPU_WRAPPERS */
        {
            pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
        }
    #endif /* portUSING_MPU_WRAPPERS */

    调用了函数pxPortInitialiseStack()初始化任务堆栈

    if( ( void * ) pxCreatedTask != NULL )
    {
        *pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    生成任务句柄,返回给参数pxCreatedTask,任务句柄其实就是任务控制块

    3. 任务堆栈初始化函数

    堆栈用来进行上下文切换时候保存现场,新创建好一个堆栈后会对其进行初始化处理,即对Cortex-M内核的某些寄存器赋初值。初值保存在任务堆栈中,保存顺序为:xPSR,R15(PC),R14(LR),R12,R3\~R0,R11~R14

    函数pxPortInitialiseStack()即为堆栈初始化函数,函数源码:

    StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
    {
        /* Simulate the stack frame as it would be created by a context switch
        interrupt. */
    
        /* Offset added to account for the way the MCU uses the stack on entry/exit
        of interrupts, and to ensure alignment. */
        pxTopOfStack--;
    
        *pxTopOfStack = portINITIAL_XPSR;   /* xPSR */
        pxTopOfStack--;
        *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK;    /* PC */
        pxTopOfStack--;
        *pxTopOfStack = ( StackType_t ) prvTaskExitError;   /* LR */
    
        /* Save code space by skipping register initialisation. */
        pxTopOfStack -= 5;  /* R12, R3, R2 and R1. */
        *pxTopOfStack = ( StackType_t ) pvParameters;   /* R0 */
    
        /* A save method is being used that requires each task to maintain its
        own exec return value. */
        pxTopOfStack--;
        *pxTopOfStack = portINITIAL_EXEC_RETURN;
    
        pxTopOfStack -= 8;  /* R11, R10, R9, R8, R7, R6, R5 and R4. */
    
        return pxTopOfStack;
    }

    参数:pxTopOfStack:堆栈栈顶;pxCode:任务函数;pvParameters:传递参数(null)

    *pxTopOfStack = portINITIAL_XPSR: 寄存器xPSR值为portINITIAL_XPSR(0x01000000),此时表示xPSR寄存器的bit24为1,即处于Thumb状态(Cortex-m系列没有ARM状态)

    *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK:寄存器PC初始化为任务函数pxCode

    *pxTopOfStack = ( StackType_t ) prvTaskExitError:寄存器LR初始化为函数prvTaskExitError()

    pxTopOfStack -= 5;  /* R12, R3, R2 and R1. */
    *pxTopOfStack = ( StackType_t ) pvParameters

    跳过4个寄存器R12,R3,R2和R1(这四个寄存器不初始化);并把寄存器R0初始化为pvParameters

    *pxTopOfStack = portINITIAL_EXEC_RETURN:保存EXC_RETURN值,用于退出SVC和PendSV中断的时候处理器该处于什么状态。当处理器进入异常或中断服务程序时,链接寄存器R14(LR)的数值更新为EXC_RETURN,这里宏定义为0xfffffffd

    pxTopOfStack -= 8:跳过8个寄存器,R11,R10,R8,R7,R6,R5,R4

    初始化之后,堆栈结果为:
    image

    4. 添加任务到就绪表

    任务创建后被添加到就绪列表中,FreeRTOS使用不同的列表表示任务的不同状态,tasks.c中定义了多个列表完成不同功能:

    PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */
    PRIVILEGED_DATA static List_t xDelayedTaskList1;                /*< Delayed tasks. */
    PRIVILEGED_DATA static List_t xDelayedTaskList2;                /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
    PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList;     /*< Points to the delayed task list currently being used. */
    PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
    PRIVILEGED_DATA static List_t xPendingReadyList;                /*< Tasks that have been readied while the scheduler was suspended.  They will be moved to the ready list when the scheduler is resumed. */
    

    其中pxReadyTasksLists[]即是任务就绪列表,数组大小为configMAX_PRIORITIES即可使用的最大优先级,所以一个优先级一个列表,相同优先级的任务则使用一个列表。

    函数prvAddNewTaskToReadyList()完成将一个新创建的任务添加到就绪列表中

    static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
    {
        taskENTER_CRITICAL();
        {
            uxCurrentNumberOfTasks++;
            if( pxCurrentTCB == NULL )
            {
                pxCurrentTCB = pxNewTCB;
                if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
                {
                    prvInitialiseTaskLists();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                if( xSchedulerRunning == pdFALSE )
                {
                    if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
                    {
                        pxCurrentTCB = pxNewTCB;
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            uxTaskNumber++;
            #if ( configUSE_TRACE_FACILITY == 1 )
            {
                pxNewTCB->uxTCBNumber = uxTaskNumber;
            }
            #endif /* configUSE_TRACE_FACILITY */
            traceTASK_CREATE( pxNewTCB );
    
            prvAddTaskToReadyList( pxNewTCB );
    
            portSETUP_TCB( pxNewTCB );
        }
        taskEXIT_CRITICAL();
    
        if( xSchedulerRunning != pdFALSE )
        {
            if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )
            {
                taskYIELD_IF_USING_PREEMPTION();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }

    taskENTER_CRITICAL():首先先进入临界区,关闭中断,使接下来函数里代码完整运行不被打断

    uxCurrentNumberOfTasks++:全局变量uxCurrentNumberOfTasks加1,统计任务数量

    if( pxCurrentTCB == NULL ){pxCurrentTCB = pxNewTCB:如果正在运行任务控制块为NULL,即为没有任务运行,则将新任务的任务控制块赋值给pxCurrentTCB,新创建的任务便是第一个任务

    if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 ){prvInitialiseTaskLists();}:如果任务数量为1,则说明创建的任务是第一个任务,此时通过函数prvInitialiseTaskLists()来初始化相应的列表(函数prvInitialiseTaskLists()即调用列表初始化函数vListInitialise()来初始化几个列表)

    if( xSchedulerRunning == pdFALSE ){if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority ){pxCurrentTCB = pxNewTCB;}:如果调度器尚未运行,新任务的优先级比正在运行的任务优先级高,则修改pxCurrentTCB为新建任务的任务控制块

    uxTaskNumber++:uxTaskNumber加1,用作任务控制块编号

    if ( configUSE_TRACE_FACILITY == 1 ){pxNewTCB->uxTCBNumber = uxTaskNumber;}#endif:条件编译如果启动了可视化跟踪调试,则将任务控制块编号赋值给新任务的任务控制块的uxTCBNumber成员变量

    prvAddTaskToReadyList( pxNewTCB ):调用函数吧任务添加到就绪表中,这个函数其实是个宏:

    #define prvAddTaskToReadyList( pxTCB )                                                              \
        traceMOVED_TASK_TO_READY_STATE( pxTCB );    \
        taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );                         \
        vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \
        tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )

    traceMOVED_TASK_TO_READY_STATE( pxTCB )和tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )都没什么用;taskRECORD_READY_PRIORITY用来记录处于就绪态任务,接下来使用函数vListInsertEnd()将任务添加到就绪列表末尾

    taskEXIT_CRITICAL():之后退出临界区

    if( xSchedulerRunning != pdFALSE ){if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority ){
    taskYIELD_IF_USING_PREEMPTION();}:如果调度器已经开始运行,并且新任务的优先级最高,则调用函数taskYIELD_IF_USING_PREEMPTION()完成一次任务切换

    展开全文
  • FreeRTOS创建静态任务

    2020-07-01 14:00:24
    1、配置FreeRTOSConfig.h 2、实现函数 3、定义实体 4、创建任务

    1、配置FreeRTOSConfig.h

    /*****************************************************************
                  FreeRTOS与内存申请有关配置选项                                            
    *****************************************************************/
    //支持动态内存申请
    #define configSUPPORT_DYNAMIC_ALLOCATION        1    
    //支持静态内存
    #define configSUPPORT_STATIC_ALLOCATION					1					
    //系统所有总的堆大小(单位:字,32位则是四个字节)
    #define configTOTAL_HEAP_SIZE					((size_t)(36*1024))    
    

    2、实现函数

    /**
      **********************************************************************
      * @brief  获取空闲任务的堆栈和任务控制块内存
    	*					ppxTimerTaskTCBBuffer	:		任务控制块内存
    	*					ppxTimerTaskStackBuffer	:	任务堆栈内存
    	*					pulTimerTaskStackSize	:		任务堆栈大小
      * @author  fire
      * @version V1.0
      * @date    2018-xx-xx
      **********************************************************************
      */ 
    void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, 
    								   StackType_t **ppxIdleTaskStackBuffer, 
    								   uint32_t *pulIdleTaskStackSize)
    {
    	*ppxIdleTaskTCBBuffer=&Idle_Task_TCB;/* 任务控制块内存 */
    	*ppxIdleTaskStackBuffer=Idle_Task_Stack;/* 任务堆栈内存 */
    	*pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;/* 任务堆栈大小 */
    }
    
    /**
      *********************************************************************
      * @brief  获取定时器任务的任务堆栈和任务控制块内存
    	*					ppxTimerTaskTCBBuffer	:		任务控制块内存
    	*					ppxTimerTaskStackBuffer	:	任务堆栈内存
    	*					pulTimerTaskStackSize	:		任务堆栈大小
      * @author  fire
      * @version V1.0
      * @date    2018-xx-xx
      **********************************************************************
      */ 
    void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, 
    									StackType_t **ppxTimerTaskStackBuffer, 
    									uint32_t *pulTimerTaskStackSize)
    {
    	*ppxTimerTaskTCBBuffer=&Timer_Task_TCB;/* 控制任务卡=块内存 */
    	*ppxTimerTaskStackBuffer=Timer_Task_Stack;/* 控制任务块大小 */
    	*pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH;/* 任务堆栈大小 */
    }
    /**
      *********************************************************************
      * @brief  APP任务创建
      * @author  
      * @version V1.0
      * @date    2018-xx-xx
      **********************************************************************
      */ 
    static void AppTaskCreate(void)
    {
      taskENTER_CRITICAL();           //进入临界区
    
      /* 创建LED_TASK 任务 */
    	LED_Task_Handle = xTaskCreateStatic((TaskFunction_t	)LED_Task,		//任务函数
    															(const char* 	)"LED_Task",		//任务名称
    															(uint32_t 		)128,					//任务堆栈大小
    															(void* 		  	)NULL,				//传参
    															(UBaseType_t 	)4, 				//任务优先级
    															(StackType_t*   )LED_Task_Stack,	//任务堆栈
    															(StaticTask_t*  )&LED_Task_TCB);	//任务控制块
    	
    	if(NULL != LED_Task_Handle)/* 创建成功 */
    		printf("LED_Task任务创建成功!\n");
    	else
    		printf("LED_Tas任务创建失败!\n");
    	
      vTaskDelete(AppTaskCreate_Handle); //删除App_task任务
      
      taskEXIT_CRITICAL();            //退出临界区
    }
    /**
      *********************************************************************
      * @brief LED_TASK任务
      * @author  
      * @version V1.0
      * @date    2018-xx-xx
      **********************************************************************
      */ 
      static void LED_Task(void* parameter)
    {	
        while (1)
        {
            HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, (GPIO_PinState)SET);
            vTaskDelay(500);   /* 延时500个tick */
            printf("LED_Task Running,LED1_ON\r\n");
            
            HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, (GPIO_PinState)RESET);   
            vTaskDelay(500);   /* 延时500个tick */		 		
            printf("LED_Task Running,LED1_OFF\r\n");
        }
    }
    
    

    3、定义实体

    /* AppTask 任务句柄 */
    static TaskHandle_t AppTaskCreate_Handle;
    /* LED_TASK 任务句柄 */
    static TaskHandle_t LED_Task_Handle;		
    
    /* AppTask任务堆栈 */
    static StackType_t AppTaskCreate_Stack[128];
    /* LED_TASK任务堆栈 */
    static StackType_t LED_Task_Stack[128];
    /* 空闲任务堆栈*/
    static StackType_t Idle_Task_Stack[configMINIMAL_STACK_SIZE];
    /* 定时任务堆栈 */
    static StackType_t Timer_Task_Stack[configTIMER_TASK_STACK_DEPTH];
    
    /* AppTask任务控制块 */
    static StaticTask_t AppTaskCreate_TCB;
    /* LED_TASK 任务控制块 */
    static StaticTask_t LED_Task_TCB;
    /* 空闲任务控制块 */
    static StaticTask_t Idle_Task_TCB;	
    /* 定时任务控制块 */
    static StaticTask_t Timer_Task_TCB;
    
    
    

    4、创建任务

     /* ´创建App_Task */
    	AppTaskCreate_Handle = xTaskCreateStatic((TaskFunction_t	)AppTaskCreate,		//任务函数
    															(const char* 	)"AppTaskCreate",		//任务名称
    															(uint32_t 		)128,	// 任务堆栈大小
    															(void* 		  	)NULL,				//传参
    															(UBaseType_t 	)3, 	//优先级
    															(StackType_t*   )AppTaskCreate_Stack,	//任务堆栈
    															(StaticTask_t*  )&AppTaskCreate_TCB);	//任务控制块
    	if(NULL != AppTaskCreate_Handle)/*任务创建成功 */
        vTaskStartScheduler();   /* 开启任务调度*/
    
    展开全文
  • 开始今天的内容之前,先补充一下上篇文章【连载】从单片机到操作系统③——走进FreeRTOS的一点点遗漏的知识点。 1BaseType_t xTaskCreate( TaskFunction_t pvTaskCode, 2 const char * const pcName, ...
  • FreeRTOS 任务调度 任务创建

    千次阅读 2016-10-13 00:30:16
    静态创建任务 动态创建任务 初始化任务控制块 栈初始化举例 插入就绪链表 参考 FreeRtos 简述FreeRTOS 的任务调度在 Source/include/task.c 中实现,包含了任务的创建、切换、挂起、延时和删除等所有功能。涉及到的...
  • FreeRTOS任务创建和删除函数

    千次阅读 2017-10-10 14:33:16
    FreeRTOS中有关任务创建和删除函数总共有4个,具体介绍如下: xTaskCreate():使用动态的方法创建一个任务 xTaskCreateStatic():使用静态的方法创建一个任务 xTaskCreateRestricted():创建一个使用MPU进行...
  • FreeRTOS有两种方式创建任务,动态方法和静态方法,他们的区别就是动态创建任务所使用到的堆栈由系统自动分配,而静态创建任务所使用到的堆栈则要由程序员自己指定了。 1.1 动态方法 FreeRTOS动态方法创建任务的API...
  • 这一节来分析一下FreeRTOS动态创建任务,FreeRTOS创建任务常用的有两种方式,一种是静态方式,一种是动态方式,静态创建方式需要用户自己提供任务堆栈,动态创建用户只需提供堆栈大小,堆栈由内核来分配,大多数应用...
  • FreeRTOS(14)---FreeRTOS 任务创建分析

    千次阅读 2018-10-11 19:17:19
    FreeRTOS 任务创建分析FreeRTOS 任务创建分析创建任务堆栈和任务TCB初始化任务TCB必要的字段初始化任务堆栈进入临界区当前任务数量增加1为第一次运行做必要的初始化更新当前正在运行的任务TCB指针将新创建的任务加入...
  • 任务创建FreeRTOS系统启动的第一个步骤,前面在启动调度器的时候先创建了空闲任务,然后再由调度器跳到任务里面去执行。任务创建函数里面做了很多的工作,先会为任务堆栈和任务控制块分配内存并初始化它们,然后将...
  • FreeRTOS高级篇2---FreeRTOS任务创建分析

    万次阅读 多人点赞 2016-05-03 13:31:08
    FreeRTOS基础系列《FreeRTOS系列第10篇---FreeRTOS任务创建和删除》中介绍了任务创建API函数xTaskCreate(),我们这里先回顾一下这个函数的声明: BaseType_t xTaskCreate( TaskFunction_tp vTaskCode,
  • (二)上面的四个函数目前只用动态创建任务和删除任务 (三)动态创建任务 函数 xTaxkCreate() 宏 configSUPPORT_DYNAMIC_ALLOCATION 必须为 1 新创建的任务默认就是就绪态的,如果当前没有比它更高优先级的任务...
  • FreeRTOS任务创建和删除函数 函数 描述 xTaskCreate 使用动态的方法创建一个任务 xTaskCreateStatic 使用静态的方法创建一个任务 vTaskDelete 删除一个任务 xTaskCreate BaseType_t xTaskCreate( Task...
  • 本文主要介绍FreeRTOS创建任务函数 xTaskCreate() 的函数原型及如何使用 xTaskCreate() 创建任务。 一、xTaskCreate() API 函数 这是我们接触到的第一个FreeRTOS函数,可能也是所有API函数中最复杂的一个,但必须...
  • 6.1 任务创建和删除API 函数FreeRTOS 最基本的功能就是任务管理,而任务管理最基本的操作就是创建和删除任务,FreeRTOS 的任务创建和删除API 函数如表6.1.1.1 所示:1、...如果使用函数xTaskCreate()来创建任务的话...
  • FreeRTOS任务创建删除

    2017-12-12 17:53:00
    FreeRTOS 当前使用的api 接口为 xTaskCreate() xTaskCreateRestricted() xTaskCreateStatic() vTaskDelete() xTaskCreate() 函数原型 BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,   ...
  • FreeRTOS 最基本的功能就是任务管理,而任务管理最基本的操作就是创建和删除任务FreeRTOS任务创建和删除 API 函数如下表 所示: 函数 描述 xTaskCreate() 使用动态的方法创建一个任务 ...
  • typedef struct tskTaskControlBlock /* The old naming convention is used to prevent breaking ... //任务堆栈的栈顶指针,栈顶指针随着程序运行而移动 volatile StackType_t *pxTopOfStack; /*< Point...
  • FreeRTOS-任务通知

    2021-09-10 09:42:43
    前几章我们介绍了信号量、消息队列、事件标志组等用于任务之间同步或通信的工具,当信号量、消息队列等创建完成后所有任务都能访问这些资源。实际上,在应用过程中,很多时候任务通信或同步是一对一的,这时就可以...
  • FreeRTOS任务详解

    2021-09-07 10:33:03
    详细讲解freeRTOS任务
  • 普通任务创建及运行,参阅安富莱电子demo /* ********************************************************************************************************* * 函 数 名: vTaskTaskUserIF * 功能说明: 接口消息处理...
  • FreeRTOS 任务调度 任务切换

    万次阅读 2016-10-15 17:07:34
    FreeRtos 简述前面文章 < FreeRTOS 任务调度 任务创建 > 介绍了 FreeRTOS 中如何创建任务以及其具体实现。 一般来说, 我们会在程序开始先创建若干个任务, 而此时任务调度器还没又开始运行,因此每一次任务创建后...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,037
精华内容 414
关键字:

freertos创建任务失败