rtthread学习笔记系列(4/5/6/7/15/16)

文章目录

  • 4. 杂项
    • 4.1 检查是否否是2的幂
  • 5. 预编译命令
    • void类型和rt_noreturn类型的区别
  • 6.map文件分析
  • 7.汇编.s文件
    • 7.1 汇编指令
      • 7.1.1 BX
      • 7.1.2 LR链接寄存器
      • 7.1.4 []的作用
      • 7.1.4 简单的指令
    • 7.2 MSR
    • 7.3 PRIMASK寄存器
    • 7.4.中断启用禁用
    • 7.3 HardFault_Handler
  • 15 ARM指针寄存器
  • 16 IDLE线程
    • 16.1 defunct流程

https://github.com/wdfk-prog/RT-Thread-Study

4. 杂项

4.1 检查是否否是2的幂

  • 检查sz_blk是否是2的幂。原理如下:

如果一个数是2的幂,那么它的二进制表示中只有一个位是1,其余都是0。例如,2(10),4(100),8(1000)等。
当我们从这个数中减去1时,所有从最右边的1开始到最左边的所有位都会翻转。例如,4(100)减去1变成3(011)。
因此,如果一个数是2的幂,那么这个数与它自己减去1的结果进行位与运算,会得到0。因为没有位同时在两个数中都是1。
反之,如果一个数不是2的幂,那么它至少有一个位不是1,这样减去1之后,至少有一个位在两个数中都是1,位与运算的结果不为0。
这个技巧在编程中经常被用来快速检查一个数是否是2的幂,因为它比循环或递归方法更高效。

#define IS_POWER_OF_TWO(x) (((x) & ((x) - 1)) == 0)

5. 预编译命令


#define __RT_STRINGIFY(x...)        #x

#define RT_STRINGIFY(x...)          __RT_STRINGIFY(x)

#define rt_section(x)               __attribute__((section(x)))

#define rt_used                     __attribute__((used))

#define rt_align(n)                 __attribute__((aligned(n)))

#define rt_weak                     __attribute__((weak))

#define rt_typeof                   __typeof__

#define rt_noreturn                 __attribute__ ((noreturn))

#define rt_inline                   static __inline

#define rt_always_inline            static inline __attribute__((always_inline))

-__RT_STRINGIFY(x...)RT_STRINGIFY(x...):这两个宏用于将参数转换为字符串。__RT_STRINGIFY直接将参数转换为字符串,而 RT_STRINGIFY则通过 __RT_STRINGIFY间接完成转换,以确保参数先被宏展开再转换为字符串。

-rt_section(x):这个宏用于将特定的函数或变量放入指定的段(section)中。

-rt_noreturn:这个宏用于指示函数不会返回。这对于像 exit()abort()这样的函数很有用。

rt_noreturn 是一个函数属性,用于告诉编译器这个函数不会返回到调用者。这个属性可以帮助编译器进行优化。

在C语言中,大多数函数在完成它们的工作后都会返回到调用者。然而,有些函数,如 exit()abort(),在被调用后不会返回。这是因为它们会终止程序的执行,或者跳转到其他的执行流程,而不是返回到原来的位置。当编译器看到一个函数被声明为 noreturn,它就知道这个函数不会返回到调用者。这样,编译器就可以省略一些针对函数返回的代码生成和优化。例如,编译器可能不需要保存寄存器的值,或者不需要在函数调用后生成一些可能永远不会执行的代码。

void类型和rt_noreturn类型的区别

void类型的函数和带有 rt_noreturn属性的函数之间的主要区别在于它们的行为,而不仅仅是它们的返回值。

void类型的函数确实没有返回值,但这并不意味着它们不会返回到调用者。当 void函数完成其工作后,控制权会返回到调用该函数的代码。

然而,带有 rt_noreturn属性的函数永远不会返回到调用者。这意味着一旦调用了这样的函数,程序的控制流就不会回到原来的位置。这对于像 exit()abort()这样的函数来说是非常有用的,因为这些函数在被调用后会终止程序的执行,或者跳转到其他的执行流程。

所以,rt_noreturn并不是关于函数的返回值的,而是关于函数是否会返回到调用者。这个属性可以帮助编译器进行更好的优化,因为编译器知道一旦调用了 rt_noreturn函数,就不需要生成任何后续的代码。希望这个解释对你有所帮助!

6.map文件分析


Image$$ER_IROM1$$Base                    0x90000000   Number         0  anon$$obj.o ABSOLUTE

__Vectors                                0x90000000   Data           4  startup_stm32h750xx.o(RESET)

__Vectors_End                            0x90000298   Data           0  startup_stm32h750xx.o(RESET)

__main                                   0x90000299   Thumb Code     0  entry.o(.ARM.Collect$$$$00000000)

_main_stk                                0x90000299   Thumb Code     0  entry2.o(.ARM.Collect$$$$00000001)

_main_scatterload                        0x9000029d   Thumb Code     0  entry5.o(.ARM.Collect$$$$00000004)

__main_after_scatterload                 0x900002a1   Thumb Code     0  entry5.o(.ARM.Collect$$$$00000004)

_main_clock                              0x900002a1   Thumb Code     0  entry7b.o(.ARM.Collect$$$$00000008)

_main_cpp_init                           0x900002a1   Thumb Code     0  entry8b.o(.ARM.Collect$$$$0000000A)

_main_init                               0x900002a1   Thumb Code     0  entry9a.o(.ARM.Collect$$$$0000000B)

__rt_final_cpp                           0x900002a9   Thumb Code     0  entry10a.o(.ARM.Collect$$$$0000000D)

__rt_final_exit                          0x900002a9   Thumb Code     0  entry11a.o(.ARM.Collect$$$$0000000F)

rt_hw_interrupt_disable                  0x900002ad   Thumb Code     8  context_rvds.o(.text)

rt_hw_interrupt_enable                   0x900002b5   Thumb Code     6  context_rvds.o(.text)

rt_hw_context_switch                     0x900002bb   Thumb Code    32  context_rvds.o(.text)

rt_hw_context_switch_interrupt           0x900002bb   Thumb Code     0  context_rvds.o(.text)

PendSV_Handler                           0x900002db   Thumb Code   108  context_rvds.o(.text)

rt_hw_context_switch_to                  0x90000347   Thumb Code    76  context_rvds.o(.text)

rt_hw_interrupt_thread_switch            0x90000393   Thumb Code     2  context_rvds.o(.text)

HardFault_Handler                        0x90000395   Thumb Code    56  context_rvds.o(.text)

MemManage_Handler                        0x90000395   Thumb Code     0  context_rvds.o(.text)

rt_memcpy                                0x900003e9   Thumb Code     0  rt_memcpy_rvds.o(.text)

Reset_Handler                            0x9000060d   Thumb Code     8  startup_stm32h750xx.o(.text)

  1. Reset_Handler 根据链接脚本设置 ENTRY(Reset_Handler);应为RAM首地址位置;实际并不是

原因:

  • 在汇编启动文件中,首先设置了向量表,再设置复位函数

; Vector Table Mapped to Address 0 at Reset

    AREA    RESET, DATA, READONLY

    EXPORT  __Vectors

    EXPORT  __Vectors_End

    EXPORT  __Vectors_Size


__Vectors       DCD     __initial_sp                      ; Top of Stack

    DCD     Reset_Handler                     ; Reset Handler

-Reset_Handler 编写中调用 SystemInit__main


Reset_Handler    PROC

        EXPORT  Reset_Handler                    [WEAK]

    IMPORT  SystemInit

    IMPORT  __main


        LDR     R0, =SystemInit

        BLX     R0

        LDR     R0, =__main

        BX      R0

        ENDP

-__main中执行rtt初始化:https://www.rt-thread.org/document/api/group___system_init.html#details

7.汇编.s文件

https://zhuanlan.zhihu.com/p/98888285

7.1 汇编指令

7.1.1 BX

  • BX指令:在ARM汇编语言中,BX指令用于跳转到指令中所指定的目标地址。这个目标地址可以是ARM指令,也可以是Thumb指令。BX指令的格式为:BX {条件} 目标地址。这个指令的特点是它可以改变处理器的状态,从ARM状态切换到Thumb状态,或者从Thumb状态切换到ARM状态。这种状态切换的功能使得BX指令在实现子程序调用和处理器工作状态切换时非常有用。

7.1.2 LR链接寄存器

  • LR链接寄存器:在ARM架构中,链接寄存器(Link Register,简称LR)通常用于存储子程序返回地址。当执行BL(带返回的跳转指令)或BLX(带返回和状态切换的跳转指令)时,处理器会将下一条指令的地址保存到LR中。然后,当子程序执行完毕后,可以通过将LR的内容加载到程序计数器(PC)中,从而返回到调用者。这种机制使得子程序的调用和返回变得非常方便和高效。

  • 在用户模式下,LR(或R14)用作链接寄存器,用于存储子程序调用时的返回地址。如果返回地址存储在堆栈上,它也可以用作通用寄存器。

    在异常处理模式中,LR 保存异常的返回地址,或者如果在异常内执行子例程调用,则保存子例程返回地址。如果返回地址存储在堆栈中,LR 可以用作通用寄存器。

7.1.4 []的作用

  • 在这段ARM汇编代码中,LDR r3, [r2] 是一条加载指令。这条指令的作用是从内存中加载数据。

  • r3 和 r2 是寄存器,它们是CPU中用于临时存储数据的小存储区。在这个上下文中,r3 和 r2 只是寄存器的名称,它们没有特殊的含义,只是用于标识这些寄存器。

    [r2] 的含义是:使用 r2 寄存器中的值作为内存地址,从该地址加载数据。[] 的作用是表示间接寻址,也就是说,我们不是直接使用 r2 的值,而是使用 r2 中的值作为一个内存地址,从这个地址中获取数据。

    所以,LDR r3, [r2] 的整体含义是:从内存中的 r2 所指向的地址加载数据,然后将这些数据存储到 r3 寄存器中。这就是这条指令的作用。

7.1.4 简单的指令

  • LDR: 将地址加载到寄存器中。
  • CMP: 比较两个操作数的值。
  • BEQ

7.2 MSR

  • MSR指令[1][2][3][4]:在ARM汇编语言中,MSR(Move to Status Register)指令用于将操作数的内容传送到程序状态寄存器的特定域中。其中,操作数可以为通用寄存器或立即数。MSR指令通常用于恢复或改变程序状态寄存器的内容。例如,当需要修改状态寄存器的内容时,可以通过“读取-修改-写回”指令序列完成。这种操作通常用于切换处理器模式、或者允许/禁止IRQ/FIQ中断等。

7.3 PRIMASK寄存器

  • PRIMASK寄存器[5][6][7]:在ARM Cortex-M处理器中,PRIMASK寄存器用于控制中断的优先级,允许屏蔽(禁止)特定优先级的中断。PRIMASK寄存器是一个单比特(bit)的寄存器,只有两个有效的取值:0和1。当PRIMASK寄存器的值为0时,表示所有中断都可以触发。当PRIMASK寄存器的值为1时,会禁止所有可屏蔽的中断。这意味着通过设置 PRIMASK 寄存器为 1,可以禁用所有中断,从而实现临界区的保护或者实现禁止中断的功能。

7.4.中断启用禁用


/*

 * rt_base_t rt_hw_interrupt_disable();

 */

.global rt_hw_interrupt_disable

.type rt_hw_interrupt_disable, %function

rt_hw_interrupt_disable:

//将PRIMASK写入RO寄存器

    MRS     r0, PRIMASK

//设置CPSID为I,用于禁用中断

    CPSID   I

    BX      LR


/*

 * void rt_hw_interrupt_enable(rt_base_t level);

 */

.global rt_hw_interrupt_enable

.type rt_hw_interrupt_enable, %function

rt_hw_interrupt_enable:

//从RO取回PRIMASK

    MSR     PRIMASK, r0

    BX      LR

  • 由于将PRIMASK的值暂存在r0中,执行临界段代码时r0值会不会改变?

https://club.rt-thread.org/ask/question/d5156cdf3abb63a1.html

7.3 HardFault_Handler


.global HardFault_Handler

.type HardFault_Handler, %function

HardFault_Handler:

    /* 获取当前上下文 */

    MRS     r0, msp                 /* 从处理程序获取故障上下文 */

    TST     lr, #0x04               /* 如果!EXC_RETURN[2] */

    BEQ     _get_sp_done

    MRS     r0, psp                 /* 从线程获取故障上下文 */

_get_sp_done:


    STMFD   r0!, {r4 - r11}         /* 压入r4 - r11寄存器 */

#if defined (__VFP_FP__) && !defined(__SOFTFP__)

    STMFD   r0!, {lr}               /* 压入标志的占位符 */

#endif

    STMFD   r0!, {lr}               /* 压入exec_return寄存器 */


    TST     lr, #0x04               /* 如果!EXC_RETURN[2] */

    BEQ     _update_msp

    MSR     psp, r0                 /* 更新堆栈指针到PSP */

    B       _update_done

_update_msp:

    MSR     msp, r0                 /* 更新堆栈指针到MSP */

_update_done:


    PUSH    {LR}

    BL      rt_hw_hard_fault_exception  /* 调用硬件故障异常处理函数 */

    POP     {LR}


    ORR     lr, lr, #0x04

    BX      lr  /* 返回 */


15 ARM指针寄存器

https://blog.csdn.net/zhuguanlin121/article/details/120883025

-堆栈指针r13 SP:每一种异常模式都有其自己独立的r13,它通常指向异常模式所专用的堆栈,也就是说五种异常模式、非异常模式(用户模式和系统模式),都有各自独立的堆栈,用不同的堆栈指针来索引。这样当ARM进入异常模式的时候,程序就可以把一般通用寄存器压入堆栈,返回时再出栈,保证了各种模式下程序的状态的完整性。

栈顶指针(Stack Pointer)是寄存器页的核心,用以指向系统栈的栈顶位置,某些情况下也可以作为通用寄存器来使用,例如,在 ARM Cortex M 内核中,SP 可以作为 R13 来使用。由于栈是函数式语言的核心,在操作系统中 SP 的地位举足轻重,以 RT-Thread 为例,每个用户任务都有独享的栈,任务的切换几乎就是栈的切换,也就是栈顶指针的切换,我们可以毫不夸张的说:栈顶指针就是每个任务的生命线。

-连接寄存器r14 LR:每种模式下r14都有自身版组,它有两个特殊功能。

(1)保存子程序返回地址。使用BL或BLX时,跳转指令自动把返回地址放入r14中;子程序通过把r14复制到PC来实现返回,通常用下列指令之一:

(2)当异常发生时,异常模式的r14用来保存异常返回地址,将r14如栈可以处理嵌套中断。

(3) LR 本质上相当于一个深度为 1 的硬件栈,支持且仅支持 1 级函数调用。

PC 指针(Program Counter)和 LR 指针(Link Return)是寄存器页的核心,用于实现流水线的执

行和分支,详细内容我们在本章的开头已经详细讨论过。LR 寄存器在某些情况下也可以作为通用寄存

器来使用,例如,在 ARM Cortex M 内核中,LR 可以作为 R14 来使用。

-程序计数器r15 PC:PC是有读写限制的。当没有超过读取限制的时候,读取的值是指令的地址加上8个字节,由于ARM指令总是以字对齐的,故bit[1:0]总是00。当用str或stm存储PC的时候,偏移量有可能是8或12等其它值。在V3及以下版本中,写入bit[1:0]的值将被忽略,而在V4及以上版本写入r15的bit[1:0]必须为00,否则后果不可预测。

IF 阶段从什么地址读取指令是由 PC 指针控制的,修改其值就可以实现程序的分支。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

16 IDLE线程

  • cleanup 会在线程退出时,被空闲线程回调一次以执行用户设置的清理现场等工作。

16.1 defunct流程

  1. rt_thread_defunct_enqueue 将退出线程和分离线程插入到defunct链表中
  2. IDLE线程会在空闲时,执行defunct链表中的线程,将线程节点从链表中移除
  3. 从对象容器中移除线程对象
  4. 执行线程清除函数,释放线程控制块

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微软与腾讯技术交锋,TRELLIS引领3D生成领域多格式支持新方向

去年 11 月,腾讯推出 Hunyuan3D 生成模型,是业界首个同时支持文字和图像生成 3D 的开源大模型。紧接着不到一个月,微软便发布了全新框架 TRELLIS,加入 3D 资产生成领域的竞争中。TRELLIS 支持多格式输出,包括辐射场、3…

【C++】类与对象(中上)(难点部分)

目录 💕1.类的默认成员函数 💕2.构造函数 💕3.析构函数 💕4.缺省值 💕5.拷贝构造函数 (最新更新时间——2025.1.14) 这世间没有绝境 只有对处境绝望的人 💕1.类的默认成员函数 默…

Apache Hop从入门到精通 第三课 Apache Hop下载安装

1、下载 官方下载地址:https://hop.apache.org/download/,本教程是基于apache-hop-client-2.11.0.zip进行解压,需要jdk17,小伙伴们可以根据自己的需求下载相应的版本。如下图所示 2、下载jdk17(https://www.microsoft…

springboot房屋租赁管理系统

Spring Boot房屋租赁管理系统是一种基于Spring Boot框架构建的,旨在解决传统租房市场中房源信息更新不及时、虚假信息泛滥、交易流程繁琐等问题的信息化解决方案。 一、系统背景与目的 随着城市化进程的加快和人口流动性的增强,租房市场需求急剧增长。…

计算机网络 (35)TCP报文段的首部格式

前言 计算机网络中的TCP(传输控制协议)报文段的首部格式是TCP协议的核心组成部分,它包含了控制TCP连接的各种信息和参数。 一、TCP报文段的结构 TCP报文段由首部和数据两部分组成。其中,首部包含了控制TCP连接的各种字段&#xff…

鸿蒙-页面和自定义组件生命周期

页面生命周期,即被Entry装饰的组件生命周期,提供以下生命周期接口: onPageShow:页面每次显示时触发一次,包括路由过程、应用进入前台等场景。onPageHide:页面每次隐藏时触发一次,包括路由过程、…

道旅科技借助云消息队列 Kafka 版加速旅游大数据创新发展

作者:寒空、横槊、娜米、公仪 道旅科技:科技驱动,引领全球旅游分销服务 道旅科技 (https://www.didatravel.com/home) 成立于 2012 年,总部位于中国深圳,是一家以科技驱动的全球酒店资源批发商…

【HarmonyOS NEXT】鸿蒙跳转华为应用市场目标APP下载页

【HarmonyOS NEXT】鸿蒙跳转华为应用市场目标APP下载页 一、问题背景: 如今,大家都离不开各种手机应用。随着鸿蒙系统用户越来越多,大家都希望能在鸿蒙设备上快速找到想用的 APP。华为应用市场里有海量的 APP,但之前从鸿蒙设备进…

JavaScript动态渲染页面爬取之Splash

Splash是一个 JavaScript渲染服务,是一个含有 HTTP API的轻量级浏览器,它还对接了 Python 中的 Twisted 库和 OT库。利用它,同样可以爬取动态渲染的页面。 功能介绍 利用 Splash,可以实现如下功能: 异步处理多个网页的渲染过程:获取渲染后…

Thrustmaster Hotas Warthog飞行操作杆开发

目录 0 摘 要 :简单说一下这篇文章在搞啥 1 背 景 :什么需求以及对开发的背景调查 2 环境配置 :具体需要什么环境,对软件层面的需求 3 硬件测试 :测试遥感器…

算法-查找数组对角线上最大的质数

力扣题目:2614. 对角线上的质数 - 力扣(LeetCode) 给你一个下标从 0 开始的二维整数数组 nums 。 返回位于 nums 至少一条 对角线 上的最大 质数 。如果任一对角线上均不存在质数,返回 0 。 注意: 如果某个整数大于…

电梯系统的UML文档02

现在我们来回答用UML 设计电梯系统的实践中遇到的问题:“UML 是一种适合于实时系统的建模语言吗?”我们发现基于上段提到的特征,UML 是适合的但有不足。用UML 设计实时系统有以下问题: •特定硬件及它们特征的定义。 •在对象、任务和硬件层…

mysql set age=‘0‘ 和 set age=0的区别?

select case when(t1.business_transfer‘source’)then 0 else t1.settlement_tyy_cash_amount end as tyy from t_settlement_waybill t1 where waybill_sn in (‘2025010700001’); select case when(t1.business_transfer‘source’)then (t1.settlement_tyy_cash_amount‘…

利用Java爬虫按图搜索1688商品(拍立淘)的实践指南

在当今数字化时代,网购已成为人们生活中不可或缺的一部分。而1688作为国内领先的B2B电商平台,汇聚了海量的商品资源。然而,在面对众多商品时,传统的文字搜索方式有时难以满足我们的需求。比如,当我们看到一件心仪的商品…

达梦8-DMSQL程序设计学习笔记1-DMSQL程序简介

1、DMSQL程序简介 DMSQL程序是达梦数据库对标准SQL语言的扩展,是一种过程化SQL语言。在DMSQL程序中,包括一整套数据类型、条件结构、循环结构和异常处理结构等,DMSQL程序中可以执行SQL语句,SQL语句中也可以使用DMSQL函数。 DMSQ…

使用 WPF 和 C# 将纹理应用于三角形

此示例展示了如何将纹理应用于三角形,以使场景比覆盖纯色的场景更逼真。以下是为三角形添加纹理的基本步骤。 创建一个MeshGeometry3D对象。像往常一样定义三角形的点和法线。通过向网格的TextureCoordinates集合添加值来设置三角形的纹理坐标。创建一个使用想要显示的纹理的 …

Git版本控制 - 创建使用Repository

Git版本控制 – 创建使用Repository Version Control with Git - Create and Use Repository By JacksonML 上文提到,Git是一种分布式版本控制系统。作为全球范围内广泛使用的工具,如何将项目分步骤运用到其中呢? 本文简要介绍如何用Git工…

WINFORM - DevExpress -> devexpress版--报表(report)

devexpress report模板 1.安装devexpress(DevExpress 总结【安装、案例】_caoyanchao1的博客-CSDN博客_devexpress) 2.新建vs项目且添加standarReportDesigner控件 涛神设计器注意 3.运行后步骤 点击New Report DetailReport 涛神设计器checkbox(3.复选框只认boolean类型的 b…

【Redis】初识Redis

目录 Redis简介 Redis在内存中存储数据 Redis数据库中的应用 Redis缓存中的应用 Redis消息中间件 尾言 Redis简介 如下是Redis官网中,对Redis的一段描述 在这段描述中,我们提取如下关键要点: Redis主要用于在内存中存储数据Redis可…

YOLOv9改进,YOLOv9自研检测头融合HAttention用于图像修复的混合注意力检测头

参考文章 完成本篇内容,首先完成这篇文章,并把代码添加到 YOLOv9 中: YOLOv9改进,YOLOv9引入HAttention注意机制用于图像修复的混合注意力转换器,CVPR2023,超分辨率重建 下文都是手把手教程,跟着操作即可添加成功 目录 参考文章🎓一、YOLOv9原始版本代码下载🍀🍀…