I am in the process of going back through some 10-15 year old code to diagnosis a problem we are having on a product that is 68HC711K4 based. The issue I have having is forcing a reset of the microcontroller when ever an Illegal Opcode interrupt occurs. Periodically, we get reports of the units failing in this mode (LCD displays error code indicating the illegal opcode) - and I would like the microcontroller to automatically reset in the ISR for the Illegal Opcode, especially since I believe that EMI may be intermittently corrupting the data/addr lines going to the external Flash we use for the firmware.
I believe I am correct in stating, that, unlike the HC08, the Illegal Opcode interrupt does not force a full reset. So, I am trying to force a clock monitor reset instead, from inside the Illegal Opcode ISR. Here is the ISR:
*********************************
__mod2__ void IllegalInst(void)
{
asm("\tsei"); /* Disable all interrupts */
DisplayError(ILLEGAL_INST); /* Display the error */
SetSolenoidPWM(A, 0, 0, 0); /* Deactivate the solenoids */
SetSolenoidPWM(B, 0, 0, 0);
Register.PORTH.BIT.PW2 = 0;
Register.PORTH.BIT.PW4 = 0;
asm("\tldaa\t#$00"); /* \t(instruction)\t(operand) */
asm("\ttap"); /* clear bit 7 of CCR - enable STOP */
Register.OPTION.BIT.FCME = 1; /* 1.02 - enable Clock Monitor */
asm("\tstop"); /* 1.02 - Stop system clocks and since Clock Monitor enabled, system will reset */
}
*********************************
I thought that this would force the program to go to the Clock Monitor interrupt vector since the STOP instruction stops the clocks, but it doesn't appear to going to that vector.
Sorry for the long-winded description, but I haven't really used an HC11 since college and it's tough remember all the caveats sometimes. Any insight is greatly appreciated.
Solved! Go to Solution.
Besides getting the reset to work, your ILLOP handler should also reset the stack pointer so that the various functions can be called successfully. When the ILLOP handler is run, there are no guarantees for any register (including the SP) having correct values.
The following code will force a reset, provided the XIRQ line is not pulled low continuously.
sei
tap
anda #$7F
tap
ldx #REGS
bset OPTION,x,#CME.
Stop stop
bra Stop
Thanks for the help, I will try out this morning.
I should have known to reset the SP, the illegal opcode interrupt pushes the addr of the first byte of the illegal opcode onto the stack so it can be analyzed and possibly corrected in the interrupt handler. Otherwise, I am probably just in a stack overflow situation.
To correct myself:
The following code will force a reset, provided the XIRQ line (or edge-level IRQ) is not pulled low continuously.
sei
tpa
anda #$7F
tap
ldx #REGS
bset OPTION,x,#CME.
Stop stop
bra Stop
Well, no luck on this. I followed tonyp's instructions and can't get the darn thing to reset from the illegal opcode handler. Here is my modified code:
*****************************************
__mod2__ void IllegalInst(void)
{
asm("\tsei"); /* Disable all interrupts */
asm("\tlds\t#$037F"); /* Reset the stack pointer */
DisplayError(ILLEGAL_INST); /* Display the error */
SetSolenoidPWM(A, 0, 0, 0);
SetSolenoidPWM(B, 0, 0, 0);
Register.PORTH.BIT.PW2 = 0;
Register.PORTH.BIT.PW4 = 0;
Reset(); /* 1.02 */
}
void Reset(void)
{
asm("\ttpa");
asm("\tanda\t#$7F");
asm("\ttap");
Register.OPTION.BIT.CME = 1; /* equivalent to ldx #REGS, bset OPTION,x,#CME */
while(1)
{
asm("\tstop");
}
}
*****************************************
Sorry if the inline assembly seems unreadable, the compiler I'm using is CC11 DOS command line based and is ancient.
Well, this code works for me (and has been, for years).
Check if the remaining conditions are also met (XIRQ and IRQ staying high long enough). If any of these are pulled low (e.g.., due to noise) before the CMF is detected, you repeatedly exit STOP mode.
Does your CMF vector point to the same place as the reset vector?
Also, just in case one the functions you call re-enable interrupts, put another SEI instruction right before the TPA inside Reset().
Have you tried calling Reset() directly to test it?
I don't know how your compiler works, but some C compilers expect hex values (even for embedded assembly code) using C syntax (0x instead of dollar sign) -- for LDS and ANDA instructions in this case. Can you check the actual produced assembly code for correctness?
That's all I can think of for now.
One more think I just remembered. Some 68HC11 masksets had an error which required a NOP right before the STOP instruction to work properly. Just add that in there, just in case.
I think you should set OPTION.CME bit, not FCME.
OPTION.FCME bit seems to be writeable only in first 64 cycles after reset and if I understand it properly, it forces clock monitor enabled disregarding the state of OPTION.CME bit.