加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

【RTX操作系统教程】第19章 SVC中断方式调用用户函数

(2016-01-07 16:28:15)
标签:

安富莱

rtx

cosiii

emwin

stm32f407

分类: RTX及其中间件

第19章     SVC中断方式调用用户函数

本章节为大家讲解如何采用SVC中断方式调用用户函数。当用户将RTX任务设置为工作在非特权级模式时,任务中是不允许访问特权级寄存器的,这个时候使用SVC中断,此问题就迎刃而解了。

本章教程配套的例子含Cortex-M3内核的STM32F103Cortex-M4内核的STM32F407

19.1 SVC中断

19.2 RTXSVC中断方式调用函数方法

19.3 实验例程说明

19.4       总结

 

19.1 SVC中断

19.1.1  SVC功能介绍

SVC用于产生系统函数的调用请求。例如,操作系统通常不让用户程序直接访问硬件,而是通过提供一些系统服务函数,让用户程序使用SVC发出对系统服务函数的呼叫请求,以这种方法调用它们来间接访问硬件。因此,当用户程序想要控制特定的硬件时,它就要产生一个SVC异常,然后操作系统提供的SVC异常服务例程得到执行,它再调用相关的操作系统函数,后者完成用户程序请求的服务。

SVC这种“提出要求——得到满足”的方式很好:

l  它使用户程序从控制硬件的繁文缛节中解脱出来,而是由OS负责控制具体的硬件。

l  OS的代码可以经过充分的测试,从而能使系统更加健壮和可靠。

l  它使用户程序无需在特权级下执行,用户程序无需承担因误操作而瘫痪整个系统的风险。

l  通过SVC的机制,还让用户程序变得与硬件无关,因此在开发应用程序时无需了解硬件的操作细节,从而简化了开发的难度和繁琐度,并且使应用程序跨硬件平台移植成为可能。开发应用程序唯一需要知道的就是操作系统提供的应用编程接口(API),并且在了解了各个请求代号和参数表后,就可以使用SVC来提出要求了(事实上,为使用方便,操作系统往往会提供一层封皮,以使系统调用的形式看起来和普通的函数调用一致。各封皮函数会正确使用SVC指令来执行系统调用)。其实,严格地讲,操作硬件的工作是由设备驱动程序完成的,只是对应用程序来说,它们也相当于操作系统的一部分。如下图所示:

【RTX操作系统教程】第19章 <wbr>SVC中断方式调用用户函数

 

SVC异常通过执行”SVC”指令来产生。该指令需要一个立即数,充当系统调用代号。SVC异常服务例程稍后会提取出此代号,从而获知本次调用的具体要求,再调用相应的服务函数。例如,

SVC   0x3 ; 调用3号系统服务

SVC服务例程执行后,上次执行的SVC指令地址可以根据自动入栈的返回地址计算出。找到了SVC指令后,就可以读取该SVC指令的机器码,从机器码中萃取出立即数,就获知了请求执行的功能代号。如果用户程序使用的是PSP,服务例程还需要先执行MRS Rn, PSP指令来获取应用程序的堆栈指针。通过分析LR的值,可以获知在SVC指令执行时,正在使用哪个堆栈。

注意,我们不能在SVC服务例程中嵌套使用SVC指令(事实上这样做也没意义),因为同优先级的异常不能抢占自身。这种作法会产生一个用法fault。同理,在NMI服务例程中也不得使用SVC,否则将触发硬fault

19.1.2 SVC触发方式

SVC的异常号是11,支持可编程。SVC异常可以由SVC指令来触发,也可以通过NVIC来软件触发(通过寄存器NVIC->STIR触发软中断)。这两种方式触发SVC中断有一点不同:软件触发中断是不精确的,也就是说,抢占行为不一定会立即发生,即使当时它没有被掩蔽,也没有被其它ISR阻塞,也不能保证马上响应。这也是写缓冲造成的,会影响到与操作NVIC STIR相临的后一条指令:如果它需要根据中断服务的结果来决定如何工作(如条件跳转),则该指令可能会误动作——这也可以算是紊乱危象的一种表现形式。为解决这个问题,必须使用一条DSB指令,如下例所示:

MOV R0, #SOFTWARE_INTERRUPT_NUMBER

LDR R1,=0xE000EF00    ; 加载NVIC软件触发中断寄存器的地址

STR   R0,   [R1]        ; 触发软件中断

DSB                    ; 执行数据同步隔离指令

...

但是这种方式还有另一种隐患:如果欲触发的软件中断被除能了,或者执行软件中断的程序自己也是个异常服务程序,软件中断就有可能无法响应。因此,必须在使用前检查这个中断已经在响应中了。为达到此目的,可以让软件中断服务程序在入口处设置一个标志。而SVC要精确很多,SVC指令后,只要此时没有其它高优先级的异常也发生了,SVC中断服务程序可以得到立即执行。

19.1.3 SVC的使用

SVC是用于呼叫OS所提供的APIRTX是采用的这种方式)。用户程序只需知道传递给OS的参数,而不必知道各API函数的地址。SVC指令带一个8位的立即数,可以视为是它的参数,被封装在指令本身中,如:

SVC     ;呼叫3号系统服务

3被封装在这个SVC指令中。因此在SVC服务例程中,需要读取本次触发SVC异常的SVC指令,并提取出8位立即数所在的位段,来判断系统调用号。

19.1.4RTX使用的SVC中断服务号

SVC0号系统服务被RTX系统占用,即SVC  0,用户只能使用从1开始的服务号。而且用户使用的时候一定要保证从1开始,连续递增使用,范围1 – 255

19.2RTXSVC中断方式调用函数方法

用户实现SVC中断方式调用函数方法如下(下面以添加两个SVC中断为例):

u  1步:添加SVC_Table.s文件。

我们在前面讲解RTX的源码移植方式时这个文件已经加上。

u  2步:使用属性__svc(x)声明函数,x1开始,范围1-255。函数名随便命名,但是x的数值一定要保证是连续递增的。

void __svc(1)  SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4);

void __svc(2)  SVC_2_FunCall(void);

u  3步:写上面两个函数的实际代码,并将函数名更改成__SVC_x格式(统一改成这种命名方式是为了跟RTX系统的调用方式__SVC_0统一),x是从1开始,范围1-255。上面声明的两个函数不要动,这里修改的是实际函数名。另外用户可以根据需要加上中断开关操作,因为SVC中断可以被其它高优先级的中断抢占。

 

//这里的__SVC_1就是函数SVC_1_FunCall

void __SVC_1(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4)

{

     __disable_irq();

     printf("_arg1 = %d\r\n", _arg1);

     printf("_arg2 = %d\r\n", _arg2);

     printf("_arg3 = %d\r\n", _arg3);

     printf("_arg4 = %lld\r\n", *_arg4);

     __enable_irq();

}

 

//这里的__SVC_2就是函数SVC_2_FunCall             

void __SVC_2(void)

{

     __disable_irq();

     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

     __enable_irq();

}

u  4:将定义的两个函数添加到SVC_Table.s文件里面

首先使用IMPORT命令声明下,类似C语言中的extern。然后添加到SVC_Table列表下,整体添加后的效果如下(红色字体是用户添加的):

                AREA    SVC_TABLE, CODE, READONLY

 

                EXPORT  SVC_Count

 

SVC_Cnt         EQU    (SVC_End-SVC_Table)/4

SVC_Count       DCD     SVC_Cnt

 

; Import user SVC functions here.

                IMPORT  __SVC_1

                IMPORT  __SVC_2

 

                EXPORT  SVC_Table

SVC_Table

; Insert user SVC functions here. SVC 0 used by RTL Kernel.

               DCD     __SVC_1                 ; user SVC function

               DCD     __SVC_2                 ; user SVC function

 

SVC_End

 

                END

u  至此,RTXSVC中断的调用就实现了。实际应用的时候,用户只需调用函数SVC_1_FunCallSVC_1_FunCall即可,这两个函数就是在SVC中断里面实现的。

19.3实验例程说明

19.3.1 STM32F103开发板实验

配套例子:

V4-419_RTX实验_SVC中断方式调用用户函数

实验目的:

1.     学习SVC中断方式调用用户函数

实验说明:

1.     RTX支持配置所有任务工作特权级模式或者用户模式,宏配置在文件RTX_Conf_CM.c文件里面

#define OS_RUNPRIV     0

配置为0的话,任务工作在用户级,配置为1的话,任务工作在特权级。本实验配置为0,所有任务都工作在用户级模式。

2.     本实验演示SVC中断号调用方法。

SVC指令带一个8位的立即数(范围0-255),可以视为是它的参数,被封装在指令本身中,如:

SVC     呼叫3号系统服务

SVC 0RTX系统所使用了,用户只能使用从1开始的服务号。用户使用的时候一定要保证从1开始,而且需要连续的使用。实验中使用了SVC 1SVC 2

实验内容:

1. K1按键按下,串口打印。

2. K2键按下,向消息邮箱发送数据。任务AppTaskMsgPro接收到消息后进行消息处理。

3. K3键按下,调用SVC1号系统服务。

4. 摇杆OK键按下,任务运行在非特权级,调用SVC2号系统服务,可以在中断中设置NVIC

5. 各个任务实现的功能如下:

AppTaskUserIF任务   :按键消息处理。

AppTaskLED任务     LED闪烁。

AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。

AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。

RTX配置:

RTX配置向导详情如下:

【RTX操作系统教程】第19章 <wbr>SVC中断方式调用用户函数

 

u  Task Configuration

l  Number of concurrent running tasks

允许创建4个任务,实际创建了如下四个任务:

              AppTaskUserIF任务   :按键消息处理。

              AppTaskLED任务     LED闪烁。

              AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。

              AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。

l  Number of tasks with user-provided stack

创建的4个任务都是采用自定义堆栈方式。

l  Run in privileged mode

设置任务运行在非特权级模式

RTX任务调试信息:

【RTX操作系统教程】第19章 <wbr>SVC中断方式调用用户函数

 

程序设计:

u  任务栈大小分配:

static uint64_t AppTaskUserIFStk[512/8];   

static uint64_t AppTaskLEDStk[256/8];      

static uint64_t AppTaskMsgProStk[512/8]; 

static uint64_t AppTaskStartStk[512/8];     

将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。

u  系统栈大小分配:

【RTX操作系统教程】第19章 <wbr>SVC中断方式调用用户函数

 

u  RTX初始化:

 

int main (void)

  

    

     bsp_Init();

    

    

     os_sys_init_user (AppTaskStart,            

                       4,                        

                       &AppTaskStartStk,        

                       sizeof(AppTaskStartStk));

     while(1);

}

u  RTX任务创建:

 

static void AppTaskCreate (void)

{

     HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,            

                                           1,                        

                                           &AppTaskUserIFStk,        

                                           sizeof(AppTaskUserIFStk));

    

     HandleTaskLED = os_tsk_create_user(AppTaskLED,             

                                        2,                      

                                        &AppTaskLEDStk,         

                                        sizeof(AppTaskLEDStk)); 

    

     HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,            

                                           3,                        

                                           &AppTaskMsgProStk,        

                                           sizeof(AppTaskMsgProStk));

}

u  消息邮箱的创建:

#define PoolBlocks           10

#define PoolPerBlockSize     8

 

 

os_mbx_declare (mailbox, 10);

 

 

static void AppObjCreate (void)

{

    

      os_mbx_init (&mailbox, sizeof(mailbox));

    

}

u  SVC中断函数的创建:

void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4);

void __svc(2) SVC_2_FunCall(void);

 

 

void __SVC_1(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4)

{

    

     __disable_irq();

     printf("_arg1 = %d\r\n", _arg1);

     printf("_arg2 = %d\r\n", _arg2);

     printf("_arg3 = %d\r\n", _arg3);

     printf("_arg4 = %lld\r\n", *_arg4);

     __enable_irq();

}

                  

void __SVC_2(void)

{

    

     __disable_irq();

     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

     __enable_irq();

}

u  SVC_Table.s文件中SVC中断的设置(红色字体是需要用户添加的):

void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4);

                AREA    SVC_TABLE, CODE, READONLY

 

                EXPORT  SVC_Count

 

SVC_Cnt         EQU    (SVC_End-SVC_Table)/4

SVC_Count       DCD     SVC_Cnt

 

; Import user SVC functions here.

                IMPORT  __SVC_1

                IMPORT  __SVC_2

 

                EXPORT  SVC_Table

SVC_Table

; Insert user SVC functions here. SVC 0 used by RTL Kernel.

               DCD     __SVC_1                 ; user SVC function

               DCD     __SVC_2                 ; user SVC function

 

SVC_End

 

                END

u  四个RTX任务的实现:

 

__task void AppTaskUserIF(void)

{

     uint8_t ucMsgTra = 0;

     uint8_t ucMsg = 0;

     uint16_t usMsg = 0;

     uint32_t ulMsg = 0;

     uint64_t ullMsg = 0;

     uint8_t ucKeyCode;

 

    while(1)

    {

         ucKeyCode = bsp_GetKey();

        

         if (ucKeyCode != KEY_NONE)

         {

              switch (ucKeyCode)

              {

                  

                   case KEY_DOWN_K1:

                       printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");

                       break;  

 

                  

                   case KEY_DOWN_K2:

                       ucMsgTra++;

    

                      

                       if(os_mbx_send (&mailbox, &ucMsgTra, 100) != OS_R_OK)

                       {

                           

                            printf("K2键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");

                       }

                       else

                       {

                           

                            printf("K2键按下,向消息邮箱发送数据成功\r\n");                          

                       }

                       break;

                      

                  

                   case KEY_DOWN_K3:

                       printf(" K3键按下,调用SVC1号系统服务\r\n");

                       ullMsg++;

                       SVC_1_FunCall(++ucMsg, ++usMsg, ++ulMsg, &ullMsg);

                       break;

                  

                  

                   case JOY_DOWN_OK:

                       printf("摇杆OK键按下,任务运行在非特权级,调用SVC2号系统服务,可中断中设置NVIC

 \r\n");

                       SVC_2_FunCall();

                       break;

 

                  

                   default:                    

                       break;

              }

         }

        

         os_dly_wait(20);

     }

}

 

 

__task void AppTaskLED(void)

{

     const uint16_t usFrequency = 200;

    

    

     os_itv_set(usFrequency);

    

    while(1)

    {

         bsp_LedToggle(2);

         bsp_LedToggle(3);

 

        

         os_itv_wait();

    }

}

 

 

__task void AppTaskMsgPro(void)

{

     uint8_t *pMsg;

     OS_RESULT xResult;

     const uint16_t usMaxBlockTime = 200;

    

    while(1)

    {

         xResult = os_mbx_wait(&mailbox, (void *)&pMsg, usMaxBlockTime);

        

         switch (xResult)

         {

             

              case OS_R_OK:

                   printf("无需等待接受到消息邮箱数据,pMsg = %d\r\n", *pMsg);

                   break;  

 

             

              case OS_R_MBX:

                   printf("消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据,pMsg = %d\r\n", *pMsg);

                   break;

 

             

              case OS_R_TMO:

                   bsp_LedToggle(1);

                   bsp_LedToggle(4);

                   break;

             

             

              default:                    

                   break;

          

    }

}

 

 

__task void AppTaskStart(void)

{

    

     AppTaskCreate();

    

    

     AppObjCreate();

    

    while(1)

    {

        

         bsp_KeyScan();

        os_dly_wait(10);

    }

}

19.3.2STM32F407开发板实验

配套例子:

V5-419_RTX实验_SVC中断方式调用用户函数

实验目的:

1.     学习SVC中断方式调用用户函数

实验说明:

1.     RTX支持配置所有任务工作特权级模式或者用户模式,宏配置在文件RTX_Conf_CM.c文件里面

#define OS_RUNPRIV     0

配置为0的话,任务工作在用户级,配置为1的话,任务工作在特权级。本实验配置为0,所有任务都工作在用户级模式。

2.     本实验演示SVC中断号调用方法。

SVC指令带一个8位的立即数(范围0-255),可以视为是它的参数,被封装在指令本身中,如:

SVC     呼叫3号系统服务

SVC 0RTX系统所使用了,用户只能使用从1开始的服务号。用户使用的时候一定要保证从1开始,而且需连续的使用。实验中使用了SVC 1SVC 2

实验内容:

1. K1按键按下,串口打印。

2. K2键按下,向消息邮箱发送数据。任务AppTaskMsgPro接收到消息后进行消息处理。

3. K3键按下,调用SVC1号系统服务。

4. 摇杆OK键按下,任务运行在非特权级,调用SVC2号系统服务,可以在中断中设置NVIC

5. 各个任务实现的功能如下:

AppTaskUserIF任务   :按键消息处理。

AppTaskLED任务     LED闪烁。

AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。

AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。

RTX配置:

RTX配置向导详情如下:

【RTX操作系统教程】第19章 <wbr>SVC中断方式调用用户函数

 

u  Task Configuration

l  Number of concurrent running tasks

允许创建4个任务,实际创建了如下四个任务:

              AppTaskUserIF任务   :按键消息处理。

              AppTaskLED任务     LED闪烁。

              AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。

              AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。

l  Number of tasks with user-provided stack

创建的4个任务都是采用自定义堆栈方式。

l  Run in privileged mode

设置任务运行在非特权级模式

RTX任务调试信息:

【RTX操作系统教程】第19章 <wbr>SVC中断方式调用用户函数

 

程序设计:

u  任务栈大小分配:

static uint64_t AppTaskUserIFStk[512/8];   

static uint64_t AppTaskLEDStk[256/8];      

static uint64_t AppTaskMsgProStk[512/8]; 

static uint64_t AppTaskStartStk[512/8];     

将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。

u  系统栈大小分配:

【RTX操作系统教程】第19章 <wbr>SVC中断方式调用用户函数

 

u  RTX初始化:

 

int main (void)

  

    

     bsp_Init();

    

    

     os_sys_init_user (AppTaskStart,            

                       4,                        

                       &AppTaskStartStk,        

                       sizeof(AppTaskStartStk));

     while(1);

}

u  RTX任务创建:

 

static void AppTaskCreate (void)

{

     HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,            

                                           1,                        

                                           &AppTaskUserIFStk,        

                                           sizeof(AppTaskUserIFStk));

    

     HandleTaskLED = os_tsk_create_user(AppTaskLED,             

                                        2,                      

                                        &AppTaskLEDStk,         

                                        sizeof(AppTaskLEDStk)); 

    

     HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,            

                                           3,                         

                                           &AppTaskMsgProStk,        

                                           sizeof(AppTaskMsgProStk));

}

u  消息邮箱的创建:

#define PoolBlocks           10

#define PoolPerBlockSize     8

 

 

os_mbx_declare (mailbox, 10);

 

 

static void AppObjCreate (void)

{

    

      os_mbx_init (&mailbox, sizeof(mailbox));

    

}

u  SVC中断函数的创建:

void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4);

void __svc(2) SVC_2_FunCall(void);

 

 

void __SVC_1(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4)

{

    

     __disable_irq();

     printf("_arg1 = %d\r\n", _arg1);

     printf("_arg2 = %d\r\n", _arg2);

     printf("_arg3 = %d\r\n", _arg3);

     printf("_arg4 = %lld\r\n", *_arg4);

     __enable_irq();

}

                  

void __SVC_2(void)

{

    

     __disable_irq();

     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

     __enable_irq();

}

u  SVC_Table.s文件中SVC中断的设置(红色字体是需要用户添加的):

void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4);

                AREA    SVC_TABLE, CODE, READONLY

 

                EXPORT  SVC_Count

 

SVC_Cnt         EQU    (SVC_End-SVC_Table)/4

SVC_Count       DCD     SVC_Cnt

 

; Import user SVC functions here.

                IMPORT  __SVC_1

                IMPORT  __SVC_2

 

                EXPORT  SVC_Table

SVC_Table

; Insert user SVC functions here. SVC 0 used by RTL Kernel.

               DCD     __SVC_1                 ; user SVC function

               DCD     __SVC_2                 ; user SVC function

 

SVC_End

 

                END

u  四个RTX任务的实现:

 

__task void AppTaskUserIF(void)

{

     uint8_t ucMsgTra = 0;

     uint8_t ucMsg = 0;

     uint16_t usMsg = 0;

     uint32_t ulMsg = 0;

     uint64_t ullMsg = 0;

     uint8_t ucKeyCode;

 

    while(1)

    {

         ucKeyCode = bsp_GetKey();

        

         if (ucKeyCode != KEY_NONE)

         {

              switch (ucKeyCode)

              {

                  

                   case KEY_DOWN_K1:

                       printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");

                       break;  

 

                  

                   case KEY_DOWN_K2:

                       ucMsgTra++;

    

                      

                       if(os_mbx_send (&mailbox, &ucMsgTra, 100) != OS_R_OK)

                       {

                           

                            printf("K2键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");

                       }

                       else

                       {

                           

                            printf("K2键按下,向消息邮箱发送数据成功\r\n");                          

                       }

                       break;

                      

                  

                   case KEY_DOWN_K3:

                       printf(" K3键按下,调用SVC1号系统服务\r\n");

                       ullMsg++;

                       SVC_1_FunCall(++ucMsg, ++usMsg, ++ulMsg, &ullMsg);

                       break;

                  

                  

                   case JOY_DOWN_OK:

                       printf("摇杆OK键按下,任务运行在非特权级,调用SVC2号系统服务,可中断中设置NVIC

 \r\n");

                        SVC_2_FunCall();

                       break;

 

                  

                   default:                    

                       break;

              }

         }

        

         os_dly_wait(20);

     }

}

 

 

__task void AppTaskLED(void)

{

     const uint16_t usFrequency = 200;

    

    

     os_itv_set(usFrequency);

    

    while(1)

    {

         bsp_LedToggle(2);

         bsp_LedToggle(3);

 

        

         os_itv_wait();

    }

}

 

 

__task void AppTaskMsgPro(void)

{

     uint8_t *pMsg;

     OS_RESULT xResult;

     const uint16_t usMaxBlockTime = 200;

    

    while(1)

    {

         xResult = os_mbx_wait(&mailbox, (void *)&pMsg, usMaxBlockTime);

        

         switch (xResult)

         {

             

              case OS_R_OK:

                   printf("无需等待接受到消息邮箱数据,pMsg = %d\r\n", *pMsg);

                   break;  

 

             

              case OS_R_MBX:

                   printf("消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据,pMsg = %d\r\n", *pMsg);

                   break;

 

             

              case OS_R_TMO:

                   bsp_LedToggle(1);

                   bsp_LedToggle(4);

                   break;

             

             

              default:                    

                   break;

          

    }

}

 

 

__task void AppTaskStart(void)

{

    

     AppTaskCreate();

    

    

     AppObjCreate();

    

    while(1)

    {

        

         bsp_KeyScan();

        os_dly_wait(10);

    }

}

19.4总结

本章节主要大家讲解了如何采用SVC中断方式调用用户函数,更多SVC中断方面的知识可以看Cortex-M3或者M4权威指南。

 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有