• 自己在上学的时候,搞过2年的单片机STM32编程,当时还记得一心想在上面跑个操作系统,UCOS操作系统,但是当时自己为什么要上这个操作系统,不是特别的清楚,后来自己在实际工作中,做了应用软件,感觉有了一些深刻的...

    自己在上学的时候,搞过2年的单片机STM32编程,当时还记得一心想在上面跑个操作系统,UCOS操作系统,但是当时自己为什么要上这个操作系统,不是特别的清楚,后来自己在实际工作中,做了应用软件,感觉有了一些深刻的体会。

    1.上操作系统有很多资源可以利用,系统的内存管理,线程进程的使用。文件系统的使用,图形系统的使用,这个是你在没有上操作系统的时候不能使用的。

    2.对于多任务的处理更加简单了,原来比方说我了个机器人的程序,用裸机进行的,我有5个传感器,我还有一个液晶屏,还有1个按键,我就得用定时器来进行,进一个定时器,我就做一件事,主程序里只能做一件事,而如果我上了操作系统,我在主进程里就可以开多个线程,来同时做这样的事,不用我自己去管理这种处理顺序,由操作系统替我进行管理。

    下面的总结来自于一个博客文章,比我总结的要到位的多,转载过来

    原文的链接如下:https://blog.csdn.net/nicekwell/article/details/17177221

    本文是2013年写的,后来整理成了系统文章,请访问 http://nicekwell.net/ 查看单片机编程系列文章。

    以下是2013年原文:

    以前对单片机编程做过一些零散的总结,近两个月又学习了一下操作系统,对操作系统原理和实现有了初步了解。所以就想到写一篇长文总结,系统总结一下单片机编程和操作系统原理,作为一个从单片机编程到操作系统的过渡文章。

    本文介绍了各种单片机编程结构,可以算是本人单片机编程的一点小小的经验。从这些单片机编程结构的不断变化中逐渐过渡到操作系统,并在s3c6410上一步一步实现一个小操作系统。

    一开始想要作为一个帖子分享的,但是内容太多,所以做成了一个PDF文件,看上去比较正规,调理也清晰一点,但是内容也就停留在帖子的水平。希望能给从单片机往操作系统过渡的童鞋带来一点帮助,正如我学操作系统时也看了别人的文章一样。

    文章的PDF文件可以从http://download.csdn.net/detail/nicekwell/6671759或者http://pan.baidu.com/s/1elUFv下载到。

    以下是文章的前言和目录。

     

     

    前言

    在2011年年初,笔者开始了单片机的学习,那时还是学生的我已经深深地被单片机吸引。之后几乎放弃了学校课程,把所有精力都放在单片机上,参加了一些比赛,并取得不错的成绩。

    在开始工作之后,笔者从事单片机开发。在工作期间的高强度编程下,尝试了多种单片机编程结构,对单片机各种结构的构建做了分析和总结,并深刻感受到操作系统产生的必要性,对操作系统的探索有着越来越强的欲望。

    在工作一段时间之后,笔者决定辞职。我不想凭仅有的那么一点单片机知识做一个嵌入式码农,我渴望学习新的知识,掌握更高级的理论……好吧~至少做一个高级一点的码农。而下一步的目标就是——linux。

    但是笔者并没有直接进行linux的学习,因为操作系统对我来说还是个新事物,我甚至不知道操作系统和单片机编程的最本质区别是什么,于是我想先搞清楚操作系统的本质原理之后再进行linux的学习。笔者是物理学专业的,并没有系统学习过操作系统的概念。事实上很多介绍操作系统的书籍也没有提到操作系统的底层实现,更没有介绍它与单片机编程之间的关系。正如我在辞职的这段时间学完uCOS之后,对操作系统内核构建有了了解,但是却仍然不知底层的任务切换是如何实现的。

    However,经过两个月的学习,笔者终于清楚了操作系统的基本原理,也深刻体会到操作系统和单片机各种编程结构的区别和联系。于是我想到把之前的单片机编程经验和近期对操作系统的学习结合到一起,写一个从单片机到操作系统过渡的文章。一方面对单片机编程结构做一个系统总结,另一方面对操作系统原理也进行一次整理。把操作系统和单片机编程整合到一个知识体系中去,以便日后接受更多的操作系统内核知识。

     

    本文分为两部分——“单片机编程篇”和“操作系统篇”。

    单片机编程篇主要介绍单片机的各种编程结构,及其实现方法。是在假设已经可以驱动单片机和各个模块的前提下,讨论如何整合和使用这些资源,以实现功能。在这一篇中,将会看到程序主体逐渐从主函数转移到定时器,并且明确这些变化的目的。最后还会接触到面向对象的程序设计方式,并体会这种方式带来的好处。

    操作系统篇将会介绍操作系统的最基本的任务切换原理,以及操作系统是如何实现在单片机编程中难以实现的功能的。并在arm平台上实现任务切换和简单的操作系统。至于更复杂的操作系统内核构建本文没有多说,各种常用的操作系统内核都有很多资料可以查阅,不过我会向大家推荐一本在网上公开但没有出版的书——《底层工作者手册之嵌入式操作系统内核》,这本书详细阐述了操作系统内核的构建方法。

     

     

    目录

    第一篇  单片机编程

    第1章 主函数顺序调用     2

    1.1 主函数顺序调用的一般结构... 2

    1.2 主函数顺序调用结构的特点... 2

    第2章 界面函数结构     4

    2.1 界面函数一般结构... 4

    2.2 更高的角度分析这种结构... 5

    第3章 定时器分配任务     8

    3.1 用界面函数构成的基础框架... 8

    3.2 结合定时器编程分析... 9

    3.3 任务分割... 11

    3.4 定时器分配任务程序结构总结... 12

    第4章 占用式与非占用式程序结构分析     14

    4.1 什么是占用式程序... 14

    4.2 占用式程序的缺点... 14

    4.3 对占用式程序的改造... 15

    4.4 改造的本质... 16

    4.5 非占用式程序结构的优势... 17

    4.6 非占用式程序的一般结构... 17

    4.7 吐槽... 18

    第5章 定时器执行任务     19

    5.1 定时器执行任务的程序结构... 19

    5.2 定时器里面任务函数的特点... 20

    5.3 过程任务的定时器化... 21

    5.4 定时器执行任务程序结构总结... 25

    5.5 我们追求的是什么... 25

    第6章 面向对象思想+事件驱动结构     27

    6.1 对象和事件... 27

    6.2 C语言对一个对象的封装... 28

    6.3 事件分配机制... 31

    6.4 系统层构建... 33

    6.5 库函数... 33

    第二篇  操作系统

    第7章 为什么要有操作系统     35

    第8章 任务切换的具体工作     36

    8.1 CPU工作原理... 36

    8.2 任务切换做的事... 38

    第9章 在s3c6410上实现任务切换     39

    9.1 了解s3c6410的寄存器... 39

    9.2 要用到的几条汇编指令... 41

    9.3 在s3c6410上实现任务切换... 45

    9.4 在s3c6410上实现简单操作系统... 46
    -------------------

     

    展开全文
  • 关于什么是微内核,这里就不赘述了,可参考之前的科普文章:华为“鸿蒙”所涉及的微内核到底是什么?一文带你认识微内核在开始今天的正文之前,我们先通过下面的视频,来更直观的感受下微内核操作系统...

    关于什么是微内核,这里就不赘述了,可参考之前的科普文章:

    华为“鸿蒙”所涉及的微内核到底是什么?一文带你认识微内核

    在开始今天的正文之前,我们先通过下面的视频,来更直观的感受下微内核操作系统:

    为什么要选择微内核操作系统?

    微内核操作系统,单从名字上来说可能被误解为操作系统非常小,但这并不是它本身的意义,而是指内核非常小,内核只保留一些基本的功能,一些系统服务,例如文件系统,网络协议栈等则放到了用户态。

    例如原来在宏内核操作系统中,用户应用程序是通过系统调用,陷入到内核中,然后再读取、访问文件。而在微内核操作系统中,则是用户应用程序通过发送IPC消息给到运行在用户态的文件系统服务来访问文件。

    针对于微内核操作系统,我们看到最近两三年有些新的发展:

    • Google在推进Fuchsia微内核操作系统

    • Intel在CPU的管理引擎中使用Minix微内核操作系统

    • 华为在推进鸿蒙分布式微内核操作系统

    可以看到相关厂商都一致性的选择了微内核架构或和微内核架构相关的技术方式。

    图片来源网络

    这个背后的可能原因会有哪些?

    • 原⽣进程沙箱,解决应⽤安全和分发问题 -- Google Fuchsia(⿊客)

    • 稳定的驱动接⼝,硬件⼚商可独⽴维护硬件驱动 -- Google Fuchsia(硬件)

    • 系统模块化,分层,设备⼚商可以灵活定制专有系统 -- Google Fuchsia(友商)

    • Linux越来越庞大,更多的为服务器进行优化,针对低性能、低资源设备显得臃肿;

    • 可以提供网络,文件,web服务等的功能轻型系统;-- MINIX on Intel

    以上内容:部分是许中兴博士的Fuchsia一文的摘录,部分则出自网络上一些文章)

    2019年年初,微内核也在RT-Thread提上了日程,同年4月便正式开始推进这件事情。还有一个促使我们决定的重要原因是,我们从中看到一些市场需求:

    • 快速启动,终端上的系统可以在500ms内完成启动并就绪;

    • 安全方面的考虑,当应用出问题时不会影响到其他无关功能;

    • 在进行系统升级时,不类似传统RTOS需要把整个固件进行升级;

    • 当要在ARM11、Cortex-A等带MMU的处理器上跑一套操作系统时,RT-Thread已经不那么能够得到适应:整体一起开发,代码维护相对困难;升级时也需要对系统一起进行升级。

    RT-Thread Smart 混合微内核

    RT-Thread Smart 之所以采用混合微内核架构,更多是从工程、实用层面考虑如何有效的解决需求:

    • 系统启动需要足够快,功能就绪时<500ms

    在初始启动时,时间会花很大一部分在系统加载上。传统的方式,都是整个映像程序一起加载。新的系统则只需要加载一个非常小的系统,然后其他应用部分按需加载,同时保持整体资源占用足够小;

    • 应用崩溃时不再影响到内核、系统其他无关功能

    每个应用都是地址隔离的,拥有自己的独立地址空间。当应用执行出错,或访问错误地址时,应用程序会core dump,而不会影响到其他应用,系统内核;

    • 在工程引入新的特性时,对原有的功能不影响

    继续沿用目前的RT-Thread整体内核代码,在原有基础上增加、完善lwP(轻型进程)功能,保留原有的实时性和小巧的特点。

    RT-Thread混合微内核架构

    从架构图可以看出内核的功能相对基本,一些系统服务则挪到了用户态,例如elmFATKit - FAT的文件系统,lwIPKit - lwIP轻型TCP/IP协议栈等,而在用户态则使用嵌入式系统中常用的musl libc库:一个轻型,但相对完整的libc实现。不过另外一点,这些系列的用户态系统服务,如果需要追求高性能,也可以在menuconfig中定制这个功能组件继续在 内核中保留,这样可以达到最佳的性能。

    通过混合微内核改造RT-Thread操作系统后,RT-Thread将成为最适合物联网产业的IoT OS之一,因为它可以完美覆盖小资源场景的MCU用于简单控制<使用RT-Thread nano版本>;中等规模的IoT节点<使用RT-Thread宏内核版本>;功能丰富的智能设备<使用RT-Thread混合微内核版本,也称之为RT-Thread Smart>。

    报名测试条件及内容

    上面已经对RT-Thread混合微内核操作系统进行了简单的介绍,还有许多没有公布的细节。如果你有兴趣了解,欢迎报名RT-Thread混合微内核系统内测,从更全面的方位来了解RT-Thread Smart。

    在参与测试前,先说明下参与的条件:名额有限,希望您可以认真对待报名表中的每一个问题

    1. 希望是从事嵌入式系统终端开发的行业,具备开发经验;

    2. 希望有一定的Linux开发基础,前期一些开发环境可能是在Linux下;

    3. 对于参与的同学,我们会提供一份柿饼M7的开发板,同时根据情况收取一定的押金,后续开发板归还后返回押金;

    以下这个就是柿饼M7的开发板:

    柿饼M7开发板包括:

    • 全志R11处理器,1.2GHz ARM Cortex-A7,64MB DRAM

    • 板载16MB SPI NorFlash

    • 支持AP6181 WiFi

    • USB接口(用于USB Device连接PC),USB转串口TTL

    • 40/50pin标准RGB屏接口

    • 6线Touch电容触摸屏接口

    • 音频Speaker接口,MIC模拟麦克风

    • MIPI/DVP camera接口(目前还未包括驱动)

    对于参与测试的同学,需要做些什么:

    1. 提供一份使用的测试报告,反馈混合微内核使用上的最直观感受;

    2. 在上面进行一定的开发,反馈开发层面哪里不足、需要改进;

    3. 希望可以有1 - 2个月的时间来和我们持续的沟通和反馈;

    快来参与内测吧

    报名截止时间:5月30号

    1.7位专家汇集| 不可不听的线上嵌入式技术讲座在这里!

    2.树莓派 4:全新的背后,依然是优秀的表现吗?

    3.对国内半导体代工厂“保留无限追溯”,里面有误读!

    4.既想马儿一直跑又想马儿不吃草,这款Wi-Fi 芯片帮你实现了!

    5.单片机里面的CPU使用率是什么鬼?

    6.学Linux驱动:应先了解总线驱动模型!

    免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或者删除内容。

    展开全文
  • 如何写一个微内核

    2018-04-12 11:56:32
    有时常关注我博客的朋友知道,去年我自己开发过一个很简单的微内核 Totoro,目前已经暂时停止更新。从开发到能真正运行花了一两个月的时间,当然都是我在业余时间做的啦。还记得当时那种兴奋的心情,可能跟 Linux 的...

    原文:https://io-lab.net/archives/218

    导言

    有时常关注我博客的朋友知道,去年我自己开发过一个很简单的微内核 Totoro,目前已经暂时停止更新。从开发到能真正运行花了一两个月的时间,当然都是我在业余时间做的啦。还记得当时那种兴奋的心情,可能跟 Linux 的最初开发者 Linus 差不多,有兴趣可以看这篇文章 Linux - a free unix-386 kernel 。

    当然了,水平毕竟不是一个层次的。不过今天,我想把如何开发这样一个简单的内核给记录下来,一来是让有兴趣的后来者可以很快的摸到门路,二来是做一个阶段性的总结,再来就是看看自己还有没有兴致继续把它做得更好,毕竟现在漏洞百出,也不可能给别人拿去用。总的来说,出来做了三年的软件开发,没做过什么高端的有难度的东西,这样一个作品让我自己还是比较开心的!

    关于单线程

    从单片机(又称单板机)玩过来的同学应该知道,我们刚开始写代码的时候,几乎都是裸奔在处理器上的。写个流水灯,点亮数码管,高端点的来个串口打印。这对刚接触的同学其实就有很多东西可以学了。但是人也总不会一直停步不前,写了太多的单线程代码的菜鸟开始思考,多线程到底多了什么了呀?说到这其实我很想笑,假如你去问一问那些入门语言是 Java,Python 的同学,他们一定会说,多线程有什么了不起啊!对呀,对这些这些高级语言来说,多线程?开玩笑,随便调个接口,要几十个线程,甚至几百个,分分钟给你造好了。在这些人眼里,这个东西,没什么了不起。但对于出身即低端又比较吝啬的嵌入式的同学们来说,这个多线程词汇,却魔咒般的充满了太多的神秘感。那么多线程到底指的是什么?我们不去讨论太复杂的东西,不去讨论进程空间,虚拟内存等等高端神秘的词汇。我们只关注上下文环境。这个对于容易满足的嵌入式开发者来说,以及很知足了。时常感慨,是不是嵌入式开发做久了,人也会对自己变吝啬。

    上下文环境

    上下文(Context)环境,指的是这个线程运行时的一些状态,比如局部变量的值,寄存器里保存的值,比如,PC 指针指向那里,代表程序即将运行到那里,SP 指针,记录了调用信息,LR 记录了回去的路(返回地址)等等。那么要实现这个多线程我们需要做些什么?

    保存上下文。我们在做线程调度的时候,将当前线程的上下文环境保存在那个线程申请的“栈”内存里(其实就是一个大数组)。然后通过一系列的底层操作,将要被调度的线程唤出来。其实也就是把之前保存的上下文从内存里读到寄存器上啦,只不过这个过程需要一些技巧,我们会在代码解析里面讲到。其实多线程就是这样的啦,那么我的这篇文章是不是该完结了?不尽然,我们要做到微内核的基本功能,那还得有调度器呀。

    傻逼式调度器

    我们要实现这样一个调度器。对于平级线程,也就是优先级一样的应用线程,我们会去分片(Time-sharing)执行它们。对于高优先级应用线程,我们会义无反顾的一直执行它,直到它愿意自己挂起。我觉得这是最自然的调度器,因为优先级既然高,那么也就得优先执行。当然,也是很傻逼的调度器啦。我们现在的目标是,保持一切尽量的简单。这样才有兴趣继续干下去嘛。这样约定好了以后,我们开辟了两个队列,一个用于保存处于准备态的线程,一个用于保存挂起的线程。而当前运行的进程会由一个 current 任务结构体指针来标记。所以一个任务执行完之后会有两种状态,一个是挂起,一个是再次处于准备状态。这样我们就需要一个链表接口模块。

    基础数据结构

    我们用单链表结构来实现这两个队列。

    include/totoro/taskq.h

    struct tasklist {

        struct ttr_tcb *tcb;
    
        struct tasklist *next;
    

    };

    实现单链表的几个接口:

    static struct tasklist *migrate(struct ttr_tcb *tcb, struct tasklist **src, struct tasklist **dst);

    这个接口做任务迁移,将挂起任务迁移到准备态或者反过来。注意到,我们采用了二级指针来管理这个单链表,这样可以省掉很多不必要的条件判断。

    static void insert(struct tasklist *node, struct tasklist **list);

    这个接口用于插入任务之用。

    extern ttr_err_t task_enqueue(struct ttr_tcb *tcb);

    这个接口用于注册任务之用。

    extern struct ttr_tcb *task_next(void);

    这个接口用于提取下一个要运行的任务。

    extern void task_init(void);

    猜猜这是干嘛的。

    任务结构

    include/totoro/taskq.h

    struct ttr_tcb
    {

        /* stack pointer */
    
        volatile void *sp;
    
        /* current state of the thread */
    
        uint8_t stat;
    
        /* priority of the thread */
    
        uint8_t prior;
    
        /* thread's stack size */
    
        uint32_t stack_size;
    
        /* thread's stack */
    
        void *stack;
    
        /* thread function */
    
        void (*ttr_thread)(void);
    

    };

    看到这里,聪明的同学一定能看到了,我都帮你们注释好了每个成员的作用,因此也不赘述,大家如果看了代码应该不难发现,大部分关键的地方都 加上了注释。

    任务优先级

    include/totoro/taskq.h

    define TASK_HIGHEST_PRIORITY ( 0 )

    define TASK_LOWEST_PRIORITY (255)

    define TASK_DEFAULT_PRIORITY ( 1 )

    我们提供给应用程序一个默认优先级,这样用户就不需要做太多纠结了。

    任务状态

    include/totoro/taskq.h

    define TASK_SUSPENDED ( 0 )

    define TASK_READY ( 1 )

    define TASK_RUNNING ( 2 )

    任务内存申请

    include/totoro/taskq.h

    define MALLOC_TASK_NODE(node, _tcb) \

        ((node = (struct tasklist *)malloc(sizeof(struct tasklist))), \
    
        (!!node ? (node->tcb = _tcb, TTR_ERR_OK) : TTR_ERR_MEM))
    

    define DELETE_TASK_NODE(node) \

        if (node) { \
    
               free(node); \
    
               node->tcb = NULL; \
    
               node = NULL; \
    
        }
    

    对的,我们实现了两个漂亮的宏来做任务结构体内存申请和释放,史上最小的 MM。

    线程切换

    是不是很紧张,终于来到破解魔咒的关键点。COME WITH ME!

    arch/cortex-m0/gcc/port.S

       cpsid i
       mrs r0, psp
       subs r0, #32
       stmia r0!, {r4 - r11}
       subs r0, #32
    
       ldr r2, =ttr_running_task
       ldr r1, [r2]
       str r0, [r1]
    
       ldr r1, =ttr_running_task
       ldr r2, =ttr_next_task
       ldr r3, [r2]
       str r3, [r1]
    
       ldr r2, =ttr_next_task
       ldr r1, [r2]
       ldr r0, [r1]
    
       ldmia r0!, {r4 - r11}
       msr psp, r0
    
       ldr r0, =0xfffffffd
       cpsie i
       bx r0
    

    这份代码是从 GCC 分支拷贝下来的,没有一行注释,大家可以去看 ARM 分支里面的同一个文件,写全了注释,我这个人很懒,不喜欢写太多注释。 以换行为分界,这段代码有六段。

    1,关全局中断,保存程序栈指针,调整栈指针,保存当前线程的寄存器值;

    2,保存当前运行线程的任务指针;

    3,加载即将运行线程的任务指针;

    4,加载即将运行线程的上下文环境;

    5,恢复程序栈指针;

    6,开全局中断,返回调用处;

    驱动接口

    drivers/clock, drivers/gpio, drivers/serial

    Totoro 提供了 Clock, GPIO, Serial 底层驱动的框架与实现。参见代码。

    信号量

    等等,一个内核最基本的东西是什么?很明显,它需要线程切换,肯定也要一个线程同步机制啦。我们根据 POSIX 规范的接口实现了这样一个模块。

    include/totoro/sem.h

    extern int sem_signal(sem_t *sem);

    extern int sem_wait(sem_t *sem, uint32_t timeout);

    互斥锁

    include/totoro/simplelock.h

    define simplelock_get()

    define simplelock_put()

    Softirq

    include/totoro/softirq.h

    kernel/softirq.c

    当然了,为了提供 Bottom Half 机制,用于提供用户定时任务,耗时任务,中断 tasklet 延迟处理我们加入了软中断模块。

    3 Test Cases

    test/ab.c

    test/sem.c

    test/sirq.c

    大家看名字就知道干嘛用的。我们也不再贴代码了,要玩就自己去看了。好的,整个微内核玩下来就是这么个流程。说简单也很简单,但要一步一步自 己做起来,还是需要花时间,耐心。我们现在只注重优雅的实现,简单,漂亮。

    感悟

    终于来到了个人时间了,大家有这样的感觉吗,看自己以前写的代码,竟然感觉很美妙。特别是用 plain text 模式浏览的时候,我仿佛在查阅某 上世纪大神写出来的神作。呵呵,开个玩笑。好了,这篇文章差不多就这样了,未来会怎样,我暂时也没什么想法。

    展开全文
  • 在我看来,单片机处理器、dsp都可以称作是cpu,只是它们的侧重点有所不同罢了。具体来说,传统意义上的单片机更偏重于嵌入式的计算,比如说我们经常使用的51、avr、arm芯片中不仅仅含有了运算和控制功能,它还...

    【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】


        cpu是数字处理系统中的一个重要环节。在我看来,单片机、微处理器、dsp都可以称作是cpu,只是它们的侧重点有所不同罢了。具体来说,传统意义上的单片机更偏重于嵌入式的计算,比如说我们经常使用的51、avr、arm芯片中不仅仅含有了运算和控制功能,它还涵盖了定时器、串口、并口、usb、i2c总线等外部资源。dsp呢,cpu一般只是作为dsp的一个核存在,它通常还会包含另外一个核,专门用于数字信号的处理工作。而微处理器,也就是我们经常说的pc上的处理器,它的工作比较单一,专注于计算和控制功能的处理,因此一般来说在这方面的性能上面,单片机和dsp都是不能和它相比的,有了南桥芯片和北桥芯片的帮助,pc的微处理器就可以专注于自己的本职工作了,效率上面也会有一个很大的提高。


        对于朋友们来说,生活中遇到的最多的cpu其实是x86的cpu。当然,如果有哪位朋友喜欢apple之类的玩具,也会知道一些arm的相关事情。剩下的就是一些专用领域的cpu了,比如说在通信行业用到的比较多的powerpc芯片,在高性能服务器用的到的sun sparc芯片,在科学计算领域使用到的mips芯片。所以,无论遇到什么芯片,对于应用层开发的朋友都是一样的,只是在一些小地方需要还有一些注意的地方。比如说,

    (1)数据的对齐方式

    (2)数据的字节序问题

    (3)函数参数的压栈问题

    (4)cpu的乱序执行问题

    (5)cpu中cache和内存一致性的问题


        当然,如果我们所要思考只是简单的应用层设计,考虑到这些内容本身已经实属不易了。然而,我们考虑的是如何设计嵌入式操作系统的问题,所以接下来还要看看一般cpu下面都包含了那些内容。这样,只要熟练掌握了一款cpu的设计和实现,对其他cpu的知识也会触类旁通了。


        任何一款cpu,不管是完成的功能是什么样的,通常都会有这样一些基本设计:

    (1)寄存器

        堆栈寄存器    

        pc寄存器

        状态寄存器

        运算寄存器

        寄存器是cpu内部的基本资源。不管cpu的代码执行到什么时候,这些资源都是共享的,所以在cpu发生中断、函数调用、线程切换的时候,都需要对这些寄存器进行保护,常用的基本措施就是把把它们保存到临时堆栈当中去。堆栈寄存器记录了当前堆栈使用到了什么地方,pc寄存器则记录当前代码跑到了什么地方,下一条指令在什么地方等。状态寄存器则保存了当前cpu的执行情况,包括计算有没有溢出、中断是关还是开、有没有o除数异常等等。至于运算寄存器就因cpu而异了,有的cpu寄存器比较少,比如说x86的寄存器;有的cpu寄存器就比较多,比如说powerpc。运算寄存器的用途很多,比如说数据访问、计算、移位、返回计算结果等等。


    (2)指令集

        寻址指令

        数学运算指令

        逻辑运算指令

        软中断指令

        跳转指令

        远程调用指令

        io访问指令

        栈操作指令

        指令集在某种程度上直接决定了某一种cpu的类型。就像intel和amd生产的cpu虽然有差别,但是它们的cpu使用的都是x86的指令集,而marwell、samsung和高通生产的cpu当然也不同,但是它们的指令集都是arm指令集。所以,如果软件在marwell上跑,一般来说也可以在Samsung上跑起来。指令集很复杂,内容很多。但是通常来说,上面这些内容都是cpu所必须要完成的几种指令。当然重中之重的还是中断和栈处理指令。


    (3)中断、异常处理机制

        不管是什么cpu,中断部分的内容都是少不了的。试想一想,如果一颗cpu只知道不停地运行,那么它的执行效率实际上是很低的。拥有了中断的cpu不仅使得cpu可以和更多的外设io打交道,还能极大地提高自身运行的效率。不同的cpu处理中断的方法其实都差不多,在整个cpu的地址空间里面,通常在低地址区域会有一张中断向量表,表中每一项记录了每一个中断对应的处理函数。所以,只要中断发生时,cpu就会首先将下一条pc地址压入堆栈,然后跳转到中断向量表中对应的中断地址处执行的相应的处理函数。这个过程是cpu自动完成的,不需要我们关心。这样对我们来说,它和cpu中的函数调用其实没有什么区别。等待中断处理结束后,我们使用ret指令返回到之前压入的那个ip地址处,继续下面的代码。整个过程就好像中断根本没有发生过一样。


        所以,对于cpu的了解其实主要就是对寄存器、指令集和中断的了解。有了对中断和堆栈的深入理解,其实也就没有什么困难的了。在这里我们大家可以考虑一个问题,如何在Windows或者linux下仿真中断完成我们的操作系统开发呢?大家可以自己先思考一下,我们会在随后的博客中继续介绍。整篇文章,我们没有介绍编码的相关内容,其实只要把这里的基本概念弄清楚了,剩下来其实就是一些流程性的工作了。在软件开发中,设计其实是最难的,剩下的才是开发和调试。



    展开全文
  • STM32F103RCT6是一种嵌入式-控制器的集成电路(IC),32位 Cortex-M3内核处理器,速度是72MHz,程序存储器容量是256KB,程序存储器类型是FLASH,RAM容量是48K,封装LQFP64。 STM32单片机命名规则: ...
    STM32F103RCT6
    STM32F103RCT6是一种嵌入式-微控制器的集成电路(IC),32位 Cortex-M3内核处理器,速度是72MHz,程序存储器容量是256KB,程序存储器类型是FLASH,RAM容量是48K,封装LQFP64。

     

     
     
    STM32单片机命名规则:

     
     
    STM32单片机最小系统:
    所谓单片机最小系统,就是让单片机能够正常运行,最少且必须的器件所组成的系统。
    单片机最小系统上电之后,单片机可以正常复位,下载程序,除此之外没有其他任何功能。
    在最小系统保证正确的基础上,可以依次添加其他功能模块或器件,使之单片机具有实际功能。
     
     
    STM32单片机最小系统包括一个复位电路和一个时钟电路。如下图1所示。
    图中复位电路使用的是上电复位电路,STM32单片机NRST引脚输入低电平,则发生复位。
    标题图1  STM32F103单片机最小系统
     
     
     
    电源引脚:
     
    VDD是单片机的数字电源正极,VSS是数字电源负极,共有5个VDD引脚,5个VSS引脚。VDDA是单片机的模拟电源正极,负责给内部的ADC、DAC模块供电,VSSA是模拟电源负极。
     
     
    还有一个电源引脚,就是VBAT,BAT就是Battery(电池),这个引脚用来连接电池的正极的。STM32带RTC功能(实时时钟),所以有VBAT引脚。
     
     
    原理图上预留了一个CR1220纽扣锂电池,当主电源供电存在的情况下,由系统中的VCC3.3给VBAT供电;
    当主电源断电之后,由CR1220纽扣电池给STM32自带的RTC模块供电,从而能够保证实时时钟模块在主电源掉电的情况下还能够正常工作。
     
     
    但是这样设计的话,这里有一个矛盾需要解决。如果VBAT引脚直接与VCC3.3和CR1220连接的话,会存在下面问题:
    1、当电池电压高于3.3V,电池就会输出电流到AMS1117,使得芯片发烫,还会很快消耗电池电量。
    2、如果电池电压低于3.3V,AMS1117产生的3.3V,就会给电池充电,而这种CR1220电池是不能够充电的。
     
    为了解决上面问题,我们将VBAT引脚的供电电路设计如下:
     

     
     
    D1防止电池的电流流向AMS1117,D2防止AMS1117产生的3.3V流向电池。
    之所以这样设计,用的就是“二极管的单向导通性”。
     
    正常产品设计的时候,每个电源引脚旁边,最好放置一个0.1uF的电容滤波,用来滤除电源的噪声杂波。
     
     
    复位引脚NRST
     
    复位就是重启。STM32复位引脚是低电平复位,正常工作状态,复位引脚是高电平。
     

     
      单片机的置位和复位,其目的都是为了把电路初始化到一个确定状态。复位时在单片机内部单片机是将存储设备和一些寄存器装入生产厂商预设的一个值。一般来说,单片机复位电路的作用是把一个状态机初始化到一个空的状态。
     
    单片机实现上电复位的原理:
    在复位引脚NRST上外接电容和电阻。
     
    当复位电平(低电平)持续两个机器周期以上时复位有效,系统上电后由于电容的充电,会保持一段时间的低电平来使单片机复位。
     
    刚上电,电容两端电压为0,即低电平复位,RC电路有个充电曲线(即电容两端电压变化曲线),单片机识别外部电平有一个连接电压,保证rc电路电容电压充到单片机临界电压的时间在两个机器周期以上就能满足单片机复位条件;
     
    当3.3V电源加到VCC3.3时,RC电路导通,NRST与地的电位差为电容与地的电位差。NRST与地的电位差只有电容充电完毕后才会达到3.3V,所以在电容的充电过程中,给芯片引脚的信号都是低电平。根据RC电路充电方程式V(t)=U+A*e-(t/RC),只要合理的选择好R跟C的值就可以保证充电时间大于芯片复位所要求的时间。我们一般R选择10K电阻,C选择0.1uF电容。
     
     
    晶振引脚
     
    STM32有两组晶振,一组用来给单片机提供主时钟(5:OSC_IN,6:OSC_OUT),主时钟晶振使用8MHz的晶振(为了程序内部倍频方便,一般选用8MHz的晶振)。
     
    一组用来给RTC提供时钟(3:OSC32_IN,4:OSC32_OUT),RTC时钟晶振,需要连接32.768K的晶振,关于为什么要用32.768KHz,大家可以去百度了解一下哈。
     
    实际应用中,如果不用RTC功能的话,RTC的晶振不必连接。
     
    STM32的时钟电路又分为内时钟和外时钟两种模式。
     
    外部时钟是在OSC_IN和OSC_OUT之间加上一个晶振,单片机内部振荡器便能产生自激震荡,产生时钟信号,在晶振的两侧加上20~30pF的瓷片电容起到了微调时钟频率的作用,让频率更加稳定。
     
    内部时钟是STM32内部有时钟产生,所以如果不用外部晶振的话,也可以不用连接,内部时钟是用芯片内部振荡电路,精度不高,温飘也较大,不需要外部振荡器件。
     
     

     
     
    BOOT引脚
     
    STM32有两个BOOT引脚,分别是BOOT0和BOOT1,这两个引脚的高低电平,决定了单片机的启动方式和运行方式。
     
     

    第一种(BOOT1=X,BOOT0=0)启动方式是最常用的用户FLASH启动。默认启动方式
    第二种(BOOT1=0,BOOT0=1)启动方式是系统存储器启动方式。STM32中自带的BootLoader( 就是通常说的ISP程序)就是在这种启动方式中,如果出现程序硬件错误的话可以切换BOOT0=1到该模式下重新烧写Flash即可恢复正常。 BootLoader所在区域的内容在芯片出厂后没有人能够修改或擦除,即它是一个ROM区。
    第三种(BOOT1=1,BOOT0=1)启动方式是STM32内嵌的SRAM启动。该模式用于调试。
     
     

    一般我都是将BOOT0和BOOT1接地。
     
     
    上面就是最小系统的全部内容,当然只有上面的部分还不行,一般最小系统还包括下面几部分:
     
     
    电源电路:
    因为STM32单片机一般都是3.3V供电,而生活中一般常见的都是5V电源(电脑的USB口,手机充电器,移动电源...),所以一般使用AMS1117-3.3V 稳压电源芯片将5V降压为3.3V,该芯片的封装一般为SOT223。

     
    下载电路:
    当然除了上面几部分以为,还需要一个下载电路,STM32的下载方式有如下几种:
    (1)串口下载:使用串口下载需要单片机内有相应的程序的支持,而系统存储器中就放了这么一段程序,由ST 在生产线上写入,用于通过可用的串行接口对闪存存储器进行重新编程。(在系统存储器启动模式下下载,因为在厂家提供的BootLoader中,提供了串口下载程序的固件,可以通过这个BootLoader将程序下载到系统的Flash中。程序烧录在FLASH)。
    注意:使用此种方式需要BOOT0=1,即需要有外部电路支持才可以实现串口下载。
     
    (2)JLINK或者STLINK下载
    一般我们使用JTAG或者SWD模式下载程序。
     
    推荐使用SWD模式下载,SWD模式只需要三个引脚(GND、SWCLK、SWDIO)即可实现程序的下载功能。
     

     
     

    从六月份开始,每个月会制作一个毕业设计难度的DIY作品,

    前期作品以模块组合的形式搭建,降低门槛,方便大家一起跟着做;

    DIY过程只在微信公众号中分享,大家没关注的,赶紧关注哈。

     

    每个月时间大致安排:

    上个月25号,公布DIY作品名称;

    每月1日公布作品功能点及所需要的功能模块链接;

    每月10日前绘制完模块配合的线路板;

    每月15日之前硬件搭建完毕,之后按模块撰写代码,调试,随时公众号更新进展;

    每月月底开源整个作品的源码和PCB工程文件。

     

    题目选取原则:

    公众号每个月20日发起投票,25号截止,票数最多的作为下个月的DIY内容;

    投票的备选项大家可以后台留言给我,我会选出五种留言最多的作为选项;

    每个月的DIY内容尽量与上个月分享的文章有一定的相关度,起到温故知新的作用。

     

    有什么想法或者建议,留言给我哈。


    喜欢请关注微信公众号:嵌入式从0到1

    公众号内容面向在校大学生、电子爱好者、嵌入式工程师;

    涉及电子制作、模块使用、单片机技术、物联网相关知识分享;

    软硬件全栈工程师,玩模块,学硬件,带你从0走到1

    展开全文
  • 全平台通用微内核

    2019-09-02 12:17:36
    下载地址: github: ...gitee: ...整个系统仍然是一个文件,源码压缩包4MB以内 支持众多先进特性: 带用户手册,适合进阶用户。...目前支持的是STM32单片机,以及将其他操作系统作为虚拟机来进行运行的能力。 整个系
  • 单片机内核分类

    2019-12-24 00:34:54
    51单片机由一个IP核和片上外设组成,IP核就是上图中的CPU,片上外设就是上图中的:时钟电路、SFR和RAM、ROM、定时/计数器、并行I/O口、串行I/O口、中断系统。IP核跟外设之间由系统总线连接,且是8bit的,速度有限。 ...
  • 单片机中嵌入操作系统的利弊早在20世纪60年代,就已经有人开始研究和开发嵌入式操作系统。但直到最近,它才在国内被越来越多的提及,在通信、电子、自动化等需要实时处理的领域所日益显现的重要性吸引了人们越来越...
  • 单片机由中央处理单元(CPU...单片机发展的过程中,出现过很多的中央处理单元设计,俗称CPU内核,例如Zilog的Z80内核、Intel的8051内核、Microchip的PIC16、18、dsPIC、PIC32内核、Motorola的68000内核、Atmel的AVR...
  • 嵌入式操作系统内核原理和开发(开篇) 操作系统是很多人每天必须打交道的东西,因为在你打开电脑的一刹那,随着bios自检结束,你的windows系统已经开始运行了。如果问大家操作系统是什么?可能有的人会说操作...
  • 操作系统内核Hack:(二)底层编程基础在《操作系统内核Hack:(一)实验环境搭建》中,我们看到了一个迷你操作系统引导程序。尽管只有不到二十行,然而要完全看懂还是需要不少底层软硬件知识的。本文的目的就是跟大家...
  • 单片机中嵌入操作系统的利弊摘要:近年来,在单片机系统中嵌入操作系统已经成为人们越来越关心的一个话题。本文通过对一种源码公开的单片机嵌入式实时操作系统μC/OS-II为例,阐述了在单片机中使用该嵌入式操作...
  • 核态:Kernel Mode, CPU运行操作系统程序时; 管态:Supervisor Mode, 不能修改CPU状态; 用户态:User Mode, 不能直接使用系统资源,并且只能访问用户程序所在的存储空间。 特权指令: 核态可以使用所有指令: ...
  • 单片机和ARM的区别

    2016-03-12 21:43:58
    引入了操作系统。为什么引入操作系统?有什么好处嘛? 1)方便。主要体现在后期的开发,即在操作系统上直接开发应用程序。不像单片机一样一切都要重新写。前期的操作系统移植工作,还是要专业人士来做。 2)安全。...
  • 嵌入式操作系统是ARMCPU的软件基础,从8位/16位单片机发展到以ARMCPU核为代表的32位嵌入式处理器,嵌入式操作系统将替代传统的由手工编制的监控程序或调度程序,成为重要的基础组件。更重要的是嵌入式操作系统对应用...
  • 早在20世纪60年代,就已经有人开始研究和开发嵌入式操作系统。但直到最近,它才在国内被越来越多的提及,在通信、电子、自动化等需要实时处理的领域所日益显现的重要性吸引了人们越来越多的注意力。但是,人们所谈论...
  • 前言 操作系统是物联网时代的战略制高点,今天 PC 和手机时代的操作系统霸主未必能在物联网时代延续霸业。操作系统产业的规律是,当垄断已经形成,后来者就很难颠覆,只有等待下一次产业浪潮。如今,一个全新的、...
  • 摘要:近年来,在单片机系统中嵌入操作系统已经成为人们越来越关心的一个话题。本文通过对一种源码公开的嵌入式实时操作系统ucosii的分析,以51系列单片机为例,阐述了在单片机中使用该嵌入式操作系统的优缺点,以及...
1 2 3 4 5 ... 20
收藏数 4,741
精华内容 1,896