A subroutine is "re-entrant" if it is designed so that, if it is ever interrupted in the middle, and then the interrupt routine calls the same subroutine, then everything works the way it ought to work.
Alas, it is very difficult to write re-entrant code on the Microchip PIC processors.
For example, if you have a "square_root" subroutine, and you call it with "9", but while it is still calculating it gets interrupted, and the interrupt routine decides it needs to find the square root of "4" -- what happens? Most square root routines for the PIC will return the proper value "2" to the interrupt routine ... but when the calculation of the square root of "9" resumes, they wig out and return "2" or some other completely wrong answer.
Our options are:
write code that we know is not re-entrant, and whenever an interrupt might mess up the calculation, disable interrupts temporarily. (The section between disabling interrupts and re-enabling interrupts is called the "critical section").
(see also software stacks on the Scenix )
Nikolai Golovchenko says:
Yes, the nested interrupts are possible. The method I used on 16F84 processed two interrupts (RBIF and TMR0IF), but more interrupts could be okay. To do this, I use software stack macros (see attachment) that use FSR as a stack pointer. A typical interrupt handler looks like this:ORG 0x004 ; interrupt vector location PUSHW ;store W PUSHSTATUS ;store STATUS ;code goes here POPSTATUS ;restore W POPW ;restore STATUS retfie ; return from interruptAfter storing W and STATUS goes usual interrupt flags polling .
As soon as a set flag is detected, it should be cleared and GIE=1 to allow other interrupts to actually interrupt the process.
Be careful not to allow too many interrupts to be processed, only the ones that have critical response time, because hardware stack may overflow. The best way is to keep GIE reset during the most critical interrupt so that it could finish without unwanted interrupts.
Priority of different interrupts is programmed by flags polling sequence(in case they trigger at the same time).
That's it.By the way, I find software stack macros very useful in practically every program. The best example is when you need one scratch pad register. Using stack it's simple:
PUSH ;reserve one byte on stack ....use INDF as a scratch pad reg POP ;restore stackGood luck.
;******************************* ;Software stack organization ;******************************* ;FSR is a stack pointer ;Top of stack is in INDF ;Stack grows in upper addresses direction ;******************************************************************* ;MACRO: INSTR.NUMBER: STATUS INFLUENCE: W INFLUENCE: ; ;PUSHW 2 no no ;POPW 3 no yes ;POPW2 2 yes!!! yes ;PUSHSTATUS 3 no yes!!! ;POPSTATUS 3 yes yes!!! ;PUSH 1 no no ;POP 1 no no ;******************************************************************* ;Notes: 1) FSR should point at the stack top ; 2) PUSHSTATUS and POPSTATUS must be used in pair, ; because these macros mangle quadruples ;******************************************************************* PUSHW MACRO INCFSZ FSR, F ;never goes zero, but STATUS is safe MOVWF INDF ENDM POPW MACRO SWAPF INDF, F SWAPF INDF, W ;same as movfw indf, but STATUS unchanged DECFSZ FSR, F ;never goes zero, but STATUS is safe ENDM POPW2 MACRO MOVF INDF, W DECFSZ FSR, F ;the popped W STATUS is safe ENDM PUSHSTATUS MACRO SWAPF STATUS, W INCFSZ FSR, F ;never goes zero, but STATUS is safe MOVWF INDF ENDM POPSTATUS MACRO SWAPF INDF, W MOVWF STATUS DECFSZ FSR, F ENDM PUSH MACRO INCFSZ FSR, F ENDM POP MACRO DECFSZ FSR, F ENDM
Robin Abbott of Forest Electronic Developments says:
This might be of use to someone. Recently I had a project where a subroutine took a value in W and saved to a software stack:movwf Temp movfw sp ; Stack pointer movwf FSR ; Point to it movfw Temp movwf 0Trouble is it uses a temporary variable which I didn't have (it is in an interrupt). This alternative which makes use of XOR uses no temporary variable at the expense of 1 extra word:
movwf FSR movfw sp xorwf FSR xorwf FSR,w xorwf FSR movwf 0You can also use this to swap two variables (say x and y) without a temporary variable leaving X (or Y if order is reversed) in W.
movfw x ; Get X xorwf y ; Y is now X^Y xorwf y,w ; W is now (X^y)^X==Y (say OldY) movwf x ; Now X is OldY xorwf y ; finally Y is (OldX^Y)^Y==OldXI think this may be an old technique - I have vague memories of something similar from the pre-history of programming, but only found a use for it now
(See math/bit/swap.htm for details. )
Timer tutorial (incl prescalers) by Andrew Warren
Are the stack-based math routines /techref/microchip/pfu.htm compatible with the above code?
James Cameron [quozl at us.netrek.org] says:
I've also done a software stack, mainly for mathematical functions, in order to significantly reduce memory (file register) utilisation on a 12C509. Not a call and return stack, just a parameter stack. http://quozl.netrek.org/stack-math.asm{ed: This has now been expanded at http://quozl.netrek.org/uptime/ to include
- LCD display access, put a data byte or a command on stack and call the function,
- vectored execution, put a pointer to a function on the stack and call the function,
- data table handler, give it a pointer to the table function, a pointer to a function to be called for each table entry, and call the function,
- binary coded decimal conversion, nice wasteful code that takes a high and a low byte of a 16-bit word on the stack, and returns three bytes of binary coded decimal,
- hexadecimal conversion, takes a byte and returns two ASCII characters on the stack.
"PIC12C509 - Getting Around the Stack Limitation" by Peter H. Anderson 1997 http://www.phanderson.com/PIC/12C509/stack.html says "The 12C5 series PIC has only a two level stack which limits the number of nested subroutine calls to two. This may be a very serious limitation. (The 16C84 has an eight level stack which permits nested subroutines to eight deep. I can't imagine a program where this will not be sufficient).". That article describes one way of implementing a deep return stack, when the hardware return stack is inadequate.
Interested: