内核移植笔记 Cortex-M移植

news2024/12/23 23:12:17

常用寄存器

PRIMASK寄存器
为1位宽的中断屏蔽寄存器。在置位时,它会阻止不可屏蔽中断(NMI)和HardFault异常之外的所有异常(包括中断)。
实际上,它是将当前异常优先级提升为0,这也是可编程异常/中断的最高优先级。

FAULTMASK寄存器
FAULTMASK与PRIMASK相类似,但同时它能屏蔽HardFault异常,它实际上是将异常优先级提升到了-1。

程序状态寄存器(xPSR)
xPSR包含:

  • 应用PSR(APSR)
  • 执行PSR(EPSR)
  • 中断PSR(IPSR)

在这里插入图片描述
注:GE 在 Cortex-M4 等 ARMv7E-M 处理器中存在,在 Cortex-M3 处理器中则不可用。

  • N:负标志
  • Z:零标志
  • C:进位(或者非借位)标志
  • V:溢出标志
  • Q:包含标志
  • GE:大于或等于标志
  • ICI/IT:中断继续指令位
  • T:Thumb状态,总是1,清除此位会引起错误异常
  • 异常变化:表示处理器正在处理的异常

中断向量表
Cortex-M系列处理器的中断向量表位于0x00000000,单Cortex-M3/4系列提供了SCB_VTOR,所以中断向量表的位置位于0x00000000+SCB_VTOR。

异常相关指令

  • CPSIE I:使能中断(清除PRIMASK)
  • CPSID I:禁止中断(设置PRIMASK),NMI和HardFault不受影响
  • CPSIE F:使能中断(清除FAULTMASK)
  • CPSID F:禁止中断(设置FAULTMASK),NMI不受影响

移植过程

在嵌入式领域有多种不同CPU架构,例如Cortex-M,ARM920T、MIPS、RISC-V等等。
为了使RT-Thread能够在不同CPU架构的芯片上运行,RT-Thread提供了一个libcpu抽象层适配不同的CPU架构

libcpu层向上对内核提供统一的接口,包括全局中断的开关,线程栈的初始化,上下文切换等。

libcpu抽象层向下提供了一套统一的CPU架构移植接口,这部分接口包含了全局中断开关函数,线程上下文切换函数,时钟节拍的配置和中断函数、Cache等等内容。

libcpu移植相关API,要对CPU进行移植只需要实现这些接口

关闭全局中断

/*rt_base_t rt_hw_interrupt_disable(void);*/

.global rt_hw_interrupt_disable
.type rt_hw_interrupt_disable,%function

rt_hw_interrupt_disable:
	MRS R0,PRIMASK ;将PRIMASK关中断前的状态存入R0,并作为函数返回值返回
	CPSID I	;关闭中断
	BX LR
/*void rt_hw_interrupt_enable(rt_base_t level); level是调用关中断函数时的返回值,代表关中断前PRIMASK的值*/
.global rt_hw_interrupt_enable
.type rt_hw_interrupt_enable,%function

rt_hw_interrupt_enable:
	MSR PRIMASK,R0 ;将level写入PRIMASK寄存器,恢复关中断前的状态
	BX LR

实现线程栈初始化

在动态创建线程和初始化线程的时候,会使用到内部的线程初始化函数_rt_thread_init(),_rt_thread_init()函数会调用栈初始化函数rt_hw_stack_init(),在栈初始化函数里会手动构造一个上下文内容,这个上下文内容将被作为每个线程第一次执行的初始值。
上下文在栈里的排布如图:
在这里插入图片描述

rt_uint8_t *rt_hw_stack_init(void *tentry,
							void *parameter,
							rt_uint8_t *stack_addr,
							void *texit)
{
	struct stack_frame *stack_frame;
    rt_uint8_t         *stk;
    unsigned long       i;

    stk  = stack_addr + sizeof(rt_uint32_t);
    stk  = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
    stk -= sizeof(struct stack_frame);

    stack_frame = (struct stack_frame *)stk;

    /* init all register */
    for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
    {
        ((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
    }
     /* 根据 ARM  APCS 调用标准,将第一个参数保存在 r0 寄存器 */
    stack_frame->exception_stack_frame.r0  = (unsigned long)parameter; 
    stack_frame->exception_stack_frame.r1  = 0;                        /* r1 */
    stack_frame->exception_stack_frame.r2  = 0;                        /* r2 */
    stack_frame->exception_stack_frame.r3  = 0;                        /* r3 */
    /* 将 IP(Intra-Procedure-call scratch register.) 设置为 0 */
    stack_frame->exception_stack_frame.r12 = 0;    
    //将线程退出函数的地址保存在lr寄存器
    stack_frame->exception_stack_frame.lr = (unsigned long) texit;
    //将线程入口函数的地址保存在pc寄存器
    stack_frame->exception_stack_frame.pc = (unsigned long) tentry;
    /* 设置 psr 的值为 0x01000000L,表示默认切换过去是 Thumb 模式 */
    stack_frame->exception_stack_frame.psr = 0x01000000L;              /* PSR */
    return stk;
}

实现上下文切换

在Cortex-M里面上下文切换都是统一使用PendSV异常来完成。
为了能适应不同的CPU架构,RT-Thread的libcpu抽象层需要实现三个线程相关的函数:

  1. rt_hw_context_switch_to():没有来源线程,切换到目标线程,在调度器启动第一个线程的时候被调用。
  2. rt_hw_context_switch():在线程环境下,从当前线程切换到目标线程。
  3. rt_hw_context_switch_intrrupt():在中断环境下,从当前线程切换到目标线程。

PendSV_Handler

产生PendSV异常时,Cortex-M系列处理器硬件会自动将from线程的PSR、PC、LR、R12、R3-R0压栈,因此在PendSV_Handler中,我们需要把from线程的R11-R4压栈,并把to线程的R11-R4弹出。修改PSP为to线程的栈地址,在退出PendSV中断时,硬件会自动弹出R3-R0、R12、LR、PC、PSR寄存器。

/*R0->保存from线程的栈,R1->保存to线程的栈*/
/*PSR PC LR...被放入from线程的栈*/
.global PendSV_Handler
.type PendSV_Handler, %function

PendCV_Handler:
	MRS R2,PRIMASK
	CPSID	I

	LDR R0, =rt_thread_switch_interrupt_flag
	LDR R1,[R0]
	CBZ R1,pendsv_exit 

	MOV R1,#0
	STR R1,[R0]

	LDR R0,=rt_interrupt_from_thread
	LDR R1,[R0]
	CBZ R1,switch_to_thread

	MRS R1,PSP
	STMFD R1!,{R4-R11} //将from线程的数据寄存器R4-R11压栈
	LDR R0,[R0] 
	STR R1,[R0]

switch_to_thread:
	LDR R1,=rt_interrupt_to_thread
	LDR R1,[R1]
	LDR R1,[R1]

	LDMFD R1!,{R4-R11} //将to线程寄存器弹出
	MSR PSP,R1 //更新栈指针

pendsv_exit:
	MSR PRIMASK,R2
	ORR LR,LR,#0X4
	BX LR

rt_hw_context_switch_to

在这里插入图片描述

.global rt_hw_context_switch_to
.type rt_hw_context_switch_to,%function

rt_hw_context_switch_to:
	LDR R1,=rt_interrupt_to_thread
	STR R0,[R1]

	LDR R1,=rt_interrupt_from_thread
	MOV R0,#0
	STR R0,[R1]
	
	LDR R1,=rt_thread_switch_interrupt_flag
	MOV R0,#1
	STR R0,[R1]

	
	LDR R0,=SHPR3
	LDR R1,=PENDSV_PRI_LOWEST
	LDR.W R2,[R0,#0]
	ORR     R1, R1, R2              /* modify */
    STR     R1, [R0]                /* write-back */

	LDR     R0, =ICSR               /* trigger the PendSV exception (causes context switch) */
    LDR     R1, =PENDSVSET_BIT        ;0x10000000,ICSR 的第 28 位为 PendSV set-pending bit.
    STR     R1, [R0]                ;Writing 1 to this bit is the only way to set the PendSV exception state to pending.

	//恢复MSP 
	LDR R0,=SCB_VTOR
	LDR R0,[R0] //读取中断向量表的位置
	LDR R0,[R0] //读取 SP初始值
	NOP
	MSR MSP,R0 ;将SP初始值赋给MSP

	   /* enable interrupts at processor level */
    CPSIE   F
    CPSIE   I

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1189672.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【代码随想录】算法训练营 第二十天 第六章 二叉树 Part 6

654. 最大二叉树 题目 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回…

西部数码的域名如何实现DDNS功能

功能简介&#xff1a; 动态域名解析&#xff08;Dynamic DNS&#xff0c;简称DDNS&#xff09;可以让用户使用固定的域名来访问动态IP地址&#xff0c;解决因IP地址变化造成服务无法访问的情况。 本文将介绍如何使用西部数码的API实现DDNS功能&#xff0c;使您的域名始终指向您…

SpringCloudGateway--Sentinel限流、熔断降级

目录 一、概览 二、安装Sentinel 三、微服务整合sentinel 四、限流 1、流控模式 ①直接 ②关联 ③链路 2、流控效果 ①快速失败 ②Warm Up ③排队等待 五、熔断降级 1、慢调用比例 2、异常比例 3、异常数 一、概览 SpringCloudGateway是一个基于SpringBoot2.x的…

第一次pta认证P测试C++

第一题 试题编号&#xff1a;20210701-1 试题名称&#xff1a;标题统计 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 128.0MB 【问题描述】 小明阅读了一篇特别优美的英文文章&#xff0c;读到最后总结段落的时候&#xff0c;突发奇 想&#xff0c;想要数一数这个段落中…

python+pytorch人脸表情识别

概述 基于深度学习的人脸表情识别&#xff0c;数据集采用公开数据集fer2013&#xff0c;可直接运行&#xff0c;效果良好&#xff0c;可根据需求修改训练代码&#xff0c;自己训练模型。 详细 一、概述 本项目以PyTorch为框架&#xff0c;搭建卷积神经网络模型&#xff0c;训…

数据采集中的基本参数

分辨率(resolution) 分度数量越多则分辨率越高&#xff0c;测量精度也越高 区间(range) 模数转换所能处理模拟信号电平的极限 应尽量使输入与此区间匹配&#xff0c;物尽其用 信号极限幅度集合 所测信号的最大值和最小值 应与输入信号的最大值和最小值相接近 LSB 最低有效…

python编程复习系列——week1(Input Output)

Input & Output 前言0、我们的第一个Python程序一、变量和数据类型1.变量是用来存储值的保留存储位置2.变量以特定的数据类型存储值。常见数据类型&#xff1a;3.字符串添加&#xff08;连接&#xff09;4.字符串乘法&#xff08;带数字&#xff09;&#xff01;5.从用户处…

4K壁纸下载器,多种风格壁纸,一键批量下载到本地,桌面壁纸,高清壁纸,壁纸下载

一个桌面壁纸爬虫工具&#xff0c;该工具可以从内置的多个壁纸网站爬取高清壁纸&#xff0c;并支持将壁纸一键下载到本地&#xff0c;真正实现了所见即所得&#xff0c;不必再费心费力的翻看多个网站。 文末附工具下载链接~ 一、软件简介 本次带来的工具由吾爱的一位大佬开发…

DVWA - 2

文章目录 SQL Injectionlowmediumhigh SQL Injection low 输入 1&#xff0c;可以展示 id 1 的人员信息&#xff1a;输入 1’&#xff0c;有报错信息。可以看出是mysql数据库&#xff0c;‘‘1’’’ 去除两边的引号&#xff0c;再去除1两端的引号&#xff0c;可以看出闭合符…

【遮天】叶凡首次高燃时刻,暴打姜峰逼其下跪,故事逐渐燃情

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析国漫资讯。 深度爆料&#xff0c;《遮天》国漫30集剧情最新内容解析&#xff0c;前面剧情中&#xff0c;叶凡被姜峰如疯狗一般追杀&#xff0c;他像一只被狼群追逐的鹿&#xff0c;在山林中亡命逃窜。身后是姜峰那歇斯底…

Mac电脑专业raw图像处理 DxO PhotoLab 7中文最新 for mac

DxO PhotoLab 7是一款专业的图像处理软件&#xff0c;为摄影师和摄影爱好者提供了强大而全面的照片处理和编辑功能。 该软件可以处理来自各种相机的RAW格式图像&#xff0c;包括佳能、尼康、索尼、富士等品牌&#xff0c;同时也支持JPEG格式的处理。这使得用户可以在不损失图像…

uniapp使用vur-cli新建项目并打包

新建项目 npm install -g vue/cli vue create -p dcloudio/uni-preset-vue my-project选择默认模板npm run dev:h5 运行 安装sass和uview &#xff08;npm安装失败&#xff09; bug&#xff1a;使用uni.scss中的变量或样式&#xff0c;<style lang"scss"> 必…

命令行远程操作windows

如遇安装python模块问题&#xff0c;请参考此连接处理&#xff1a;http://t.csdnimg.cn/l9W6f 一、命令行中使用ssh连接 1、安装 OpenSSH 客户端&#xff1a; 在 Windows 10 中&#xff0c;打开“设置”应用&#xff0c;选择“应用” > “可选功能” > “添加功能”。…

request安装完不可用?编辑器没选对

问题&#xff1a; 在vscdo中request安装完不可用 解决方案&#xff1a; 右下角的编辑器选一下。

一种ESDF地图实现方法:FIESTA

背景&#xff1a; 在机器人定位、行动规划中建图是一个很重要的工作&#xff0c;只有通过感知器感知到自己在哪、周围有什么&#xff1b;才能为下一步行动作出决策的依据。然而要知道自己在哪&#xff0c;就必须要有一个整体规划和参照也就是所谓的地图。地图相当于是一次规划…

论文实验可视化方法

真实值预测值误差 张永, 龚众望, 郑英, 等. 工业设备的健康状态评估和退化趋势预测联合研究. 中国科学: 技术科学, 2022, 52: 180–197 Zhang Y, Gong Z W, Zheng Y, et al. Joint study on health state assessment and degradation trend prediction of industrial equipment…

blender动画制作全流程软件

blender官网下载地址 Download — blender.org blender菜单中英文对照表 blender常用快捷键&#xff1a; ~切换视图 z切换着色模式 shiftA新建物体 tab进入编辑模式 在编辑模式下: 1编辑点 2编辑线 3编辑面 shfit空格弹出所有快捷键 游标一般配合标注使用 常用:G移动物体…

接口测试|HttpRunner模拟发送GET请求自动生成测试报告

HttpRunner模拟发送GET请求&自动生成测试报告 前面说到&#xff0c;HttpRunner必须使用yaml或者json文件来进行使用&#xff0c;测试场景文件推荐使用yaml文件进行编辑。 httprunner 项目下yaml文件的格式 在python项目下新建一个 testcases 文件夹&#xff0c;然后再新…

IDEA 设置 Git 在左侧展示

File->settings->Version Control->commit 勾选 Use non-model commit interface

计算当月工作日时间进度

目录 1.按一个月平均算 2.除去星期六星期天算 3.自定义节假日算 1.按一个月平均算 // 获取当前时间 const now new Date(); // 获取当前年份和月份 const currentYear now.getFullYear(); const currentMonth now.getMonth() 1; // 计算当月天数 const daysInMonth ne…