Reply by "One...@bigpond.net.au [msp430]" January 25, 20152015-01-25
Hi Peter, this was never intended for public consumption. I literally
dashed it off in a few minutes for a long time friend who wanted to
understand the basics behind interrupts, so that he could modify some
simple code I wrote for him, and understand it better, and yes, it would
have been improved by mentioning interrupt priority and stacking, and I
could also have mentioned that NMI's are still active despite the GIE
bit being off, but hindsight and more time are great things!

Cheers

Al

On 26/01/2015 12:12 AM, Peter Johansson r...@gmail.com [msp430]
wrote:
> On Sat, Jan 24, 2015 at 6:23 AM, Onestone o...@bigpond.net.au
> [msp430] > > wrote:
>
> > earlier today I was asked by a friend to point him to a document
> that explains interrupts
>
> One thing I would add is a description of what happens when another
> (or multiple) interrupt condition(s) occurs while interrupts are
> disabled when inside an interrupt handler.
>
> -p.

Beginning Microcontrollers with the MSP430

Reply by "Pet...@gmail.com [msp430]" January 25, 20152015-01-25
On Sat, Jan 24, 2015 at 6:23 AM, Onestone o...@bigpond.net.au [msp430] <
m...> wrote:

> earlier today I was asked by a friend to point him to a document that
explains interrupts

One thing I would add is a description of what happens when another (or
multiple) interrupt condition(s) occurs while interrupts are disabled when
inside an interrupt handler.

-p.
Reply by "One...@bigpond.net.au [msp430]" January 24, 20152015-01-24
earlier today I was asked by a friend to point him to a document that
explains interrupts to him in a simple way. Chapter 2 of the User Guide
is a starting point, but a bit on the bland side about why and how, so I
dashed this off. Re-reading it this evening I thought that it might be
of some use to people out there since interrupts seem to be a frequent
cause of questions and dilemma in this and other groups. Obviously what
follows is my opinion. It has been formed over some 45 years in this
industry as an active designer of hardweare and software, so is very
unlikely to change anytime soon, and I'm definitely not going to get
dragged into arguments about the merits of polling vs interrupts.

Hope this is of use to somebody

Al
"As you know a program normally executes linearly. so it will start
running at the first instruction, then the next and so on executing in
sequence unless redirected by a jump instruction.

To handle things that happen in real time, and to make sure that those
things are handled as rapidly as possible, most microcontrollers have
one or more interrupt sources. An interrupt is simply a small section of
program that is generally self contained, and which is only accessed
when it's associated event occurs.

An event can be almost anything a microcontroller does. A pin changing
state, a timer reaching its set value, a a character received ona UART,
a DMA channel completing a transfer, an ADC conversion completing etc.

When that event occurs the foreground program (the one that runs
sequentially) is temporarily halted and action jumps to the start of the
interrupt 'handler', the common term for the short piece of program that
deals with the interrupt.

Imagine the foreground program as a Movie you are watching on your DVD
player. Somebody bursts into the room (the event) and shouts that there
is a news flash on CNN. You pause the video, and change channels to the
TV station , watch the breaking news, then return to the video without
having lost any of the movie. that is the event and its interrupt handler.

On a micro controller you don't have a pause button, but there is built
in hardware that detects when an event that you want to handle has
occurred. When this happens

1. the microcontroller completes the current instruction it is
executing (finds a convenient place to pause).
2. stores the information that it needs to return to the exact place it
is currently running in the program (presses the pause button)
3. finds the address of the routine which will handle the interrupt, and
moves that into the program counter (changes channel)
4. runs the interrupt handler (watches the newsflash)
5. recovers the information it needs to return to the main program
(changes channels back to the video)
6. recovers the address in the main program where it was originally
running (presses play)

Nothing was lost. More specifically.

1. MSP430 instructions are 1-6 clock cycles long so it could take up to
6 cycles before the interrupt handler starts to execute. This is called
interrupt latency. Because this changes each time an interrupt occurs it
can cause 'jitter' in event handlers that output pulses, for example.
that jitter will be 1 -6 clock cycles. To minimise the effect of jitter
run the micro at the highest clock speed (6 clocks at 1MHz is longer
than 6 clocks at 16MHz)

2. The only information the micro needs to return to exactly what it was
doing is the address of the next instruction it was going to execute,
which is held in a special memory register called the PC, and the status
of the CPU, which holds things like the result of the last action, carry
bit state and even low power modes, so an interrupt even brings the
micro out of low power mode. This status information is all held in
another special register called the SR or Status Register. To save this
data the micro uses a special part of RAM memory called the STACK,
because information the CPU might need is 'stacked there'. In fact it
stacks downward. Typically the stack is allocated at the last RAM
addresses in memory, so if RAM was from address 2000H to 3000H the stack
would be at 2FFEH, the last word address in RAM. The position in the
stack is kept track of using another special memory register called the
SP or Stack Pointer. The stack on the MSP is 16 bits wide. Because the
stack grows downward in memory the stack pointer is decremented by 2
whenever information is being placed there, this is called PUSHing to
the stack. Similarly when information is recovered from the stack the SP
is incremented by 2, and the recovery is called POPping the stack.

Because the SP is pre-decremented when pushing, the start address is
always the word address 1 greater than the desired end of stack, so, in
our 3000H example the SP would be initialised by the user program to
3000H, so that when the first value is pushed the SP decrements to 2FFEH.

When the interrupt occurs the first value pushed to the stack is the PC,
then the SR is pushed.

3. The address of each available interrupt handler is held in a Vector
table at the end of the first 64K byte flash memory block. On the MSP430
this is typically FFE0H. Each type of interrupt that device is capable
of has its allocated position within that table, with the RESET VECTOR
being the last entry at FFFEH. To stray a little, when the MSP430 powers
on the PC is automatically loaded with the value at the reset vector by
the equivalent of a MOV data at FFFEH, PC. When an interrupt occurs an
internal ghost register (for ease of explanation) is loaded with the
offset address of that interrupt vector and the equivalent of a MOV
VECTOR_TABLE(Rg),PC.

This 'says' move the data at the address of Vector Table + the value in
Ghost register into the PC and continue executing the program from there.

4. The program automatically continues executing the interrupt handler
until it meets the RETI instruction, when control is retunred to the
original program. Caution, one of the most common mistakes, and a pain
to debug is a RET instead of a RETI and vice versa.

5. The SR is now recovered from the STACK and the SP is double incremented.

6. finally the PC is recovered from the stack and the main program
continues running as if nothing had happened.

CAUTIONS and THINGS TO AVOID

1. On entry to an interrupt the Global interrupt bit is cleared,
disabling interrupts so they cannot occur while another is being
executed. You can nest interrupts on the MSP430, but it is extremely
complicated and to be avoided until you are an absolute expert.

2. Register modes are amazing at speeding up execution , and are
especialyl useful in speeding up interrupt handlers. Beware NOT to use a
register in an interrupt that is also used in the main program. Imagine
you are counting bytes received in a UART handler in a register, R4,
which is currently 17 counting down to a 32 byte data packet, an
interrupt occurs, and in the interrupt you use R4 as the address pointer
to a table. The table sits at E000H in memory. Suddenly you are sat
looking for a 60k data packet because you inadvertently changed your
counter. I normally reserve 2 registers for interrupt only use.

3. In the same vein, be careful when altering variables that are used in
the main program, again you can alter them and lose track of what they
were doing in the main program.

4. Keep interrupt handlers as short as possible, treat them as
signallers to the main program. For example if you are using a handler
on your UART receiver and a byte of data is received set a bit in a
variable used as a status register to tell the main program that
something has occurred.

5. likewise don't call other sub-routines from an ISR, execute lengthy
bits of test code like if then else constructs. A good interrupt has
just 3-5 instructions:-

a. clear the interrupt flag
b. do the business (set a flag) or (set a flag and exit sleep
mode) or (read a register, write a register, exit sleep mode)
c. RETI

6. Almost the opposite of rapid execution of interrupts is AVOID
POLLING. Very few people understand, or are comfortable with interrupts,
especially those who write in C, so they tend to poll things like:-
WAIT FOR A BYTE:
is the RXD flag set
IF NO JMP TO WAIT FOR BYTE
else continue

If a byte never arrives the program gets stuck in this loop unable to do
anything else. The only way around this is to add a timer to every
polling action, but this is ridiculous, so most people just hope. It
takes 4 instructions to set up a timer, and 2 to detect it, so every
poll now requires 8 instructions. Imagine a bit banged I2C hanlder which
typically has 20 or more potential polling points!! Of course you could
use 1 timer at the start of the process, or one timer across each byte,
but each poll point is still 4 instructions instead of 2. DUMB.

So use interrupts always if you can, but do so thoughtfully."