STM32入门学习笔记之uCOS-II系统移植3

发布时间:2024-05-17  

⑤这两个函数都用于任务切换,它们的本质都是触发PendSV中断,具体切换过程在PendSV的中断函数中进行,其中OSCtxSw是任务级切换,OSIntCtxSw是中断级切换,是从中断退出时切换到一个任务中,从中断切换到任务的过程中,CPU的寄存器入栈工作已经完成。


OSCtxSw

  PUSH    {R4, R5}

  LDR     R4, =NVIC_INT_CTRL        ;触发PendSV异常

  LDR     R5, =NVIC_PENDSVSET

  STR     R5, [R4]              ;向NVIC_INT_CTRL写入NVIC_PENDSVSET触发PendSV中断

  POP     {R4, R5}

  BX      LR

OSIntCtxSw

  PUSH    {R4, R5}

  LDR     R4, =NVIC_INT_CTRL        ;触发PendSV异常

  LDR     R5, =NVIC_PENDSVSET

  STR     R5, [R4]              ;向NVIC_INT_CTRL写入NVIC_PENDSVSET触发PendSV中断

  POP     {R4, R5}

  BX      LR

  NOP

⑥这部分代码才是真正的任务切换函数,通过触发PendSV中断来进入该函数内进行任务切换



PendSV_Handler

  CPSID  I                                ;任务切换过程中必须关闭所有中断

  MRS    R0, PSP                          ;如果在用PSP堆栈,则可以忽略保存寄存器

  CBZ    R0, PendSV_Handler_Nosave    ;如果PSP为0就转移到PendSV_Handler_Nosave



  SUBS    R0, R0, #0x20                                        ;R0-=20H

  STM     R0, {R4-R11}



  LDR     R1, =OSTCBCur

  LDR     R1, [R1]

  STR     R0, [R1]



PendSV_Handler_Nosave

    PUSH    {R14}              ;保存R14的值

    LDR     R0, =OSTaskSwHook        ;调用OSTaskSwHook()

    BLX     R0

    POP     {R14}



    LDR     R0, =OSPrioCur

    LDR     R1, =OSPrioHighRdy

    LDRB    R2, [R1]

    STRB    R2, [R0]



    LDR     R0, =OSTCBCur

    LDR     R1, =OSTCBHighRdy

    LDR     R2, [R1]

    STR     R2, [R0]



    LDR     R0, [R2]              ;R0作为新任务的SP

    LDM     R0, {R4-R11}            ;从堆栈中恢复R4-R11

    ADDS    R0, R0, #0x20

    MSR     PSP, R0              ;用新任务的SP加载PSP

    ORR     LR, LR, #0x04          ;确保LR的bit2为1,返回后使用进程堆栈

    CPSIE   I                ;开启所有中断

    BX      LR                ;中断返回



  end

(2)os_cpu.h文件详解


①这部分主要用于定义一些数据类型,其中重点关注OS_STK这个数据类型,我们在定义任务堆栈的时候就是该类型数据,这是一个32位的数据类型,按字节算的话实际堆栈大小是我们定义的4倍。


typedef unsigned char  BOOLEAN;

typedef unsigned char  INT8U;

typedef signed   char  INT8S;

typedef unsigned short INT16U;

typedef signed   short INT16S;

typedef unsigned int   INT32U;

typedef signed   int   INT32S;

typedef float          FP32;

typedef double         FP64;



typedef unsigned int   OS_STK;

typedef unsigned int   OS_CPU_SR;

②这部分代码定义了堆栈的增长方向,任务机切换的宏定义OS_TASK_SW,如果OS_CRITICAL_METHOD被定义为3的话那么进出临界段的宏定义分别为OS_ENTER_CRITICAL和OS_EXIT_CRITICAL,这两个函数都是用汇编语言编写的


//OS_CRITICAL_METHOD = 1 :直接使用处理器的开关中断指令来实现宏 

//OS_CRITICAL_METHOD = 2 :利用堆栈保存和恢复CPU的状态 

//OS_CRITICAL_METHOD = 3 :利用编译器扩展功能获得程序状态字,保存在局部变量cpu_sr



#define  OS_CRITICAL_METHOD   3     //进入临界段的方法



#if OS_CRITICAL_METHOD == 3

#define  OS_ENTER_CRITICAL()  {cpu_sr = OS_CPU_SR_Save();}

#define  OS_EXIT_CRITICAL()   {OS_CPU_SR_Restore(cpu_sr);}

#endif



void       OSCtxSw(void);

void       OSIntCtxSw(void);

void       OSStartHighRdy(void);

void       OSPendSV(void);



#if OS_CRITICAL_METHOD == 3u

OS_CPU_SR  OS_CPU_SR_Save(void);

void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);

#endif

OS_CPU_EXT INT32U OSInterrputSum;

(3)sys.h文件修改


添加关于条件编译的定义,在文件中添加以下代码即可。


#define SYSTEM_SUPPORT_OS 1


当宏定义为1的时候,编译器在编译的时候会只编译满足条件的代码,当为0时,这部分代码不会被编译。


(4)delay.c文件修改


①添加Sys_Tick中断服务函数与函数定义


#include "includes.h"

//支持UCOSII

#ifdef  OS_CRITICAL_METHOD

#define delay_osrunning    OSRunning              //OS是否运行标记,0,不运行;1,在运行

#define delay_ostickspersec  OS_TICKS_PER_SEC            //OS时钟节拍,即每秒调度次数

#define delay_osintnesting  OSIntNesting                //中断嵌套级别,即中断嵌套次数

#endif

//systick中断服务函数,使用OS时用到

void SysTick_Handler()

{

  //OS开始跑了,才执行正常的调度处理

  if( delay_osrunning==1 )

  {

    OSIntEnter() ;                        //进入中断

    OSTimeTick() ;                      //调用ucos的时钟服务程序

    OSIntExit() ;                        //触发任务切换软中断

  }

}

②时钟初始化函数修改


复制

void SysTick_Init( u8 SYSCLK )

{

#if SYSTEM_SUPPORT_OS

  u32 reload;

#endif

   SysTick->CTRL &= ~( 1<<2 ) ;                  //SYSTICK使用外部时钟源

  fac_us = SYSCLK/8 ;                      //fac_us都需要使用

#if SYSTEM_SUPPORT_OS

  reload = SYSCLK/8 ;                      //每秒钟的计数次数,单位为K     

  reload *= 1000000/delay_ostickspersec ;              //根据delay_ostickspersec设定溢出时间

  fac_ms = 1000/delay_ostickspersec ;                //代表OS可以延时的最少单位

  SysTick->CTRL |= 1<<1 ;                    //开启SYSTICK中断

  SysTick->LOAD = reload ;                    //每1/delay_ostickspersec秒中断一次

  SysTick->CTRL |= 1<<0 ;                    //开启SYSTICK

#else

  fac_ms = ( u16 )fac_us*1000 ;                  //代表每个ms需要的systick时钟数

#endif

}


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>