25/09/2013
Embedded Systems Design ELEN90066
Lecture 17 Interrupts and Good Code David Jahshan
Notes from last lecture
• AVR C tool chain, .c and .h files are compiled to a .hex file which is then loaded onto the microcontroller
• Header files how to #include and macros using #define
• Variables, how to declare and use them, ++, –, +=, comments, if and else, while, for loops.
• Conditions, ==, !=, &&, ||, case statements
Example Exam Questions
• Describe how a file is converted from a .c and .h file into machine code
• What does these lines of code do?
• Why don’t you use malloc of calloc on an AVR?
Code Execution
• Perfect code is code that executes every line every time without fail.
main(void) {
while(1) {
} }
read_input; modify_input; write_output;
All possible execution paths can be tested easily.
Everything happens at exactly the same point in time, guaranteed timing.
Conditional execution path
• Every conditional introduces a new execution path, making it harder to test.
• Every conditional makes it harder to predict when things will happens.
– This makes it very difficult to predict timing of events.
A possible solution to the challenge
if (z < 10)//and z can only be between 0 and 15 y++;
//Non
z – 10;// 1010-1010 = 0000 0000, //if z is 10
1001-1010 = 1111 1111, //if z is 9 0001-1010 = 1111 0111, //if z is 1 1111-1010 = 0000 0101 //if z is 15
z >>= 7; // 0000 0001 y+z;
1
25/09/2013
Interrupts
• When a hardware trigger happens, code branches to a specific point in memory and starts executing.
• Assist in ensuring correct timing.
• Fantastic for power saving (sleep modes)
• Makes testing hard, code can branch at any point in time. Can create unexpected results.
• What happens if you get an interrupt in an interrupt? (nested interrupts)
Timer Interrupts
• Areattheheartofalloperatingsystems,ata specific time the processor switches tasks.
• Morereliablethanwhileloopsforcreatingevents at a given time.
– Does not get effected by branches – Does not get optimised out
– Permits other tasks while waiting
• Ensurethattheprevioustaskiscompletedbefore the next timer interrupt else a growing queue till stack overrun.
Interrupt Service Routine • WhathappensduringanISR
– Interrupt arrives at the interrupt unit • If the Global Interrupt Enable (GIE) is set:
– GIE is cleared (instruction is CLI CLear Interrupt) disabling new interrupts
– The program counter is pushed to the stack
– The processor jumps to the interrupt vector (hard wired)
– The interrupt vector ordinarily has a jump instruction to the ISR
– Once the ISR is complete it runs a return from interrupt inst
– This returns the previous program counter from the stack
– Enables GIE (instruction is SEI SEt Interrupt)
– Executes one more instruction before servicing any more ISRs
Interrupt types
• 21Interruptvectors
• 2bytesperinterruptvector,itordinarilystoresa jump to address command where the ISR is but does not have to.
• Therearetwotypesofinterrupts – One that sets a flag
• If GIE is not set, it will store that interrupt for later – One that is only triggered when active
• If GIE is not set it will not trigger if the condition is not active
AVR has a minimal ISR
• The ATMEGA16 has very fast interrupts, it only stores the program counter.
– 4 clock cycles to store the program counter and branch to the Interrupt vector
– 3 clock cycles for a direct jump
• Does not store status registers, this is up to
the user (or the users compiler)
• 4 clock cycles to return from interrupt
Reset Vector
• You would have noticed that the first ISR vector is Reset
• When you reset your chip (or power it up) the MCU runs code at the reset vector, must be a jump to where you want your code to execute from.
• Clears all the IO registers to their default state (input no pull up)
2
25/09/2013
ISRs in C
ISR(name of vector) {
Your code }
Do not add a return at the end, this will cause problems.
Keep your ISRs short, often set a flag that will run code in the main loop.
Nested ISRs • You must SEI inside the ISR
• Risk that your stack will grow and overwrite data
– The stack starts at the end of RAM and grows upwards. You only have 1k and you store 2 bytes each time you get an interrupt. You can run out of space very quickly.
Adding Assembly to your code
asm volatile(“assembly1\n\t” “assembly2\n\t”
“assembly3\n\t”::); asm volatile(“mov r16, r10\n\t”
“rol r16\n\t”
“out 0x18, r16\n\t”::);
Clean Code • AVR code is traditionally messy.
– To set PORTD to 0x55 you could write: *0x32 = 0x55
– 5 minutes later you don’t know what and why. • And nobody else every will
– You could comment but this has a lot of overhead and comments are not always clear
• Try to achieve self documenting code is the best way.
Self documenting code
BAT_LOW_LED(OFF); BAT_LOW_LED(ON); BAT_LOW_LED_DIR(OUT); #define INFINITE_LOOP 1 while (INFINITE_LOOP){} if (UP_BUTTON){}
Are all examples of clean code.
while (i<100) i++;
Variable names
This is not very descriptive
while (delay_counter < DELAY_LENGTH) delay_counter++;
3
25/09/2013
Over the break
• Designwhatyoursoftwarewilldo
• Minimumetchasketch
– One button to clear the screen
– Up sets the pixel above the current pixel
– Down sets the pixel below the current pixel – Left and right sets the pixel...
• Reminderwriteyourowncode,don’tcopy others, if you are caught you will be reported.
• Youwillbeexaminedsoifyoucopyyouwillfail the exam!
4