Embedded Systems_L9(OS1&Ring_buffers)

advertisement
Embedded Systems
Lecture 9: Operating Systems,
buffered i/o
Ian McCrum
Room 5B18, Tel: 90 366364 voice mail on 6th ring
Email: IJ.McCrum@Ulster.ac.uk Web site: http://www.eej.ulst.ac.uk
www.eej.ulster.ac.uk/~ian/modules/EEE527/files
Operating Systems
In a conventional PC, an Operating systems allows easy
access to the resources of the computer
•
•
•
•
•
•
•
Disk drives, Optical, magnetic and solidstate (e.g SD)
Printers,
Serial ports, USB and RS232
Ethernet/WifI interfaces,
Sound generations and playback,
Screens and keyboard.
Memory
In a modern windowing environment it manages access to
the screen, allows multiple programs to run at once,
including hidden programs running in the background
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE527/files
2
Embedded Operating Systems
Again, it manages the resources of the (micro)computer;
memory. i/o and CPU access.
• Task & Resource management
• When you execute a program the OS creates a task
• A task can not “hog” a resource (memory/serial
port/timer)
• Normally we consider multi-tasking but even single
tasking systems can use an OS – e.g
– to manage memory (malloc() and free() )
– To abstract hardware, (printf or a network socket connection)
– This offers portability, we would not want to write a malloc
function for every system that could run our code.
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE527/files
3
Multitasking
• Gives the appearance of doing two (or more) things at once
• A simple example would use interrupts and have a “main”
program and a “interrupt routine”
• A more managed system might have a timer interrupt only and
give each task a 20 millisecond slice of time. (c.f co-routines)
– Wasteful if a task is waiting for an i/o, e.g a ADC to complete
– Better if a task takes its slice or hands it back, better if the OS handles all
i/o and knows if a task can run or not.
• Early windows give a task a time-slice but let the task itself
relinquish control – or not! If it hung or waited forever for a human
to do something. We could call this “co-operative non-preemptive
multitasking. In practice tasks call system calls often and the OS
intervenes
• More efficient to allow the OS or a task to preempt another and
get the CPU resource, maybe because data has arrived that a
task was waiting for. For this to work the i/o must be buffered
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE527/files
4
Scheduling
18/11/13
From http://www.freertos.org 18/11/13
5
Scheduling
• Here we only briefly mention this, c.f Meng module on RTOSs.
• Co-operative is straight forward to implement
• Preemptive can have different strategies;
– Round Robin
– Priority-Based Round Robin
– Shortest Process Next
– Lottery Scheduling
– First Come First Served
– Shortest Job First (SJF)
– Shortest Remaining Time Next
– Highest Response Ratio Next
– Rate Monotonic Scheduling
– Earliest Deadline First
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
6
Round Robin
• Each time the scheduler has to decide which
task to run it goes searches a queue. Imagine
the queue is circular and its starting point
varies – just after the last task to run.
• With Priority-Based Round Robin a number of
queues are used. If there are tasks in the high
priority queue ready to run they get picked
first.
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
7
Classification of OSes
• Non Real time, a task will get to run at some time in the
future
• Soft Real time, a task will run in the future, nearly always
before a deadline
• Hard Real time, a task will run by a deadline, guaranteed!
The Issue is not speed, it is predictability and deterministic
responses that are needed.
Often a mixture is used, non-critical tasks mop up spare cpu or
resources but are pre-empted if necessary. Use of a Hardware
Abstraction Layer gives a more robust system, portable and
fault tolerant.
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
8
Other features of OSes
• Memory management – Virtual memory helps
• Interrupt management – top half/bottom half
• Protection, Kernel space and User space, privilege
levels
• Security and auditing
• Inter Task Communication is important –
–
–
–
–
18/11/13
Sempahores (counting and single)
Other types of flags, mutexes and event flags
Pipes, Queues, buffers and shared memory
Sockets and Streams
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
9
Issues
• Tasks can be “Ready” ,”Running” or “Waiting” (aka Blocked)
modern OSes use Queues and Lists to manage these, and
we also need Per Process Data Area blocks of memory
(PPDA tables) So memory is needed
• The source of the Linux Kernel has 35 different tables!
• The kernel must ideally be in protected memory so user
processes cannot access and corrupt these.
• Interrupt latency, context switch time and jitter affect
performance
• All i/o must be buffered and managed. Implies interrupts all
handled by the OS and tasks cannot interrupt.
• Potential snags still possible – deathly embrace, deadlock
must be monitored for, as well as memory “faults” when a task
attempts to get at memory it does not own.
• Virtual memory made this much easier.
• Security is now also very important, to protect against rogue
code, by accident or design!
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
10
Buffered i/o is useful
• A user does not read hardware registers
directly
• A user accesses a buffer in memory
• E.g typical serial input functions are kbhit()
and getch(). For buffered i/p we do not use
these
• We can test to see if the buffer has data in it
and we can get data from the buffer.
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
11
Incoming data – e,g UART
• We arrange an interrupt to occur when data
arrives
• We get the incoming char and place it in the
buffer (if there is room)
• There is some housekeeping to do.
• There are some data structures and variables
needed (and a couple of ways of
implementing ring buffers)
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
12
Taken from
http://thesqldude.com/2012/01/31/sql-server-ring-buffers-and-the-fellowship-of-the-ring/ 18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
18/11/13
7/files
13
Beware! Some implementations
have head pointing one beyond the
end of the data, at the next empty
space, liekwise for tail so make sure
you are clear which convention is in
effect.
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
14
Ring buffers (assume an array)
• Need a head pointer – holds last data written
– Alternative implementations point it at the next empty space,
• Need a tail pointer - holds oldest data yet to be read
• Need to know when the buffer is full – either keep a count variable
or check pointer values
• When putting data into the buffer we advance the head pointer, if it
is beyond the end of the buffer we point it at the beginning of the
buffer. We might check first to see if there is room
• When reading data we see if there is data there, we use the tail
pointer, get the array contents and increment the tail pointer, if is
beyonf the end of the array we reset it to the beginning of the array.
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
15
Ring buffer in C
#define BUFSIZE 256 // make this a power of 2
unsigned char buffer[ BUFSIZE]; // better to use a struct to hold the array and variables
// here we will just use global variables to make the code simpler
// could use pointers or just ints to hold array index, ints simpler to understand
int head; // holds index of last byte put into the array, used to store data after incrementing
int tail;
// holds index of the last data read from the array, one past the next one to get
// alternative code might do this differently,
// do we need to post increment or preincrement the indexes – think and check!
int count; // zero means full, if equal to BUFSIZE then the array is full
void initbuffer(void);
int putdata(unsigned char data); // typically used by ISR to plant data in the array, return 0/-1
// should check to see if buffer full (count==BUFSIZE) or empty (count==0)
int getdata (); /./ returns 0 to 255 for a character or -1 if buffer empty
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
16
Functions for ringbuffer
void initbuffer(void){
tail=0; head=0; count=0; memset(buffer,0,sizeof(buffer);// optional, clear array
}
int putdata(unsigned char data){
if(count<BUFSIZE){
head++;if(head==BUFSIZE)head=0; // preincrement head
buffer[head]=data;
count++; return(0);
}// could rewrite to overwrite old, here we throw away the newest data
return(-1); // if buffer full return a code to the caller, not much can be done!
}
int getdata (){
unsigned char c;
if(count>0){ // there is data to be read
c=buffer[]; // go read it!
tail++; if(tail==BUFSIZE)tail=0; // postincrement tail
count--; // no need to check it less than zero…
return(c); // gets promoted to int, and it will be positive
}
return(-1); // lets the caller know the buffer was empty, but they should have checked first!
}
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
17
Variations on a theme
• The reason for making the buffer a power of
two is to allow making the code more
efficient. Instead of using if statements to
correct the pointers you can use the mod
function (or the OR function in assembler)
(head++)%256; forces head to be 0..0xFF
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
18
Variations on a theme
Most prfessional C programmers avoid arrays and
use pointers, this allows use of malloc and dynamic
memory allocation – more portable.
Also collections of objects that are related are often
put in a struct.
By writing functions that take a struct pointer you
can use the same ring buffer code with different
ring buffers – you might have half a dozen in a big
system.
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
19
from http://www.embedded.com/electrical-engineer-community/industry-blog/4419407/3/The-ring-buffer at 18/11/13
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
20
from http://www.embedded.com/electrical-engineer-community/industry-blog/4419407/3/The-ring-buffer at 18/11/13
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
21
from http://www.embedded.com/electrical-engineer-community/industry-blog/4419407/3/The-ring-buffer at 18/11/13
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
22
from http://www.embedded.com/electrical-engineer-community/industry-blog/4419407/3/The-ring-buffer at 18/11/13
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
23
Other types of buffer - case study
• I once worked with a system that collected sporadic data from an
ADC but needed to write a block of data to a floppy disk.
• We used two buffers, one was always filling and one was emptying
(it sometimes took a good fraction of a second to write a sector to
the disk)
• We used a boolean variable flag, if it held 0 the current buffer for
writing was buffer0 and if 1 then the current buffer was buffer1.
• We still used head and tail pointers, rather than a count variable we
used tail==head to indicate empty and head=tail-1 to indicate full.
• We also conceived of having more buffers and “chaining” them
together to allow a human to change a floppy
• A good programmer should know about data structures and
algorithms – single and double linked lists, hashing, binary trees and
search and sort methods as well as compression.
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
24
Exercise
• You have seen code that uses interrupts. Modify it to put
numbers into a buffer every second.
• Each time a pushbutton is pressed read out the number on
an LED.
• Use the other LEDs to indicate empty half full and overfull
(blink rapidly)
• Or wait until we have the uart working and use it for o/p
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
25
Bonus, outputting numbers on one LED
Morse code uses a 5 value system (not binary!)
A dah is three times longer than a dit.
A dit delay is used between symbols in a letter
A dah delay is used between letters
A 5 dit time is used between letters.
Digits are exactly 5 symbols long
‘1’ is dit dah dah dah dah
‘2’ is dit dit dah dah dah
…
‘5’ is dit dit dit dit dit
‘6’ is dah dit dit dit dit
‘7’ is dah dah dit dit dit
…
‘9’ is dah dah dah dah dit
‘0’ is dah dah dah dah dah
18/11/13
[• — — — — ]
[• • — — — ]
[• • • • • ]
[— • • • • ]
[— — • • • ]
[— — — — • ]
[— — — — —]
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
26
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
27
Old C PIC code…
You will need to write a delay
routine (maybe __delayms() is
available. Also the output_high
and output_low needs changed
for XC32
18/11/13
www.eej.ulster.ac.uk/~ian/modules/EEE52
7/files
28
Download