找回密码
 立即注册
查看: 845|回复: 8

STC32G FreeRTOS入门(11):现场保护与恢复机制—FreeRTOS与C251中断异同

[复制链接]

该用户从未签到

66

主题

714

回帖

1万

积分

荣誉版主

积分
10975
发表于 2023-8-7 02:01:48 | 显示全部楼层 |阅读模式
现场的保护与恢复,不但是前后台多任务系统的中断任务必备的组成,同样也是FreeRTOS抢占式实时多任务操作系统的核心组成部分。本文对比介绍这它们实现现场保护与恢复的不同方法和特点。
一、80251CPU的寄存器
(1)STC32G单片机与Keil的C251编译器都是基于80251CPU内核的。当单片机的某个任务运行时,最重要的资源就是全部寄存器。80251CPU的寄存器见下图:
Fig_X01_寄存器.jpg
从图中可以看到80251CPU的寄存器分为32位(双字)寄存器10个,16位(字)寄存器16个,8位(字节)寄存器16个,图中表格中的名称就是80251汇编语言中的寄存器名称。
80251和8051是Intel经过精心设计的两款CPU内核,80251CPU中包含了一个完整的8051CPU,80251指令集中包含了一个完整的8051指令集。8051的8位累加器A和B对应80251的R11和R10,这与80251CPU是大端数据存储模式对应。
80251的所有寄存器并不位于内存地址空间,它们位于专门的“寄存器文件组”空间,除了“R0~R7”寄存器,其余寄存器只能用寄存器寻找模式对它们进行赋值和读取,不能用对内存地址空间的寻址方式来操作它们,在上图中用浅绿色表示。

(2)上图中深绿色的8051的通用8位寄存器R0~R7是一组很特殊的寄存器,它是位于内存地址空间的4组寄存器中的一组,见下图所示:
Fig_X02_51寄存器.jpg
8051的4组寄存器Bank0~Bank3,位于内存DATA区域,占头32个字节。在单片机运行时根据程序状态字“PSW”中的“RS1”和“RS0”两位来决定8051指令中的“R0~R7”寄存器对应的是哪个地址的数据。
比如加法指令“ADD  A, R4”,当RS1RS0=00时,是将存在DATA空间地址04H的8位数据与A寄存器内容相加,但是当RS1RS0=10时,却是将存在DATA空间地址14H的8位数据与A寄存器内容相加。
8051CPU采用这样结构两个最重要的原因一是初期的51单片机运行速度很低,二是1981年左右受工艺限制在集成电路中集成RAM很难很贵,因此对于要使用多个变量的程序没有那么多内存空间可以使用。采用的是4组寄存器的方法,本质上是让用户在同一时刻拥有8个寄存器和24个字节的临时寄存器变量,经过优化编译,以较小的RAM空间实现大数据处理的需求。
(3)重要:在80251指令中涉及“R0~R7”寄存器的操作,并不唯一对于8个内存地址,而是依赖于PSW中的字段“RS1RS0”的值将DATA空间的4组地址映射为“R0~R7”寄存器。
(4)在80251CPU中,8位、16位和32位寄存器不是独立的,而是像金字塔一样组成的。

下图为80251通用寄存器的组成方法
Fig_X03_寄存器组成.jpg
比如32位的DR4寄存器由两个16位的寄存器WR4和WR6组成,而16位的WR6寄存器由两个8位的寄存器R6和R7组成。每一组的寄存器中一个发生变化,则这一组的寄存器都按组成方式变化。
(5)重要提示:从上面的组成图可以看出,DR0和DR4、WR0~WR6寄存器依赖“R0~R7”寄存器,即使你没有改变它们,但只要PSW中的字段“RS1RS0”的值发生变化,那么R0~R7就会被映射到不同的DATA区域,它们的值就会发生变化。
因此为了避免这种歧义,Keil的C251编译器在对C语言程序进行编译的时候不会对PSW的字段“RS1RS0”进行设置(其他字段在各种操作时由硬件设置)。
由于80251有很多的寄存器和DATA空间了,特别建议用户如果没有特别的目的不要用汇编语言去设置“RS1RS0”字段。

(6)由于80251指令集完整包含8051指令集,因此为了保证8051指令也能正确地运行,80251CPU的特殊寄存器在SFR区域中也有一个对应的映射。标准的80251CPU映射见下图,具体的采用80251内核的单片机的映射应参考其技术手册。
Fig_X04_SFR寄存器.jpg
二、FreeRTOS任务切换时的现场保护与恢复
(7)当前任务现场是指任务程序执行到切换点时程序进一步正确执行时所需要的资源。FreeRTOS主要依靠定时器0的1KHz的中断来扫描和调度任务,因此当前执行的实时任务的切换点就是定时器0的中断点。
定时器0中断发生时,24位的PC值(用户下一条要执行的程序地址)和PSW1程序状态字已经被组合位4个字节32位由硬件压入堆栈了,其余的中断服务程序由移植的FreeRTOS程序来完成。其中涉及中断现场保护和恢复功能用汇编语言写在“portasm.h”文件中。

(8)寄存器现场的保存与恢复。STC官方移植的FreeRTOS定时器0中断现场的寄存器保护与恢复的程序见下图:
Fig_X05_FT寄存器现场.jpg
上图中第81行到第90行依次将9个32位的寄存器压入堆栈保存,在将8051的程序状态字PSW压入堆栈保存。
在中断退出时或者任务恢复时,第97行到第106行程序将这些寄存器原样从堆栈中恢复。
(9)关于R0~R7寄存器的讨论。注意第88行和第89行是将R0~R7寄存器用对应的32位寄存器DR0和DR4推入堆栈的,然后把PSW推入堆栈,这样按照前面对R0~R7寄存器映射的讨论,不管当前任务用户对字段“RS1RS0”的设置如何,这3条指令都已把当前任务的正在使用的R0~R7寄存器现场保存了,无论它们处于哪个Bank。
要点:对于STC官方移植的FreeRTOS,不需要像8051单片机一样,在第90行后面加“PSW=0”这样的语句来对字段“RS1RS0”进行设置了。
(10)任务切换时对于任务堆栈的保存与恢复。
80251的系统SPX堆栈运行在也只能运行在EDATA内存区域中,任务切换点的现场不但包括寄存器,还包括整个堆栈里面的内容。比如在进行函数访问和嵌套时,函数的返回地址就被LCALL或者ECALL指令保存在堆栈中,另外,可重入函数的参数和局部变量也放在了堆栈中,最后,为了实现某些算法,编程者需要把某些变量和数据临时存放在堆栈中,当然,还包括中断发生时被压入堆栈的寄存器数据。

由于STC官方移植的FreeRTOS运行的内存模式为“XSmall”模式,在这个模式下,用户定义的任务的堆栈也放在了EDATA区域中。因此FreeRTOS采取了哪个任务运行,就将SPX堆栈运行在那个任务的任务堆栈中的方法,任务切换时只需要保存和恢复SPX的值,整个任务堆栈的内容就被保存和恢复了。下图是任务堆栈保存与恢复的程序:
Fig_X06_堆栈现场.jpg
其中DR60包括了SPX,第49行将其赋值到DR0,第50行将当前任务的任务表地址赋值给DR4,然后第51行和第52行分两个16位用间接寻址的方式保存SPX的值,实现了任务堆栈的保存。第59行到第62行是恢复任务SPX的值,完成恢复任务的功能。
采用这种将用户任务堆栈设置在EDATA空间的方法,由于只保存和恢复SPX寄存器的值,不用进行堆栈内容复制,所以任务切换速度极快。但也注定STC官方移植的FreeRTOS V1.02版本只能运行在“XSmal”模式。
三、C251中断时的现场保护与恢复
在实际的FreeRTOS项目中,除了系统的定时器0中断外,还有其他的中断,在这些中断中,如何保存中断保存和恢复当前任务现场,如何协调这些中断与FreeRTOS任务调度之间的关系,对于保障RTOS程序的正确运行很重要。

(11)C251无局部变量中断服务函数。下图为一个典型的例子:
Fig_X07A_无变量中断.jpg
这个例子里,实际的中断服务程序写在另一个程序文件中,这里就只有一个函数访问语句,在中断函数里没有使用局部变量。下面是对应的编译后的汇编语言列表:
Fig_X07B_无变量中断.jpg
对比前面FreeRTOS的定时器0系统中断,一个是没有保存DR12,另一个是DR56中,只保存了DPTR部分,没有保存DPXL8位寄存器部分。
这是C251的约定:首先DR12(包括WR12、WR14、R12~R15)寄存器,保留给中断函数中的局部变量使用,其他地方对C语言的编译都不会使用,用户编程时可以把它作为临时变量使用;其次,DPXL的值由Keil的C251编程环境在单片机启动时设置,用户程序和C251编译器自己都不得改变它。

(12)C251有局部变量中断服务函数。下图为一个典型的例子:
Fig_X08A_有变量中断.jpg
这是CAN1的中断服务程序,里面有两个8位的变量“isr”和“store”,下图是编译后的中断现场保存程序:
Fig_X08B_有变量中断.jpg
从上图中可以看到比无变量情况,增加了“PUSH  R15”指令。这是因为C251编译器将R15作为“store”变量使用。由于本中断程序使用了“R15”,所以将用户任务的“R15”作为现场保存,待中断任务完成后再与其他寄存器一起恢复出来。

(13)C251简单中断服务函数。下图为一个典型的例子:
Fig_X09A_简单中断.jpg
这是定时器1的中断程序,它只是将P66的LED灯的电平翻转。下图是对应的编译后汇编语言列表:
Fig_X09B_简单中断.jpg
从图中可以看到,除了硬件中断本身推入堆栈的24位PC和PSW1外,没有再保存任何寄存器,包括PSW。这是因为“CPL   P66”这条指令,不涉及任何寄存器,也不改变任何PSW中的标志位,所以不需要保存和恢复硬件中断外的其他现场。
(14)结论。对于C251编译器,如果用户打开高级别优化选项,那么编译器就会分析中断程序的内容,自动地决定要保存或恢复多少中断现场。

(15)下面是C51编译器对STC8H8K单片机键盘扫描范例中的中断程序:
Fig_X10A_C51.jpg
其对应的编译结果为:
Fig_X10B_C51.jpg
对比上面C251和这里C51保存中断现场的程序,这里在保存寄存器现场中明显第加入了“MOV PSW, #00”指令,而C251在任何情况下都没有这条指令,这是为什么?限于篇幅,后文将给出详细的原因分析。
下面是本文范例的程序:
FreeRTOS-STC32G-CORE-V1.0.2.rar (3.66 MB, 下载次数: 50)
回复 送花

使用道具 举报

该用户从未签到

0

主题

5

回帖

22

积分

新手上路

积分
22
发表于 昨天 14:19 | 显示全部楼层
老师:下载下来后,把工程原程序打开,重新编译,显示如下
TO ".\Objects\FreeRTOS_Demo"
PRINT(".\Listings\FreeRTOS_Demo.map") IXREF
CASE DISABLEWARNING (16, 57)
REMOVEUNUSED
CLASSES (EDATA (0x0-0xFFF),
HDATA (0x0-0xFFF))
******************************************************************************
* RESTRICTED VERSION WITH 0800H BYTE CODE SIZE LIMIT; USED: 95E6H BYTE (1873%) *
******************************************************************************
Program Size: data=15.3 edata+hdata=3683 xdata=0 const=255 code=14829
*** ERROR L250: CODE SIZE LIMIT IN RESTRICTED VERSION EXCEEDED
    LIMIT:   0800H BYTES
Target not created.
Build Time Elapsed:  00:00:32

不知道什么原因?
回复 支持 反对 送花

使用道具 举报

  • TA的每日心情
    奋斗
    昨天 02:25
  • 签到天数: 28 天

    [LV.4]偶尔看看III

    0

    主题

    24

    回帖

    474

    积分

    中级会员

    积分
    474
    发表于 昨天 15:59 | 显示全部楼层
    zjw700807 发表于 2024-6-2 14:19
    老师:下载下来后,把工程原程序打开,重新编译,显示如下
    TO ".\Objects\FreeRTOS_Demo"
    PRINT(".\Listin ...

    keil没有和谐,代码超了
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    0

    主题

    5

    回帖

    22

    积分

    新手上路

    积分
    22
    发表于 昨天 18:38 | 显示全部楼层
    老师:我从工程文件的Objects目录下把FreeRTOS_Demo.hex写入到实验箱9.62中,实验箱的LED灯是可以运行的。但我重新编译一下想下载就是通不过,老师是怎样通过编译的?我看网上说要Keil注册License之类的,是不是这个原因?现在Keil版本是V5.60.0.0。编译以前不用FreeRTOS的程序都可以,现在这个例程就不行,也不知道怎么回事。
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    0

    主题

    5

    回帖

    22

    积分

    新手上路

    积分
    22
    发表于 昨天 19:07 | 显示全部楼层
    蜗牛 发表于 2024-6-2 15:59
    keil没有和谐,代码超了

    老师:我从工程文件的Objects目录下把FreeRTOS_Demo.hex写入到实验箱9.62中,实验箱的LED灯是可以运行的。但我重新编译一下想下载就是通不过,老师是怎样通过编译的?我看网上说要Keil注册License之类的,是不是这个原因?现在Keil版本是V5.60.0.0。编译以前不用FreeRTOS的程序都可以,现在这个例程就不行,也不知道怎么回事。

    点评

    就是这个原因,你其它能编译通过的,code超过2K了吗?  发表于 昨天 19:14
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    0

    主题

    5

    回帖

    22

    积分

    新手上路

    积分
    22
    发表于 昨天 22:47 | 显示全部楼层
    zjw700807 发表于 2024-6-2 19:07
    老师:我从工程文件的Objects目录下把FreeRTOS_Demo.hex写入到实验箱9.62中,实验箱的LED灯是可以运行的 ...

    用冲哥的“任意频率的PWM输出和死区互补波形输出”编译出来的软件CODE是7713,

    Program Size: data=8.4 edata+hdata=422 xdata=192 const=66 code=7713
    creating hex file from ".\Objects\Demo"...
    ".\Objects\Demo" - 0 Error(s), 2 Warning(s).
    Build Time Elapsed:  00:00:04

    这个是可以运行,也可以重新编译的,应该不是Keil v5.60的问题吧。冲哥的这个软件不是FreeRTOS的,是一个裸机版,这两的编译区别到底在哪里?请各位老师同学指导,FreeRTOS新手上路,要学习的地方太多了。

    点评

    感觉还是这个原因, 我的 license:PK251 Prof. Developers Kit 看一下你的一样吗  详情 回复 发表于 15 小时前
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    1 小时前
  • 签到天数: 190 天

    [LV.7]常住居民III

    5

    主题

    620

    回帖

    2535

    积分

    荣誉版主

    积分
    2535
    发表于 15 小时前 | 显示全部楼层
    zjw700807 发表于 2024-6-2 22:47
    用冲哥的“任意频率的PWM输出和死区互补波形输出”编译出来的软件CODE是7713,

    Program Size: data=8.4  ...

    感觉还是这个原因,
    我的 license:PK251 Prof. Developers Kit
    看一下你的一样吗
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    0

    主题

    5

    回帖

    22

    积分

    新手上路

    积分
    22
    发表于 14 小时前 | 显示全部楼层
    蜗牛 发表于 2024-6-2 15:59
    keil没有和谐,代码超了

    老师:折腾了一晚上,原来是Keil的License没有注册,下载一个注册机重新注册后,把工程原代码重新编译,没有问题了。
    linking...
    Program Size: data=15.3 edata+hdata=3683 xdata=0 const=255 code=14957
    creating hex file from ".\Objects\FreeRTOS_Demo"...
    ".\Objects\FreeRTOS_Demo" - 0 Error(s), 0 Warning(s).
    Build Time Elapsed:  00:00:23

    重新下载FreeRTOS_Demo.hex文件,程序正常启动。

    谢谢老师,幸苦了。
    回复 支持 反对 送花

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

    GMT+8, 2024-6-3 16:22 , Processed in 0.070124 second(s), 61 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

    快速回复 返回顶部 返回列表