28
www.eej.ulster.ac.uk/~ian/modules/EEE502/ files/lectures 1 Embedded Systems Lecture 9: Operating Systems, buffered i/o Ian McCrum Room 5B18, Tel: 90 366364 voice mail on 6 th ring Email: [email protected] Web site: http://www.eej.ulst.ac.uk

Www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures 1 Embedded Systems Lecture 9: Operating Systems, buffered i/o Ian McCrumRoom 5B18, Tel: 90 366364

Embed Size (px)

Citation preview

www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures 1

Embedded SystemsLecture 9: Operating Systems,

buffered i/o

Ian McCrum Room 5B18, Tel: 90 366364 voice mail on 6th ringEmail: [email protected] Web site: http://www.eej.ulst.ac.uk

Operating SystemsIn 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

www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures 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 3www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

4

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/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

Scheduling

From http://www.freertos.org 18/11/1318/11/13 5www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

6

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/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

7

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/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

8

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/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

9

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 –

– Sempahores (counting and single)– Other types of flags, mutexes and event flags– Pipes, Queues, buffers and shared memory– Sockets and Streams

18/11/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

10

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/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

11

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/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

12

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/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

1318/11/13

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/EEE502/files/lectures

1418/11/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.

www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

15

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/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

16

#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

Ring buffer in C

www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

17

Functions for ringbuffervoid 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/EEE502/files/lectures

18

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/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

19

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

Variations on a theme

www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

20

from http://www.embedded.com/electrical-engineer-community/industry-blog/4419407/3/The-ring-buffer at 18/11/13

18/11/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

2118/11/13

from http://www.embedded.com/electrical-engineer-community/industry-blog/4419407/3/The-ring-buffer at 18/11/13

www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

2218/11/13

from http://www.embedded.com/electrical-engineer-community/industry-blog/4419407/3/The-ring-buffer at 18/11/13

www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

2318/11/13

from http://www.embedded.com/electrical-engineer-community/industry-blog/4419407/3/The-ring-buffer at 18/11/13

www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

24

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/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

25

Tutorials

• 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)

• Use the uart working and use it for o/p, gather data from ADC, put

it in the buffer once a second. When a button is pressed, empty

the buffer using the UART to send a value to the PC

18/11/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

26

Bonus, outputting numbers on one LEDMorse code uses a 5 value system (not binary!)

A dah (dash) is three times longer than a dit (dot).A dit delay is used between symbols in a letter or digit.A dah delay is used between letters or digitsA 5 dit time delay is used between words.Digits are exactly 5 symbols long and have a regular pattern.

‘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/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

2718/11/13www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures

There are longer codes for punctuation symbols [ . , ? ] and abbreviations are used a lot

28

Old C PIC code… (from CCS compiler)

18/11/13

You will need to write a delay routine (maybe __delayms() is available). Also the output_high and output_low needs changed for your compiler

www.eej.ulster.ac.uk/~ian/modules/EEE502/files/lectures