a data-centric event-oriented rtos for mcus

30
A data-centric event- oriented RTOS for MCUs Simplify multithreaded programming And Boost Performance by Dirk Braun

Upload: laban

Post on 16-Jan-2016

43 views

Category:

Documents


0 download

DESCRIPTION

A data-centric event-oriented RTOS for MCUs. Simplify multithreaded programming And Boost Performance. by Dirk Braun. The Concept of the Data-Centric RTOS 3 Ideas combined SW-Interrupts switch tasks – performance up, overhead down - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: A data-centric event-oriented RTOS for MCUs

A data-centric event-oriented RTOS for MCUs

Simplify multithreaded programming And Boost Performance

by Dirk Braun

Page 2: A data-centric event-oriented RTOS for MCUs

Contents

2. The DCEO-RTOS in practise• Example Application• Define Task-Groups, Mini-Tasks & Data Objects• Performance Measurements

1. The Concept of the Data-Centric RTOS3 Ideas combined• SW-Interrupts switch tasks – performance up, overhead down• Publisher-Subscriber Mechanism distributes data – easy & safe

data use in multithreaded environment• Design Task-Group Priorities – avoid need for synchronization

3. Summary & Outlook

Page 3: A data-centric event-oriented RTOS for MCUs

Goal 1: Fast Real Time Reaction

• Real-Time Reaction – objective: fast & deterministic

• Cause of a Reaction is an Event

• Event– change of state of connected HW– Time has elapsed– New: Data item has changed

Event

Reaction• Reaction– SW reaction– Ultimately – HW reaction

Page 4: A data-centric event-oriented RTOS for MCUs

Reaction & Task Switches• DCEO – RTOS directly uses the processors built in

way to React: the Interrupt– Processor status saved on interrupt entry automatically– Interrupt controllers priority management used– Mini-tasks (reactions) called directly from designated

ISRs. They are implemented by the application programmer and execute at interrupt priority.

– A „task switch“ involves backing up the current task. (copy processor state vars once)

– Only one stack - no stack management during task switch

• Benefits / costs– No. of save/restore cycles for processor status reduced– Task priority management done by HW (instead of software)– Number of separate priorities is limited by interrupt-hardware

Page 5: A data-centric event-oriented RTOS for MCUs

Goal 2: Reduce Programming Overhead – use SW Interrupts

Common Event-Reaction Implementation

1 main()2 {3 CreateTask(MyTask);4 ...5 while (TRUE);6 }78 MyTask()9 { // implements reaction10 while (TRUE)11 {12 WaitForEvent(&myEvent);13 // react to myEvent here14 // todo: sync access to g_input15 reaction = g_input * xxx16 };17 }1819 MyISR() __irq20 { // do some HW stuff to 21 // retrieve input22 // todo: sync access to g_input23 g_input = HW;24 SetEvent(&myEvent);25 }

Event-Reaction Implementation using SW-Interrupts

1 main()2 {3 // setup ISRs4 while (TRUE);5 }67 MyTask() __irq8 { // implements reaction9 // react to myEvent here10 reaction = g_input * xxx11 }1213 MyISR() __irq14 { // do some HW stuff to 15 // retrieve input16 g_input = HW;17 myTaskTrigger = 1;18 }

• No infinite loop• No “active” waiting• No synchronization

Page 6: A data-centric event-oriented RTOS for MCUs

Goal 3: Publisher-Subscriber Mechanism puts Focus on Data

• Data triggers itself through the application

• The changing of data itself is and replaces the event

ADC-ISR

Generic Scaler

Realize Output

Bus Network

DeviceReaction

raw AD value

scaled AD value

output

Display

Scaling range

DCEO-RTOS

Data-Publisher

safe data copy passed into callbacks

change data object

Subscriber 1 (callback function)at low priority

Subscriber n (callback function)at priority m

Publisher Subscriber engine

Page 7: A data-centric event-oriented RTOS for MCUs

Goal 4: Module Independency Increased by Data Centric View …

ADC-ISR

raw AD value

Check value

ADC Test App

ADC-ISR

Data Logger writes to file

raw AD value

scaled AD value

Generic Scaler

Scaling range

Data Logger Random Generator

Check scaling

raw value

scaled value

Generic Scaler

Scaling range

Scaler Test App

Ref. scaled value

Reuse Modules

Page 8: A data-centric event-oriented RTOS for MCUs

… by using simpler interfaces …

// adc.h

// ADC value, a WORD

extern DWORD obIdAdcVal;

void AdcInit();

void AdcConvStart();

Simple Interface

// adc.h

// ADC value, a WORD

WORD g_adcVal;

EVENT g_adcValAvailEvent;

MUTEX g_adcValAccMutex;

void AdcInit();

void AdcConvStart();

Interface using Data-Object

Interface using global data & event

Module independency easier to maintain

Page 9: A data-centric event-oriented RTOS for MCUs

… by avoiding global variables

// myCode.c

void UseVarValueFunction() {

MyType myVar;

myVar = GetVar();

}

void WriteVarValueFunction() {

MyType myVar;

...

SetVar(myVar);

}

„Avoid global variables in interfaces, i.e. header files. Provide access functions instead.“ (Rule for modular programming)

Separate get/set access functions for each variable

// myCode.c

void UseVarValueFunction() {

MyType myVar;

GetDataObject(&myVar, obIdMyVar);

}

void WriteVarValueFunction() {

MyType myVar;

...

SetDataObject(&myVar, obIdMyVar);

}

void OnMyVarChanged(BYTE* pData, …) {

MyType* pNewMyVar = pData;

...

}

Universal access function for all data-objects + notification

Instead of providing a separate set of access functions just publish a Data-Objects ID (a handle).

Page 10: A data-centric event-oriented RTOS for MCUs

Mutual Dependency -> non reusable code

One module cannot compile without the other

Module MyCode1

// myCode1.c

#include “myCode2.h”

WORD myVar1;

...

// myCode1.h

#include “myCode2.h”

Extern WORD myVar1;

...

Module MyCode2

// myCode2.c

WORD myVar2;

...

// myCode2.h

#include “myCode2.h”

Extern WORD myVar2;

...

modules cannot be reused without each other cannot be used in a layered model

#include “myCode2.h”

Page 11: A data-centric event-oriented RTOS for MCUs

Synchronization• Purpose

– Safety measure to avoid inconsistent data and possible crashes when two process threads interrupt each other at the wrong moment

• Unneccessary most often– This simultaneous occurence is unlikely and rare

• Costly– Entering and leaving synchronization objects involve function

calls and consume processor performance.– Causes expensive task-switches when really needed

• Multithreaded SW-development more difficult– Often difficult to identify the resources that require

synchronization

Page 12: A data-centric event-oriented RTOS for MCUs

low prio

high prio

Critical Section 1

Task 1 enters Mutex A Section 1

OS calls higher prio task 2

Process flow

Task 1

Task 2

Task 2 tries to enter Mutex A. This causes a priority inversion and Task 1 is resumed at HIGH priority.

inactive Task running Task suspended Task

Task 1 leaves Mutex A and is suspended to low priority again. Task 2 is resumed.

Task 2 leaves Mutex A

Task 2 finished

Task 1 finished

spare processor time ;-)

1

2

3 4

5

Mutexes rarely cause task switches

void Task1() {

// do something

EnterMutex(g_mutexA);

// use shared resource

.

.

.

.

LeaveMutex(g_mutexA);

.

.

// do something

}

void Task2() {

// do something

EnterMutex(g_mutexA);

// use shared resource

LeaveMutex(g_mutexA);

}

suspended

suspended

1

2

3

4

5

suspended

Page 13: A data-centric event-oriented RTOS for MCUs

Supersede the need for Synchronization

• Idea– Tasks with same priority cannot interrupt each other -> so

they cannot execute concurrently– Other tasks at higher priority still pre-empt lower priority tasks

• Realization:– Timed-Mini-Tasks and Event-Mini-Tasks (Subscribers)

grouped into Task-Groups. – A Task-Group has a single priority for all of its mini-tasks.

Page 14: A data-centric event-oriented RTOS for MCUs

Tasks at same priority

Three tasks „Generic Scaler“ „Device Reaction“ and „Realize Output“ are subscriber mini-tasks of one task-group at a single priority.

ADC-ISR Generic

Scaler

Realize Output

Bus Network

DeviceReaction

raw AD value

scaled AD value

output

Display

Scaling range

LowPrio

MedPrio

HighPrioHWIRQ

ADC-ISR

Generic Scaler

Realize Output

Bus Network

DeviceReaction

Display

ADC-ISR

Generic Scaler

Realize Output

Bus Network

DeviceReaction

Displaycontinued

Display pre-empted

Time

Page 15: A data-centric event-oriented RTOS for MCUs

Low Prio

Software - Interrupt

Publisher – Subscriber•Manages Data-Objects and subcriber mini-tasks•Subscribers invoked when data-of-interest changed

Time – Engine

•Timed mini-task invoked when time has come

•Cyclic and one-time (time out) timed tasks supported

Med Prio

Software - Interrupt

Publisher – Subscriber•Manages Data-Objects and subcriber mini-tasks•Subscribers invoked when data-of-interest changed

Time – Engine

•Timed mini-task invoked when time has come

•Cyclic and one-time (time out) timed tasks supported

Timed & Subscriber Mini-Tasks

• Multiple Timer Reactions and multiple Data Event Reactions can share the same priority.

• All mini-tasks are called from Interrupt Service Routines, run at predefined priorities and use the processors preemptive interrupt logic.

High Prio

Software - Interrupt

Publisher – Subscriber•Manages Data-Objects and subcriber mini-tasks•Subscribers invoked when data-of-interest changed

Time – Engine

•Timed mini-task invoked when time has come

•Cyclic and one-time (time out) timed tasks supported

Page 16: A data-centric event-oriented RTOS for MCUs

End of Theory

Page 17: A data-centric event-oriented RTOS for MCUs

Example Application

Objective: Create an analog-to-frequency converter with user-interface. This involves

• doing cyclic AD-conversions with an adjustable cycle period to be set via user-interface (RS232 command)

• setting the output frequency depending on the current analogue input

• reporting AD-values via RS232 (which represents the user interface)

• implementing a simple clock to report time to RS232

Todo’s:• Design modules, their relations, interfaces, data-objects• Plan Tasks – timed and subscriber mini-tasks• Identify Synchronization Requirements – Group mini-tasks into

task-groups

Page 18: A data-centric event-oriented RTOS for MCUs

Modules

ADC

ADC• Function for triggering conversions

• Provide Data-Object for conversion result

// adc.h

// ADC value, a WORD

extern DWORD obIdAdcVal;

void AdcInit();

void AdcConvStart();

Description Interface Module

AscString

AscString• Send complete strings via RS232

using function call

• Provide Data-Object for new received string

• Provide Data-Object for event when string-sending has completed

// ascString.h

extern DWORD obIdRecvString;

extern DWORD obIdSentString;

void AscStrInit(DWORD gapTime, char endChar);

BOOL AscStrSend(BYTE* pSendString, WORD len);

MainMain application• React on new AD values

• Set Output Reaction

• React to UI

• Time Output

Empty

Page 19: A data-centric event-oriented RTOS for MCUs

More Modules

ASC

ASC• Byte-wise RS232 communication

// adc.h

void AscInit(DWORD baudrate);

void AscSendByte(BYTE sendByte);

// register callbacks

BOOL AscSetRxCallBack(

AscRXCbPtr pRxCallback);

BOOL AscSetTxCallBack(

AscTXCbPtr pTxCallback);

Description Interface Module

CmdInterpreter

CmdInterpreter (helper module)• Provides functions to interpret

commands in a string

// CmdInterpreter.h

typedef enum CmdCodeEnum { CmdHelp, // general CmdPeriod, CmdCodeInvalid, CmdNull } CmdCode;

CmdCode CiGetCommand(char* cmdString, int len);

FrequencyOutput

FrequencyOutput• HW-Output for frequency

• Provide Data-Object for frequency

// freqOut.h

// frequency, a WORD

extern DWORD obIdFrequency;

void FreqOutInit();

Page 20: A data-centric event-oriented RTOS for MCUs

Module Relations & Data Objects

Data Objects:

HW-Abstraction Layer

HW-Logic Layer

Application Layer

ASC

CmdInterpreter

FrequencyOut

ADC

AscString

Main

Function call Call Callback Data Notification

DCEO -RTOS

Timer0

• AD value • passing from ADC to scaling (Main)• passing from ADC to RS232

• AscStrRX• received command via RS232

• Frequency Out• passing from scaling (Main) to Frequency Out

Page 21: A data-centric event-oriented RTOS for MCUs

Task Groups & Priorities

• Task-group-priorities ARE interrupt-priorities, so task-group-priorities & interrupt-priorities belong into the same priority list

Cyclic Mini-Task Triggering

Conversions

ADC ISRSet Data Object

ReactionRealizing Output

Write to UI

ASC ISR

Cyclic Mini-Task incrementing

& writing clock

ASCBuffer &Control

Sync required

• Data-objects are safely shared across priority-boundaries

• Priority plan identifies synchronization requirements

High Priority Task Group

Medium Priority Task Group

Low PriorityTask Group

ADC InterruptPriority

ASC (UART)Interrupt Priority

Page 22: A data-centric event-oriented RTOS for MCUs

Setup - codeDefining Priorities

int main (void) {

...

Task_Init(); // init DCEO-RTOS

AscInit(115200); // init ASC

AscStrInit(0, '\r'); // init AscString

AdcInit(); // init ADC

// enter callbacks for task-group prioss

DataAddNotifyCB(OnAdValChangedHigh,

obIdAdcVal, 0);

TaskT_CallBackCyclicAt(30,

OnCyclicAdcConvTimer, 1, 1);

DataAddNotifyCB(OnRxStrRecv,

obIdRecvString, 2);

DataAddNotifyCB(OnAdValChangedLow,

obIdAdcVal, 2);

INTERRUPT_ENABLE()

while (TRUE);

}

Setting up Mini-Tasks// priorities.h

// define your Task Groups Priorities here

const TaskGroup g_taskGroups[] = {

// ilvl vicChannel

{ 7, 25}, // high (0)

{ 11, 26}, // medium (1)

{ 14, 28} // low (2)

};

// define your own interrupts here

ILVL VIC channel

#define ADC_ILVL 8

#define ADC_CHANNEL 18

 

#define ASC_ILVL 12

#define ASC_CHANNEL 7

 

#define TASK_T_ILVL 4

#define TASK_T_CHANNEL 5

Interrupt levels & task priorities shown in red Mini-Task creation shown in red

Page 23: A data-centric event-oriented RTOS for MCUs

Implementing Module ADCInterface // implementation continued

void AdcConversionStart()

{ // trigger conversion

AD0CR |= 0x01200000;

}

void adcIsr (void) __irq

{ // ISR, pick up conversion result & set

// data object

WORD adVal;

// ARM7 specific, re-enable interrupts, so higher priority IRQ get through again

IENABLE

// Read A/D Data Register

adVal = (AD0DR & 0xffc0) >> 6;

...

if (adVal != g_lastAdVal)

{

DataSetObject((BYTE*)&adVal,

sizeof(adVal), obIdAdcVal);

g_lastAdVal = adVal;

}

IDISABLE

// Acknowledge Interrupt

VICVectAddr = 0;

}

Implementation

// adc.h

// ad converted value, a WORD, OUT

extern DWORD obIdAdcVal;

void AdcInit();

void AdcConversionStart();

// adc.c

DWORD obIdAdcVal;

void adcIsr (void) __irq ;

WORD g_lastAdVal;

void AdcInit()

{ // set up HW

...

IsrCreate((unsigned long)adcIsr, ADC_ILVL, ADC_CHANNEL);

obIdAdcVal =

DataCreateObject(sizeof(g_lastAdVal));

g_lastAdVal = 0;

DataSetObject((BYTE*)&g_lastAdVal, sizeof(g_lastAdVal), obIdAdcVal);

}

Page 24: A data-centric event-oriented RTOS for MCUs

Implementing Module ascStringInterface void ascStr_OnRxRecv(BYTE recvByte)

{ // byte received callback from lower layer

... Add byte to buffer

// set timeout if not set yet

if (ascOnTimeoutId != (DWORD)NULL)

// modify timeout time to NOW +

allowed gaptime

TaskT_ChangeCallbackTime(TaskT_Now()

+ g_ascStrMaxRecvInterByteGapTime,

ascOnTimeoutId, 1);

else

{ // first byte of new string coming in

// set timeout to now + max. gaptime

ascOnTimeoutId = TaskT_CallBackAt(

TaskT_Now() +

g_ascStrMaxRecvInterByteGapTime,

ascStr_OnRxComplete, 1, 1);

}

...

}

// timeout mini-task

void ascStr_OnRxComplete() //

{ // set data object with received string

DataSetObject((BYTE*)&g_ascStrRecvStr,

sizeof(g_ascStrRecvStr), obIdRecvString);

...

}

Implementation

// ascString.h - excerpt of

// Reception of a string is complete when the

// gapTime between two bytes has expired

extern DWORD obIdRecvString;

...

void AscStrInit(DWORD gapTime, char endChar);

BOOL AscStrSend(BYTE* pSendString, WORD len);

// ascString.c

// ringbuffer containing received bytes

DWORD g_ascStrMaxRecvInterByteGapTime;

// max. time allowed between any two bytes

DWORD obIdRecvString;

...

RecvStr g_ascStrRecvStr;

// forward declaration of callbacks

void ascStr_OnRxRecv(BYTE recvByte);

void ascStr_OnRxComplete(int);

Page 25: A data-centric event-oriented RTOS for MCUs

Implementing Module FreqOutInterface

Implementation

// freqOut.h

extern DWORD obIdFrequency;

void FreqOutInit();

//freqOut.c

// includes

DWORD obIdFrequency; // Data Object ID

WORD g_foHalfPeriod; // in 100 us

DWORD g_foTaskId;

// forward declaration of mini-tasks

void OnFreqChanged(BYTE* pData, DWORD objectId);

void OnFreqOutHalfPeriod(int timerVal);

void FreqOutInit() {

WORD freq;

obIdFrequency = DataCreateObject(sizeof(freq));

freq = 1; // initialized to 1 Hz

DataSetObject((BYTE*)&freq, sizeof(freq), obIdFrequency);

g_foHalfPeriod = 10000 / freq / 2;

DataAddNotifyCB(OnFreqChanged, obIdFrequency, 0);

g_foTaskId = TaskT_CallBackCyclicAt(g_foHalfPeriod, OnFreqOutHalfPeriod, 0, 0);

}

// Subcriber mini-task

void OnFreqChanged(BYTE* pData, DWORD objectId) {

// calculate half period

g_foHalfPeriod = 10000 / (*(WORD*)pData) / 2;

TaskT_ChangeCallbackTime(g_foHalfPeriod, g_foTaskId, 0);

}

// timed mini-task

void OnFreqOutHalfPeriod(int unusedInt){

unusedInt = 0;

LED_TOGGLE(1)

}

Page 26: A data-centric event-oriented RTOS for MCUs

Implement Subscribers & Reaction in Main Module

Initialization Task - Implementation// forward declaration of mini-tasks

void OnCyclicAdcConvTimer(int i);

void OnAdValChangedHigh(BYTE* pData, DWORD objectId);

void OnAdValChangedLow(BYTE* pData, DWORD objectId);

void OnRxStrRecv(BYTE* pData, DWORD objectId);

int main (void) {

...

Task_Init(); // init DCEO-RTOS

AscInit(115200); // init modules

AscStrInit(0, '\r');

AdcInit();

FreqOutInit();

// create mini-tasks

DataAddNotifyCB(OnAdValChangedHigh, obIdAdcVal, 0);

TaskT_CallBackCyclicAt(300, OnCyclicAdcConvTimer,

1, 1);

DataAddNotifyCB(OnRxStrRecv, obIdRecvString, 2);

DataAddNotifyCB(OnAdValChangedLow, obIdAdcVal, 2);

...

while (TRUE) { } // loop forever

}

void OnCyclicAdcConvTimer(int i){

// start AD-conversion

AdcConversionStart();

}

void OnAdValChangedHigh(BYTE* pData, DWORD objectId){

...

UpdateVar(pData, objectId, obIdAdcVal, (BYTE*)&adcValue, sizeof(adcValue));

outFreq = algorythm(adcValue)

if (outFreq != g_freq) {

g_freq = outFreq;

DataSetObject((BYTE*)&g_freq,

sizeof(g_freq), obIdFrequency);

}

}

void OnAdValChangedLow(BYTE* pData, DWORD objectId) {

...

UpdateVar(pData, objectId, obIdAdcVal,

(BYTE*)&adcValue, sizeof(adcValue));

sprintf(adValStr, "AD Val = %04d\r\n", adcValue);

AscStrSend(adValStr, strlen(adValStr));

}

void OnRxStrRecv(BYTE* pData, DWORD objectId)

...

Page 27: A data-centric event-oriented RTOS for MCUs

Performance Measurement1 - toggles with 22 - trigger AD conversion3 - ADC ISR (start – end)4 - High prio reaction

(intercepts ISR)5 - Low prio report to UI6 - 3 minus 47 - time base 100µs8 - not idle

Reaction Times (for ARM7 60MHz)• Timed mini-task < 8 s

(time-base-tick to start of mini-task including context switch, 7 low to 2 high)

• Subscriber mini-task < 16 s (set data object to invocation of subscriber including context switch, 6 high (1st) to 6 low (1st)

• Total reaction time > 20 s (external HW-event to external HW-reaction)

Page 28: A data-centric event-oriented RTOS for MCUs

SummaryMain differences between traditional RTOS and

DCEO-RTOS

• Stop thinking in terms of processes -> Start thinking about Data, Events and Reactions

• Gain flexibility – use data from all priority mini-tasks without worrying about synchronization

• Gain performance – use 100% processor time and still have a deterministic reaction of higher priority tasks. Use processors interrupt priorization.

Page 29: A data-centric event-oriented RTOS for MCUs

Process vs. Data Centric ViewProcess Oriented Data Centric

Central Element Tasks Data Objects & Timers

Reaction implemened by

RTOS involving task switch

HW Interrupt Controller schedules reaction which executes in uses SW ISRs

Synchronization Involves saving / resumption of task status

Not required due to proper design of task-groups.

Programmers job Create producer-tasks and consumer-tasks of events

Design Data-flow, create modules

Inter-Module-Dependancy

Easily becomes high More easy to keep low

Independant Module reusability

Easily becomes low More easy to keep high

Project Fexibility Coded Run-time configurable Data-flow

Page 30: A data-centric event-oriented RTOS for MCUs

Outlook & Ideas• DCEO-RTOS is well suited for

– Embedded Software Development– Multi-Core Support -> assign a task-group to a core, only means

of communication is through data-objects– Distributed Computing -> many nodes of a network react to

global data-ojects using a real time communication network

• Next development steps of DCEO-RTOS will address – Support more processors (currently ARM7)– Bus-Interfaces (with HW-abstraction layer)– UML-Tool Integration

• Idea– Development-Tool for easy linking of data-objects to UI-controls

ContactEmail [email protected] rtosdeveloperWeb cleversoftware.de