33
ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineeri ng

Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Embed Size (px)

Citation preview

Page 1: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

ulster.ac.uk

Embedded SystemsIntroduction to Interrupts, Timers and the Seven Segment Display

Ian McCrumSchool of

Engineering

Page 2: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Executing codeSome simple concepts

A program is just a list of machine instructions burnt into memory. A program has a starting address, the compiler/linker decides where to place code.

Each CPU executes lines of code sequentially, it uses an internal register called the Program Counter to keep track of the address in memory of what to execute.

On Power up or reset the Program Counter is initialised to zero (in the PIC range of microprocessors). There is a “JUMP” instruction there that jumps to an actual program.

Page 3: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

InterruptsDoing two things at once (apparently!)

If an “event” can force a new value into the Program Counter this will force a “jump” to the new value. We describe this as “interrupting the main code”

Most microprocessors allow this – and have mechanisms to ensure a return can be made, back to wherever the code was before it was interrupted. Any internal registers used in the CPU must also be saved before and restored after the execution of the interrupt code. This is done for you in XC8.

Most microprocessors have instructions to enable and disable the interrupt mechanism, perhaps main code has to do something which should not be interrupted.

Page 4: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Events – hardware interruptsTypical sources of interrupt

It is useful to setup a timer so that when it reaches a trigger value it generates an interrupt, this allows main code to be doing something useful whilst waiting for a temporal event

If a external activity will take a long time, or an unknown time then it is useful to have that activity interrupt the CPU when it occurs.

The external event can be a change of voltage on an input pin, you can choose rising or falling edge events. Or it can be any change on a group of digital inputs. (see RBO/INT0 and the Interrupt on change feature on RB4,5,6, and 7 – section 4.2 in the databook)

Page 5: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Events – hardware interruptsTypical sources of interruptIf one of the built in peripherals such as the ADC, UART, SPI or IIC might take a bit of time to complete an data transfer then it can be useful to interrupt the CPU when that transfer is complete and needs CPU interaction.

Some peripherals have several possible sources of interrupt. The UART transmit hardware can interrupt the CPU when it has just finished transmitting, the UART receive hardware can interrupt the CPU when an incoming character has arrived. (it can take thousands of microseconds to send or receive a serial character at 1200 baud for example – 10 bits at 1/1200 second for each bit)

Page 6: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Interrupts in the PIC16F877Refer to the databook; chapter 14, section 11There are 15 sources of interrupt; three tiers deep in the hardware.

To use interrupts you must;

• Set the specific peripheral interrupt enable and also • Set the generic interrupt enable bit.

There may be other enables needed( see PEIE) and other PICs may allow two or more interrupts, high priority and low priority, the CPU can almost do three things at once!

Page 7: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Interrupt Logic – PIC16F877From: figure 14-10 of Microchip PIC16F87XA databook

Thus a ‘1’ on TMR0IE will enable a Timer 0 interrupt, but you also need a ‘1’ on the Global Interrupt Enable (GIE) to fully arm the hardware.

The Interrupt will only happen when the Timer 0 Interrupt Flag (TMR0IF) goes to a ‘1’

Your software must (manually) clear TMR0IF inside the interrupt code, to avoid an immediate re-interrupt on leaving the Interrupt code.

To use Timer 1 or Timer 2 you must also remember to set PEIE

Page 8: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Timer 0• TMR0 is an 8-bit timer/counter Readable & writable

• 8-bit programmable prescaler (2:1 …256:1)

• Internal or external clock select

• T0IF Interrupt on overflow of FF to 00

• Edge select for external clock

We will use an Internal clock with a prescale; hence T0CS=0, PSA=0

Page 9: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Timer 0 (note ZERO not “Oh”)DetailsIn general timer 0 can either count input changes on RA4 or time things, the system clock is FOSC/4 which for a 4MHz crystal gives one microsecond resolution.

The prescaler divides by 2, 4, 8,16, 32, 64,128 or 256 depending on the 3 bit value stored in PS2, PS1 and PS0 in the OPTION_REG.

The TMR0 interrupt is generated when the TMR0 register overflows from 0xFF to 0x00. This overflow sets bit T0IF (INTCON<2>). The interrupt can be masked by clearing bit T0IE (INTCON<5>). Bit T0IF must be cleared in software by the Timer0 module Interrupt Service Routine (ISR)

Page 10: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Using Timer 0Three ways of timing things

After initialising the OPTION_REG, If you store 00 in the TMR register it will start incrementing at the chosen period.

You can either

(a) Keep checking TMR0 until it reaches a target value

(b) Store (0xff-your target), start the timer then keep checking TMR0IF – it gets set on a ff->00 rollover

(c) Set up as for (b) above but allow an interrupt to occur

Page 11: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Timer 0 Special Function RegistersSFRs which can be accessed from software

Page 12: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Timer 0 – setting it up

Refer to the block diagram of the hardware – then it is obvious we want T0CS = 0 and PSA=0 and a value in PS2:0

Page 13: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

The XC8 CompilerUsing it with the PIC16FBy including <xc.h> the compiler can find a number of declarations - each hardware register is known as a SFR and each bit or group of bits are accessible by using the structure below; these are often the same names as the databook (XC32 is better than the XC8…)

TMR0=0x00; // an 8 bit register, clear to zero or a start value

OPTION_REGbits.T0CS=0; // use internal clock source

OPTION_REGbits.PSA=0; // use prescale unless divide by 1

OPTION_REGbits.PS=0b101; // this is the pattern for 1:64

INT_CONbits.T0IE=1; // Enable interrupts for timer zero

We will also need to do a GIE=1 to fully allow interrupts to happen.

Note that XC8 also allows other GIE and T0IE to be referred to in

code without the SFRbits. prefix

This may change in future versions of XC8

Page 14: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Interrupt Service Routines & vectorsYou have seen how the PIC16F877 has 15 sources of interrupt. These can cause a jump to interrupt code (if enabled correctly)• The code is described as an Interrupt Service Routine (ISR)• The jump is described as using an Interrupt Vector• The vector must be setup to point to the address of the ISR

A vector is simply an address stored in memory where the CPU can find it – the reset vector is at 0b000 and the interrupt vector is at 0b004. The compiler places a “JUMP” instruction at both of these, and the hardware inside the CPU jumps to the appropriate address when reset or interrupted. Some CPUs just read the vector table and take action themselves.

PIC18’s have two interrupt vectors, PIC32’s have hundreds!

Page 15: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

The XC8 compiler and interruptsThere are several ways of doing this

The function qualifier interrupt (or __interrupt) can be applied to a C function definition so that it will be executed once the interrupt occurs. It must have void return and parameter lists – obviously since no code will ever “call it”

The compiler will process the interrupt function differently to any other functions, generating code to save and restore any registers used and return using a special instruction.

Other Microchip compilers used other keywords;

__attribute__((interrupt,auto_psv,(irq(52)))) or

__ISR(_TIMER_0_VECTOR, ipl2auto) – nearly every event in the PIC32 architecture has its own vector

So be sure to check in the compiler manual as this is non standard C

From section 5.9 of Microchips XC8 Compiler manual

Page 16: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Example code – 7 segment displaysSee the code section of the website

If 4 separate seven segment displays are wired to parallel output ports so that one digit at a time can be driven then a workable 4 digit display can be created.

It is important to let each display show its digit for 5 msecs out of every 20 – the human eye’s persistence of vision will appear to see all 4 digits lit. This is known as a multiplexed display it suits a simple ISR.

We drove the segments with PORTD and the 4 digit select lines (DIGITS_CTRL) with PORTB<3:0>

Page 17: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Example code – 7 segment displaysThe ISR and main code must communicate.

4 memory locations are set aside to hold what is to be sent to each of 4 displays. (we use 5 locations – see later)

The 4 locations are written to by main code and read by the ISR

The write to the 4 locations must not be interrupted (literally), for example if writing ‘1’ ‘9’ ‘4’ ‘2’ over the top of ‘2’, ‘0’, ‘1’ ,’4’ and an interrupt occurred half way through this write sequence, it is likely the display would read 1914 or 2042 depending on the direction of main’s writing sequence

Thus we disable interrupts whilst altering the digit array in main.

Page 18: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Global VariablesFor main to communicate to the ISR

Variables declared outside a function are considered to be global and readable by any function in the declaring file. As a matter of style I declare then as extern in a header file and then define them (initialise them) in a file called setup.c. Any program wanting to access them need only include “setup.h” and ensure setup.c is compiled and included in the list of project files

Page 19: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Timer functions: Initialisation

This should make sense if you read 5.0 of the databook.I would prefer the modern XC8 convention of accessing each bit on a line by itself – the code is more self documenting and easier to read, though more typing is involved.

TMR0=156; // an 8 bit register, 256 to 156 is 100 in decimal i.e every 100 clocksOPTION_REGbits.T0CS=0; // use internal clock sourceOPTION_REGbits.PSA=0; // use prescale unless divide by 1OPTION_REGbits.PS=0b100; // this is the pattern for 1:32 (i.e 3200 clocks)INT_CONbits.T0IE=1; // Enable interrupts for timer zero - 3.2 milliseconds

Page 20: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Timer functions: ISR

If timer zero has its interrupts enabled and the interrupt has actually happened the code inside the if statement gets executed. In practice there is only one source of interrupt so the checks are not actually needed – but a future coder could alter the code so it is better to be sure

It is vital to reload the TMR register and reset the T0IF flag, then we don’t get interrupted for another 3.2 milliseconds

Page 21: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Seven Segment display: main code

Inside main you must setup (initialise) timer 0 so that interrupts occurAnd simply drop a digit into each of the first 4 elements in the digits arrayThe code here drops in the ASCII code for each digit, the ISR extracts an actual number. Note how interrupts are disabled whilst updating the array and then re-enabled after the update is complete.

Note: sprintf acts just like printf except that the destination for the formatted characters is a string instead of the screen. Thus

sprintf(astringname,”%04d”,1942);Plants ‘1’ , ‘9’, ‘4’ and ‘2’ inside the string, it must already have a ‘\0’

Page 22: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Seven Segment display: ISR code

Working backwards, if the array digit contains “1942”, then digit[0] = ‘1’, digit[1]=‘9’ and so on. The ascii character ‘1’ has an actual value of 0x30 and the ASCII character ‘9’ has the actual value 0x39. Since the ASCII character ‘0’ has a value 0x30 the 2nd line[digits[current_digit]-’0’] will have a value of the number 1,9,4 or 2 depending on whether the variable current_digit has a value of 0,1,2 or 3.

Assuming 1, then sevseg[digits[current_digit]-’0’] will have a value of 0b1101111, the code for sevseg[9]. Hence a 9 is displayed on the appropriate 7-seg display, all segments apart from f are lit on the second display in from the left… for 3.2 milliseconds.

The 1st line above outputs the correct pattern 0b0100 if curreent_digit is a 1 and the 3rd and 4th lines adjust current_digit for the next interrupt (the ‘4’ has to be dispalyred on the 3rd digit in)

Page 23: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Complete Code to drive 7-segmentsThis also shows how multiple file compilation works (there are 9 files!)• You must add files to the project navigator in MPLAB X (the window in the

top left of the IDE)• Normal convention is that every .c file has a .h apart from main• .h files should not use memory, you should never #include .c files, only .h

files• Every .h file should be guarded so its contents are only read once, see the

top 2 and last lines of my .h files• Every .c file should compile on its own (right click in the navigator and

select compile file)• These rules (recommendations) ease porting drivers to new projects.

I have used the software “Programmers Notepad” to display the code in the overhead slides that follow, note the tab at the top that is highlit.

Page 24: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering
Page 25: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering
Page 26: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering
Page 27: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering
Page 28: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering
Page 29: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering
Page 30: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering
Page 31: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering
Page 32: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Other Interrupts and TimersBe careful if you use 2 or more interrupts

Multiple interrupts are very tricky to code, very, very tricky to debug and analyse in a deterministic way.

On the PIC16F there is only one interrupt vector so the one ISR must check all xxIF flags to see who interrupted.

Such code must consider what to do if an interrupt occurs whilst in an ISR and must consider if an interrupt might get missed (if 2 occur from the one source before the first one is serviced.)

PICs with multiple vectors are slightly easier to code – but a good embedded systems engineer must still consider if an interrupt might get missed, and if the priority is correct, some interrupts are more important than others.

Page 33: Ulster.ac.uk Embedded Systems Introduction to Interrupts, Timers and the Seven Segment Display Ian McCrum School of Engineering

Other Interrupts and TimersDifferent PIC chips vary

The PIC16F877 has 3 timers, timer 1 and timer 2 are both 16 bits and have extra registers that trigger wraparound – when TMR1 reaches the value stored in PR2 it resets to zero, it need not go up to 0xFFFF.

Each timer has special functionality, timer 2 is useful for generating PWM signals

PIC32 chips and some PIC18F have 5 timers, on the PIC32m a pair of timers can be used to provide a 32 bit peripheral.