移值UCOS2到M4核与M3核的区别
之前移值过ucos2到stm32f2系列的单片机,这个单片机是属于arm的m3内核的。最近在学习永磁同步电机的控制,对于这个电机的控制,有比较多的数学计算,甚至于还有浮点的运算。所以用到了stm32f4系列的单片机,这个单片机内置FPU,可以用几条指令就可以处理单精度的浮点数据,而它是属于M4内核的。因为原先移植过M3的基础,想着应该很快会搞定,没想到移植了几天的时间才搞清楚,下面就记录下M3与M4内核的ucos2的移植不同之处。其实M3与M4内核相差不大,对于我应用的来说,其实最大的不同一是M4的最大主频提高了,二是M4带浮点功能。
1、ucos2移植到M3核的重点(对于ucos2移植到M3内核详细的讲解以及ucos2的结构后续会单独写一篇博客描述)
M3核对于操作系统的支持很好,它有一个NVIC向量中断控制器,它管理着对CM3的所有中断请求。其中有几个队操作系统很重要的中断:
a、SVC(系统服务调用),用于产生系统函数的调用请求,例如操作系统通常不让用户程序直接访问硬件,而是通过提供一些系统服务函数,让用户程序使用SVC发出对系统服务函数的呼叫请求,以这种方法调用它们来间接访问硬件。因此,当用户程序想要控制特定的硬件时,它就要产生一个SVC异常,然后操作系统提供的SVC异常服务例程得到执行,它再调用相关的操作系统函数,后者完成用户程序请求的服务。这与传统的arm核比如arm7与amr9等的SWI的软件中断异常类似。
b、PendSV(可悬起的系统中断),它是可以像普通的中断一样被悬起的(不像SVC那样会上访)。OS可以利用它“缓期执行”一个异常——直到其它重要的任务完成后才执行动作。悬起PendSV 的方法是:手工往NVIC的PendSV悬起寄存器中写1。悬起后,如果优先级不够高,则将缓期等待执行。所以它常常 被用来进行任务的切换,UCOS2的任务切换就是在这个中断里面实现的。
c、SysTick定时器被捆绑在NVIC中,用于产生SysTick异常(异常号:15)。SysTick定时器能产生中断,CM3为它专门开出一个异常类型,并且在向量表中有它的一席之地。它用于操作系统的滴答时钟。在以前,操作系统还有所有使用了时基的系统,都必须一个硬件定时器来产生需要的“滴答”中断,作为整个系统的时基。滴答中断对操作系统尤其重要。例如,操作系统可以为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。
ucos2对每一个任务都会分配一个任务控制块,任务控制块的首地址存放着该任务的堆栈指针,它存放的数据的格式如在函数,可以看到它的堆栈是向下递增的,也就是说堆栈顶部的位置始终是数值大的地址。首先存放的是M3内核发生异常时自动保存的数据,可以看到任务的函数地址也被保存在内,它的值其实就是任务发生切换时PC的值,如果后续要切换回这个任务了只要做一次PendSV中断,切换PSP指针为这个任务的堆栈指针,当从PendSV中断返回时task的值就会自动的存放到PC寄存器中,这样就做到了任务切换。接着保存M3内核发生异常时没有自动保存的寄存器,剩下的堆栈内容就保存任务函数的一些变量以及函数调用等等。
OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt)
{
OS_STK *p_stk; (void)opt; /* 'opt' is not used, prevent warning */
p_stk = ptos; /* Load stack pointer */
/* Registers stacked as if auto-saved on exception */
*(--p_stk) = (OS_STK)0x01000000uL; /* xPSR */
*(--p_stk) = (OS_STK)task; /* Entry Point */
*(--p_stk) = (OS_STK)OS_TaskReturn; /* R14 (LR) */
*(--p_stk) = (OS_STK)0x12121212uL; /* R12 */
*(--p_stk) = (OS_STK)0x03030303uL; /* R3 */
*(--p_stk) = (OS_STK)0x02020202uL; /* R2 */
*(--p_stk) = (OS_STK)0x01010101uL; /* R1 */
*(--p_stk) = (OS_STK)p_arg; /* R0 : argument */
/* Remaining registers saved on process stack */
*(--p_stk) = (OS_STK)0x11111111uL; /* R11 */
*(--p_stk) = (OS_STK)0x10101010uL; /* R10 */
*(--p_stk) = (OS_STK)0x09090909uL; /* R9 */
*(--p_stk) = (OS_STK)0x08080808uL; /* R8 */
*(--p_stk) = (OS_STK)0x07070707uL; /* R7 */
*(--p_stk) = (OS_STK)0x06060606uL; /* R6 */
*(--p_stk) = (OS_STK)0x05050505uL; /* R5 */
*(--p_stk) = (OS_STK)0x04040404uL; /* R4 */
return (p_stk);
}
接着看到UCOS2在M3内核下运行时的任务切换代码,可以看到任务切换函数,主要是将被打断任务的堆栈保存好,然后将需要运行的任务的堆栈出栈,任何以从进程堆栈中做出栈操作,进行任务切换
PendSV_Handler //;中断处理函数
CPSID I //; Prevent interruption during context switch ;在任务切换时禁止其它中断
MRS R0, PSP //; PSP is process stack pointer ;
CBZ R0, OS_CPU_PendSVHandler_nosave //; Skip register save the first time ;检查是否是从进程中进来的,如果不是,直接跳到OS_CPU_PendSVHandler_nosave SUBS R0, R0, #0x20 //; Save remaining regs r4-11 on process stack; 保存中断上下文未自动保存的寄存器
STM R0, {R4-R11} LDR R1, =OSTCBCur // ; OSTCBCur->OSTCBStkPtr = SP;
LDR R1, [R1]
STR R0, [R1] //; R0 is SP of process being switched out 保存当前任务堆栈指针到当前任务控制块 //; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
PUSH {R14} //; Save LR exc_return value
LDR R0, =OSTaskSwHook //; OSTaskSwHook();
BLX R0 //;
POP {R14} //;//只是为了调用OSTaskSwHook函数 LDR R0, =OSPrioCur //; OSPrioCur = OSPrioHighRdy;
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0] //当前优先级变为找出的需要运行最高优先级任务 LDR R0, =OSTCBCur //; OSTCBCur = OSTCBHighRdy;
LDR R1, =OSTCBHighRdy
LDR R2, [R1]
STR R2, [R0] //当前任务控制块变为找出需要运行的任务控制块 准备切换任务堆栈 LDR R0, [R2] //; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
LDM R0, {R4-R11} // ; Restore r4-11 from new process stack 取出新任务的R4-R11寄存器值
ADDS R0, R0, #0x20
MSR PSP, R0 // ; Load PSP with new process SP 切换新任务指针给PSP
ORR LR, LR, #0x04 // ; Ensure exception return uses process stack 从进程堆栈中作出出栈操作
CPSIE I // ; 开启中断
BX LR // ; Exception return will restore remaining context 任务切换,切换到新任务被切换时的地址 END
2、ucos2移植到M4核
UCOS2在M3与M4运行任务切换时的原理是一样的,都是利用的PendSV中断。但是保存的寄存器有所不同,因为M4内核可以支持单精度浮点操作,这样就会有了浮点相关的寄存器的保存。这就是与M3内核最大的不同之处。支持浮点运算的M4内核比M3内核多一个FPU模块,它里面有33个寄存器,其中S0-S16是异常上下文会自动保存的。

a、M4内核堆栈的初始化,与M3相比多了保存34个寄存的内容
OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt)
{
OS_STK *p_stk; (void)opt; /* 'opt' is not used, prevent warning */
p_stk = ptos; /* Load stack pointer */ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
*(--p_stk) = (INT32U)0x00000000L; //No Name Register
*(--p_stk) = (INT32U)0x00001000L; //FPSCR
*(--p_stk) = (INT32U)0x00000015L; //s15
*(--p_stk) = (INT32U)0x00000014L; //s14
*(--p_stk) = (INT32U)0x00000013L; //s13
*(--p_stk) = (INT32U)0x00000012L; //s12
*(--p_stk) = (INT32U)0x00000011L; //s11
*(--p_stk) = (INT32U)0x00000010L; //s10
*(--p_stk) = (INT32U)0x00000009L; //s9
*(--p_stk) = (INT32U)0x00000008L; //s8
*(--p_stk) = (INT32U)0x00000007L; //s7
*(--p_stk) = (INT32U)0x00000006L; //s6
*(--p_stk) = (INT32U)0x00000005L; //s5
*(--p_stk) = (INT32U)0x00000004L; //s4
*(--p_stk) = (INT32U)0x00000003L; //s3
*(--p_stk) = (INT32U)0x00000002L; //s2
*(--p_stk) = (INT32U)0x00000001L; //s1
*(--p_stk) = (INT32U)0x00000000L; //s0
#endif /* Registers stacked as if auto-saved on exception */
*(--p_stk) = (OS_STK)0x01000000uL; /* xPSR */
*(--p_stk) = (OS_STK)task; /* Entry Point */
*(--p_stk) = (OS_STK)OS_TaskReturn; /* R14 (LR) */
*(--p_stk) = (OS_STK)0x12121212uL; /* R12 */
*(--p_stk) = (OS_STK)0x03030303uL; /* R3 */
*(--p_stk) = (OS_STK)0x02020202uL; /* R2 */
*(--p_stk) = (OS_STK)0x01010101uL; /* R1 */
*(--p_stk) = (OS_STK)p_arg; /* R0 : argument */ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
*(--p_stk) = (INT32U)0x00000031L; //s31
*(--p_stk) = (INT32U)0x00000030L; //s30
*(--p_stk) = (INT32U)0x00000029L; //s29
*(--p_stk) = (INT32U)0x00000028L; //s28
*(--p_stk) = (INT32U)0x00000027L; //s27
*(--p_stk) = (INT32U)0x00000026L; //s26
*(--p_stk) = (INT32U)0x00000025L; //s25
*(--p_stk) = (INT32U)0x00000024L; //s24
*(--p_stk) = (INT32U)0x00000023L; //s23
*(--p_stk) = (INT32U)0x00000022L; //s22
*(--p_stk) = (INT32U)0x00000021L; //s21
*(--p_stk) = (INT32U)0x00000020L; //s20
*(--p_stk) = (INT32U)0x00000019L; //s19
*(--p_stk) = (INT32U)0x00000018L; //s18
*(--p_stk) = (INT32U)0x00000017L; //s17
*(--p_stk) = (INT32U)0x00000016L; //s16
#endif
/* Remaining registers saved on process stack */
*(--p_stk) = (OS_STK)0x11111111uL; /* R11 */
*(--p_stk) = (OS_STK)0x10101010uL; /* R10 */
*(--p_stk) = (OS_STK)0x09090909uL; /* R9 */
*(--p_stk) = (OS_STK)0x08080808uL; /* R8 */
*(--p_stk) = (OS_STK)0x07070707uL; /* R7 */
*(--p_stk) = (OS_STK)0x06060606uL; /* R6 */
*(--p_stk) = (OS_STK)0x05050505uL; /* R5 */
*(--p_stk) = (OS_STK)0x04040404uL; /* R4 */ return (p_stk);
}
a、M4内核的任务切换,与M3相比多了保存16个寄存器
PendSV_Handler //;中断处理函数
CPSID I //; Prevent interruption during context switch ;在任务切换时禁止其它中断
MRS R0, PSP //; PSP is process stack pointer ;
CBZ R0, OS_CPU_PendSVHandler_nosave //; Skip register save the first time ;检查是否是从进程中进来的,如果不是,直接跳到OS_CPU_PendSVHandler_nosave //;Is the task using the FPU context? If so, push high vfp registers.支持M4内核保存S16-S31寄存器
TST R14, #0x10
IT EQ
VSTMDBEQ R0!, {S16-S31} SUBS R0, R0, #0x20 //; Save remaining regs r4-11 on process stack; 保存中断上下文未自动保存的寄存器
STM R0, {R4-R11} LDR R1, =OSTCBCur // ; OSTCBCur->OSTCBStkPtr = SP;
LDR R1, [R1]
STR R0, [R1] //; R0 is SP of process being switched out 保存当前任务堆栈指针到当前任务控制块 //; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
PUSH {R14} //; Save LR exc_return value
LDR R0, =OSTaskSwHook //; OSTaskSwHook();
BLX R0 //;
POP {R14} //;//只是为了调用OSTaskSwHook函数 LDR R0, =OSPrioCur //; OSPrioCur = OSPrioHighRdy
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0] //当前优先级变为找出的需要运行最高优先级任务 LDR R0, =OSTCBCur //; OSTCBCur = OSTCBHighRdy;
LDR R1, =OSTCBHighRdy
LDR R2, [R1]
STR R2, [R0] //当前任务控制块变为找出需要运行的任务控制块 准备切换任务堆栈 LDR R0, [R2] //; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
LDM R0, {R4-R11} // ; Restore r4-11 from new process stack 取出新任务的R4-R11寄存器值
ADDS R0, R0, #0x20 ;Is the task using the FPU context? If so, push high vfp registers.支持M4内核出栈S16-S31寄存器
TST R14, #0x10
IT EQ
VLDMIAEQ R0!, {S16-S31} MSR PSP, R0 // ; Load PSP with new process SP 切换新任务指针给PSP
ORR LR, LR, #0x04 // ; Ensure exception return uses process stack 从进程堆栈中作出出栈操作
CPSIE I // ; 开启中断
BX LR // ; Exception return will restore remaining context 任务切换,切换到新任务被切换时的地址 END
以上就是移值UCOS2到M4核与M3核的区别
移值UCOS2到M4核与M3核的区别的更多相关文章
- dotnet core 在 MIPS 下的移值进度
本文仍处于修订中 写在开始前 我们的主要业务基于 dotnet core 2.x 与 3.1 完成,目前 dotnet core 3.1 支持的 CPU 架构列表中还不包含龙芯,且在 gitlab i ...
- 物理CPU、物理核跟逻辑核的区分
一般来说,物理CPU个数×每颗核数就应该等于逻辑CPU的个数,如果不相等的话,则表示服务器的CPU支持超线程技术 ,所以您的电脑是双核的. 一 概念① 物理CPU 实际Server中插槽上的CPU个数 ...
- sql 中获取最后生成的标识值 IDENT_CURRENT ,@@IDENTITY ,SCOPE_IDENTITY 的用法和区别
原文:sql 中获取最后生成的标识值 IDENT_CURRENT ,@@IDENTITY ,SCOPE_IDENTITY 的用法和区别 IDENT_CURRENT 返回为任何会话和任何作用域中的指定表 ...
- 04. prosition 的值都有哪些,其最本质的区别在哪里?
4.prosition 的值都有哪些,其最本质的区别在哪里? position:relative 相对定位 position:fixed 相对浏览器定位 position:absolute 绝对定位 ...
- dm9000c 移值新内核 linux-4.1.24
错误 1 /home/dm9000/dm9dev9000c.c:309: error: conflicting types for 'phy_read'include/linux/phy.h:637: ...
- s3c2440 移值u-boot-2016.03 第6篇 支持mtd yaffs 烧写
1, 解决启动时的错误 Warning - bad CRC, using default environment 搜索发现 在 /tools/env/fw_env.c 中 /* 放在NAND FLAS ...
- s3c2440 移值u-boot-2016.03 第3篇 支持Nor flash 识别
当选择,NOR flash 启用时,才可以访问 NOR FLASH ./common/board_r.c 364 line:initr_flash()flash_size = flash_init() ...
- uCos-II移值(一)
os_cpu.h文件 该文件主要是完成操作系统使用的内部数据类型.常数以及宏的定义,这些都是与处理器平台密切相关的: 第一部分 以下部分定义了系统内部常用的数据类型,为了增加系统的可移植性,系统内核只 ...
- uCos-II移值(二)
os_cpu_c.c文件 该文件主要是根据处理器平台特点完成任务堆栈初始化函数OSTaskStkInit以及其他几个用户Hook函数的编写,其中必须要实现的函数是OSTaskStkInit(在创建任务 ...
随机推荐
- 命令纠正工具 thefuck 的简单使用
在unix系列的系统中,总会出现 命令拼写或者执行错误的情况, 比如 把 python 写成了pythou, cd 到一个不存在的目录,执行任务的权限 不够的问题, 这是心里 总是 在 fuck,但是 ...
- React Native仿京东客户端实现(首页 分类 发现 购物车 我的)五个Tab导航页面
1.首先创建 这几个文件 myths-Mac:JdApp myth$ yarn add react-native-tab-navigator 2.各个文件完整代码 1)CartPage.js imp ...
- 利用jvisualvm使用btrace进行线上调试案例
用途:btrace主要用于线上调试.通过btrace,可在不改动代码的前提下,方便的发现以下问题: 1.定位性能慢的接口服务: 2.实时打印堆栈信息,定位死锁位置: 3.定位占用大量内存空间的代码块: ...
- css样式的书写顺序及原理——很重要!
记得刚开始学习前端的时候,每次写css样式都是用到什么就在样式表后添加什么,完全没有考虑到样式属性的书写顺序对网页加载代码的影响.后来逐渐才知道正确的样式顺序不仅易于查看,并且也属于css样式优化的一 ...
- 每日一练之大整数加法(P1255 数楼梯)
走楼梯走一步还是两步的问题其实就是斐波那契数列(F(n)=F(n-1)+F(n-2),而在int型范围内存在45个相异的数,题干说明楼梯总数可以为5000,则考虑使用字符串进行存储.当两个数相加产生进 ...
- requests和session的区别
简单说 request对象和session对象的最大区别是生命周期. -request request对象的生命周期是针对一个客户端(说确切点就是一个浏览器应用程序)的一次请求,当请求完毕之后,req ...
- 颜色空间的转换系列 (一) ——RGB2XYZ/LAB
http://www.wk78.com/forum.php?mod=forumdisplay&fid=2&page=1 文件在论坛. 然后需要解决一个问题: 我直接复制过来了,自己看吧 ...
- JS创建一个数组1.求和 2.求平均值 3.最大值 4.最小值 5.数组逆序 6.数组去重 0.退出
rs = require("readline-sync"); let arr = []; console.log("请输入数组的长度:"); let arr_l ...
- python中re正则表达式
1.re匹配的语法 re.math 从头开始匹配,没有匹配到返回None re.seach 匹配包含,,没有匹配到返回None re.findall 把所有匹配到的字符,以列表的形式返回,没有匹配到返 ...
- 关于activity的一点总结(一)
关于activity的重点: 参考网址:https://blog.csdn.net/qq_26787115/article/details/52556842 一.activity生命周期. 二..启动 ...