I'm using Keil compiler for 8051Warp uP. I would like to make a jump from an interrupt routine back to the main function, this way: main () { init_function(); if (setjmp(env)!=0) { // Recovery procedure here ... } while (1) { // body of my program ... } } void irq (void) interrupt (12) { if (condition) longjmp (env,1); } void init_function() { IE = 0xA0; IEN1 = 0xC4; IP = 0x00; IP1= 0x40; } I'm experiencing the following problem. Right after the longjmp instruction, the execution actually restarts at the setjmp instruction point (as i wish), but no more interrupt can be serviced after this jump. It looks like the IE.7 bit has been reset in some way. Anyway, even if i set the IE / IE1 registers after the jump, no more interrupt are serviced by the uP. Somebody could help me? Thanx.
Thanks a lot for your suggestion. But my problem is a little bit different from pure reset. Actually i don't need to restart the execution at the beginning of main, because in this case, the code would execute also the init_function(), what takes very long time. I only need to make the execution after the RETI restart at the point after the init_function. Do you know maybe some way to do that in assembly code? Thank you.
You can do it in C. Just stuff the address of main() on to the stack and do a RETI. See my reset example at http://www.embeddedfw.com and inline the code in you ISR.
Inside init_function(), save the address it will be returning to:
restartAddrMSB = *(SP - 0); restartAddrLSB = *(SP - 1);
| ... | +-------------+ | RETADDR_LSB | +-------------+ | RETADDR_MSB |<-- SP - 11 +-------------+ | ACC | +-------------+ | B | +-------------+ | PSW | +-------------+ | R0 | +-------------+ | R1 | +-------------+ | R2 | +-------------+ | R3 | +-------------+ | R4 | +-------------+ | R5 | +-------------+ | R6 | +-------------+ | R7 |<-- SP +-------------+ | |
*(SP - 11) = restartAddrMSB; *(SP - 12) = restartAddrLSB;
...And a high priority ISR needs to know if it interrupted a low priority ISR and if so, don't perform the return address replacement. Let the low priority ISR do that.
Sheesh! ...And in main() after the call to init_function(), you'll want to reset SP to its initial value.
I know, I'm becoming tedious, but to properly terminate the interrupt posture and ensure that interrupts are disabled upon ISR return, you'd still want to do the ISR return address replacement I described above, but you'd also want to RETI to a CLR EA instruction. The MCU will always execute one instruction after the RETI, the CLR EA in this case. So the init_function() would look something like:
void init_function( void ) { initialSP = SP - 2; restartAddrMSB = *(SP - 0); restartAddrLSB = *(SP - 1); /* ... */ }
void main( void ) { init_function(); EA = 0; /* CLR EA */ SP = initialSP; /* No effect on 1st through */ /* ... */ EA = 1; /* Ready to rumble */ /* ... */ }