RTOS精进(一):深入FreeRTOS内核

深入FreeRTOS内核

目录

FreeRTOS基础

  • 见下图,下图有可能不是最新的, 最新文件见FreeRTOS.xmind

在这里插入图片描述

  • 互斥量、互斥锁,本来的概念确实是:谁上锁就得由谁解锁。** (放到xmind中)**
    但是FreeRTOS并没有实现这点,只是要求程序员按照这样的惯例写代码。韦东山freeRTOS系列教程之【第七章】互斥量(mutex)_悦己之作,方能悦人的技术博客_51CTO博客
  • vTaskStartScheduler调用后,才开始调度
  • FreeRTOS操作系统支持三种调度方式:抢占式调度(Pre-emptive),时间片调度(time slice , 同优先级任务才会是使用时间片调度)和合作式调度(co-operative, 使用合作调度器时,只有在Running状态任务进入Blocked状态,或者Running状态任务通过调用taskYIELD()显式让步(手动请求重新调度)时才会发生任务切换。)。实际应用主要是抢占式调度和时间片调度结合的调度方法,合作式调度用到的很少

学习总结

任务创建

FreeRTOS的任务(其实就是线程)创建, 会创建在堆区划分一块空间, 这块空间用来放置TCB和任务栈空间 , 栈空间就是申请的栈大小, 这个TCB就是一个结构体, 用于记录优先级,运行时间,运行状态等信息。 结构体定义如下

/*
 * Task control block.  A task control block (TCB) is allocated for each task,
 * and stores task state information, including a pointer to the task's context
 * (the task's run time environment, including register values)
 */
typedef struct tskTaskControlBlock
{
    /* 栈顶<元素>指针,注意与 pxEndOfStack 的区别。 必须是结构体的第一个成员. */
    volatile StackType_t * pxTopOfStack; 

    /* MPU 模块设置,必须是结构体的第二个成员 */
    #if ( portUSING_MPU_WRAPPERS == 1 )
        xMPU_SETTINGS xMPUSettings;
    #endif

    ListItem_t xStateListItem;                  /* 列表项指示任务当前的状态 (Ready, Blocked, Suspended ). */
    ListItem_t xEventListItem;                  /* 用于在事件列表中. */
    UBaseType_t uxPriority;                     /* 任务优先级(0为优先级最低). */
    StackType_t * pxStack;                      /* 栈底指针,指向栈开始处. */
    char pcTaskName[ configMAX_TASK_NAME_LEN ]; /* 任务名 */

    /* 如果栈向上生长,则定义栈顶指针 */
    #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
        StackType_t * pxEndOfStack; 
    #endif

    #if ( portCRITICAL_NESTING_IN_TCB == 1 )
        UBaseType_t uxCriticalNesting; /* 保存临界区的栈深度. 在函数vTaskEnterCritical() 和 vTaskExitCritical()中会维护这个值*/
    #endif

    #if ( configUSE_TRACE_FACILITY == 1 )
        UBaseType_t uxTCBNumber;  /*TCB的编号,每次增加一个task,TCB的编号就会增加. */
        UBaseType_t uxTaskNumber; /*task的编号,其值和uxTCBNumber相等,可用于调试追踪. */
    #endif

    #if ( configUSE_MUTEXES == 1 )
        UBaseType_t uxBasePriority; /*上一次分配给该任务的优先级,用于优先级继承机制. */
        UBaseType_t uxMutexesHeld; /* 持有的信号量 */
    #endif

    #if ( configUSE_APPLICATION_TASK_TAG == 1 )
        TaskHookFunction_t pxTaskTag;
    #endif

    /* 存储一些私有的变量 */
    #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
        void * pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
    #endif

    /* task 运行的总时间 */
    #if ( configGENERATE_RUN_TIME_STATS == 1 )
        uint32_t ulRunTimeCounter; 
    #endif

    /*  See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html for additional information. */
    #if ( configUSE_NEWLIB_REENTRANT == 1 )
        struct  _reent xNewLib_reent;
    #endif

    /* 任务通知相关变量 */
    #if ( configUSE_TASK_NOTIFICATIONS == 1 )
        volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
        volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
    #endif

    /* FreeRTOS.h 中有关于 tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE 的详细注释。主要的作用是决定task创建的资源是动态还是静态分配内存. */
    #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) 
        uint8_t ucStaticallyAllocated; /* 标记stack 和 TCB分配方式,在删除任务时,根据此标志来对应释放内存 */
    #endif

    /* delay 终止标志 */
    #if ( INCLUDE_xTaskAbortDelay == 1 )
        uint8_t ucDelayAborted;
    #endif

    /* error number*/
    #if ( configUSE_POSIX_ERRNO == 1 )
        int iTaskErrno;
    #endif
} tskTCB;
这里有必要跟linux进行区分下, 在linux中(从 Linux 内核的角度来说,其实它并没有线程的概念。Linux 把所有线程都当做进程来实现,它将线程和进程不加区分的统一到了 task_struct 中。线程仅仅被视为一个与其他进程共享某些资源的进程,而是否共享地址空间几乎是进程和 Linux 中所谓线程的唯一区别), 另外线程的栈是从进程地址空间mmap一段独有的地址(堆和栈之间有一段空间是用于mmap的), 另外在每一个进程的生命周期中,必然会通过到系统调用陷入内核。在执行系统调用陷入内核之后,这些内核代码所使用的栈并不是原先进程用户空间中的栈,而是一个单独内核空间的栈,这个称作进程内核栈。进程内核栈在进程创建的时候
内存管理

FreeRtos的堆区分配方法共有4种, 第一种, 我的理解就是一个数组, 从从未分配过的地方开始进行分配, 无法被释放,没有内存释放, 好处是可确定性, 且没有碎片。例子: 已经分配 ABC , 如果要分配D, 则从C后面分配D, 变成ABCD。 并且分配后都无法释放, 因为没有释放函数

第二种方法,已经被heap4.c取代了, 了解下就好。 有释放函数, 分配时, 从最开始的地址开始找, 找到一个空闲块可以容纳就放。 例子, 一开始ABD,后面B释放了, 变为A空格D, 这个要分配C, C比B小, 则从一开始找, 找到了B能放下, 则就变为AC(B-C)D 。 实现上, 就是用一个链表来记录空闲块, 一开始链表只有一个(块大小为分配的堆总大小), 对于AC(B-C)D , 则变为 两个元素的链表, B-C是一个, D后面又是一个。

第三种方法,其实就是调用malloc和free, 具体实现由编译器来实现, 这里仅仅只是封装了一下malloc和free,并确保线程安全

第四种方法,heap_4.c, 就是在free一块空闲内存时, 如果左和右相邻 有空闲块, 则把空闲块合为一个, 方法为将当前空想块插入链表时,查看左边和右边空闲块地址是否相邻,是的话,合并就可以了。

第五种方法, heap_5.c , 用的就是heap4.c的方法, 但是支持不相邻的堆区, 类似于支持多个堆区

FreeRTOS的调度分为三种, 抢占式时间片(就是谁优先级高谁执行,相同优先级则轮流执行), 抢占式无时间片(谁优先级高谁执行, 相同优先级则谁先谁执行),合作模式(非抢占, 高优先级不抢占,等低优先级执行完或者阻塞后再轮到高优先级)

软件定时器
  • FreeRTOS 通过一个prvTimerTask任务(也叫守护任务Daemon)管理软定时器,它是在启动调度器时自动创建的,为了满足用户定时需求。prvTimerTask任务会在其执行期间检查用户启动的时间周期溢出的定时器,并调用其回调函数。只有设置 FreeRTOSConfig.h 中的宏定义configUSE_TIMERS设置为1 ,将相关代码编译进来,才能正常使用软件定时器相关功能
  • 指定时间到达后要调用回调函数(也称超时函数),用户在回调函数中处理信息, 在回调函数中调用任何会阻塞任务的 API 函数
  • 硬件定时器的定时精度与系统时钟的周期有关,一般系统利用SysTick作为软件定时器的基础时钟,系统节拍配置为FreeRTOSConfig.h中的configTICK_RATE_HZ,默认是1000,那么系统的时钟节拍周期就为1ms
  • FreeRTOS 提供的软件定时器支持单次模式和周期模式

LiteOS、RT-thread、FreeRTOS、uCOS II的区别

一、freeRTOS比uCOS II优胜的地方:

1。内核ROM和耗费RAM都比uCOS 小,特别是RAM。 这在单片机里面是稀缺资源,uCOS至少要5K以上, 而freeOS用2~3K也可以跑的很好。

2。freeRTOS 可以用协程(Co-routine)(目前官方已经废弃了,不再维护),减少RAM消耗(共用STACK)。uCOS只能用任务(TASK,每个任务有一个独立的STACK)。

3。freeRTOS 可以有优先度一样的任务,这些任务是按时间片来轮流处理,uCOSII 每个任务都只有一个独一无二的优先级。因此,理论上讲,freeRTOS 可以管理超过64个任务,而uCOS只能管理64个。

4。freeRTOS 是在商业上免费应用。uCOS在商业上的应用是要付钱的。

二、freeRTOS 不如uCOS的地方:

1。比uSOS简单,任务间通讯freeRTOS只支持Queque, Semaphores, Mutex。 uCOS除这些外,还支持Flag, MailBox.

2。uCOS的支持比freeRTOS 多。除操作系统外,freeRTOS只支持TCPIP, uCOS则有大量外延支持,比如FS, USB, GUI, CAN等的支持

3。uCOS可靠性更高,而且耐优化,freeRTOS 在我设置成中等优化的时候,就会出问题。

参考资料

FreeRTOS从基础到高级 - 极术社区 - 连接开发者与智能计算生态 极术社区致力于连接开发者与智能计算生态。提供人工智能、物联网、嵌入式开发、SoC芯片设计、自动驾驶、服务器与云计算等智能计算技术领域的资讯、知识及教育培训、会议活动,与合作伙伴共建中国智能计算生态。 https://aijishu.com/blog/freertoscongjich

FreeRTOS 从入门到精通1–实时操作系统的前世今生 专栏前言笔者计划用一些篇幅介绍当前在嵌入式系统中比较流行的开源实时操作系统FreeRTOS及其在意法半导体 STM32平台,乐鑫科技ESP32平台和Arduino平台上的开发与运用。在当前工业4.0,智能制造,物联网IoT和工业物… https://zhuanlan.zhihu.com/p/90608412

FreeRTOS Plus TCP - A free thread aware TCP/IP stack for FreeRTOS FreeRTOS+TCP is a free and fully thread aware TCP/IP implementation with a Berkeley sockets style interface for FreeRTOS https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/index.html

任务管理 — FreeRTOS内核实现与应用开发实战指南—基于STM32 文档 https://doc.embedfire.com/rtos/freertos/zh/latest/application/tasks_management.html

FreeRTOS内核实现与应用开发实战指南

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值