Exceptions and Interrupts Interrupts Handlers vs. Subroutines Accept or hold Pending: Priority control Exception vector table Example Karl-Ragmar Riemschneider
Exceptions in H8S/2357
Interrupt Controller
Interrupt Controller
Two interrupt control Mode 0 or Mode 2: 2 interrupt control modes can be set INTM1 and INTM0 bits in the system control register (SYSCR). Priorities settable with IPR Interrupt priority register (IPR) is provided for setting interrupt priorities. 8 priority levels can be set for all interrupts except NMI. NMI is assigned the highest priority level of 8, and can be accepted at all times. Independent vector addresses All interrupt sources are assigned independent vector addresses No need for interrupt handling routine to determine the source of interrupts.
Comfortable but NOT typical !! Often the handler has to find out the source of the interrupt, see daisy chain principles in the literature of other processors.)
Nine external interrupts IRQ_7 to IRQ_0 + NMI Edge of interrupt signal is selectable:
IRQ_7 to IRQ_0: falling edge, rising edge, or both edge detection, or level sensing. NMI: Rising edge or falling edge.
Additional switch to enable/disable the IRQ lines Remark: before use one IRQ you have enable this
Interrupt Request (IRQ) Sense Control Registers ISCRH, ISCRL defines the effective event or state on IRQ Pins (falling, rising edge both edges or low level)
Bit NMIEG sets the active edge (falling/rising) of the Signal which effects non maskable interrupts NMI
NMI
Setting of Interrupt Control Mode 0 INTM1=0 and INTM0=0 Interrupt acceptance will controlled by One single bit (I bit) in Status Register CCR [Condition Control Register] Function:
I bit set to 1 = allowed interrupts I bit reset to 0 = interrupts not allowed
Setting of Interrupt Control Mode 2 INTM1=1 and INTM0=0 8 interrupt priorities for:
8 external interrupts sources ( = IRQ interrupts) and 16 internal interrupts sources (on-chip supporting module interrupts).
System Byte
Status Register(s)
Code Condition Register
User Byte
System Byte
Status Register(s)
Code Condition Register
User Byte
Used in Interrupt Control Mode 0
Feature of Exceptions
Each exception is associated with a vector number. This vector number gives the address of an exception vector table entry. An exception vector table is an array of the type long (short jump addresses). The address of an exception vector table entry is the vector number multiplied by 4. Address of an Entry in EVT = Vector number (Index of EVT) x 4.
All the H8S/2357 exception handler start addresses are stored in a table of 92 longwords. This table is reaching from address 0x00 0000 to 0x00 0016F.
11 Interrupt Priority Registers IPRx to set the Priority Level of 21 Exceptions Sources
Correspondence between interrupt sources and settings in the 11 Interupt Priority Registers IPRx
and ... ?
Two functions: 1) Highest Priority will be at started first (if there more then one with different Priorities) 2) Priority equal or or lower is not accepted (the source is set to held pending)
How handling Interrupts with same Priorities happens at the same time ?
ISR flag clearing: Cleared by reading IRQnF flag when IRQnF = 1, then writing 0 to IRQnF flag. When interrupt exception handling is executed AND low-level detection is set (IRQnSCB = IRQnSCA = 0) AND IRQn input is high (again). When IRQn interrupt exception handling is executed AND falling, rising, or both edge detection is set (IRQnSCB=1 and/or IRQnSCA = 1). These Flags block the re-entry of the own handler !
C Areas
Task: Detect the Direction of Rotation ! Input: one the digital light barrier signal for interrupting the other digital light barrier signal will be polled Output: output clockwise rotation with one LED output counterclockwise rotation with one other LED Control: stop with one manual switched High Level on one Pin
else
direction = 1;
void main(void) { P5DDR= 0x03; /* P5(1) and P5(0) as outputs */ changes independent 0x00; /* initialize Output Clockwise = Countercl. = 0 */ P5DR= of program flow => instruction to compiler SYSCR|= 0x20; /* Interrupt mode 2 */ nothing to optimize IPRA = 0x30; /* Priority 3 for IRQ_0 */ ISCRL = 0x02; /* Rising edge of IRQ_0 */ SHADOW_IH(IRQ_0) = IRQ0hnd; /* Update shadow EVT */ SHADOW_JMP(IRQ_0)= OPCODE_JMP; /* Add the JMP instruction */ and_exr(0xF8); /* Mask level = 0 */ IER |=0x01; /* Enable IRQ_0 interrupt */ do { if (direction == 0) P5DR= 0x02; /* Clockwise */ else P5DR = 0x01; /* Counterclockwise */ /* ... */ /* Execute additional tasks*/ } while(PORT4 & 0x04 == 0); /* while no stop signal */ IER & = 0xF; /* Disable IRQ_0 interrupt */ }
no parameters !
else
direction = 1;
void interrupt pragmamain(void) { P5DDR= 0x03; /* P5(1) and P5(0) as outputs */ P5DR= 0x00; /* initialize Output Clockwise = Countercl. = 0 */ SYSCR|= 0x20; /* Interrupt mode 2 */ IPRA = 0x30; /* Priority 3 for IRQ_0 */ ISCRL = 0x02; /* Rising edge of IRQ_0 */ SHADOW_IH(IRQ_0) = IRQ0hnd; /* Update shadow EVT */ SHADOW_JMP(IRQ_0)= OPCODE_JMP; /* Add the JMP instruction */ and_exr(0xF8); /* Mask level = 0 */ IER |=0x01; /* Enable IRQ_0 interrupt */ do { if (direction == 0) P5DR= 0x02; /* Clockwise */ else P5DR = 0x01; /* Counterclockwise */ /* ... */ /* Execute additional tasks*/ } while(PORT4 & 0x04 == 0); /* while no stop signal */ IER & = 0xF; /* Disable IRQ_0 interrupt */ }
No output at first
else
direction = 1;
void main(void) { P5DDR= 0x03; /* P5(1) and P5(0) as outputs */ P5DR= 0x00; /* initialize Output Clockwise = Countercl. = 0 */ SYSCR|= 0x20; /* Interrupt mode 2 */ IPRA = 0x30; /* Priority 3 for IRQ_0 */ ISCRL = 0x02; /* Rising edge of IRQ_0 */ SHADOW_IH(IRQ_0) = IRQ0hnd; /* Update shadow EVT */ SHADOW_JMP(IRQ_0)= OPCODE_JMP; /* Add the JMP instruction */ and_exr(0xF8); /* Mask level = 0 */ IER |=0x01; /* Enable IRQ_0 interrupt */ do { if (direction == 0) P5DR= 0x02; /* Clockwise */ else P5DR = 0x01; /* Counterclockwise */ /* ... */ /* Execute additional tasks*/ } while(PORT4 & 0x04 == 0); /* while no stop signal */ IER & = 0xFE; /* Disable IRQ_0 interrupt */ }
else
void main(void) { Entry pointer (start address) P5DDR= 0x03; /* P5(1) and P5(0) as outputs */ of a self defined handler P5DR= 0x00; /* initialize Output Clockwise = Countercl. EVT (SVT) in Shadow = 0 */ SYSCR|= 0x20; /* Interrupt mode 2 */ at IRQ_O number ! IPRA = 0x30; /* Priority 3 for IRQ_0 */ write the Opcode of unconditional ISCRL = 0x02; /* Rising edge of IRQ_0 */ Jump Opcode SHADOW_IH(IRQ_0) = IRQ0hnd; /* Update shadow EVT */ before the start addresses SHADOW_JMP(IRQ_0)= OPCODE_JMP; /* Add the JMP instruction */ and_exr(0xF8); /* Mask level = 0 */ IER |=0x01; /* Enable IRQ_0 interrupt */ do { if (direction == 0) P5DR= 0x02; /* Clockwise */ else P5DR = 0x01; /* Counterclockwise 0*/EXR Bit 2, Bit 1, Bit 0 Write in without changes of the other bits ! /* ... */ /* Execute additional tasks*/ } while(PORT4 & 0x04 == 0); /* while no stop signal */ IER & = 0xF; /* Disable IRQ_0 interrupt */ Last step of initialization: Enable the IRQ_0 signal }
else
Test the content of the global buffer void main(void) { P5DDR= 0x03; /* P5(1) and P5(0) as outputs */ P5DR= 0x00; /* initialize Output Clockwise = Countercl. = 0 */ SYSCR|= 0x20; /* Interrupt mode 2 */ IPRA = 0x30; /* Priority 3 for IRQ_0 */ Output P5DR = 0000 0010 (binary) ISCRL = 0x02; /* Rising edge of IRQ_0 */ SHADOW_IH(IRQ_0) = IRQ0hnd; /* Update shadow EVT */ SHADOW_JMP(IRQ_0)= OPCODE_JMP; /* Add the JMP instruction */ Output P5DR = 0000 0001 (binary) and_exr(0xF8); /* Mask level = 0 */ Check one Pin: P4(2) IER |=0x01; /* Enable IRQ_0 interrupt */ if high leave the loop do { else loop again if (direction == 0) P5DR= 0x02; /* Clockwise */ else P5DR = 0x01; /* Counterclockwise */ of using interrupts is Last step disabling /* ... */ /* Execute additional tasks*/ } while(PORT4 & 0x04 == 0); /* while no stop signalprevents not wished handler */ starts for the future IER & = 0xF; /* Disable IRQ_0 interrupt */ (here disable the IRQ_0) }
#include <mpp1.h> volatile unsigned char direction; interrupt void IRQ0hnd(void) { if(PORT4 & 0x01 == 0) direction = 0; }
Start busy waiting & output loop
else
direction = 1;
void main(void) { P5DDR= 0x03; /* P5(1) and P5(0) as outputs */ Test the content of the global buffer P5DR= 0x00; /* initialize Output Clockwise = Countercl. = 0 */ SYSCR|= 0x20; /* Interrupt mode 2 */ IPRA = 0x30; /* Priority 3 for IRQ_0 */ Output P5DR = 0000 0010 (binary) ISCRL = 0x02; /* Rising edge of IRQ_0 */ Output SHADOW_IH(IRQ_0) = IRQ0hnd; /* Update shadow EVT */ P5DR = 0000 0001 (binary) SHADOW_JMP(IRQ_0)= OPCODE_JMP; /* Add the JMP instruction */ Check one Pin: P4(2) and_exr(0xF8); /* Mask level = 0 */ if high leave the loop else loop again IER |=0x01; /* Enable IRQ_0 interrupt */ do { if (direction == 0) P5DR= 0x02; /* Clockwise */ else P5DR = 0x01; /* Counterclockwise */ /* ... */ /* Execute additional tasks*/ Last step of using interrupts is disabling } while(PORT4 & 0x04 == 0); /* while no stop signal */
(here disable the IRQ_0)
else
direction = 1;
void main(void) { P5DDR= 0x03; /* P5(1) and P5(0) as outputs */ P5DR= 0x00; /* initialize Output Clockwise = Countercl. = 0 */ SYSCR|= 0x20; /* Interrupt mode 2 */ IPRA = 0x30; /* Priority 3 for IRQ_0 */ ISCRL = 0x02; /* Rising edge of IRQ_0 */ SHADOW_IH(IRQ_0) = IRQ0hnd; /* Update shadow EVT */ SHADOW_JMP(IRQ_0)= OPCODE_JMP; /* Add the JMP instruction */ and_exr(0xF8); /* Mask level = 0 */ IER |=0x01; /* Enable IRQ_0 interrupt */ do { if (direction == 0) P5DR= 0x02; /* Clockwise */ else P5DR = 0x01; /* Counterclockwise */ /* ... */ /* Execute additional tasks*/ } while(PORT4 & 0x04 == 0); /* while no stop signal */ IER & = 0xF; /* Disable IRQ_0 interrupt */ }
Dont modify any general purpose register CPU pushes no registers automatically for interrupts ! Assembler: Push the needed registers
(and pop them at end - under all circumstances)
C: Use local Variables only if really needed (Interrupt latency time !!) Keep Handlers short ! Avoid Nested Interrupts ! => Priority /Level change in Handler could be dangerous Dont forget Re-enable or Unmask Interrupts !!! Assembler : Use the proper Return instruction RTE => NOT RTS !! Stop Interrupts if not more in use