420 likes | 729 Views
dr. Stefan Dulman Embedded Software Group. Embedded Software. TI2720-C. 5 . Embedded software design. Previous lecture overview. RTOSes Task/context switching Reentrancy Usage of semaphores. Code example.
E N D
dr. Stefan Dulman Embedded Software Group Embedded Software TI2720-C 5. Embedded software design
Previous lecture overview • RTOSes • Task/context switching • Reentrancy • Usage of semaphores
Code example Given the following RTOS (pseudo)code with priority of task T1>priority of task T2: void T1(void){ while(1){ OS_Pend(sem1); // event #1 may unblock any time f(1); delay(10); }} void T2(void){ while(1){ OS_Pend(sem2); // event #2 may unblock any time f(‐1); delay(30); } } void f(inti){ OS_Pend(mutex); counter=counter+i; // modify some global counter OS_Post(mutex); }
Question 1 • Which of the following statements is NOT correct? a) Shared data problem occurs between T1, T2 due to the function f() b) function f() is reentrant c) priority inversion does not occur in this case d) there is no data sharing problem
Question 2 • Which statement is correct? For the program to work correctly, the “mutex” variable needs to be initialized with... a) 0 b) 1 c) none of the above d) any value will work
Question 3 • The order of events is #1,#1,#2,#2,#1; they occur within 10ms from each other. Which of the following is true? a) the final value of the counter will be decreased by 1 b) the final value of the counter will be the same c) the final value of the counter will be increased by 1 d) the final value of the counter will be undefined
Code example • Given the following RTOS (pseudo)code(priority of Task1 is greater than priority of Task2): void isr_buttons(void){ if (!!Buttonsreleased) {}; //donothing if (!!Buttonspressed) OS_Post(sem); // signal the tasks that a button has been pressed } void Task1(void){ while (TRUE){ OS_Pend(sem); // wait for event random_delay(); OS_Post(sem); // produce the event } } void Task2(void){ while (TRUE){ OS_Pend(sem); // wait for event random_delay(); } }
Question • In the case in which the user presses (and immediately releases) the button twice, which of the following statements is true? (the button is considered debounced)a) the “random_delay()” function is executed four timesb) the “random_delay();” line in Task1 is always executed twice c) the “random_delay()” function is executed an infinity of times d) the behavior of this code cannot be predicted
Overview • Timing services • RTOS and ISRs • Design of embedded systems • General principles
Timing Functionality • Basic requirement of an embedded RTOS • Suspend task for some time (vs. busy wait) • Produce a result at a certain time • Timeout (wait for an acknowledgement for some time) • X32: delay(dt) • busy waits (loops) until X32 clock has advanced dt ms (“polling”) • RTOS: OSTimeDly(n) • suspends caller (task) until time has advanced n OS ticks (“interrupt”) !! set a timer variable to x ticks;!! decrement each tick; !! if zero move task to ready
delay() /*--------------------------------------------- * delay -- busy-wait for ms milliseconds *-------------------------------------------*/ void delay(int ms) { int time = X32_clock; while(X32_clock - time < ms) {}; }
OSTimeDly(3) OSTimeDly(3) time Time Delay Functionality • OSTimeDly() is more efficient than delay() • schedules other tasks (does useful work) while waiting for time to pass • OS needs a timer interrupt mechanism to periodically check time • NOTE: without OS, context switching is initiated by task calls=> no timer interrupts are needed • Timer interrupt => tick => delay resolution (and OS overhead) • Timeouts in semaphores, etc. • Blocking with WAIT_FOREVER is simple! • Blocking for X timer ticks is more difficult • Accuracy of a tick:
OS Delay Processing highest priority task starts first context switch timer ISR RTOS Task 1 Task 2 timer IRQ tick tick OS_Delay(2) delay expired
Questions • Is the parameter of OSTimeDly() given in ms? • How accurate is the result of OSTimeDly()? • How does the RTOS know how to setup the timer HW? • What is normal length of a system tick? • What if I need very accurate timing?
X32: Demo • Demo .. ucos_delay.c
Overview • Timing services • RTOS and ISRs • Design of embedded systems • General principles
RTOS and Interrupts • RTOS and interrupts are two separate worlds • Exception are timers -> OS delays • Embedded programs use interrupts to react to events(buttons, I/O lines, UART, decoder, ..) • Interrupts and RTOS = trouble! • Rule 1: No blocking • Rule 2: No RTOS calls without a fair warning
RTOS and Interrupts • Rule 1: • an ISR must not call any RTOS function that might block the caller • no pend-type calls • no semaphores to protect shared data in ISRs • no reading queues, etc … in ISR • Violating this rule may affect response time and may even cause deadlock!
ISR Deadlock! Example Violating Rule 1 void isr_read_temps(void) // (reactor) { OS_Pend(s); iTemp[0] = peripherals[..]; iTemp[1] = peripherals[..]; OS_Post(s); } void main(void) { ... OS_Pend(s); iTemp[0] = iTemperatures[0]; iTemp[1] = iTemperatures[1]; OS_Post(s); ... } interrupt
Helping tools for rule 1 • System calls that do not block • Examples: • Function giving the status of a semaphore • Queues: use post() in ISR, use pend() in task code • If queue is full, error is returned in ISR -> nonblocking • Task code might miss a number of elements • This code works only if rule #2 is obeyed
RTOS and Interrupts • Rule 2: • An ISR must not call any RTOS function that might cause a context switch unless RTOS knows that it’s an ISR (and not a task) that is calling • no post()-type calls (which is typical use!) unless RTOS knows it’s an ISR • No semaphore release events • No writing to a queue, etc … • Violate this rule! • RTOS will switch to other task • ISR may not complete for a long time • No guarantees on response time anymore
Example Violating Rule 2 void isr_buttons(void) // (UTMS) { if (peripherals[BUTTONS] & 0x01) // button 0 OS_Post(event); // signal event } void vButtonTask(void) { while (TRUE) { OS_Pend(event); // wait for event printf(“current float levels: \n”); !! list them } } Context switch may block all lower priority ISRs
context switch after ISR finished context switch before ISR finished! Example Violating Rule 2 How ISRs should work: button ISR RTOS vButtonTask vLevelsTask OS_Post What would really happen: button ISR RTOS vButtonTask vLevelsTask OS_Post
Solution to Satisfy Rule 2 (uC/OS) • Let the RTOS know an ISR is in progress by calling OSIntEnter()/OSIntExit() (uC/OS) void isr_buttons(void) // (UTMS) { OSIntEnter(); // warn uC/OS not to reschedule if (peripherals[BUTTONS] & 0x01) // button 0 OS_Post(event); // signal event OSIntExit(); // uC/OS free to reschedule } button ISR RTOS vButtonTask vLevelsTask OS_Post but NO context switch
Alternative solution • Specialized functions for ISR • Instead of OS_Post() use OS_ISR_Post() • … • Not all OSes provide these alternatives
X32: Demo • Demo .. ucos_isr.c
Overview • Timing services • RTOS and ISRs • Design of embedded systems • General principles
Overview • Design of an embedded system • Specify the real-time system can be very difficult • What must the system do? • How fast should the system serve the inputs? • Example: bar-code scanner • It must send the data to the terminal within reasonable time (fraction of a second – one second) • 100% guarantee can be hard • A longer delay in a small amount of cases can be tolerated • Choosing the right processor • Example: serial port interface • can we run ISR 1000 times a second? • Should we go for a processor with DMA support?
Principles – general operation • System is in “sleep” state most of the time • Tasks are in the blocked state waiting for events • Processor may be in a low-power mode • ISR are active • External event triggers ISR that trigger a whole series of tasks to start running • When processing is done, system goes back to sleep • Example: telegraph system
Principles – short ISRs • Short ISRs are preferred over long ISRs • Lowest-priority ISR runs before highest-priority task • Longer ISR -> slower task response time • ISRs exhibit more bugs/nr. lines of code • ISRs are harder to debug • Example: serial port communication • System responds to commands coming from serial port • Commands always end up with “\n” • Commands arrive one at a time, after completion of prev. • Serial port has a buffer of one character • System can take a long time to respond to commands
Trade-off designs • Everything in the ISR • Provides excellent response time for the serial port block • System response for other tasks is disaster • ISR for each event – individual tasks for each event • “perfect architecture” • Will trigger a very low output from the processor • A lot of time spent by RTOS in context switching • Possible solution?
Principles – how many tasks? • Advantages of many tasks • More tasks -> usage of priority -> faster system response • 1 task versus 8 tasks • Modularity • A task for each: the display, printer, buttons, etc. • More tasks -> better data encapsulation • Network task – the only one that needs to access the HW signals
Principles – how many tasks? • Disadvantages of many tasks • More tasks = more shared data = more semaphores • More semaphore bugs and RTOS overhead • More tasks = more data passed around in queues, pipes, … • More bugs and more RTOS overhead • Each task has a stack -> more memory needed • General throughput smaller in a system with more tasks
Example of time constants • RTOS on 20MHz Intel 80386 • Get a semaphore – 10 microsec. • Release a semaphore – 6-38 microsec. • Switch tasks – 17-35 microsec. • Write to a queue – 49-68 microsec. • Read from a queue – 12-38 microsec. • Create a task – 158 microsec. • Destroy a task – 36-57 microsec.
Principles – tasks = encapsulation Paper handling task “Paper jam” “Out of paper” Display high-level task “Copies = 1” “Form = 66 lines” Button handling task HW display task Display
Principles – task structure !! private static data declared here void mytask(void) { !! More private data declared here !! either static either on the stack !! Initialization code here while(1) { !! wait for signal event switch(!! type of signal) { case !! signal type 1: ... break; case !! signal type 2: ... break; ... }; } } mytask.c
Create/destroy tasks • Most RTOS allow dynamic tasks – dynamic create/destroy • Avoid this functionality • Lengthy operation – throughput is minimized • Task destruction is dangerous • Task owns a semaphore? • Messages on the task input queues? • What if these messages contain pointers to data that needed to be deleted by other tasks? • Alternative: create all the dynamic tasks at the startup • If memory is not an issue – do not destroy the task!
Time slicing? • Tasks with same priority -> one options is to “time slice” • Round-robin scheduling • Time slice used a lot in desktops -> “fairness” • Embedded systems -> “timely response”! • Responses of all tasks with the same priority is needed • Avoid time slicing • Avoid having the same priority for two tasks
Restrict use of RTOS!!! • If you need to use an RTOS use it, but… • Restrict the functionality you are making use of! • Example: use pipes and one queue • If queue can be emulated through pipes easily, use one more pipe • You will not include the code for the queues • Smaller system • More memory for something else • Hopefully less bugs
Summary • Timing services • RTOS and ISRs • Design of embedded systems • General principles