硬汉嵌入式论坛

 找回密码
 立即注册
查看: 5831|回复: 8
收起左侧

[FreeRTOS] 基于STM32 操作系统 任务切换 原理 个人心的(基于 U/COS II 和 FreeRTOS)

[复制链接]

32

主题

262

回帖

363

积分

高级会员

积分
363
发表于 2018-11-12 14:54:17 | 显示全部楼层 |阅读模式
本帖最后由 在水一方 于 2018-11-12 16:44 编辑

STM32的 堆栈分析
STM32 xPSR影响的条件指令
STM32寄存器说明:
R0-R12:通用寄存器
R0‐R12 都是 32 位通用寄存器,用于数据操作。但是注意:绝大多数 16 位 Thumb 指令只能访
问 R0‐R7,而 32 位 Thumb‐2 指令可以访问所有寄存器。
Banked R13: 两个堆栈指针
Cortex‐M3 拥有两个堆栈指针,然而它们是 banked,因此任一时刻只能使用其中的一个。
主堆栈指针(MSP),这个地址就是我们进入main 函数时使用的堆栈 查看工程的map文件 __initial_sp:
进程堆栈指针(PSP),由用户的应用程序代码使用。
R14:连接寄存器, 存储返回地址
/*在中断前未使用FPU*/
0xFFFF_FFF1 返回handler模式0xFFFF_FFF9 返回线程模式,并使用主堆栈(SP=MSP)
0xFFFF_FFFD 返回线程模式,并使用线程堆栈(SP=PSP)

/*在中断前使用FPU*/

0xFFFF_FFE1 返回handler模式   0xFFFF_FFE9 返回线程模式,并使用主堆栈(SP=MSP)
0xFFFF_FFED 返回线程模式,并使用线程堆栈(SP=PSP)


R15:程序计数寄存器指向当前的程序地址。如果修改它的值,就能改变程序的执行流特殊功能寄存器
程序状态字寄存器组(PSRs)
中断屏蔽寄存器组(PRIMASK, FAULTMASK, BASEPRI)
控制寄存器(CONTROL)

请在 《Cortex M3权威指南》中查看 26页寄存器的意义 ,在121页查看 SVC 和 PendSV 异常

1.堆栈的初始化
①. 堆栈的定义:uint32_t TEST_TASK_STK[128],这里存放着 临时变量压栈信息,以及R0~R15,xPSR 寄存器 。在任务切换的时候使用
②. 堆栈的位置: STM32为 堆栈向下生长的方式,所以我们的堆栈定义位置则是 TEST_TASK_STK[128 - 1] 这个数组的最后一位地址。
③. 堆栈的初始化:
堆栈在内存的的排列
;xPSR        状态寄存器                        栈顶
;R15        PC
;R14        LR
;R12
;R3
;R2
;R1
;R0                任务形参

;手动保存寄存器                                其他形参都在压栈中
;R14
;R11
;R10
;R9
;R8
;R7
;R6
;R5
;R4

uint32_t  *stk = (uint32_t *)&TEST_TASK_STK[128 - 1];               /* 这里定义一个指针指向堆栈顶部  */
/* 这里的赋值顺序根据 寄存器在堆栈中的排列         */
*(stk)   = (uint32_t)0x01000000L;                                                         /* xPSR 程序状态寄存器 这一部分值PSP自动保存         */
*(--stk) = (uint32_t)task;                                                                        /* 加载任务函数         这里是我们线程函数                 */
*(--stk) = (uint32_t)SX_TaskError;                                                               /* R14 (LR) 加载退出任务 错误函数 任务不能return         */
        stk -= 4;                                                                                               /* 这里存放 R12, R3, R2 and R1. 四个寄存器            */
*(--stk) = (uint32_t)p_arg;                                                                     /* R0 : 形参                     任务的入口形参                 */                                                                        
*(--stk) = (uint32_t)0xfffffffdL;                                                                       /* R14默认返回线程模式,并使用线程堆栈(SP=PSP)*/
        stk -= 8;                                                                                          /* R11, R10, R9, R8, R7, R6, R5 and R4.                         */
此时堆栈的指针位置在 stk ,在任务切换的时候 加载的就是此时的stk值。

④.通过链表 把 任务的 控制块 连接到一起,实现了任务的讯轮


2.任务的启动

①.调用启动函数
SXTCBCur:当前运行任务  初始化 为0
SXTCBReady :为当前就绪任务  初始化为 第一个需要运行的任务

SXTCBStart                                          ; 任务启动函数
        LDR     R0, =NVIC_SYSPRI14      ; 设置 PendSV 优先级
        LDR     R1, =NVIC_PENDSV_PRI
        STR     R1, [R0]

        CPSIE   I                                        ; 使能中断
        SVC           0                                    ;触发SVC中断
        NOP

SVC_Handler                                          ; SVC_Handler异常中断处理
        LDR     R0, =SXRunning                   ; SSRunning = TRUE    全局变量 系统启动标志
        MOV     R1, #1
        STRB    R1, [R0]
        
        LDR     R0, =SXTCBCur              ; 把 SXTCBReady 任务 加载到 SXTCBCur
        LDR     R1, =SXTCBReady
        LDR     R2, [R1]
        STR     R2, [R0]

        LDR     R0, [R2]                        ; 我们将新的栈地址送到R0
        LDMIA   R0!, {R4-R11,R14}     ; 将R4-R11,R14从栈弹出加回偏移地址(回到R0 的地址),在执行BX跳转指令时,硬件能从正确的栈地址自动弹出;R0-R3,R12,LR,PSR,PC的内容

        MSR         PSP, R0                   ; 给加载 堆栈指针到 PSP中
        BX                R14                        ;跳转到第一个任务


3.任务的切换
①.任务的切换思想
    最简单的任务切换时轮训 没有优先级的,每次滴答定时器中断时从当前任务指向的下一个任务轮训查找就绪任务;有优先级的 通过优先级组,从高优先级轮训到低优先级查询人物状态。
②.任务的切换触发
        LDR     R0, =NVIC_INT_CTRL          ; 触发PendSV_Handler 异常 中断(causes context switch)
        LDR     R1, =NVIC_PENDSVSET
        STR     R1, [R0]
        BX      LR

③.任务的切换
PendSV_Handler
        CPSID   I                                                   ; 关闭中断 避免 任务切换被打断
        MRS     R0, PSP                                        ; 保存 PSP 堆栈 (PSP 堆栈为线程堆栈,MSP 堆栈为 主堆栈 main)

        TST                R14, #0x10                                ; 堆栈是否使用 FPU ?
        IT                EQ                                           ;  如果使用
        VSTMDBEQ R0!,{S16-S31}                        ;  要将高 16个vfp 寄存器压栈

        STMDB   R0!, {R4-R11,R14}                        ; 保存当前任务的 R4-R11,        R14的寄存器值;进入中断时 R0-R3,R12,LR,PSR,PC会自动存储到当前任务堆栈 R0地址-32

        LDR     R1, =SXTCBCur                             ; 将当前的 TCB 赋值给R1 寄存器
        LDR     R1, [R1]                                        ;
        STR     R0, [R1]                                        ; 将 R0 保存的堆栈信息 保存到 R1 中 到此 堆栈保存已经结束  下面开始任务的切换

        LDR     R0, =SXTCBCur                             ; 把 SXTCBCur         赋值给 R0
        LDR     R1, =SXTCBReady                                ; 将 SXTCBReady        赋值给 R1
        LDR     R2, [R1]                                        ; 加载 SXTCBReady 到R2寄存器
        STR     R2, [R0]                                        ; 存储 SXTCBReady 到 R0寄存器

        LDR     R0, [R2]                                       ; 我们将新的栈地址送到R0
        LDMIA   R0!, {R4-R11,R14}                    ; 将R4-R11,R14从栈弹出加回偏移地址(回到R0 的地址),在执行BX跳转指令时,硬件能从正确的栈地址自动弹出;R0-R3,R12,LR,PSR,PC的内容

        TST         R14, #0x10                                       ; 堆栈是否使用 FPU ? 如果使用 要将高 16个vfp 寄存器弹出
        IT                 EQ
        VLDMIAEQ R0!, {S16-S31}

        MSR     PSP, R0                                       ; 将R0中的栈地址送到PSP线程栈
        ORR     LR, LR, #0x04                             ; 这句是确保后面执行BX命令时使用的是线程栈 SP,而不是主堆栈MSP
        CPSIE   I                                                       ; 开总中断
        BX      LR                                                 ; 执行中断返回,此时R0-R3,R12,LR,PSR,PC自动 ;出栈  在这里任务 任务切换完毕
由于不能上传文件,放网盘了
链接:https://pan.baidu.com/s/1Z731y7d_sf3RGUWc4FzBZQ
提取码:17r6


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106705
QQ
发表于 2018-11-12 14:59:31 | 显示全部楼层
谢谢楼主分享。
回复

使用道具 举报

32

主题

262

回帖

363

积分

高级会员

积分
363
 楼主| 发表于 2018-11-12 15:08:04 | 显示全部楼层
本帖最后由 在水一方 于 2018-11-12 15:21 编辑

为什么  我图片 和 程序 都发不上了啊,给您QQ发消息了
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106705
QQ
发表于 2018-11-12 15:29:13 | 显示全部楼层
在水一方 发表于 2018-11-12 15:08
为什么  我图片 和 程序 都发不上了啊,给您QQ发消息了

可以上传和提交,你可以这样,你编辑好,保存下。

我来给你提交下
回复

使用道具 举报

32

主题

262

回帖

363

积分

高级会员

积分
363
 楼主| 发表于 2018-11-12 16:23:17 | 显示全部楼层
eric2013 发表于 2018-11-12 15:29
可以上传和提交,你可以这样,你编辑好,保存下。

我来给你提交下

还是不行,上传不成功,提示我 IO 错误。
回复

使用道具 举报

32

主题

262

回帖

363

积分

高级会员

积分
363
 楼主| 发表于 2018-11-12 17:44:32 | 显示全部楼层
遇到什么问题可以,可以在本贴讨论
回复

使用道具 举报

0

主题

22

回帖

22

积分

新手上路

积分
22
发表于 2020-6-16 14:35:37 | 显示全部楼层
谢谢分享!
回复

使用道具 举报

38

主题

196

回帖

320

积分

高级会员

积分
320
发表于 2021-5-18 11:22:24 | 显示全部楼层
为什么要有R0~R12这么多寄存器?
我看那些文章,PC,和SP指针我能理解,但是R0~R12这些寄存器又是做什么用的呢?
回复

使用道具 举报

95

主题

297

回帖

582

积分

金牌会员

123

积分
582
发表于 2021-5-21 08:13:19 | 显示全部楼层
我帮上传一下

操作系统任务切换_bysx.zip

499.46 KB, 下载次数: 18

回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-4-30 09:41 , Processed in 0.211973 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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