ERIKA OS学习和使用总结

ERIKA是一款开源的、遵循OSEK/VDX标准的实时操作系统。

一、周期任务的实现(方式一:使用普通COUNTER,Alarm通过SetRelAlarm()函数手动启动和设置)

(1)code.c

/* ERIKA Enterprise. */
#include "ee.h"

/* TASKs */
DeclareTask( Task1 );

extern void clock_handler( void );
ISR( stm0_handler ) {

    osEE_tc_stm_set_sr0_next_match( 1000U );
    IncrementCounter( myCounter );  //(1)在stm中断中为counter计数。counter在OIL文件的定义(COUNTER myCounter),用于唤醒Task1的Alarm会与myCounter绑定,
}                                   //并且也会和Task1绑定,并通过函数SetRelAlarm() 来设置Task1的唤醒周期T,一旦myCounter计数达到T,就唤醒Task1.

TASK(Task1)
{
    toggle_led( LED_1 );
    TerminateTask();  //每个任务的最后必须添加这一函数用于结束任务
}int main(void)
{
    osEE_tc_stm_set_clockpersec();
    osEE_tc_stm_set_sr0( 1000U, 1U );  //设置stm

    leds_init();

    SetRelAlarm( AlarmTask1, 2000U, 500U );  //(2)设置用于激活Task1的Alarm的开始时间和周期

    StartOS( OSDEFAULTAPPMODE );  //启动erika os。在本条语句之前,不能使用其他erika os的原语,除非在启用startupHook并在其中可以调用部分原语

    return 0;
}

(2)OIL

CPU mySystem {

  OS myOs {
    EE_OPT = "OSEE_DEBUG";  //OS的一些可选项
    EE_OPT = "OS_EE_APPL_BUILD_DEBUG";
    EE_OPT = "OS_EE_BUILD_DEBUG";

    CPU_DATA = TRICORE {  //CPU类型必须选择TRICORE
      CPU_CLOCK = 300.0;
      MULTI_STACK = TRUE;
      COMPILER = GCC;
      IDLEHOOK = FALSE;
    };

    MCU_DATA = TC29X {  //MCU选择相应的芯片型号,这里选择TC29x后再编译,ERIKA就会引入TC29x对应的寄存器和外设等相应的定义(默认是TC27x的)
DERIVATIVE = "tc297tf"; //下面这两个参数影响不大 REVISION = "B"; }; KERNEL_TYPE = OSEK { //内核类型。除了选择正常的OSEK,还可以选择FP/EDF/FRSK/HR,这些类型是ERIKA在OSEK标准之外自己加入的一些一致性类 CLASS = BCC1; //一致性类 BCC1和BCC2只支持基础任务,不能使用waitevent等阻塞相关的功能,可以共享堆栈;而ECC1和ECC2支持扩展任务,可以使用阻塞相关 }; //功能,但因为阻塞,必须使用私有堆栈;BCC1和ECC1不支持pending activation,即连续激活一个任务时,能否挂起激活次数;BCC2和ECC2支持。 }; APPDATA periodic_task { APP_SRC = "code.c"; }; TASK Task1 { //设置Task1的属性 PRIORITY = 1; // 设置优先级 STACK = PRIVATE { //使用私有栈 SIZE = 1024; }; SCHEDULE = FULL; //参与基于优先级的抢占 }; COUNTER myCounter; //定义counter ALARM AlarmTask1 { //将Alarm与counter及task进行绑定 COUNTER = myCounter; ACTION = ACTIVATETASK { TASK = Task1; }; }; ISR TimerISR { // 设置STM的相关属性 CATEGORY = 2; //ISR的类型设置为type2,即由Erika进行管理。ISR Type1和ISR Type2的区别是:ISR1是一般的中断,与OS无关,handler中只能执行少数OS API; SOURCE = "STM0SR0"; //ISR2由OS进行管理,该类型的中断类似于任务。Handler中可以执行OS API,该类型的中断需要在OIL文件中声明;ISR1的优先级必须高于ISR2。 HANDLER = "stm0_handler"; //使用的STM资源和中断处理函数名 PRIORITY = 1; }; };

由此可以看出.c文件用于编写任务实体,而OIL文件中定义任务属性,如下图所示。

ERIKA OS学习和使用总结

 

 

 


二、周期任务的实现(方式二:使用Hardware COUNTER——System Timer,且Alarm自动启动和设置)

(1)code.c

/* ERIKA Enterprise. */
#include "ee.h"
/* TASKs */ DeclareTask( Task1 ); TASK(Task1) { toggle_led( LED_1 ); TerminateTask(); }

// 不用初始化STM,也不用在STM中断里为COUNTER计数,Alarm设置为自启动,且启动时间和周期在OIL文件中设置
int main(void) { leds_init(); StartOS( OSDEFAULTAPPMODE ); return 0; }

(2)OIL文件

CPU mySystem {

  OS myOs {
    EE_OPT = "OSEE_DEBUG";  //OS的一些可选项
    EE_OPT = "OS_EE_APPL_BUILD_DEBUG";
    EE_OPT = "OS_EE_BUILD_DEBUG";

    CPU_DATA = TRICORE {  //CPU类型必须选择TRICORE
      CPU_CLOCK = 300.0;
      MULTI_STACK = TRUE;
      COMPILER = GCC;
      IDLEHOOK = FALSE;
    };

    MCU_DATA = TC29X {  //MCU选择相应的芯片型号,这里选择TC29x后再编译,ERIKA就会引入TC29x对应的寄存器和外设等相应的定义(默认是TC27x的)
DERIVATIVE = "tc297tf"; //下面这两个参数影响不大 REVISION = "B"; }; KERNEL_TYPE = OSEK { //内核类型。除了选择正常的OSEK,还可以选择FP/EDF/FRSK/HR,这些类型是ERIKA在OSEK标准之外自己加入的一些一致性类 CLASS = BCC1; //一致性类 BCC1和BCC2只支持基础任务,不能使用waitevent等阻塞相关的功能,可以共享堆栈;而ECC1和ECC2支持扩展任务,可以使用阻塞相关 }; //功能,但因为阻塞,必须使用私有堆栈;BCC1和ECC1不支持pending activation,即连续激活一个任务时,能否挂起激活次数;BCC2和ECC2支持。 }; APPDATA periodic_task { APP_SRC = "code.c"; }; TASK Task1 { //设置Task1的属性 PRIORITY = 1; // 设置优先级 STACK = PRIVATE { //使用私有栈 SIZE = 1024; }; SCHEDULE = FULL; //参与基于优先级的抢占 };

    COUNTER system_timer_1 {
      CPU_ID = 0x0;  //指定system timer是哪个内核的,一个内核只能使用一个system timer
      MINCYCLE = 1;  //alarm周期的最小tick数
      MAXALLOWEDVALUE = 2147483647;  //counter的最大tick计数值
      TICKSPERBASE = 1;  // 每个计数单元(unit)包含的tick数,即时基
      TYPE = HARDWARE {  //设置使用hardware counter
        DEVICE = "STM_SR0";  //设置system counter所使用的stm资源
        SYSTEM_TIMER = TRUE;
        PRIORITY = 2;
      };
      SECONDSPERTICK = 0.001;  //设置tick的粒度,这里为每个tick为1ms
    };

    ALARM AlarmTask1 {
      COUNTER = system_timer_1;  //与hardware counter进行绑定
      ACTION = ACTIVATETASK { TASK = Task1; };  //与对应的task进行绑定
      AUTOSTART = TRUE { ALARMTIME = 500; CYCLETIME = 2000; };  //设置alarm自启动,同时设置开始时间和周期。任务也可以设置autostart
    };

};

三、Erika如何应用在多核中

(1)master.c

/* ERIKA Enterprise. */
#include "shared.h"

//master.c对应于core0,其任务TaskCore0执行后,延迟200ms唤醒TaskCore1,TaskCore1延迟200ms唤醒TaskCore2.
TASK(TaskCore0) { led_blink(OSEE_TRIBOARD_2X5_LED_1); SetRelAlarm( AlarmCore1, 200, 0 ); TerminateTask(); } OsEE_reg myErrorCounter; void ErrorHook(StatusType Error) //当OS运行出错时进行ErrorHook进行处理,ErrorHook通过OIL文件设置是否启用。 { (void)Error; ++myErrorCounter; led_blink(OSEE_TRIBOARD_2X5_ALL_LEDS); } void idle_hook_core0(void); void idle_hook_core0(void) { idle_hook_body(); } /* * MAIN TASK */ int main(void) { StatusType status; AppModeType mode; CoreIdType const core_id = GetCoreID(); if (core_id == OS_CORE_ID_MASTER) { //注意main函数,每个核都会进入main函数,core0启动另外两个核,而core1和core2只需要进行各自的初始化工作 /* Init leds */ osEE_tc2x5_leds_init(); StartCore(OS_CORE_ID_1, &status); StartCore(OS_CORE_ID_2, &status); mode = OSDEFAULTAPPMODE; } else { mode = DONOTCARE; } StartOS(mode); return 0; }

(2)slave1.c和slave2.c

#include "shared.h"

void idle_hook_core1(void);
void idle_hook_core1(void)
{
  idle_hook_body();
}

TASK(TaskCore1)
{
  led_blink(OSEE_TRIBOARD_2X5_LED_2);
  SetRelAlarm( AlarmCore2, 200, 0 );
  TerminateTask();
}

#include "shared.h"

void idle_hook_core2(void);
void idle_hook_core2(void)
{
  idle_hook_body();
}

TASK(TaskCore2)
{
  led_blink(OSEE_TRIBOARD_2X5_LED_3);

  TerminateTask();
}

(3)OIL文件

CPU test_application {

  OS EE {
    /* EE_OPT = "OS_EE_VERBOSE"; */
    EE_OPT = "OSEE_DEBUG";
    EE_OPT = "OSEE_ASSERT";
    EE_OPT = "OS_EE_APPL_BUILD_DEBUG";
    EE_OPT = "OS_EE_BUILD_DEBUG";
    //EE_OPT = "OSEE_TC_CLONE_OS";

    CPU_DATA = TRICORE {
      ID = 0x0;
      CPU_CLOCK = 300.0;
      COMPILER = GCC;
      IDLEHOOK = TRUE {
        HOOKNAME = "idle_hook_core0";
      };
    };

    CPU_DATA = TRICORE {  //启用core1
      ID = 0x1;
      MULTI_STACK = TRUE;
      IDLEHOOK = TRUE {
        HOOKNAME = "idle_hook_core1";
      };
    };

    CPU_DATA = TRICORE {  //启用core2
      ID = 0x2;
      IDLEHOOK = TRUE {
        HOOKNAME = "idle_hook_core2";
      };
    };

    MCU_DATA = TC29X {
      DERIVATIVE = "tc297tf";
      REVISION = "BD";
    };

    STATUS = EXTENDED;
    ERRORHOOK = TRUE;  //使用errorhook
    USERESSCHEDULER = FALSE;

    USEORTI = TRUE;  

    KERNEL_TYPE = OSEK {
      CLASS = ECC1;
      RQ    = MQ;  //就绪任务列表类型选择:RQ=LL,用链表,复杂度为O(n),n为就绪队列中的任务数;RQ=MQ,用多队列,复杂度为O(1)
    };
  };

  APPDATA tricore_mc {
    APP_SRC="master.c";
    APP_SRC="slave1.c";
    APP_SRC="slave2.c";
  };

  TASK TaskCore0 {
    CPU_ID = 0x0;  //指定任务所属内核
    PRIORITY = 1;
  };

  TASK TaskCore1 {
    CPU_ID = 0x1;
    PRIORITY = 1;
  };

  TASK TaskCore2 {
    CPU_ID = 0x2;
    PRIORITY = 1;
  };

  COUNTER system_timer_core0 {
    CPU_ID = 0x0;
    MINCYCLE = 1;
    MAXALLOWEDVALUE = 2147483647;
    TICKSPERBASE = 1;
    TYPE = HARDWARE {
        DEVICE = "STM_SR0";
        SYSTEM_TIMER = TRUE;
        PRIORITY = 2;
    };
    SECONDSPERTICK = 0.001;
  };

  COUNTER system_timer_core1 {
    CPU_ID = 0x1;
    MINCYCLE = 1;
    MAXALLOWEDVALUE = 2147483647;
    TICKSPERBASE = 1;
    TYPE = HARDWARE {
      DEVICE = "STM_SR0";
      SYSTEM_TIMER = TRUE;
      PRIORITY = 2;
    };
    SECONDSPERTICK = 0.001;
  };

  COUNTER system_timer_core2 {
    CPU_ID = 0x2;
    MINCYCLE = 1;
    MAXALLOWEDVALUE = 2147483647;
    TICKSPERBASE = 1;
    TYPE = HARDWARE {
      DEVICE = "STM_SR0";
      SYSTEM_TIMER = TRUE;
      PRIORITY = 2;
    };
    SECONDSPERTICK = 0.001;
  };

  ALARM AlarmCore0 {
    COUNTER = system_timer_core0;
    ACTION = ACTIVATETASK { TASK = TaskCore0; };
    AUTOSTART = TRUE { ALARMTIME = 500; CYCLETIME = 2000; };
  };

  ALARM AlarmCore1 {
    COUNTER = system_timer_core1;
    ACTION = ACTIVATETASK { TASK = TaskCore1; };
  };

  ALARM AlarmCore2 {
    COUNTER = system_timer_core2;
    ACTION = ACTIVATETASK { TASK = TaskCore2; };
  };
};

四、Erika特点

(1)Erika的任务调度:①完全抢占式任务(Full Preemptive):参与基于优先级的抢占式任务调度;②非抢占式任务(Non Preemptive):不会被其他任务抢占;③混合式任务。

(2)堆栈使用:①main堆栈用于运行main()函数,当一个task设置堆栈为shared时,将会共享使用main堆栈;而当task设置了private堆栈时,则分配私有堆栈;②ISR1类中断发生时,使用当前激活的堆栈;ISR2型中断使用main堆栈。

(3)Erika优先级最大值:127

 

上一篇:队列顺序存储3


下一篇:Google Earth Engine(GEE)—CART分类(样本为点)