3.3 Support for OIL language
3.3.1 Stack Resource Policy support
Erika kernel provides the SRP protocol for accessing shared resources when using EDF. This is a priority-based protocol that assigns each task a prior- ity level. These priorities are assigned in the OIL file through the PRIORITY field. This field is used for filling two operating system data structures, namely EE th ready prio and EE th dispatch prio. With this approach, the respon- sibility to set the proper priorities, is assigned to the user, so it might be wrong assignments causing a malfunction of EDF, for instance a task with a longest deadline may be activated before a task with a shortest deadline even if no shared resources are defined.
To avoid this behavior, a new OIL keyword, TASK PRIORITY ASSIGNMENT, has been added in the kernel configuration section. This field can be set with two values:
Chapter 3. Support for EDF scheduling for AVR tasks
• DEADLINE MONOTONIC: priorities redefined following the deadline monotonic priority assignment policy. With this approach the priority is inversely proportional to the relative deadline length (the higher priority task is the task with the early deadline).
PRIORITY is a required field, so exploiting this feature, the RT-Druid was mod- ified to redefine the priorities values for reusing the existing code to create the data structures. In this way RT-Druid is able to handle two scenarios under DEADLINE MONOTONIC kernel configuration:
1. No resource defined: all task priorities are set to zero, in this way the proper behavior of EDF is guaranteed.
2. One or more resources defined: RT-Druid analyzed the relative deadline of each task; for the AVR tasks, it computes the worst case deadline, cor- responding to the case of maximum angular speed; tasks are sorted by deadline and the proper priority is assigned to each task.
A r r a y s . s o r t ( t a s k D L _ s o r t e d ) ; for(int i =0; i < t a s k s D L . s i z e () ; i ++) { int p r i o = -1; for(int j =0; j < t a s k D L _ s o r t e d . l e n g t h ; j ++) { if( t a s k D L _ s o r t e d [ t a s k D L _ s o r t e d . length -1 - j ]== t a s k D L [ i ]) { p r i o = j ; b r e a k; } } p r i o = 1 < < p r i o ; I S i m p l e G e n R e s c u r r T a s k = t a s k s . get ( i ) ; c u r r T a s k . r e m o v e A P r o p e r t y ( I S i m p l e G e n R e s K e y w o r d s . T A S K _ R E A D Y _ P R I O R I T Y ) ; c u r r T a s k . s e t P r o p e r t y ( I S i m p l e G e n R e s K e y w o r d s . T A S K _ R E A D Y _ P R I O R I T Y ," "+ p r i o ) ; }
Listing 3.17: Priorities reconfiguration
The listing 3.17 implements the operations for assigning the proper priority to the each tasks. The taskDL array contains the task relative deadline without any order (in the order as they are defined in the OIL file). The taskDL sorted array contains, through the java static method Arrays.sort(int[]), the task relative deadlines into ascending numerical order (the earliest one is the first
Chapter 3. Support for EDF scheduling for AVR tasks
element of the array, hence the last element of the array represent the lower priority task). In this way the priorities are represented by the position in the array. The outer for loop scans the taskDL array and the inner one scans backwards the sorted array, for finding the counterpart element and store the corresponding index j. This index is used to set the proper bit in the bitmask that represent the priority level value. The last instruction set the ISimpleGenResKeywords.TASK READY PRIORITY, an RT-Druid internal property. In this way the existing RT-Druid code, for creating the system data structures relative to the SRP protocol, can be reused.
Chapter 4
Simulation environment for
EDF-based RTOS in Lauterbach
Trace32
A simulation framework has been used for testing the kernel support devel- oped and for studying the execution of tasks under this kernel. The framework is based on the Lauterbach Trace32 PowerView IDE.
Such a IDE provides only the instruction set simulator, hence, the framework has been extended with two custom plugins to support the execution of both periodic and engine-triggered tasks with the proposed kernel for Erika.
• Free running timer, used by the EDF kernel to handle the time represen- tation in the system;
• Crankshaft simulator, used to generate interrupts related to the rotation of a crankshaft, hence generating the activation of the AVR tasks.
The Peripherals Simulation Model (PSM) allows to write a custom software that reacts and accesses to the microcontroller registers. Moreover, it provides functions for interacting with the simulated processor and other modules of the Trace32 simulator.
The custom plugins are developed in C language and compiled as dynamic linked libraries that can be loaded into Trace32 PowerView by using PRACTICE
Chapter 4. Simulation environment for EDF-based RTOS in Lauterbach Trace32
commands. Moreover two files, simul.c and simul.h, provided by Lauterbach, implement the API functions for communicating with the PSM.
4.1
Timer implementation
The free running timer module simulates a 32-bit timer available in the STM32F4 MCU, using the PSM interface for reacting to specific registers of the microcontroller that are used for configuring the timer and reading its value. The value of such a timer is the temporal reference for the kernel needed to define absolute tasks deadlines and it is configured with the resolution specified in the TICK TIME field in the OIL configuration file.
For the timer implementation, the first step was to define a struct for repre- senting the timer registers (Lst.4.1). The PSM provides a special variable type, called simulWord32, to represent a 32-bit memory area. In this way, the timer registers can be accessed as a simple variables.
# d e f i n e T I M E R 2 _ B A S E 0 x 4 0 0 0 0 0 0 0 # d e f i n e T I M E R 5 _ B A S E 0 x 4 0 0 0 0 C 0 0 # d e f i n e C R 1 _ O F F S E T 0 x00 # d e f i n e C N T _ O F F S E T 0 x24 # d e f i n e P S C _ O F F S E T 0 x28 # d e f i n e A R R _ O F F S E T 0 x2C t y p e d e f s t r u c t { s i m u l W o r d 3 2 CR1 ; /* A d d r e s s o f f s e t : 0 x00 */ s i m u l W o r d 3 2 CNT ; /* A d d r e s s o f f s e t : 0 x24 */ s i m u l W o r d 3 2 PSC ; /* A d d r e s s o f f s e t : 0 x28 */ s i m u l W o r d 3 2 ARR ; /* A d d r e s s o f f s e t : 0 x2C */ } T I M _ R e g i s t e r ;
Listing 4.1: Timer registers struct for library development.
The STM32F4 MCU provides two 32-bit timers and the struct definition is the same for both of them. The TIMER2 BASE and TIMER5 BASE macros represent the base address of each timer.
The Lst.4.2 defines a particular structure used for describing the timer proper- ties, in particular it is used for accessing to the timer registers. Moreover, the bustype, reset, work, intport and chport variables are used by the PSM
Chapter 4. Simulation environment for EDF-based RTOS in Lauterbach Trace32
to allow the communication between the modules; regs represents the timer register struct and the freqDivider represents the frequency divider. This last variable is needed because the update frequency of the timer is always less than processor frequency (also in case the timer prescaler value is set to zero).
t y p e d e f s t r u c t {
s i m u l W o r d 3 2 s t a r t a d d r e s s ;
int bustype , reset , work , intport , c h p o r t ; T I M _ R e g i s t e r r e g s ;
s i m u l T i m e c t i m e s t a m p ;
int f r e q D i v i d e r ;
v o i d * p t i m e r ; } T i m e r ;
Listing 4.2: Timer simulator properties.
When the dynamic linked library is loaded from the Trace32 PowerView, the PSM executes the SIMUL Init function. Such a function must be used to initial- ize the timer simulation structure and to register the callback functions for the timer registers. int S I M U L A P I S I M U L _ I n i t ( s i m u l P r o c e s s o r p r o c e s s o r , s i m u l C a l l b a c k S t r u c t * cbs ) { T i m e r * t i m e r ; int i ; c h a r t i m 5 [] = " t i m e r 5 "; s t r c p y ( cbs - > x . i n i t . m o d e l n a m e , _ _ D A T E _ _ " T i m e r M o d e l ") ; t i m e r = ( T i m e r *) S I M U L _ A l l o c ( p r o c e s s o r , s i z e o f( T i m e r ) ) ; timer - > f r e q D i v i d e r = 2; timer - > b u s t y p e = 0; timer - > i n t p o r t = -2; timer - > s t a r t a d d r e s s = T I M E R 2 _ B A S E ; if( cbs - > x . i n i t . a r g c == 2) { if( s t r c m p ( cbs - > x . i n i t . argp , t i m 5 ) == 0) timer - > s t a r t a d d r e s s = T I M E R 5 _ B A S E ; } R e g s _ I n i t ( p r o c e s s o r , t i m e r ) ; S I M U L _ R e g i s t e r R e s e t C a l l b a c k ( p r o c e s s o r , T I M E R _ R e s e t , ( s i m u l P t r ) t i m e r ) ; timer - > p t i m e r = S I M U L _ R e g i s t e r T i m e r C a l l b a c k ( p r o c e s s o r , I n t R e q T i m e r , ( s i m u l P t r ) t i m e r ) ; T I M E R _ R e s e t ( p r o c e s s o r , cbs , t i m e r ) ; S I M U L _ P r i n t f ( p r o c e s s o r , " % s \ n ", " T i m e r l i b r a r y l o a d e d ") ; r e t u r n S I M U L _ I N I T _ O K ;
Chapter 4. Simulation environment for EDF-based RTOS in Lauterbach Trace32
The initialization function (Lst.4.3) has two input parameters:
t y p e d e f s t r u c t { int t y p e ; s i m u l T i m e t i m e ; u n i o n { s i m u l P a r a m C a l l b a c k S t r u c t i n i t ; s i m u l P a r a m C a l l b a c k S t r u c t c o m m a n d ; s i m u l B u s C a l l b a c k S t r u c t bus ; s i m u l B u s C a l l b a c k S t r u c t 3 2 b u s 3 2 ; s i m u l B u s C a l l b a c k S t r u c t 6 4 b u s 6 4 ; s i m u l P o r t C a l l b a c k S t r u c t p o r t ; s i m u l P o r t C a l l b a c k S t r u c t 3 2 p o r t 3 2 ; s i m u l P o r t C a l l b a c k S t r u c t 6 4 p o r t 6 4 ; s i m u l T e r m i n a l C a l l b a c k S t r u c t t e r m i n a l ; } x ; } s i m u l C a l l b a c k S t r u c t ;
Listing 4.4: Simul callback structure definition.
• simulProcessor processor, that represents the simulated processor, it can be used to retrieve some information such as the clock frequency; • simulCallbackStruct * cbs that contains information about the simu-
lation (for instance the time elapsed from the beginning of the simulation) and information about the simulated system status, (Lst.4.4).
For instance the initialization function uses the simulCallbackStruct for setting the simulated model name. Moreover, the simulCallbackStruct con- tains a char array that store the potential parameters specified in the library load command. In this way the user can select the proper timer.
The Regs Init function is used to set the register callbacks. These callbacks are called when the simulator tries to access to memory address specified in the callback register function (Lst.4.5).
s t a t i c v o i d R e g s _ I n i t ( s i m u l P r o c e s s o r p r o c e s s o r , T i m e r * t i m e r ) {
s i m u l W o r d from , to ;
int i ;
Chapter 4. Simulation environment for EDF-based RTOS in Lauterbach Trace32
{
f r o m = timer - > s t a r t a d d r e s s + r e g s _ o f f s e t [ i ]; to = f r o m + 3;
S I M U L _ R e g i s t e r B u s W r i t e C a l l b a c k ( p r o c e s s o r , w r i t e F u n c [ i ] , ( s i m u l P t r ) timer , timer - > bustype , & from , & to ) ;
S I M U L _ R e g i s t e r B u s R e a d C a l l b a c k ( p r o c e s s o r , r e a d F u n c [ i ] , ( s i m u l P t r ) timer , timer - > bustype , & from , & to ) ;
} }
Listing 4.5: Register callback function example.
The callback functions take the memory addresses range as input arguments (the variable from and to), in this way the the plugin detects when the simulator tries to access in that range.
The writeFunc and readFunc arrays contain the functions for handling memory accesses (Lst.4.6).
s t a t i c int S I M U L A P I C N T _ R e a d ( s i m u l P r o c e s s o r p r o c e s s o r , s i m u l C a l l b a c k S t r u c t * cbs , s i m u l P t r p r i v a t e )
{
T i m e r * t i m e r = ( T i m e r *) p r i v a t e ;
S I M U L _ E x t r a c t W o r d ( p r o c e s s o r , & timer - > r e g s . CNT , 32 , & cbs - > x . bus . address , cbs - > x . bus . width , & cbs - > x . bus . d a t a ) ;
r e t u r n S I M U L _ M E M O R Y _ O K ; }
s t a t i c int S I M U L A P I C N T _ W r i t e ( s i m u l P r o c e s s o r p r o c e s s o r , s i m u l C a l l b a c k S t r u c t * cbs , s i m u l P t r p r i v a t e ) {
T i m e r * t i m e r = ( T i m e r *) p r i v a t e ;
S I M U L _ I n s e r t W o r d ( p r o c e s s o r , & timer - > r e g s . CNT , 32 , & cbs - > x . bus . address , cbs - > x . bus . width , & cbs - > x . bus . d a t a ) ;
r e t u r n S I M U L _ M E M O R Y _ O K ; }
Listing 4.6: Read and write register functions.
Lst.4.7 shows the core of the plugin. This function, called every clock cycle, implements the timer behavior. For testing the proposed kernel, only the free runner timer in up mode has been implemented.
int S I M U L A P I I n t R e q T i m e r ( s i m u l P r o c e s s o r p r o c e s s o r , s i m u l C a l l b a c k S t r u c t * cbs , s i m u l P t r p r i v a t e ) {
Chapter 4. Simulation environment for EDF-based RTOS in Lauterbach Trace32 T i m e r * t i m e r = ( T i m e r *) p r i v a t e ; s i m u l W o r d d a t a ; if ( d i v i d e r == timer - > f r e q D i v i d e r - 1) { if ( timer - > r e g s . CR1 & 0 x1 ) { timer - > r e g s . CNT ++; } } d i v i d e r = ( d i v i d e r + 1) % timer - > f r e q D i v i d e r ; r e t u r n S I M U L _ T I M E R _ O K ; }
Listing 4.7: Timer behavior implementation.
Before updating the counter value (timer->regs.CNT++;), the function checks if the timer has been activated by the software using the timer->regs.CR1 vari- able.