RT-Thread 内核基础学习笔记

/**
***来源:RT-Thread 在校大学生雄鹰计划
***文档:RT-Thread 内核基础
***内容:RT-Thread 内核基础学习笔记
**/
一、RT-Thread 内核介绍
1、RT-Thread内核架构
    1.1 内核处于硬件层之上
    1.2 内核部分包括内核库、实时内核
        内核库(kernel Library)有:kservice.h/kservice.c(提供内核服务的),这里的库仅用到一小部分C库函数
        实时内核有:object.c(对象管理),schedule.c(实时调度器),thread.c(线程管理),ipc(线程间通信)
        clock.c,timer.c(时钟、定时管理之类的),mem.c,memheap.c(内存管理的)
    1.3 上面实时内核部分的源代码均位于kernel-sample文件夹目录下
2、线程调度:
    2.1 线程是RT-thread操作系统中的最小的调度单位
    2.2 线程调度算法:基于优先级的全抢占式多线程调度算法
    2.3 哪些不能抢占:中断处理函数、调度器上锁部分的代码、禁止中断的代码
    2.4 STM32默认配置是32个线程优先级,0代表是最高优先级,最低优先级给空闲线程使用
    2.5 相同优先级的线程:支持创建,采用时间片的轮转调度算法进行调度,让每个线程运行相同时间
    2.6 调度器寻找最高优先级的线程(就绪状态)时,所经历的时间是恒定。
    2.7 线程数目只和硬件平台的具体内存有关
3、时钟管理
    3.1 时钟节拍是RT-thread操作系统中最小的时钟单位
    3.2 定时器的两类定时机制:
         3.2.1 单次触发定时器,启动只会触发一次定时器事件,会自动停止,不需手动操作
         3.2.2 周期触发定时器,启动会周期性触发定时器事件,不会自动停止,需用户手动     
         3.2.3 RT-Thread的定时器可以设置为HARD_TIMER模式或者SOFT_TIMER模式,此时需根据超时函数所处的上下文环境选择
4、线程间同步
    4.1 RT-Thread采用信号量、互斥量与事件实现线程间同步。
    4.2 线程通过对信号量、互斥量的获取与释放进行同步;
        互斥量采用优先级继承方式解决实时操作系统常见的优先级翻转。
5、线程间通信
    5.1 RT-Thread支持的通信机制:邮箱、消息队列等
    5.2 邮箱:邮件的固定长度为4个字节大小
        消息队列:不固定长度,将消息缓存在内存空间
    5.3 邮箱效率更高效    
    5.4 通信机制支持:线程按按优先级等待、按先进先出方式获取
6、内存管理
    6.1 RT-Thread支持:静态内存池管理、动态内存堆管理
    6.2 静态内存池:
        6.2.1 静态内存池可用:系统对内存块分配的时间是恒定的
        6.2.2 静态内存池为空:系统挂起申请内存块的线程、阻塞。当其它线程释放内存块到内存池,
              如果有挂起的待分配内存块的线程存在,则系统会将这个线程唤醒。
    6.3 动态内存堆管理:
        6.3.1 面向小内存系统的内存管理算法
        6.3.2 大内存系统的SLAB内存管理算法
        6.3.3 memheap:适用于系统含有多个地址可不连续的内存堆
7、I/O设备管理
    7.1 RT-Thread统一将PIN、I2C、SPI、USB、UART等作为外设设备通过设备注册完成。
       实现了按名称访问的设备管理子系统,可按照统一的API界面访问硬件设备。

二、RT-Thread 内启动流程
1、RT-Thread 内启动流程    
    1.1 从汇编启动代码开始,在project下的STM32_HAL库下的startup_stm32f103xe.s(不同芯片不同)
       这里完成了以下内容
       设置初始化栈(为调用C代码准备),设置初始PC,绑定异常向量表和中断ISR,配置时钟系统,跳转到C代码。
    1.2 进入位于components.c 源文件下面的int $Sub$$main(void)函数,调用 rtthread_startup()函数进行RT-Thread系统功能初始化,
       再调用$Super$$main 转到 main.c 中的main()函数执行。main()函数是RT-Thread的用户代码。。。完毕
        
2、rtthread_startup()函数启动代码分为四个部分
    2.1 初始化与系统相关的硬件
    2.2 初始化系统内核对象,例如定时器、调度器、信号
    2.3 创建main线程、在main线程中对各类模块依次进行初始化
    2.4 初始化定时器线程、空闲线程、并启动调度器
        
三、RT-Thread程序内存分布
1、MCU存储空间
    1.1 一般MCU包含的存储空间:片内Flash(相当于硬盘)与片内RAM(相当于内存)。
2、MDK编译后空间提示信息:
linking...
Program Size: Code=54872 RO-data=8656 RW-data=764 ZI-data=21812  
After Build - User command #1: fromelf --bin .\build\rtthread-stm32.axf --output rtthread.bin
".\build\rtthread-stm32.axf" - 0 Error(s), 0 Warning(s).
Build Time Elapsed:  00:00:26
    2.1 Program Size分解
        2.1.1 Code:代码段,存放程序的代码部分
        2.1.2 RO-data:只读数据段,存放程序中定义的常量。
        2.1.3 RW-data:读写数据段,存放初始化的全局变量。
        2.1.4 ZI-data:读写数据段,存放未初始化的全局变量及初始化为0的变量。
    2.2 .map文件
        编译完成后生成一个.map文件,位于/build/rtthread-stm32.map
        ==============================================================================

    Total RO  Size (Code + RO Data)                63528 (  62.04kB)      //表示程序占用Flash空间的大小
    Total RW  Size (RW Data + ZI Data)             22576 (  22.05kB)      //表示运行时占用的RAM的大小
    Total ROM Size (Code + RO Data + RW Data)      63676 (  62.18kB)      //表示烧写程序所占用的Flash的大小

       ==============================================================================
    2.3 程序烧写时文件:可执行镜像文件
         .bin .hex
         包括:Code + RO Data + RW Data +ZI-data(这里为0)
    2.4 STM32上电启动
        从Flash启动,启动之后搬运 RW-data搬运的内存RAM中,但不会搬运Code,CPU的执行代码从FLASH中读取。
    2.5 动态内存堆:
        可以从内存布局中看出动态内存堆未使用的RAM空间,应用程序申请和释放的内存块都来自该空间
        rt_uint8_t* msg_ptr;
        msg_ptr = (rt_uint8_t*)rt_malloc(128);
        rt_memset(msg_ptr,0,128);           //msg_ptr 指针指向的 128 字节内存空间位于动态内存堆空间中

四 RT-Thread自动初始化机制
  1、什么是自动初始化机制
     自动化初始化机制是指初始化函数不需要被显式调用,只需要在函数定义处通过宏定义的方式进行申明
  2、组件初始化相关宏接口
    2.1 “board init functions” 为所有通过 INIT_BOARD_EXPORT(fn) 申明的初始化函数。
    2.2 “pre-initialization functions” 为所有通过 INIT_PREV_EXPORT(fn) 申明的初始化函数。
    2.3 “device init functions” 为所有通过 INIT_DEVICE_EXPORT(fn) 申明的初始化函数。
    2.4 “components init functions”为所有通过 INIT_COMPONENT_EXPORT(fn) 申明的初始化函数。
    2.5 “enviroment init functions” 为所有通过 INIT_ENV_EXPORT(fn) 申明的初始化函数。
    2.6 “application init functions” 为所有通过 INIT_APP_EXPORT(fn) 申明的初始化函数。
    
    INIT_BOARD_EXPORT(fn) : 非常早期的初始化, 此时调度器还未启动
    INIT_PREV_EXPORT(fn):主要是用于纯软件的初始化、 没有太多依赖的函数
    INIT_DEVICE_EXPORT(fn):外设驱动初始化相关, 比如网卡设备
    INIT_COMPONENT_EXPORT(fn):组件初始化, 比如文件系统或者 LWIP
    INIT_ENV_EXPORT(fn):系统环境初始化, 比如挂载文件系统
    INIT_APP_EXPORT(fn):应用初始化, 比如 GUI 应用
    
五 RT-Thread 内核对象模型
1、静态对象和动态对象
   1.1、什么是内核对象
   RT-Thread内核对象是为系统对象(线程、信号量、邮箱)维护的一些数据结构,这些数据结构保存了与系统级对象相关的信息
   1.2、静态内核对象和动态内核对象
   静态内存对象:存放在RW段和ZI段,在系统启动后在程序中初始化;
   动态内核对象:从内存堆中创建,而后手工做初始化。
2、内核对象管理架构
   2.1 RT-Thread内核对象包括: 线程, 信号量, 互斥量, 事件, 邮箱, 消息队列和定时器, 内存池,
                               设备驱动等
   2.2 对象容器:存放着每类内核对象的信息,包括对象的类型,大小等
   2.3 对象链表: 对象容器为每类内核对象分配了一个链表,所有的内核对象都被链接到该链表上。
       比如,对象容器给线程分配一个对象链表,所有的线程,包括线程1,线程2...线程n都被链接到该链表上。
   2.4对象控制块:每一种内核对象除了基本结构,还有自己的扩展属性(私有属性)
       比如:对于线程控制块,在基本类对象基础上进行扩展,增加线程状态、优先级等属性。类似面向对象思想的派生,
             继承基本对象的属性并在此基础上扩展了与自己相关的属性。
       对象控制块定义在rtdef.h文件中
   
 3 、内核对象管理方式 
       一类对象由一个 rt_object_information (也是在rtdef.h中)结构体来管理, 每一个这类对象的具体实例都通过链表
       的形式挂接在 object_list 上。 而这一类对象的内存块尺寸由 object_size 标识出来(每一类对象的具
       体实例, 他们占有的内存块大小都是相同的) 
   
    3.1 初始化对象
        使用一个未初始化的静态对象前必须先对其进行初始化,初始化对象调用接口:
        void rt_object_init(struct rt_object* object ,
        enum rt_object_class_type type ,
        const char* name)
    3.2 脱离对象
        void rt_object_detach(rt_object_t object);
        
    3.3 分配对象
    面向对象内存块已有的情况下,而动态的对象则可以在需要时申请,不需要时释放出内存空间给其他应用使用
        rt_object_t rt_object_allocate(enum rt_object_class_typetype ,
        const char* name)
    
    //这里的type是动态的,不能是静态的
    3.4 删除对象
    对于一个动态对象, 当不再使用时, 可以调用如下接口删除对象, 并释放相应的系统资源:
    void rt_object_delete(rt_object_t object)
    
    3.5 辨别对象
    判断指定对象是否是系统对象(静态内核对象)
    rt_err_t rt_object_is_systemobject(rt_object_t object);
    
    
    

你可能感兴趣的:(嵌入式)