硬汉嵌入式论坛

 找回密码
 立即注册
查看: 4868|回复: 10
收起左侧

[RTOS] 烧脑子,分享RTX5的自定义SVC软中断两种实现方法,直接调用__svc_indirect弹了一天的bug,折磨死人

  [复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107023
QQ
发表于 2020-4-15 18:50:07 | 显示全部楼层 |阅读模式
RTX5中的这种定义方式,简直没人性,太高级了,玩不转,不过还是实现了这种方式的自定义使用方法:
  1. #define SVC0_3(f,t,t1,t2,t3)                                                   \
  2. __SVC_INDIRECT(0) t    svc##f (t(*)(t1,t2,t3),t1,t2,t3);                       \
  3. __attribute__((always_inline))                                                 \
  4. __STATIC_INLINE   t  __svc##f (t1 a1, t2 a2, t3 a3) {                          \
  5.   return svc##f(svcRtx##f,a1,a2,a3);                                           \
  6. }

  7. #define SVC0_4(f,t,t1,t2,t3,t4)                                                \
  8. __SVC_INDIRECT(0) t    svc##f (t(*)(t1,t2,t3,t4),t1,t2,t3,t4);                 \
  9. __attribute__((always_inline))                                                 \
  10. __STATIC_INLINE   t  __svc##f (t1 a1, t2 a2, t3 a3, t4 a4) {                   \
  11.   return svc##f(svcRtx##f,a1,a2,a3,a4);                                        \
  12. }
复制代码



SVC 的0号系统服务被 RTX5 系统占用,即 SVC 0,当前列出的SVC0_X都是用的SVC 0中断。而用户可以使用从 1 开始的服务号。使用的时候要保证从 1 开始,连续递增使用,范围 1 – 255。

方法一:

1、这里下载个V7的RTX5例子:http://www.armbbs.cn/forum.php?mod=viewthread&tid=93238

2、比如实现函数svcUsertest的SVC软中断调用:

添加如下代码:


  1. void svcUsertest(void)
  2. {
  3.    bsp_SetTIMforInt(TIM6, 10,0,0);
  4. }

  5. #define SVC1_0N(f,t)                                                           \
  6. __SVC_1 t    svc##f (t(*)());                                                                \
  7. __attribute__((always_inline))                                                 \
  8. __STATIC_INLINE   t  __svc##f (void) {                                         \
  9.   svc##f(svcUser##f);                                                           \
  10. }

  11. SVC1_0N(test, void);

  12. void * const osRtxUserSVC[2] = {(void *)1, svcUsertest};
复制代码


解释下osRtxUserSVC,这个是在RTX5的port文件里面要调用的,第1个参数是要自定义的函数个数,我们这里仅定义了一个,这里就写1即可。

3、用户调用的时候要写函数__svctest(),这点要特别注意。

4、由于调用的定时器中断,添加上一个中断函数处理:

  1. void TIM6_DAC_IRQHandler(void)
  2. {
  3.         if((TIM6->SR & TIM_FLAG_UPDATE) != RESET)
  4.         {
  5.                 TIM6->SR = ~ TIM_FLAG_UPDATE;
  6.                 bsp_LedToggle(4);
  7.         }
  8. }
复制代码



方法二:

1、同方法1,下载V7的RTX5的例子。

2、比如要实现函数bsp_SetTIMforInt的软中断调用,添加如下代码:

  1. #define __SVC_1        __svc_indirect(1)
  2. #define OS_SetTIMforInt(t1,t2,t3,t4) _bsp_SetTIMforInt((uint32_t)bsp_SetTIMforInt, t1,t2,t3,t4)
  3. void _bsp_SetTIMforInt(uint32_t p, TIM_TypeDef* TIMx, uint32_t _ulFreq, uint8_t _PreemptionPriority, uint8_t _SubPriority)  __SVC_1;
  4. void * const osRtxUserSVC[2] = {(void *)1, bsp_SetTIMforInt};
复制代码


3、调用的时候写函数OS_SetTIMforInt(TIM, 10, 0, 0);

4、由于调用的定时器中断,添加上一个中断函数处理:

  1. void TIM6_DAC_IRQHandler(void)
  2. {
  3.         if((TIM6->SR & TIM_FLAG_UPDATE) != RESET)
  4.         {
  5.                 TIM6->SR = ~ TIM_FLAG_UPDATE;
  6.                 bsp_LedToggle(4);
  7.         }
  8. }
复制代码














回复

使用道具 举报

610

主题

3062

回帖

4912

积分

至尊会员

积分
4912
发表于 2020-4-15 19:12:23 | 显示全部楼层
貌似太复杂, 没有看懂
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107023
QQ
 楼主| 发表于 2020-4-15 19:18:23 | 显示全部楼层
直接在函数后面挂__svc_indirect不让用,非得宏定义改下,

#define __SVC_1        __svc_indirect(1)

回复

使用道具 举报

3

主题

11

回帖

20

积分

新手上路

积分
20
发表于 2020-4-16 17:46:52 | 显示全部楼层
硬汉哥,在svc_user.c中将程序写完后(使用方法2),如果在main.c文件中调用函数OS_SetTIMforInt(TIM, 10, 0, 0); 这个宏定义如何声明?
svc_user.c中程序如下:
#include "cmsis_os2.h"
#include "sys.h"

extern osEventFlagsId_t Measureflag_id;
extern osStatus_t status1,statys2;

extern void LED_thread(void *argument);

void bsp_SetTIMforInt(uint32_t arr,uint32_t 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寄存器
//        NVIC->ISER[0] = (1UL << 18);
        TIM_Cmd(TIM3, ENABLE);  //使能TIMx
}

#define __SVC_1        __svc_indirect(1)
#define OS_SetTIMforInt(arr,psc) _bsp_SetTIMforInt((uint32_t)bsp_SetTIMforInt, arr,psc)
void _bsp_SetTIMforInt(uint32_t p,uint32_t _arr, uint32_t _psc)  __SVC_1;
void * const osRtxUserSVC[2] = {(void *)1,bsp_SetTIMforInt};

void TIM3_IRQHandler(void)
{
        if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
                {
                TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中断标志
//                status1 = osEventFlagsSet (Measureflag_id,0x01);
          osThreadNew(LED_thread,NULL,NULL);
                }
}
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107023
QQ
 楼主| 发表于 2020-4-16 17:58:31 | 显示全部楼层
sldx 发表于 2020-4-16 17:46
硬汉哥,在svc_user.c中将程序写完后(使用方法2),如果在main.c文件中调用函数OS_SetTIMforInt(TIM, 10,  ...

将定义放到头文件里面即可。
回复

使用道具 举报

6

主题

57

回帖

75

积分

初级会员

积分
75
发表于 2020-4-17 08:54:46 | 显示全部楼层
这是ac5还是ac6编译器,ac6貌似不支持这么搞。
ac5:

void __svc(1) EXTI_GLOBAL_INT_CTRL(uint32_t is_enable);

void* const osRtxUserSVC[] = {
    (void*)1,
    EXTI_GLOBAL_INT_CTRL_CALL,
};

void EXTI_GLOBAL_INT_CTRL_CALL(uint32_t flag)
{

}

正常使用SVC的时候直接调用EXTI_GLOBAL_INT_CTRL即可。

AC6我还不晓得怎么弄
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107023
QQ
 楼主| 发表于 2020-4-17 10:07:22 | 显示全部楼层
sl3340 发表于 2020-4-17 08:54
这是ac5还是ac6编译器,ac6貌似不支持这么搞。
ac5:

我这里这种直接添加__svc(1)就不行,编译无法通过,邪门,按说也没啥问题,用的MDK5.27。

ps:你的这个 EXTI_GLOBAL_INT_CTRL和EXTI_GLOBAL_INT_CTRL_CALL没有关联起来,貌似会有没有进入SVC软中断的问题。

AC6要麻烦些,不过还是他们这种这种通用的方法:
#define SVC1_0N(f,t)                                                           \
__attribute__((always_inline))                                                 \
__STATIC_INLINE t __svc##f (void) {                                            \
  SVC_ArgF(svcRtx##f);                                                         \
  SVC_Call0(SVC_In0, SVC_Out0, SVC_CL2);                                       \
}
回复

使用道具 举报

6

主题

57

回帖

75

积分

初级会员

积分
75
发表于 2020-4-21 08:23:26 | 显示全部楼层
eric2013 发表于 2020-4-17 10:07
我这里这种直接添加__svc(1)就不行,编译无法通过,邪门,按说也没啥问题,用的MDK5.27。

ps:你的这 ...

关联起来了,确实是可以用的,单步也确实进svc中断了。SVC指令本身就会触发SVC服务去osRtxUserSVC查找函数,并运行。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107023
QQ
 楼主| 发表于 2020-4-21 09:02:26 | 显示全部楼层
sl3340 发表于 2020-4-21 08:23
关联起来了,确实是可以用的,单步也确实进svc中断了。SVC指令本身就会触发SVC服务去osRtxUserSVC查找函 ...

我这里不行,关联不起来,邪门。
回复

使用道具 举报

4

主题

16

回帖

28

积分

新手上路

积分
28
发表于 2021-4-12 11:56:12 | 显示全部楼层
请问实现的模板有吗?想参考一下。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107023
QQ
 楼主| 发表于 2021-4-12 12:20:35 | 显示全部楼层
alban 发表于 2021-4-12 11:56
请问实现的模板有吗?想参考一下。

没有做完整模板,参考我楼主位的可以实现。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-14 10:46 , Processed in 0.178975 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表