Jump to content
43oh

Using Subroutines as Regular Functions and Interrupt Service Routines


Recommended Posts

Hello All,

 

This is my first post on this forum and I am using an MSP430G2553 and coding with Energia.

 

I started fiddling with my MSP430 Launchpad a few weeks ago and I am now doing a few projects that will be much simpler using Interrupt Service Routines. While discussing how interrupts work with some friends, it came up that a return from a ISR is different than from that of a regular subroutine. I do not mean the "return val;" but the actual PUSHes and POPs from the stack.

 

I have heard that the ISR PUSHes the status register, or some such containing current flags, onto the stack in addition to the program counter. The return from ISR must then POP 2 items from the stack (both the status register and the program counter). This is in contrast to a regular function which only PUSHes and POPs the program counter.

 

My concern now arises that the attachInterrupt(interrupt, function, mode) changes how the subroutine functions. This implies that the attachInterrupt function changes code, which as a programmer I find a bit troublesome.

 

All of this leads to a couple questions:

1. Can I use a subroutine that has been setup as an interrupt with attachInterrupt as a regular function?

2. Does the attachInterrupt function actually change the way my subroutines behave in the MSP430?

Link to post
Share on other sites

In many cases people use interrupts on wrong way, putting all code in ISR body, and as result application get stacked in ISR. Interrupts must be small/light as possible, just with few lines (of assembler), and rest of job (depending on interrupts) must be executed in background, in main program/function. 

Link to post
Share on other sites

You are right that an interrupt function is compiled differently, however this doesn't apply to functions used with attachInterrupt.

 

The MSP430 calls an interrupt function when an interrupt occurs on port 1, and a different function when an interrupt occurs on port 2. You will notice however that Energia's attachInterrupt allows you to put a different function on each pin. This Is a bit of magic done in software. The Energia framework provides the Interrupt Service Routines (ISR) for Port 1 & Port 2 interrupts. It also has a table recording which pins have a user function associated with them through attachInterrupt. When an interrupt occurs, the MSP430 calls either the Port1or Port2 ISR provided by the Energia framework. This ISR checks to see which pin triggered the interrupt, and if there is a user function associated with that pin from a prior attachInterrupt call. If there is, the ISR calls your function. This is a normal function call, so your function is compiled the same as any normal function. When your function returns, execution continues in Energia's interrupt function, which has the special ISR exit code.

Link to post
Share on other sites

If you want to learn about interrupts using the MSP430 as an example, you should be able to search around ti.com until you find a good users' guide.  In any case, if you want to learn, read them all.  Target the sections that discuss the core, instruction set, and interruptor (often chapter 4).

 

http://www.ti.com/lsds/ti/microcontroller/16-bit_msp430/tech_docs.page?familyId=342&docCategoryId=6

 

To give you a head start, here is how MSP430 interrupts work.

 

1. some peripheral has an event that invokes an interrupt to the core.

2. core run the interrupt service routine, which includes an instruction that copies the registers onto the stack

3. your interrupt service routine code runs

4. at the end of the interrupt service routine, there contents of the stack are copied back into the registers

 

During a normal subroutine/function, there is some manipulation of stack and registers, but not in total.

 

If you are familiar with thread programming for an OS, you'll realize that thread context switching is basically the same concept.

Link to post
Share on other sites

In many cases people use interrupts on wrong way, putting all code in ISR body, and as result application get stacked in ISR. Interrupts must be small/light as possible, just with few lines (of assembler), and rest of job (depending on interrupts) must be executed in background, in main program/function. 

I disagree completely.  Interrupts are automatically prioritized and queued in hardware.  This strategy recommends to eschew that feature, and instead replicate it in software.  Using software state machines and flags is more resource-heavy than using ISRs.

 

For many architectures, however, it is wise to keep interrupts short.  In Cortex-M, for example, the stack can quickly get out-of-hand because there is hardware support for cascading interrupts.  In MSP430, this is not by default.  To get cascading interrupts on the 430, you need to manually re-enable interrupts in the body of each ISR.  Without cascading interrupts, though, there is no practical difference between using some form of semaphores outside the ISR (e.g. a state machine with flags) and the hardware interrupt priority chain.

Link to post
Share on other sites

I disagree completely.  Interrupts are automatically prioritized and queued in hardware.  This strategy recommends to eschew that feature, and instead replicate it in software.  Using software state machines and flags is more resource-heavy than using ISRs.

 

For many architectures, however, it is wise to keep interrupts short.  In Cortex-M, for example, the stack can quickly get out-of-hand because there is hardware support for cascading interrupts.  In MSP430, this is not by default.  To get cascading interrupts on the 430, you need to manually re-enable interrupts in the body of each ISR.  Without cascading interrupts, though, there is no practical difference between using some form of semaphores outside the ISR (e.g. a state machine with flags) and the hardware interrupt priority chain.

I mostly agree with you. You can certainly do a lot more in an interrupt routine than the typical "set a flag & return" that is commonly espoused. But at the same time it isn't wise to load them up with time-consuming tasks and hope the hardware scheduler will take care of several interrupts piling up. 

 

In short there is no single "right way" to do things. 

 

There are several considerations such as:

 - the likely frequency of the interrupt

 - how much work the background operation needs to do.

 - what happens if multiple interrupts come through before the previous one has been completely dealt with - ie, can multiple interrupts be ignored, or does every one need to be attended to.  

 - The 430's low power modes can make things interesting too - depending on the task, you can sometimes put all your functionality in the main loop, and all the ISR has to do is wake the processor from sleep.

 - RAM requirements - on uCs with very small RAM, it can be easy to chew through the stack if the main routine calls functions a few levels deep and the ISR also calls multiple levels of functions.

 - Another risk is calling code that is not re-entrant.  An example of this might be if you have an LCD module - The main routine may have called a function to write data to the LCD. Halfway through writing a sequence of data an interrupt is triggered, and the ISR also tries to write data. In this case, corruption is guaranteed. 

 

Personally, while I agree that useful work can be done inside an ISR, I would prefer to err on the side of doing too little in the ISR than trying to do too much.

Link to post
Share on other sites
1. Can I use a subroutine that has been setup as an interrupt with attachInterrupt as a regular function?

2. Does the attachInterrupt function actually change the way my subroutines behave in the MSP430?

You're right, a ISR will call upon the RETI (return from interrupt) instruction, while a normal subroutine/function will cal upon the RET (return) pseudo-instruction.

The difference is in there that a RET is a pseudo-instruction. This means that it is actually another instruction in disguise. What is actually executed is MOV @SP+,PC. Better translated as "copy the value currently at the location pointed to by the stack ponter into the program counter and then increment the stack pointer by 1 word". Since this is done after all other data has been popped from the stack, this means that the PC is loaded with the PC that was pushed onto the stack by the CALL instruction.

On the other hand RETI is a real instruction, it does something in one go that could not be done any other way. It is essnetially MOV @SP+,SR. MOV @SP+,PC in one go. Better read as "move the top value of the stack to the status register and before its effects start, do a RET". Because the status register contains the LPM bits, they are restored (return to LPM after the ISR), but before you actually go to sleep, you restore the program counter, which does effectively let you leave the ISR and clear the stack.

 

Second question: no. An attachInterrupt() will just call the given function, the real ISR (which is part of Energia) might act upon the return value from your function, but this would be part of Energia, not of the MSP430.

Link to post
Share on other sites

You're right, a ISR will call upon the RETI (return from interrupt) instruction, while a normal subroutine/function will cal upon the RET (return) pseudo-instruction.

The difference is in there that a RET is a pseudo-instruction. This means that it is actually another instruction in disguise. What is actually executed is MOV @SP+,PC. Better translated as "copy the value currently at the location pointed to by the stack ponter into the program counter and then increment the stack pointer by 1 word". Since this is done after all other data has been popped from the stack, this means that the PC is loaded with the PC that was pushed onto the stack by the CALL instruction.

On the other hand RETI is a real instruction, it does something in one go that could not be done any other way. It is essnetially MOV @SP+,SR. MOV @SP+,PC in one go. Better read as "move the top value of the stack to the status register and before its effects start, do a RET". Because the status register contains the LPM bits, they are restored (return to LPM after the ISR), but before you actually go to sleep, you restore the program counter, which does effectively let you leave the ISR and clear the stack.

 

Second question: no. An attachInterrupt() will just call the given function, the real ISR (which is part of Energia) might act upon the return value from your function, but this would be part of Energia, not of the MSP430.

 

Very well written and it cleared up my confusion. Thanks roadrunner84.

Link to post
Share on other sites

... In short there is no single "right way" to do things. ...  Personally, while I agree that useful work can be done inside an ISR, I would prefer to err on the side of doing too little in the ISR than trying to do too much.

You make all good points.  Rarely is a complex task black and white in how it can be implemented well.

 

I make a point that systems with two or more low-latency interrupt sources -- in this example a protocol-oriented communication bus -- usually need some sort of RTOS that can offload the higher latency protocol processing while a tight ISR in the driver takes care of the data transfer.  I could make other data acquisition & processing examples, too, such as streaming DSP implementations.  

 

But sometimes you can just pile everything into the ISRs and come-out cleanly.  In my experience, a lot (but not all) of the projects done on 43oh.com fall into that latter category, but I probably should have written more conditions in my first argument.

 

:)

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...