Upload
loren-lawrence
View
216
Download
0
Embed Size (px)
DESCRIPTION
Task Loop Coding Issues Some tasks are periodic Should be run every k milliseconds Some tasks are sporadic Run when needed, not other times Tasks don’t know about other tasks Timing demands for example Tasks need to communicate Tasks have different priorities
Citation preview
CSCI1600: Embedded and Real Time SoftwareLecture 15: Advanced Programming ConceptsSteven Reiss, Fall 2015
Task Loop Tasks are modeled as automata Code consists of executing each task periodically What is the main loop
void loop() {task1();task2();taskn();
}
What are the problems
Task Loop Coding Issues Some tasks are periodic
Should be run every k milliseconds Some tasks are sporadic
Run when needed, not other times Tasks don’t know about other tasks
Timing demands for example Tasks need to communicate Tasks have different priorities
Example
Suppose we have 3 tasks One should be run every 6 ms One should be run every 10 ms One should be run when a flag is set
Timed Task Loop
long last_time = 0;int cycle_counter = 0;boolean run_task = false;const int PERIOD = 2000;
void loop() {long time = micros();if ((time – last_time) >= PERIOD) {
last_time = time;cycle_counter = (cycle_counter+1)%15;if (cycle_counter%3 == 0) taskA();if (cycle_counter%5 == 0) taskB();
}if (run_task) taskC();
}
Other Alternatives Wait at the end for next cycle to begin Use a (priority) queue of tasks to run
Tasks can be added/removed from queue Main loop
Pop top task off queue, execute it Task can add itself back to queue if periodic
Priority can be when the task needs to be run This looks a lot like scheduling
Coding a Task Given a FSA model, what should the code do The code should be designed to be quick
State actions should never wait The code should take the next step, no more
Any actions it does should be fast Setting output, reading input, setting flags
It shouldn’t do any waiting Long computations should be broken up
Coding a Taskenum State { S1, S2, … Sn }State cur_state = S1;void taskA() {
switch (cur_state) { case S1 :
// check for transitions, set cur_state if so// also, do any action associated with transition
case S2 : …
}switch (cur_state) {
case S1 :// Do any action associated with state
}}
Coding Timing Information Suppose a state has a timeout transition
How should this be coded Example: beep for 5 seconds
What’s wrong here:Turn on tone()wait(5000)Turn off tone()go to next state
Coding a Timer Transition
Keep track of time of state entry Static variable (global or static for function)
Set to current time when entering a state with a timeout Or to timeout time
Code for the state checks if current time>last_time+TO If so, it transitions to the next state
Coding a Timer Transition
If task is periodic with fixed period Runs every 10 ms for example Use the task timing in place of the real clock
Can model the delay as a set of interim states Or just have a counter of the number of runs since you
entered the current state
Light Array Task
What should this task look like? What is the appropriate model?
Floating Point Problem: computations sometimes need real numbers
Floating point is slow Integers aren’t accurate enough
Solution Use fixed point arithmetic Essentially scaled integers
Fixed Point Suppose we want to add 10.234 + 5.1
We could use integers scaled by 10^3 Add 10234 + 5100 = 15334 === 15.334
Multiplying is slightly more complex Mutliply 10234 * 5100 = 52193400 Divide by 10^3 = 52193.400 = 52193 === 52.193
Actually want to round (52193400+500) / 1000 What do you do for division?
Fixed Point Arithmetic Suppose we want to divide 10.234 / 5.1
Multiple 10234 * 10^3 = 10234000 Divide by 5100 = 2006 with remainder 3400
3400 > 5100/2 so set result to 2007 === 2.007 Can also multiply by 10^4 to get more accuracy and scale back Can also take (10234*10^3 + 5100/2)/5100
Computers don’t do this with powers of 10 Why not? Do it with powers of two (eg 8 bit fraction, 24 bit int)
Simplifying Computations Embedded systems deal with limited domain
We can use this to simplify coding Suppose we know angle to a degree
Want to compute next position in x,y coordinates This requires sin/cos computation
How to compute sin and cos These require multiple floating point computations Taylor series approximation
Look Up Tables Instead of computing it as needed, precompute it
We only need it for 90 values (0..90) Set up a table sin_data[90] with the result for each degree sin and cos then can be done with table lookup
cos(X) = sin(X+90) sin(X+90) = 1-sin(X-90) sin(X+180) = -sin(X) …
This can often be used for complex computations
Look up Tables
How could you use look up tables in tic-tac-toe?
Tasks Need to Communicate Simple communication is one-way
Task A decides what lights should be on Task B just displays what it is told
Global variable Written only by task A Read by task B
This is safe as long as there is only one writer Why care about multiple writers?
Problem to Consider Keypad for entering alarm code
Task to read the keypad Determine when a button has been pushed
Want to check a sequence of button presses against known code(s) Task that does the checking
How do these communicate?
Making Communication Simple
Handshake Communication The previous depended on timing to some extent What should we do when tasks need to synchronize
Task A sends a request to Task B Task A needs to know when Task B is done
In order to send another request Ensure no new button is pressed until current one is processed
Can use 2 variables rather than one Task A owns variable REQ Task B owns variable ACK
Handshake Communication Code
A: set REQ, wait for ACK, clear REQ, wait for ~ACK B: wait for REQ, do action, set ACK, wait for ~REQ, clear ACK
Sequence A: set REQ B: wait for REQ, do action, set ACK A: wait for ACK, clear REQ, wait for ~ACK B: wait for ~REQ, clear ACK
Communicating Arduinos
Suppose you want to have two Arduinos talk to each other Just simple message back and forth (sequence of bits)
How would you do this?
Communication: Queues
More complex communication involves multiple requests Model railroad: multiple switches can be triggered
But only one can be activated at a time This is generally implemented as a queue
Allows the two tasks to be asynchronous
Queue-based Tasks
Queue Implementation
Queues in embedded programs Are generally fixed in size Often sized so they never overflow
How to program a queue?
Simple Queue byte queue[10]; int qp = 0; void push(byte x) [ TASK A ]
if qp < 10, then queue[qp++] = x else exception
byte pop() [ TASK B ] if (qp == 0) exception rslt = queue[0]; for (i = 1; i < qp; ++i) queue[i-1] = queue[i] qp = qp-1 return rslt
What’s wrong with this?
Circular Buffer Queue Use a single array
Maintain a start and end pointer Treat the array as a circular buffer
Element beyond the last is the first, etc. Maintain two pointers
Head (read): pointer to the first element to extract Tail (write): pointer to the next place to insert
Circular Buffer
Pop: if read == write then exception result = buf[read]; read = (read + 1) % size
Circular Buffer
Push(data): If read == write then exception buf[write] = data write = (write + 1)%size
Circular Buffer Advantages
Little data movement Pointers are only changed by one task Queue cells are safely read/written Code is simpler
Extensions Can read/write multiple things at once Data stream or communications channel
Circular Buffers and Handshakes
What happens with a circular buffer of size one?
Homework
Read Chapter 10