FreeRTOS的第一个任务是怎么跑起来的

2023-05-16

一、一般在程序末尾会有一个vTaskStartSheduler();函数

int main(void)
{
        BSP_INIT();
       BinarySemaphore=xSemaphoreCreateBinary();
       if(BinarySemaphore!=NULL)
         {
                printf("semaphore create successfully .\r\n");
         }

      xTaskCreate(vLED1Task,"led1",50,NULL,1,NULL);


     //
    xTaskCreate((TaskFunction_t )DataProcess_task,     
                (const char*    )"DataProcess_task",   
                (uint16_t       )DATAPROCESS_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )DATAPROCESS_TASK_PRIO,
                (TaskHandle_t*  )&DataProcess_Handler); 
                            //  (TaskHandle_t*  )NULL); 

      vTaskStartScheduler();//启动调度器,任务开始执行。
      return 0;

}

二、下面看一下vTaskStartScheduler的具体内容:

void vTaskStartScheduler( void )
{
BaseType_t xReturn;

    /* Add the idle task at the lowest priority. */
    #if( configSUPPORT_STATIC_ALLOCATION == 1 )
    {
        StaticTask_t *pxIdleTaskTCBBuffer = NULL;
        StackType_t *pxIdleTaskStackBuffer = NULL;
        uint32_t ulIdleTaskStackSize;

        /* The Idle task is created using user provided RAM - obtain the
        address of the RAM then create the idle task. */
        vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
        xIdleTaskHandle = xTaskCreateStatic(    prvIdleTask,
                                                "IDLE",
                                                ulIdleTaskStackSize,
                                                ( void * ) NULL,
                                                ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
                                                pxIdleTaskStackBuffer,
                                                pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */

        if( xIdleTaskHandle != NULL )
        {
            xReturn = pdPASS;
        }
        else
        {
            xReturn = pdFAIL;
        }
    }
    #else
    {
        /* The Idle task is being created using dynamically allocated RAM. */
        xReturn = xTaskCreate(  prvIdleTask,
                                "IDLE", configMINIMAL_STACK_SIZE,
                                ( void * ) NULL,
                                ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
                                &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
    }
    #endif /* configSUPPORT_STATIC_ALLOCATION */

    #if ( configUSE_TIMERS == 1 )
    {
        if( xReturn == pdPASS )
        {
            xReturn = xTimerCreateTimerTask();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    #endif /* configUSE_TIMERS */

    if( xReturn == pdPASS )
    {
        /* Interrupts are turned off here, to ensure a tick does not occur
        before or during the call to xPortStartScheduler().  The stacks of
        the created tasks contain a status word with interrupts switched on
        so interrupts will automatically get re-enabled when the first task
        starts to run. */
        portDISABLE_INTERRUPTS();

        #if ( configUSE_NEWLIB_REENTRANT == 1 )
        {
            /* Switch Newlib's _impure_ptr variable to point to the _reent
            structure specific to the task that will run first. */
            _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
        }
        #endif /* configUSE_NEWLIB_REENTRANT */

        xNextTaskUnblockTime = portMAX_DELAY;
        xSchedulerRunning = pdTRUE;
        xTickCount = ( TickType_t ) 0U;

        /* If configGENERATE_RUN_TIME_STATS is defined then the following
        macro must be defined to configure the timer/counter used to generate
        the run time counter time base. */
        portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();

        /* Setting up the timer tick is hardware specific and thus in the
        portable interface. */
        ***if( xPortStartScheduler() != pdFALSE )***
        {
            /* Should not reach here as if the scheduler is running the
            function will not return. */
        }
        else
        {
            /* Should only reach here if a task calls xTaskEndScheduler(). */
        }
    }
    else
    {
        /* This line will only be reached if the kernel could not be started,
        because there was not enough FreeRTOS heap to create the idle task
        or the timer task. */
        configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );
    }

    /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0,
    meaning xIdleTaskHandle is not used anywhere else. */
    ( void ) xIdleTaskHandle;
}

可以看到vTaskStartScheduler()函数调用了xPortStartScheduler()函数。

三、下面再看一下xPortStartScheduler()函数

BaseType_t xPortStartScheduler( void )
{
    #if( configASSERT_DEFINED == 1 )
    {
        volatile uint32_t ulOriginalPriority;
        volatile uint8_t * const pucFirstUserPriorityRegister = ( uint8_t * ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
        volatile uint8_t ucMaxPriorityValue;

        /* Determine the maximum priority from which ISR safe FreeRTOS API
        functions can be called.  ISR safe functions are those that end in
        "FromISR".  FreeRTOS maintains separate thread and ISR API functions to
        ensure interrupt entry is as fast and simple as possible.

        Save the interrupt priority value that is about to be clobbered. */
        ulOriginalPriority = *pucFirstUserPriorityRegister;

        /* Determine the number of priority bits available.  First write to all
        possible bits. */
        *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;

        /* Read the value back to see how many bits stuck. */
        ucMaxPriorityValue = *pucFirstUserPriorityRegister;

        /* Use the same mask on the maximum system call priority. */
        ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;

        /* Calculate the maximum acceptable priority group value for the number
        of bits read back. */
        ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
        while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
        {
            ulMaxPRIGROUPValue--;
            ucMaxPriorityValue <<= ( uint8_t ) 0x01;
        }

        /* Shift the priority group value back to its position within the AIRCR
        register. */
        ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
        ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;

        /* Restore the clobbered interrupt priority register to its original
        value. */
        *pucFirstUserPriorityRegister = ulOriginalPriority;
    }
    #endif /* conifgASSERT_DEFINED */

    /* Make PendSV and SysTick the lowest priority interrupts. */
    portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
    portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;

    /* Start the timer that generates the tick ISR.  Interrupts are disabled
    here already. */
    vPortSetupTimerInterrupt();

    /* Initialise the critical nesting count ready for the first task. */
    uxCriticalNesting = 0;

    /* Start the first task. */
    prvStartFirstTask();

    /* Should not get here! */
    return 0;
}

可以看到xPortStartScheduler()函数调用了prvSetupTimerInterrupt()函数。
四、下面再看一下prvSetupTimerInterrupt()函数。

#if configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0

    void vPortSetupTimerInterrupt( void )
    {
        /* Calculate the constants required to configure the tick interrupt. */
        #if configUSE_TICKLESS_IDLE == 1
        {
            ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
            xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
            ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
        }
        #endif /* configUSE_TICKLESS_IDLE */

        /* Configure SysTick to interrupt at the requested rate. */
        portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
        portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
    }

#endif /* configOVERRIDE_DEFAULT_TICK_CONFIGURATION */

注意,这里使用了条件编译。只有在configOVERRIDE_DEFAULT_TICK_CONFIGURATION=0的时候才会进行编译。从函数名称可以看出来,这个函数是对stm32系统滴答定时器进行配置的。
配置的参数主要是两个:configSYSTICK_CLOCK_HZ和configTICK_RATE_HZ 。滴答定时器时钟和滴答定时器的运行频率。
那么configOVERRIDE_DEFAULT_TICK_CONFIGURATION是在哪里定义的呢?我们可以在port.c的101行发现它的定义。

#ifndef configOVERRIDE_DEFAULT_TICK_CONFIGURATION
    #define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 0
#endif

那么SysTick的中断处理函数在哪里呢?我们同样可以在port.c文件的第431行找到。

void xPortSysTickHandler( void )
{
    /* The SysTick runs at the lowest interrupt priority, so when this interrupt
    executes all interrupts must be unmasked.  There is therefore no need to
    save and then restore the interrupt mask value as its value is already
    known - therefore the slightly faster vPortRaiseBASEPRI() function is used
    in place of portSET_INTERRUPT_MASK_FROM_ISR(). */
    vPortRaiseBASEPRI();
    {
        /* Increment the RTOS tick. */
        if( xTaskIncrementTick() != pdFALSE )
        {
            /* A context switch is required.  Context switching is performed in
            the PendSV interrupt.  Pend the PendSV interrupt. */
            portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
        }
    }
    vPortClearBASEPRIFromISR();
}

可以看到,进入中断处理函数后,进行了三个动作。
1、关闭中断;
2、进行上下文切换;
3、开启中断。
其中,整个中断处理函数最重要的部分是在xTaskIncreamentTick()里。这里完成了许多功能。暂时不是很了解。
具体可以参考以下链接:
xTaskIncreamentTick()
这样整个系统就跑起来了。

五、总结。
从以上步骤我么可以看出:
1、stm32的滴答定时器给FreeRTOS提供基准心跳时钟;
2、SysTICK默认使用FreeRTOS系统配置。配置的参数由两个 因数决定。即configSYSTICK_CLOCK_HZ和configTICK_RATE_HZ 。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS的第一个任务是怎么跑起来的 的相关文章

随机推荐

  • 关于LINUX的NVIDIA显卡驱动安装

    LINUX 中已经集成了一些组件的相关驱动 xff0c 但是随着机器相关组件芯片不断更新 xff0c 相应的驱动程序也在不断的更新 xff0c LINUX 中集成的驱动程序难免有些不能满足需要 xff0c 其最突出的问题 xff0c 莫过于
  • 性能专题

    if与switch 当多个条件语句判断时 xff0c switch比多个if语句的性能高 转载于 https www cnblogs com lanchong archive 2011 11 03 2234180 html
  • 自制户外登山地图傻瓜书(转载)

    自制户外登山地图傻瓜书 2009 02 19 灰羊羊 转载请注明出处 第一章 前言 大概4年前喜欢上了户外运动 xff0c 从此一发不可收拾 xff0c 07年初买了一个GPS xff0c 最初只是为了避免在山中迷路 xff0c 随着使用的
  • 文件加密和解密 - 密钥存储

    当我们想要做一次加密系统 xff0c 或者只是有一个关于这个问题 xff0c 它是如何保存的加密和解密密钥 一般认为想要的文件加密和解密 xff0c 对称算法用于 一般是AES要么DES 这就存在密钥管理的问题 xff0c 它是如何 xff
  • spring mvc绑定复杂对象报错“Could not instantiate property type [com.ld.net.spider.pojo.WorkNode] to auto-gro...

    解决方法之一 xff1a 1 确保所有的Pojo都包含了默认的构造器 xff1b
  • Docker容器 暴露多个端口

    1 创建容器是指定 docker run p lt host port1 gt lt container port1 gt p lt host port2 gt lt container port2 gt 2 修改dockerfile ex
  • 巴特沃斯(Butterworth)滤波器 (1)

    下面深入浅出讲一下Butterworth原理及其代码编写 1 首先考虑一个归一化的低通滤波器 xff08 截止频率是1 xff09 xff0c 其幅度公式如下 xff1a 当n gt 时 xff0c 得到一个理想的低通滤波反馈 xff1c
  • 用预训练的densenet121模型训练cifar10数据集

    densenet121采用pytorch预训练模型 xff0c 这里用cifar10作为数据集 import torchvision models as models import ssl ssl create default https
  • Ubuntu环境下安装DBoW2

    简介 DBoW2 is an improved version of the DBow library an open source C 43 43 library for indexing and converting images in
  • java如何将二进制转换为十进制

    1 使用java内部提供的方法 xff0c 直接进行api的调用 public static void binaryTodecimal2 int n String res 61 Integer toBinaryString n System
  • Spring Cloud Feign 请求动态URL

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 1 FeignClient 中不要写url 使用 64 RequestLine 修饰方法 2 调用地方必须引入 FeignClientConfiguration 必须有De
  • 折半查找:查找成功的最少/多次数、平均次数,查找不成功的最少/多次数、平均次数...

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 最方面的方法是建立一个判定树 现在有11个数 xff1a xff08 第1行是索引 xff0c 第2行是数 xff09 0 1 2 3 4 5 6 7 8 9 10 7 1
  • 关于maven打包 “程序包com.sun.deploy.net不存在” 的问题

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 关于maven打包 程序包com sun deploy net不存在 的问题 遇到问题如下 xff1a INFO payGateway 1 0 SNAPSHOT SUCCE
  • 印度理工学院有多难考?

    http app myzaker com news article php pk 61 599546401bc8e08604000085 印度理工学院有多难考 xff1f 何赟08 17 原文是六月高考季时给公众号 34 中印对话 34 x
  • iOS系统下 的手机屏幕尺寸 分辨率 及系统版本 总结

    今天 我对iOS系统下 的手机屏幕尺寸 分辨率 及系统版本做了一次系统总结 供大家参考 首先 是系统 xff1a 随着iOS 系统不断升级 xff0c 现在已经到iOS7 0了 xff0c 并且TA有了很多新变化 xff0c 最震撼的就是
  • android ViewFlipper的使用

    屏幕切换指的是在同一个Activity内屏幕见的切换 xff0c 最长见的情况就是在一个FrameLayout内有多个页面 xff0c 比如一个系统设置页面 xff1b 一个个性化设置页面 通过查看 OPhone API文档可以发现 xff
  • Linux下路由配置梳理

    在日常运维作业中 xff0c 经常会碰到路由表的操作 下面就linux运维中的路由操作做一梳理 xff1a 先说一些关于路由的基础知识 xff1a 1 xff09 路由概念 路由 xff1a 跨越从源主机到目标主机的一个互联网络来转发数据包
  • ASP.NET成员角色系列(一)--验证与授权入门

    在当今的信息世界里 无论是门户网站 电子商务 社区论坛 都有一个共性 它们通常都需要验证当前用户的身份并根据验证结果判断用户所具有的权限 例如博客园 它允许未注册的匿名用户可能查看帖子 但是不允许他们发表帖子 为了能够发表帖子 匿名用户必须
  • 老赵谈IL(4):什么时候应该学IL,该怎么学IL

    又是一个拖了半年的系列 xff0c 可能是前几篇主要以事实为准 xff0c 举例子的文章总是比较容易写的 xff0c 因此十分顺畅 而最后一篇打算做一个总结 xff0c 以讲道理为主 却发现该将的似乎都已经讲完了 不过做事要有始有终 xff
  • FreeRTOS的第一个任务是怎么跑起来的

    一 一般在程序末尾会有一个vTaskStartSheduler 函数 span class hljs keyword int span main span class hljs keyword void span BSP INIT Bina