;/*********************** (C) COPYRIGHT 2010 Libraworks *************************
;* File Name : os_cpu_a.asm
;* Author : Librae
;* Version : V1.0
;* Date : 06/10/2010
;* Description : μCOS-II asm port for STM32
;*******************************************************************************/
EXTERN CPU_ExceptStkBase
EXTERN p_TCB_Cur
EXTERN p_TCBHighRdy
;IMPORT OSPrioCur
;IMPORT OSPrioHighRdy
;IMPORT OSTCBCur
;IMPORT OSTCBHighRdy
EXPORT OSStartHighRdy
EXPORT OSCtxSw
EXPORT OSIntCtxSw
EXPORT OS_CPU_SR_Save ; Functions declared in this file
EXPORT OS_CPU_SR_Restore
EXPORT PendSV_Handler
NVIC_INT_CTRL EQU 0xE000ED04 ; 中断控制寄存器
NVIC_SYSPRI14 EQU 0xE000ED22 ; 系统优先级寄存器(2)
NVIC_PENDSV_PRI EQU 0xFF ; PendSV中断和系统节拍中断
; (都为最低,0xff).
NVIC_PENDSVSET EQU 0x10000000 ; 触发软件中断的值.
PRESERVE8
AREA |.text|, CODE, READONLY
THUMB
;********************************************************************************************************
; CRITICAL SECTION METHOD 3 FUNCTIONS
;
; Description: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you
; would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then
; disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II's functions that need to
; disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr'
; into the CPU's status register.
;
; Prototypes : OS_CPU_SR OS_CPU_SR_Save(void);
; void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
;
;
; Note(s) : 1) These functions are used in general like this:
;
; void Task (void *p_arg)
; {
; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
; OS_CPU_SR cpu_sr;
; #endif
;
; :
; :
; OS_ENTER_CRITICAL(); /* cpu_sr = OS_CPU_SaveSR(); */
; :
; :
; OS_EXIT_CRITICAL(); /* OS_CPU_RestoreSR(cpu_sr); */
; :
; :
; }
;********************************************************************************************************
OS_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
;*
;* 功能描述: 使用调度器运行第一个任务
;*
;* 参 数: None
;*
;* 返 回 值: None
;**************************************************************************************/
OSStartHighRdy
LDR R4, =NVIC_SYSPRI14 ; set the PendSV exception priority
LDR R5, =NVIC_PENDSV_PRI
STR R5, [R4]
MOV R4, #0 ; set the PSP to 0 for initial context switch call
MSR PSP, R4
LDR R4, =CPU_ExceptStkBase ; 中断嵌套时有用
LDR R5, [R4]
MSR MSP, R5
;切换到最高优先级的任务
LDR R4, =NVIC_INT_CTRL ;rigger the PendSV exception (causes context switch)
LDR R5, =NVIC_PENDSVSET
STR R5, [R4]
CPSIE I ;enable interrupts at processor level
OSStartHang
B OSStartHang ;should never get here
;/**************************************************************************************
;* 函数名称: OSCtxSw
;*
;* 功能描述: 任务级上下文切换
;*
;* 参 数: None
;*
;* 返 回 值: None
;***************************************************************************************/
OSCtxSw
PUSH {R4, R5}
LDR R4, =NVIC_INT_CTRL ;触发PendSV异常 (causes context switch)
LDR R5, =NVIC_PENDSVSET
STR R5, [R4]
POP {R4, R5}
BX LR
;/**************************************************************************************
;* 函数名称: OSIntCtxSw
;*
;* 功能描述: 中断级任务切换
;*
;* 参 数: None
;*
;* 返 回 值: None
;***************************************************************************************/
OSIntCtxSw
PUSH {R4, R5}
LDR R4, =NVIC_INT_CTRL ;触发PendSV异常 (causes context switch)
LDR R5, =NVIC_PENDSVSET
STR R5, [R4]
POP {R4, R5}
BX LR
NOP
;/**************************************************************************************
;* 函数名称: OSPendSV
;*
;* 功能描述: OSPendSV is used to cause a context switch.
;*
;* 参 数: None
;*
;* 返 回 值: None
;***************************************************************************************/
PendSV_Handler
CPSID I ; Prevent interruption during context switch
MRS R0, PSP ; PSP is process stack pointer 如果在用PSP堆栈,则可以忽略保存寄存器,参考CM3权威中的双堆栈-白菜注
CBZ R0, PendSV_Handler_Nosave ; Skip register save the first time
SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack
STM R0, {R4-R11}
LDR R1, =p_TCB_Cur ; 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
PendSV_Handler_Nosave
LDR R0, =p_TCB_Cur ; OSPrioCur = OSPrioHighRdy;
LDR R1, =p_TCBHighRdy
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
ADDS R0, R0, #0x20
MSR PSP, R0 ; Load PSP with new process SP
ORR LR, LR, #0x04 ; Ensure exception return uses process stack
CPSIE I
BX LR ; Exception return will restore remaining context
end
#include "timer.h"
#include "led.h"
#include "OS_Need.h"
//////////////////////////////////////////////////////////////////////////////////
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK战舰STM32开发板
//定时器 驱动代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/3
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////
//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIMx
}
//定时器3中断服务程序
void TIM3_IRQHandler(void) //TIM3中断
{
char i=0;
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志
for(i=0;i<TCB_Task_NUM;i++)
{
if(TCB_Task[i].Dly > 0)
{
TCB_Task[i].Dly--;
if(TCB_Task[i].Dly == 0)
{
OSSetPrioRly(i);
}
}
}
}
}
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
uint32_t OSRdyTbl;//此系统有32个优先级,同时只能有32个任务,每个任务和优先级对应
uint32_t OSPrioHighRdy;
uint32_t OSPrioCur;
struct os_tcb{ //任务控制块结构体
uint32_t *StkPtr;
uint32_t Dly;
uint32_t Prio;//没有用到
};
typedef struct os_tcb TCB;
TCB *p_TCB_Cur;
TCB *p_TCBHighRdy;
#define OS_EXCEPT_STK_SIZE (1024*10)
#define TASK_1_STK_SIZE 1024
#define TASK_2_STK_SIZE 1024
#define OS_IdleTask_STK_SIZE 1024
uint32_t TASK_1_STK[TASK_1_STK_SIZE];
uint32_t TASK_2_STK[TASK_2_STK_SIZE];
uint32_t OS_IdleTask_Stk[OS_IdleTask_STK_SIZE];
TCB TCB_Task1,TCB_Task2;
#define TCB_Task_NUM 32
TCB TCB_Task[TCB_Task_NUM];//最对创建TCB_Task_NUM个任务
uint32_t TCB_Task_NUM_Counts=0;//记录现在有几个任务
uint32_t cpu_sr;
#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}
#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}
uint32_t OS_CPU_SR_Save(void);
void OS_CPU_SR_Restore(uint32_t cpu_sr);
void OSCtxSw(void);
void OSIntCtxSw(void);
void OSStartHighRdy(void);
void OSPendSV(void);
void OSTimeDly(uint32_t ticks);
void OSSched(void);
void OS_TASK_Init(void);
void task_1(void);
void task_2(void);
void OS_IdleTask(void);
void OSSetPrioRly(uint16_t prio)
{
OSRdyTbl |= 0x01<<prio;
}
void OSDelPrioRly(uint16_t prio)
{
OSRdyTbl &= ~(0x01<<prio);
}
void OSGetHighRdy(void)
{//此函数在优先级表OSRdyTbl中选出最高的优先级
uint32_t OSNextTaskPrio;
for(OSNextTaskPrio = 0;(OSNextTaskPrio<32) && !(OSRdyTbl&(0x01<<OSNextTaskPrio));OSNextTaskPrio++)
;
OSPrioHighRdy = OSNextTaskPrio;
}
//以下是任务控制块
//以下是堆栈
uint32_t CPU_ExceptStk[OS_EXCEPT_STK_SIZE];
uint32_t *CPU_ExceptStkBase;
//建立一个任务
void Task_Create (void (*task)(void ), uint32_t *p_stk ,uint16_t prio)
{
uint32_t *stk;
stk = p_stk; /* Load stack pointer */
/* Registers stacked as if auto-saved on exception */
*(stk) = (uint32_t)0x01000000L; /* xPSR */
*(--stk) = (uint32_t)task; /* Entry Point */
*(--stk) = (uint32_t)0xFFFFFFFEL; /* R14 (LR) (init value will cause fault if ever used)*/
*(--stk) = (uint32_t)0x12121212L; /* R12 */
*(--stk) = (uint32_t)0x03030303L; /* R3 */
*(--stk) = (uint32_t)0x02020202L; /* R2 */
*(--stk) = (uint32_t)0x01010101L; /* R1 */
*(--stk) = (uint32_t)0x01010101L; /* R0 : argument */
/* Remaining registers saved on process stack */
*(--stk) = (uint32_t)0x11111111L; /* R11 */
*(--stk) = (uint32_t)0x10101010L; /* R10 */
*(--stk) = (uint32_t)0x09090909L; /* R9 */
*(--stk) = (uint32_t)0x08080808L; /* R8 */
*(--stk) = (uint32_t)0x07070707L; /* R7 */
*(--stk) = (uint32_t)0x06060606L; /* R6 */
*(--stk) = (uint32_t)0x05050505L; /* R5 */
*(--stk) = (uint32_t)0x04040404L; /* R4 */
TCB_Task[prio].StkPtr = (stk);
OSSetPrioRly(prio);
//TCB_Task[TCB_Task_NUM_Counts].Prio = prio;
//TCB_Task_NUM_Counts++;//任务数量计数器加1 , TCB_Task_NUM_Counts 必须不能大于TCB_Task_NUM
}
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
LED_Init(); //初始化与LED连接的硬件接口
uart_init(9600);
TIM3_Int_Init(49,7199);//10Khz的计数频率,计数到50为5ms
printf("this is the begin of the task ...\ntask is running ...\n");
CPU_ExceptStkBase = CPU_ExceptStk + OS_EXCEPT_STK_SIZE - 1;
OS_ENTER_CRITICAL();
Task_Create( task_1 , &TASK_1_STK[TASK_1_STK_SIZE-1] ,7);
Task_Create( task_2 , &TASK_2_STK[TASK_2_STK_SIZE-1] ,6);
OS_EXIT_CRITICAL();
//p_TCBHighRdy = &TCB_Task1;
//OSStartHighRdy();
OS_TASK_Init();
while(1);
}
/*
void Task_Switch(void)
{
if(p_TCB_Cur == &TCB_Task1)
p_TCBHighRdy = &TCB_Task2;
else
p_TCBHighRdy = &TCB_Task1;
OSCtxSw();
}*/
void OSTimeDly(uint32_t ticks)
{
if(ticks > 0)
{
OS_ENTER_CRITICAL();
OSDelPrioRly(OSPrioCur);
TCB_Task[OSPrioCur].Dly = ticks;
OS_EXIT_CRITICAL();
OSSched();
}
}
void OS_TASK_Init(void)
{
OS_ENTER_CRITICAL();
Task_Create(OS_IdleTask , &OS_IdleTask_Stk[OS_IdleTask_STK_SIZE-1],TCB_Task_NUM-1);//将空闲任务设置为最低优先级
OS_EXIT_CRITICAL();
OSGetHighRdy();
OSPrioCur = OSPrioHighRdy;
p_TCBHighRdy = &TCB_Task[OSPrioHighRdy];
OSStartHighRdy();
}
void OSSched(void)
{
OSGetHighRdy();
if(OSPrioHighRdy != OSPrioCur)
{
p_TCBHighRdy = &TCB_Task[OSPrioHighRdy];
OSPrioCur = OSPrioHighRdy;
OSCtxSw();
}
}
void task_1(void){
while(1)
{
printf("task 1\n");
//Task_Switch();
OSTimeDly(20);
}
}
void task_2(void){
while(1)
{
printf("task 2\n");
//Task_Switch();
OSTimeDly(20);
}
}
void OS_IdleTask(void)
{
while(1){
OSSched();
}
}