| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 嵌入式 -> RT-Thread内核快速入门,内核实现与应用开发学习随笔记 -> 正文阅读 |
|
[嵌入式]RT-Thread内核快速入门,内核实现与应用开发学习随笔记 |
前言新手入门官方文档: RT-Thread API参考手册: event_sample.chttps://www.rt-thread.org/document/api/event_sample_8c-example.html#a10????????以下内容是随着学习随时整理的,有些来自于野火出的《RT-Thread内核实现与应用开发》的学习笔记,有些来自官网的东西,自认为难以记忆与重点的就记下来。 ? ? ? ? 大家可以浏览认识,至于大家想深入了解希望能够自己去看相关文档。 快速入门?可以去官方有相关文档说明 首先将KEIL下载下来,官网上有相关例程 工程说明? ?调试命令打开调试公共点击运行(F5)代码,打开串口UART#1,点击Tab键或者help+回车,查看系统支持的命令。 ?系统启动步骤?????????以 MDK-ARM 为例,MDK-ARM 的用户程序入口为 main() 函数,位于 main.c 文件中。系统启动后先从汇编代码 startup_stm32f103xe.s 开始运行,然后跳转到 C 代码,进行 RT-Thread 系统功能初始化,最后进入用户程序入口 main()。 ?如果使用到了ARM内核则重新定义启动当时,最终跳到了rtthread_startup(); 是RT-Thread规定的统一启动入口。?启动程序函数初始化如下图所示: ?启动代码分为四部分: 用户入口代码????????为了在进入 main 程序之前,完成系统功能初始化,可以使用? 内核基础内核的组成部分、系统如何启动、内存分布情况以及内核配置方法。 实时内核的实现包括:对象管理、线程管理及调度器、线程间通信管理、时钟管理及内存管理等等,内核最小的资源占用情况是 3KB ROM,1.2KB RAM。 线程调度????????线程是 RT-Thread 操作系统中最小的调度单位,线程调度算法是基于优先级的全抢占式多线程调度算法,即在系统中除了中断处理函数、调度器上锁部分的代码和禁止中断的代码是不可抢占的之外,系统的其他部分都是可以抢占的,包括线程调度器自身。 时钟管理????????RT-Thread 的时钟管理以时钟节拍为基础,时钟节拍(滴答始终)是 RT-Thread 操作系统中最小的时钟单位。RT-Thread 的定时器提供两类定时器机制:第一类是单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动停止。第二类是周期触发定时器,这类定时器会周期性的触发定时器事件,直到用户手动的停止定时器否则将永远持续执行下去。 另外,根据超时函数执行时所处的上下文环境,RT-Thread 的定时器可以设置为 HARD_TIMER 模式或者 SOFT_TIMER 模式。 通常使用定时器定时回调函数(即超时函数),完成定时服务。用户根据自己对定时处理的实时性要求选择合适类型的定时器。 线程间同步????????RT-Thread 采用信号量、互斥量与事件集实现线程间同步。线程通过对信号量、互斥量的获取与释放进行同步;互斥量采用优先级继承的方式解决了实时系统常见的优先级翻转问题,信号量会导致线程阻塞即当低优先级持有信号量时,高优先级无法获取信号量。 线程间通信?????????RT-Thread 支持邮箱和消息队列等通信机制。邮箱中一封邮件的长度固定为 4 字节大小;消息队列能够接收不固定长度的消息,并把消息缓存在自己的内存空间中。邮箱效率较消息队列更为高效。邮箱和消息队列的发送动作可安全用于中断服务例程中。通信机制支持线程按优先级等待或按先进先出方式获取。 内存管理????????RT-Thread 支持静态内存池管理及动态内存堆管理。当静态内存池具有可用内存时,系统对内存块分配的时间将是恒定的;当静态内存池为空时,系统将申请内存块的线程挂起或阻塞掉 (即线程等待一段时间后仍未获得内存块就放弃申请并返回,或者立刻返回。等待的时间取决于申请内存块时设置的等待时间参数),当其他线程释放内存块到内存池时,如果有挂起的待分配内存块的线程存在的话,则系统会将这个线程唤醒。 动态内存堆管理模块在系统资源不同的情况下,分别提供了面向小内存系统的内存管理算法及面向大内存系统的 SLAB 内存管理算法。 还有一种动态内存堆管理叫做 memheap,适用于系统含有多个地址且不连续的内存堆。使用 memheap 可以将多个内存堆 “粘贴” 在一起,让用户操作起来像是在操作一个内存堆。 I/O设备管理????????RT-Thread 将 PIN、I2C、SPI、USB、UART 等作为外设设备,统一通过设备注册完成。实现了按名称访问的设备管理子系统,可按照统一的 API 界面访问硬件设备。在设备驱动接口上,根据嵌入式系统的特点,对不同的设备可以挂接相应的事件。当设备事件触发时,由驱动程序通知给上层的应用程序。 程序内存分布一般MCU包含的存储空间有:片内Flash(硬盘)与片内RAM(内存)。编译器会将一个程序分类为好几个部分,分别存储在 MCU 不同的存储区。 Keil工程在编译完成后,会相应的程序提示占用空间
编译完后工程会生成一个.map文件,说明了各个函数占用的吃尺寸和地址,在文件最后几行与场面的关系。
STM32 在上电启动之后默认从 Flash 启动,启动之后会将 RW 段中的 RW-data(初始化的全局变量)搬运到 RAM 中,但不会搬运 RO 段,即 CPU 的执行代码从 Flash 中读取,另外根据编译器给出的 ZI 地址和大小分配出 ZI 段,并将这块 RAM 区域清零。 动态内存的申请:msg_ptr 指针指向的 128 字节内存空间位于动态内存堆空间中。 ?而一些全局变量则是存放于 RW 段和 ZI 段中,RW 段存放的是具有初始值的全局变量(而常量形式的全局变量则放置在 RO 段中,是只读属性的),ZI 段存放的系统未初始化的全局变量。 自动初始化机制自动初始化机制是指初始化函数不需要被显式调用,只需要在函数定义处通过宏定义的方式进行申明,就会在系统启动过程中被执行。 内核对象模型静态与动态对象?静态内核对象通常放在 RW 段和 ZI 段中,在系统启动后在程序中初始化; 动态内核对象则是从内存堆中创建的,而后手工做初始化,最后需要释放。 静态对象会占用 RAM 空间,不依赖于内存堆管理器,内存分配时间确定。动态对象则依赖于内存堆管理器,运行时申请 RAM 空间,当对象被删除后,占用的 RAM 空间被释放。这两种方式各有利弊,可以根据实际环境需求选择具体使用方式。 内核对象管理架构静态对象会占用 RAM 空间,不依赖于内存堆管理器,内存分配时间确定。动态对象则依赖于内存堆管理器,运行时申请 RAM 空间,当对象被删除后,占用的 RAM 空间被释放。这两种方式各有利弊,可以根据实际环境需求选择具体使用方式。 ?对象控制块
遍历内核对象
内核配置与裁剪配置主要是通过修改工程目录下的 rtconfig.h 文件来进行,用户可以通过打开 / 关闭该文件中的宏定义来对代码进行条件编译,最终达到系统配置和裁剪的目的 注:在实际应用中,系统配置文件 rtconfig.h 是由配置工具自动生成的,无需手动更改。 ? 第8章 线程的定义与线程的切换定义线程栈:
????????这些经过重定义的数据类型放在rtdef.h(rtdef.h
第一次使用需要在
include
文件夹下面新建然后添加到工程
rtt/source
这个组文件)这个头文件。
????????是一个带参宏,也在rtdef.h中定义
是一个在
rtconfifig.h
(
rtconfifig.h
第一次使用需要在
User
文件夹下面新建然后添加到工程
user
这个组文件)中定义的宏
线程的构成请查看实时手册
?????
???
链表?这些函数均在 rtservice.h 中实现,rtservice.h 第一次使用需要自行在 rtthread/3.0.3/include 文件夹下新建,然后添加到工程的 rtt/source 组中。
线程栈初始化:rt_hw_stack_init() 函数
/*
获取栈顶指针
rt_hw_stack_init
在调用的时候,传给
stack_addr
的是
(
栈顶指针
)*
stk
=
stack_addr
+
sizeof
(rt_uint32_t);
?
stk
=
(rt_uint8_t
*
)RT_ALIGN_DOWN((rt_uint32_t)stk,
8
);
让
stk
这个指针向下
8
个字节对齐,确保
stk
是
8
字节对齐的地址。在 Cortex-M3
(
Cortex-M4
或
Cortex-M7
)内核的单片机中,因为总线宽度是
32 位的,通常只要栈保持
4
字节对齐就行,可这样为啥要
8
字节?难道有哪些操作是
64 位的?
确实有,那就是浮点运算,所以要 8 字节对齐(但是目前我们都还没有涉及到浮点运算,只是为了后续兼容浮点运行的考虑)
。如果栈顶指针是
8
字节对齐的,在进行向下
8 字节对齐的时候,指针不会移动,如果不是
8
字节对齐的,在做向下
8 字节对齐的时候,就会空出几个字节,不会使用,比如当
stk
是
33
,明显不能整除
8
,进行向下
8
字节对齐就是
32,那么就会空出一个字节不使用。
线程第一次运行的时候,加载到
CPU
寄存器的环境参数我们要预先初始化好。从栈顶开始,初始化的顺序固定,首先是异常发生时自动保存的 8 个寄存器,即
xPSR
、
R15
、
R14
、
R12
、
R3
、
R2
、
R1
和
R0
。
其中 xPSR 寄存器的位 24 必须是1,R15 PC 指针必须存的是线程的入口地址,R0 必须是线程形参,剩下的 R14、R12、R3、R2 和 R1 我们初始化为 0。
? 将线程插入到双向就绪列表 ????????????????线程创建好之后,我们需要把线程添加到就绪列表里面,表示线程已经就绪,系统随时可以调度。就绪列表在 scheduler.c 中定义(scheduler.c 第一次使用需要在 rtthread3.0.3src 目录下新建,然后添加到工程的 rtt/source 组中)。
????????调度器是操作系统的核心,其主要功能就是实现线程的切换,即从就绪列表里面找到优先级最高的线程,然后去执行该线程。从代码上来看,调度器无非也就是由几个全局变量和一些可以实现线程切换的函数组成,全部都在 scheduler.c 文件中实现。
定义一个局部变量,用
C
语言关键词 register 修饰,防止被编译器优化。我们把调度器初始化放在硬件初始化之后,线程创建之前
调度器启动由函数 rt_system_scheduler_start() 来完成 系统调度系统调度就是在就绪列表中寻找优先级最高的就绪线程,然后去执行该线程。但是目前我们还不 支持优先级,仅实现两个线程轮流切换,系统调度函数 rt_schedule。 main函数线程的创建,就绪列表的实现,调度器的实现均已经讲完,现在我们把全部的测试代码都放到 main.c 里面 第9章 临界段的保护
????????临界段用一句话概括就是一段在执行的时候
不能被中断的代码段
。在 RT-Thread 里面,这个临界段最常出现的就是对全局变量的操作。
????????那么什么情况下临界段会被打断?一个是系统调度,还有一个就是外部中断。在 RT-Thread,系统调度,最终也是产生
PendSV
中断,在
PendSV Handler 里面实现线程的切换,所以还是可以归结为中断。既然这样,
RT-Thread 对临界段的保护就处理的很干脆了,直接把中断全部关了,NMIFAULT
和硬
FAULT
除外。
第10章? 对象容器的实现
在
RT-Thread
中,所有的数据结构都称之为对象。
在 RT-Thread 中,每个对象都会有对应的一个结构体,这个结构体叫做该对象的控制块。
在 rtt 中,每当用户创建一个对象,如线程,就会将这个对象放到一个叫做容器的地方。?
那什么是容器,从代码上看,容器就是一个数组,是一个全局变量,数据类型为
struct
rt_object_information
,在
object.c
中定义
? C 语言知识:如果枚举类型的成员值没有具体指定,那么后一个值是在前一个成员值基础上加1。 |
|
嵌入式 最新文章 |
基于高精度单片机开发红外测温仪方案 |
89C51单片机与DAC0832 |
基于51单片机宠物自动投料喂食器控制系统仿 |
《痞子衡嵌入式半月刊》 第 68 期 |
多思计组实验实验七 简单模型机实验 |
CSC7720 |
启明智显分享| ESP32学习笔记参考--PWM(脉冲 |
STM32初探 |
STM32 总结 |
【STM32】CubeMX例程四---定时器中断(附工 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 0:33:01- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |