手上没有使用Cortex-M3内核的芯片,只有一个STM32F407VG的Discovery开发版,这款芯片使用的是Cortex-M4F的内核,这个内核是基于ARMV7E-M架构的与Cortex-M3十分类似,只是多了一个FPU(浮点运算单元)以及浮点运算需要的相关寄存器。也因为这个FPU导致进入中断的时候保存的寄存器有些差别,不过这些堆栈都是硬件自动保存的,对编写任务切换代码没有影响,在文章的最后来简单分析下浮点寄存器如何入栈。这篇文章的思路参考了《一步步写STM32 OS【三】PendSV与堆栈操作》
一、IAR工程代码
使用IAR和MDK建立的工程在系统初始化堆栈时是不一样的,MDK在启动文件的开头就初始化了堆栈的大小,而IAR工程堆栈的大小定义是在icf文件中,具体怎样在IAR工程中修改堆栈初始化信息可以参考这篇文章《STM32编程:是时候深入理解栈了》,作者写的很清晰了。从icf文件中得知MSP堆栈的大小为0x2000,下面来看具体的代码文件,os_port.asm文件是汇编代码,用于实现任务的具体切换,这次我们不再为MSP单独指定堆栈,而是使用系统上电初始化时建立的堆栈。工程里一共包含两个文件main.c和os_port.asm。
main.c源代码如下,代码里屏蔽了RTOS建立主堆栈的代码,如果像Ucos一样在中断中使用RTOS自己设置的主堆栈,可以打开这段代码。
#include "stm32f4xx.h"
/******************变量类型定义*******************************/
typedef unsigned int uint32;
typedef struct TaskTCB
{
uint32 *StackPtr;
}sTaskTCB,*pTaskTCB;
typedef void( *pFun )( void );
/********************定义任务控制块************************************/
sTaskTCB StartTaskTCB;
sTaskTCB SecondTaskTCB;
pTaskTCB OSTCBCurPtr;
pTaskTCB OSTCBHighRdyPtr;
/***********************定义进程堆栈**********************************/
#define START_STACK_SIZE 48
#define SECOND_STACK_SIZE 48
uint32 StartTaskStack[START_STACK_SIZE];
uint32 SecondTaskStack[SECOND_STACK_SIZE];
/**********************定义主堆栈*****************************************/
//#define OS_CPU_STACK_SIZE 128 未使用
//uint32 OS_CPU_ExceptStk[OS_CPU_STACK_SIZE]; 未使用
//uint32 *g_OS_CPU_ExceptStkBase; 未使用
/*************************全局变量****************************************/
static int StartTaskFlag ,SecondTaskFlag,EndFlag;
/*************************函数定义*****************************************/
extern void OSCtxSw(void);
extern void OSStartHighRdy(void);
void TaskSwitch(void)
{
if(OSTCBCurPtr == &StartTaskTCB)
OSTCBHighRdyPtr=&SecondTaskTCB;
else
OSTCBHighRdyPtr=&StartTaskTCB;
OSCtxSw();
}
void StartTask(void)
{
StartTaskFlag = 1;
TaskSwitch();
}
void SecondTask(void)
{
SecondTaskFlag = 1;
StartTaskFlag = 0;
TaskSwitch();
}
void EndTask(void)
{
EndFlag = 1;
SecondTaskFlag = 0;
while(1)
{
;
}
}
//任务创建函数
void Task_Create(sTaskTCB *pTcb,pFun task,uint32 *stk,uint32 stacksize)
{
uint32 *pStack;/*grows from high memory to low*/
pStack = &stk[stacksize];/*Top of stack*/
pStack = (uint32 *)((uint32)(pStack) & 0xFFFFFFF8u);//AAPCS(ARM application procedure all standard) Align the stack to 8bytes
/*Registers stacked as if auto-saved on exception*/
*(--pStack) = (uint32)0x01000000uL; //xPSR bit24 thumb state bit
*(--pStack) = (uint32)task; // Entry Point(PC)
*(--pStack) = (uint32)EndTask; // R14 (LR)
*(--pStack) = (uint32)0x12121212uL; // R12
*(--pStack) = (uint32)0x03030303uL; // R3
*(--pStack) = (uint32)0x02020202uL; // R2
*(--pStack) = (uint32)0x01010101uL;