Code Monkey home page Code Monkey logo

minirtos's Introduction

MiniRTOS

a MiniRTOS , a lot of comment help you understand

缘起

玩嵌入式三、四年了,我一直想搞明白rtos到底是怎样工作的,ucos freertos一直在工作中使用,书籍也看了不少,但总是觉得意犹未尽的样子,他们说的我都懂,每个部分也还算论述详尽,但我无法在头脑中架起一个rtos,或者说我闭上眼,却看不到rtos工作中的样子,这几个月难得清闲,我决定写(抄)一个自己的操作系统,开始时,无从下手,但写完任务切换后,就只剩惊喜了。 好吧,让我们开始吧。

如何用最简单的话描述rtos

试想一下,你有好几个while(1)循环,每个循环都在执行相对独立的功能,这样对于软件架构来说无疑是好事,但问题来了,我很难用裸机程序去控制这些东西,我懒得想何时执行跳转,何时回退,一旦出现问题怎么办。

操作系统就是帮你在多个while(1)循环中跳转的架构,她由中断驱动,在中断中执行相应代码,来帮助你跳转到一个while(1)循环中,这样工程师从繁琐的架构问题中解放出来,专心实现任务代码,我么可以说while(1)循环就是一个任务(task)。

void task1() 
{
    while(1)
    {
        any code --------------------------------> rtos 决定执行此处代码
    }
}




void task2()
{
    while(1)
    {
        any code
    }
}




void task3()
{
    while(1)
    {
        any code
    }
}

任务堆栈

(完全不精准的自问自答)
问:何谓栈?
答:栈就是一片内存区域。
问:堆栈究竟有何作用。
答:入栈保存调用子程序时,当前的寄存器状态。子程序调用完毕后,出栈用来恢复调用前的寄存器状态。
问:什么是寄存器状态?
答:无论用何种语言写程序,最终都被编译,成为寄存器之间的一个个操作。pc 寄存器保存当前程序的地址,lr 寄存器保存返回地址, sp寄存器保存堆栈地址......... 调用子程序前,这些寄存器的当前值被保存于栈中,从子程序返回后,这些寄存器又被由栈保存的值所覆盖。 如果我们能从栈中恢复所有寄存器的状态,这样,cpu自然而然回到了调用前的状态,也就顺利从子程序返回。

若想弄清什么是堆栈,最好多写几份汇编。尤其进行程序调用时,汇编自然便求助于堆栈这个概念。 好吧,你我写汇编的机会其实不多,如果想彻底搞定,强烈建议读王爽版《汇编语言》。

栈很重要,在rtos中我们需要为每个任务创建一个专属栈,任务被切换,栈就保存一次任务被切换前的状态,任务被恢复时,专属栈就会把最近一次切换前的状态,赋值给cpu寄存器,自然而然,cpu就又继续执行该任务的代码了。

专属栈作为一片内存区域,C语言用数组即可表示。

而这种切换又被称为为 context switch (上下文切换)。如下所示, context switch 本质上就是在各个任务堆栈间进行切换, 任务被挂起时,状态被保存在专属栈之中,任务被切换为运行状态前,context swicth 负责从专属栈中恢复上一次挂起时的状态。

void task1() 
{
    while(1)
    {
        any code ---------------Task1Stack[1000] <--------------------------
                                                                            |
    }                                                                       |
}                                                                           |
                                                                            |
                                                                            |
                                                                            |
                                                                            |
void task2()                                                                |
{                                                                           |
    while(1)                                                                |
    {                                                                       |
        any code----------------Task2Stack[1000] <-------------------------- context switch
    }                                                                       |
}                                                                           |
                                                                            |
                                                                            |
                                                                            |
                                                                            |
void task3()                                                                |
{                                                                           |
    while(1)                                                                |
    {                                                                       |
        any code---------------Task3Stack[1000] <--------------------------
    }
}

context switch(上下文切换)

最简单的上下文切换在systic(系统时钟中断)中写好即可,但cortex-m4 芯片为操作系统设计了很多feature,pend_sv中断就是其中之一。 目前主流操作系统都在pend_sv中断中实现context switch, 当然这并不意味着systic(系统时钟中断)就没作用了,实际上在我们的操作系统中,systic(时钟中断)主要实现任务调度器,当任务调度器决定进行切换时,便触发一个pend_sv. 回到任务中,任务本身被挂起时也会触发一个pend_sv,告诉系统,可以切换为下一个任务啦!

Task Block Control (任务块管理)

任务不单单要有专属堆栈,也许我们要给任务起个名字,或是指定任务的priority(优先级), 因此我们对每个任务都定义了一个任务管理块(TCB),便于管理。 TCB 在源文件中定义如下:

typedef  struct taskTaskControlBlock
{
    volatile StackType_t *pxTopOfStack;// 栈顶
    ListItem_t xStateListItem; /*the tcb is belong in an List*/
    StackType_t *pxStack;//栈边界
    char pcTaskName[configMAX_TASK_NAME_LEN];//任务名称
    TickType_t xTicksToDelay;//任务延时时间,已经弃用
    UBaseType_t uxPriority;// 任务优先级
}tskTCB;

尤其是要注意的其实是 xStateListItem , 这定义为链表的一个节点,也就是说,一个现代操作系统,其TCB其实是由一个个链表管理的。 当前MiniRTOS实现了两个链表 分别是 readyList 和 delayList。 假如任务需要延时,readyList会移除该任务TCB, delayList则会将该任务TCB增加于其之上。

在MiniRTOS种,链表以如下方式管理TCB。

readyList
----------------------
|     priority1      |---------TCB0---------------TCB2----------TCB3
----------------------
|     priority2      |
----------------------
|     priority3      |------TCB1---------------TCB4
----------------------
|     priority4      |
----------------------
|     priority5      |
----------------------
|     priority6      |
----------------------
|     priority7      |
----------------------
|     priority8      |--------TCB5
----------------------
|     priority9      |
----------------------


readyList本身作为一个数组,其索引就是任务优先级,相同优先级的任务被存储于同一链表下,任务产生延时请求后,TCB(任务控制块)会被暂时踢出readyList,随后则被delayList接收,在任务调度时,优先执行高优先级的任务,只有当高优先级任务执行完毕后(都处在延时状态),任务调度器才会执行相对更低优先级的任务。

read the fuck code

启动代码,是cubemx基于nucleo-f401自动生成的,不用管,不用修改。

list.c 完全照搬freertos , 只是用来做链表管理TCB之用,比较稳定,无实现的必要。 osKernel.s 已经完全弃用。 osKernel.c 主要定义了两个最重要的中断函数 pend_sv 和 systic systic 作为系统时钟中断,每次发生后都要运行系统调度器。 task.c 其实实现了该操作系统几乎所有主要功能, 诚然不够软件工程化,许多东西其实应该分开写在不同源文件中,但我希望文件结构越简单越好,便于理解,毕竟这只是一个业余系统。帮助你我一窥究竟而已。

硬件

真的只需要一块 stm32 neucleo-f401

minirtos's People

Contributors

123zmz123 avatar

Stargazers

悠 avatar  avatar  avatar

Watchers

James Cloos avatar  avatar

Forkers

xcj2012

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.