os_cpu_a.asm
这个文件包含着必须用汇编写的代码。
EXTERN
OSRunning
; External references
EXTERN
OSPrioCur
EXTERN
OSPrioHighRdy
EXTERN
OSTCBCur
EXTERN
OSTCBHighRdy
EXTERN
OSIntNesting
EXTERN
OSIntExit
EXTERN
OSTaskSwHook
申明这些变量是在其他文件定义的,本文件只做引用(有几个好像并未引用,不过没有关系)。
EXPORT
OS_CPU_SR_Save
; Functions declared in this file
EXPORT
OS_CPU_SR_Restore
EXPORT
OSStartHighRdy
EXPORT
OSCtxSw
EXPORT
OSIntCtxSw
EXPORT
OS_CPU_PendSVHandler
; #0
#0这里 OS_CPU_PendSVHandler 要替换为PendSV_Handler;如下图:
替换后的 PPendSV中断
声明这些函数是在本文件中定义的。EXPORT这个关键字是跟编译器有关的,能被keil识别,但不能被IAR 识别。
NVIC_INT_CTTRL
EQU
0xE000ED04
;中断控制及状态寄存器 ICSR 的地址
NVIC_SYSPRI14
EQU
0xE000ED22
;PendSV优先级寄存器的地址
NVIC_PENDSV_PRI
EQU
00xFF
; PendSV 中断的优先级为 255(最低)
NVIC_PENDSVSET
EQU
0x10000000
; 位 28 为 1
;定义几个常量,类似 C 语言中的#define预处理指令。
S_CPU_SR_Save
MRS
R0, PRIMASK
;读取 PRIMASK 到R0 中,R0 为返回值
CPSID
I
;PRIMASK=1,关中断(NMI 和硬 fault 可以响应)
BX
LR
;返回
OS_CPU_SR_Restore
MSR
PRIMASK, R0
;读取 R0 到PRIMASK 中,R0 为参数
BX
LR
;返回
OSStartHighRdy()由 OSStart()调用,用来启动最高优先级任务,当然任务必须在OSStart()前已被创建。
OSStartHighRdy
;设置 PendSV 中断的优先级 #1
LDR
R0, =NVIC_SYSPRI14
;R0 = NVIC_SYSPRI14
LDR
R1, =NVIC_PENDSV_PRI
;R1 = NVIC_PENDSV_PRI
STRB
R1, [R0]
; *(uint8_t *)NVIC_SYSPRI14 = NVIC_PENDSV_PRI
;设置 PSP 为0
#2
MOVS
R0, #0
;R0 = 0
MSR
PSP, R0
;PSP = R0
;设置 OSRunning 为TRUE
LDR
R0, =OSRunning
;R0 = OSRunning
MOVS
R1, #1
;R1 = 1
STRB
R1, [R0]
;OSRunning = 1
;触发 PendSV 中断 #3
LDR
R0, =NVIC_INT_CTRL
;R0 = NVIC_INT_CTRL
LDR
R1, =NVIC_PENDSVSET
;R1 = NVIC_PENDSVSET
STR
R1, [R0]
; *(uint32_t *)NVIC_INT_CTRL = NVIC_PENDSVSET
CPSIE
I
;开中断
OSStartHang
;死循环,应该不会到这里
B
OSStartHang
#1.PendSV 中断的优先级应该为最低优先级,原因在<
>的 7.6 节已有说明。
#2.PSP 设置为 0,是告诉具体的任务切换程序(OS_CPU_PendSVHandler()),这是第一次任务切换。做过切换后 PSP 就不会为0了,后面会看到。
#3.往中断控制及状态寄存器 ICSR(0xE000ED04)第 28 位写 1 即可产生 PendSV 中断。这个<>8.4.5 其它异常的配置寄存器有说明。
当一个任务放弃 cpu 的使用权,就会调用OS_TASK_SW()宏,而 OS_TASK_SW()就是 OSCtxSw()。OSCtxSw()应该做任务切换。但是在 CM3 中,所有任务切换都被放到PendSV 的中断处理函数中去做了,因此 OSCtxSw() 只需简单的触发 PendSV中断即可。OS_TASK_SW()是由OS_Sched()调用。
void OS_Sched (void)
{
# if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr = 0;
#endif
OS_ENTER_CRITICAL();
if (OSIntNesting ==0) {
if (OSLockNesting == 0) {
OS_SchedNew();
if (OSPrioHighRdy != OSPrioCur)
{
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
#if OS_TASK_PROFILE_EN > 0
OSTCBHighRdy->OSTCBCtxSwCtr++;
#endif
OSCtxSwCtr++;
OS_TASK_SW();
}
}
}
OS_EXIT_CRITICAL();
}
OSCtxSw ;触发PendSV 中断
LDR R0, =NVIC_INT_CTRL ;R0 = NVIC_INT_CTRL
LDR R1, =NVIC_PENDSVSET ;R1 = NVIC_PENDSVSET
STR R1, [R0] ;*(uint32_t *)NVIC_INT_CTRL = NVIC_PENDSVSET
BX LR ;返回
当一个中断处理函数退出时,OSIntExit()会被调用来决定是否有优先级更高的任务需要执行。如果有
OSIntExit()对调用 OSIntCtxSw()做任务切换。
OSIntCtxSw ;触发 PendSV 中断
LDR R0, =NVIC_INT_CTRL
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
BX LR
看到这里有人可能奇怪怎么 OSCtxSw()和OSIntCtxSw()完全一样,事实上,这两个函数的意义是不一样的,OSCtxSw()做的是任务之间的切换,如任务 A 因为等待某个资源或是做延时切换到任务 B,而
OSIntCtxSw()则是中断退出时,由中断状态切换到另一个任务。由中断切换到任务时,CPU 寄存器入栈的工作已经做完了,所以无需做第二次了(参考邵老师书的 3.10 节)。这里只不过由于 CM3 的特殊机制导致了在这两个函数中只要做触发 PendSV中断即可,具体切换由 PendSV 中断来处理。
前面已经说过真正的任务切换是在 PendSV 中断处理函数里做的,由于 CM3 在中断时会有一半的寄存器自动保存到任务堆栈里,所以在 PendSV 中断处理函数中只需保存 R4-R11并调节堆栈指针即可。 [page]
PendSV 中断处理函数伪代码如下:
OS_CPU_PendSVHandler()
{
if (PSP != NULL) {
Save R4-R11 onto task stack;
OSTCBCur->OSTCBStkPtr = SP;
}
OSTaskSwHook();
OSPrioCur = OSPrioHighRdy;
OSTCBCur = OSTCBHighRdy;
PSP = OSTCBHighRdy->OSTCBStkPtr;
Restore R4-R11 from new task stack;
Return from exception;
}
OS_CPU_PendSVHandler ;xPSR, PC, LR, R12, R0-R3 已自动保存 #0
CPSID I ;任务切换期间需要关中断
MRS R0, PSP ;R0 = PSP
;如果 PSP ==0,跳到OS_CPU_PendSVHandler_nosave 执行 #1
CBZ R0, OS_CPU_PendSVHandler_nosave
;保存 R4-R11 到任务堆栈
SUBS R0, R0, #0x20 ;R0 -= 0x20
STM R0, {R4-R11} ;保存 R4-R11 到任务堆栈
;OSTCBCur->OSTCBStkPtr = SP;
LDR R1, =OSTCBCur ;R1 = &OSTCBCur
LDR R1, [R1] ;R1 = *R1 (R1 = OSTCBCur)
STR R0, [R1] ;*R1 = R0 (*OSTCBCur = SP) #2
OS_CPU_PendSVHandler_nosave
;调用 OSTaskSwHook()
PUSH {R14} ;保存 R14,因为后面要调用函数
LDR R0, =OSTaskSwHook ;R0 = &OSTaskSwHook
BLX R0 ;调用 OSTaskSwHook()
POP {R14} ;恢复 R14
;OSPrioCur = OSPrioHighRdy;
LDR R0, =OSPrioCur ;R0 = &OSPrioCur
LDR R1, =OSPrioHighRdy ;R1 = &OSPrioHighRdy
LDRB R2, [R1] ;R2 = *R1 (R2 = OSPrioHighRdy)
STRB R2, [R0] ;*R0 = R2 (OSPrioCur = OSPrioHighRdy)
;OSTCBCur = OSTCBHighRdy;
LDR R0, =OSTCBCur ;R0 = &OSTCBCur
LDR R1, =OSTCBHighRdy ;R1 = &OSTCBHighRdy
LDR R2, [R1] ;R2 = *R1 (R2 = OSTCBHighRdy)
STR R2, [R0] ;*R0 = R2 (OSTCBCur = OSTCBHighRdy)
LDR R0, [R2] ;R0 = *R2 (R0 = OSTCBHighRdy), 此时 R0 是新任务的 SP
;SP = OSTCBHighRdy->OSTCBStkPtr #3
LDM R0, {R4-R11} ;从任务堆栈 SP 恢复 R4-R11
ADDS R0, R0, #0x20 ;R0 += 0x20
MSR PSP, R0 ;PSP = R0,用新任务的 SP 加载PSP
ORR LR, LR, #0x04 ;确保 LR 位2 为1,返回后使用进程堆栈 #4
CPSIE I ;开中断
BX LR ;中断返回
END
#0 OS_CPU_PendSVHandler 要替换为 PendSV_Handler。
#1 如果 PSP==0,说明OSStartHighRdy()启动后第一次做任务切换,而任务刚创建时 R4-R11 已经保存在堆栈中了,所以不需要再保存一次了。
#2 OSTCBStkPtr 是任务控制块结构体的第一个变量,所以*OSTCBCur = SP(不是很科学)就是 OSTCBCur->OSTCBStkPtr = SP;
#3 和#2 类似。
#4 因为在中断处理函数中使用的是 MSP,所以在返回任务后必须使用PSP,所以LR位2必须为1。
os_dbg.c
用于系统调试,可以不管。
需要修改的代码就介绍到这里,如果还有不明白之处,就再看看 AN-1018.pdf,邵老师的书和<
Cortex-M3 权威指南>>。
App.c
App.c文件中建立如下函数 App文件中有对 SysTick的初始化函数(上面已经解释过)。
static void systick_init(void); //函数声明
static void systick_init(void)
{
RCC_ClocksTypeDef rcc_clocks;
RCC_GetClocksFreq(&rcc_clocks); //调用标准库函数,获取系统时钟。
SysTick_Config(rcc_clocks.HCLK_Frequency / OS_TICKS_PER_SEC); //调用库函数,初始化并使能 SysTick
//OS_TICKS_PER_SEC是在 os_cfg.h 中定义的
}
os_cfg.h 是用来配置 ucosii 系统的,对其做如下修改: 共9处
#define OS_APP_HOOKS_EN 0 //关掉App 钩子功能
#define OS_DEBUG_EN 0 //关掉uC/OS 自带调试功能
#define OS_EVENT_MULTI_EN 0 //
#define OS_SCHED_LOCK_EN 0 //关掉调度加锁功能
#define OS_TASK_CHANGE_PRIO_EN 0 //关掉改变任务优先级功能
#define OS_TASK_QUERY_EN 0 //关掉任务查询功能
#define OS_TASK_STAT_EN 0 //关掉 CPU 使用率统计功能
#define OS_TASK_STAT_STK_CHK_EN 0 //关掉 CPU 使用率统计功能的堆栈设置
#define OS_TASK_SUSPEND_EN 0 //关掉任务挂起功能
所做的修改主要是把一些功能给去掉,减少内核大小,也利于调试。等移植完成后,如果需要该功能,
再做开启。
最后,还要记得把stm32f10x_it.h文件中的void PendSV_Handler(void);注释掉,以防和 OS_CPU.HH
文件中的声明冲突,stm32f10x_it.c 中的相应函数体也得注释掉。如图:
注释掉多余的PendSV 声明
关键字:移植 ucosII STM32F103ZE
引用地址:
移植ucosII到STM32F103ZE(五)
推荐阅读最新更新时间:2024-03-16 14:37
linux-3.0移植到FL2440(只做基本的移植)
首先补丁包来自凌云实验室: 1.先打补丁: patch -p1 ../linux-3.0-s3c2440.patch 2.修改 Makefile: ARCH ?= arm CROSS_COMPILE ?= arm-linux- 3.修改补丁的错误: 在/arch/arm/plat-s3c24xx/devs.c //#ifdef CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X /* UDA1341 add by guowenxue, 2012.03.30 */ //注释掉 . . . //#endif 4.make s3c2410_defconfig 5.裁剪
[单片机]
S3C2416裸机开发系列十七_GCC下Fatfs的移植
对于固态存储器,其存储容量可以很大,往往需要一款文件系统对存储器用户数据进行组织文件的管理。它对文件存储器空间进行组织和分配,负责文件的存储并对存入的文件进行保护和检索。在嵌入式系统中,往往需要采用windows兼容的文件系统,像相机的照片、视频监控、语音产品等,很多都需要从windows计算机上提取资源或在windows计算机上进一步处理。Fatfs由于其开源免费,支持fat32,受到了广泛的应用,笔者此处就s3c2416移植Fatfs,对sd卡进行读写访问作一个简单的介绍。 1. Fatfs概述 Fatfs是由日本工程师ChaN所编写的fat文件系统模块,从06年发布第一个Fatfs版本开始,作者就从未停止维护和更新。Fat
[单片机]
STM32F103移植到AT32F403A之MDK(二)
上一篇我们已经实现了不改硬件,只改软件情况下将STM32F103C8T6替换为AT32F403ACGT7的过程,但毕竟STM32F103C8T6已经是10多年前的东西了,用现在的AT32F403ACGT7替换实在是大材小用了,毕竟这颗是主频能到240M的M4。 上篇我们解决了替换能用的问题,本篇我们来结合AT32F403ACGT7的优势,实现不改硬件只改BOM降成本的方法。 从接触MCU开始,MCU外围电路中就缺少不了很重要的器件,那就晶振,晶振是MCU的时钟源。随着技术的不断发展,越来越多的MCU将晶振集成到了MCU内部,但集成到内部后真的就能够省略掉外部晶振吗,当然不是,由于技术和工艺问题,前些年的MCU还无法完全摆脱
[单片机]
一文了解移植3.4.2的Kernel到JZ2440
本文将介绍如何移植linux-3.4.2内核到JZ2440开发板上的全过程,使用的交叉编译工具版本为 arm-linux-gcc-4.3.2.tar.bz2 下面来一步一步介绍如何移植。 由于kernel的启动参数是由Uboot传递的,关键的参数有 R0=0 R1=Mach-Type R2=Tag参数地址 其中,Mach-Type为内核支持板子的硬件型号,tag参数为Uboot存放传递给Kernel参数的内存地址。 内核启动时,根据传入的Mach-Type参数选择对应的板级初始化函数来初始化,然后解析tag参数,设置相应系统状态值,装载驱动程序,最后挂载根文件系统。 1. 编译内核 修改根目录下面的Make
[单片机]
移植u-boot-2010.09到S3C2440(一)——硬件初始化与测试
在u-boot的代码选择中,只有201009是最近的可直接编译通过的,不带memset.s的u-boot版本。 屏蔽lowlevel_init的调用之后,将我在u-boot-201112版本中所做的硬件初始化全部挪到本版本中,包括串口驱动的修改,时钟设置,LED的点亮。 这个时候通过开发板自带的u-boot写到SDRAM调试就直接有串口输出与提示符。 注:本系列文档只注释难点部分,其它略过。
[单片机]
人体器官移植突破:男子植入3D打印椎骨获新生
如今已经两个多月过去了,约塞夫斯基的恢复情况相当不错。
据外媒报道,人体器官移植频传福音,3D打印再写医疗新里程。澳大利亚医生为一名患了癌症的男子进行一项全球第一例手术,替他移除被癌细胞严重破坏的椎骨,再为他植入一条用3D打印技术打印出来旳椎骨。该病人现时康复的进展良好,重获新生。
据报道,病人约塞夫斯基患了脊索瘤,是一种十分罕见的癌症。癌细胞攻击他的脊椎和头骨,并在他的颈项上方位置生长,令他饮食和说话都有困难。医学界估计,每100万人当中,只有一人患上这种病。
去年12月,神经科医生莫布斯为他进行长达15小时的手术,移除本来的椎骨,植入3D打印的脊骨。
莫布斯称,“如果不动手术,又不进行
[医疗电子]
Fedora8上交叉编译qtopia4移植成功到s3c2410开发板
教程是这样的: 一.硬件平台 1.主机: PC机,512M内存以上。 2.目标机: UP-NetARM2410-S实验平台。 二.移植软件资源 1.Red Hat Linux 9.0(主机操作系统) 2.gcc-3.4.1.tar.gz(主机编译器) 3.arm-linux-gcc-3.4.1.tar.bz2(交叉编译器) 4.tslib-1.3.tar.bz2(管理目标平台的触摸屏) 5.qtopia-opensource-src-4.2.1.tar.gz(包含Qt, Qtopia core) 2 . GUI(QT)的移植过程 编译前的约定: 1)我的工作目录为:/mnt/nfs。 2)qtopia-o
[单片机]
U-Boot在基于ADSP BF533的嵌入式Linux系统上的移植
1 引言 Boot Loader(内核引导程序)是在操作系统内核运行之前运行的一段自举程序,用于初始化硬件设备、改变处理器运行模式、重组中断向量和建立内存空间映射图,从而将系统的软硬件带到一个合适的状态或者用户定制的特定状态,以便为最终加载操作系统内核准备好正确的环境 。 嵌入式Linux系统常用的Boot Loader有arm-boot、redboot、U-Boot等。U-Boot (全称Universal Boot Loader)是当前比较流行的遵循GPL条件的开放源码项目。U-Boot具有源码公开的特点,开发人员可根据自身需要进行裁减;支持多种处理器和嵌入式操作系统内核;具有多种设备驱动源码:支持种引导方式;具有功能强大
[嵌入式]