An3496 Nested Interrupt HCS08
An3496 Nested Interrupt HCS08
An3496 Nested Interrupt HCS08
Rev.0, 07/2007
Application Note
1 Non-Nested Interrupts
1.1 Interrupts
If an event occurs in an interrupt enabled source, an associated read-only status flag is set, but the CPU
does not respond unless these two conditions are both met.
• Local interrupt mask is a logic 1 to enable the interrupt
• The I bit in the condition code register (CCR) is logic 0 to allow interrupts
The global interrupt mask (I bit) in the CCR is initially set after reset. It screens all maskable interrupt
sources. This allows the user program to initialize the stack pointer and perform other system setup before
clearing the I bit to allow the CPU to respond to interrupts. Figure 1 shows the I bit in CCR.
Carry
Zero
Negative
Interrupt Mask
When the CPU receives a qualified interrupt request, it completes the current instruction before responding
to the interrupt. The interrupt processing process is:
1. Saves the CPU registers to the stack.
2. Sets the I bit in the CCR to mask new interrupts.
3. Fetches the interrupt vector for the highest priority interrupt that is currently pending.
4. Fills the instruction queue with the first three bytes of program information starting from the
address fetched from the interrupt vector locations.
While the CPU responds to the interrupt, the I bit is automatically set to avoid another interrupt from
interrupting the ISR (this is called nesting of interrupts). Normally, the I bit is restored to 0 when the CCR
is restored from the value that was stacked on entry to the ISR.
In rare cases, the I bit may be cleared in an ISR (after clearing the status flag that generated the interrupt)
so other interrupts can be serviced before the first service routine is finished. This practice is not
recommended because it leads to subtle program errors that are difficult to debug.
5 1 CCR
4 2 A
3 3 X
2 4 PC HIGH
1 5 PC LOW
Stacking Order
Toward Higher Address
When an RTI instruction is executed, these values are recovered from the stack in reverse order. As part
of the RTI sequence, the CPU fills the instruction pipeline by reading three bytes of program information,
which start from the PC address that is just recovered from the stack.
Low-Priority ISR
Main Loop
Time
High-Priority ISR
Low-Priority ISR
Main Loop
Time
In Figure 5, a series of interrupts occurs by order 2, 1, 4, 1, 3, and 2. These interrupts are sorted by the
scheduler and executed in the order of 1, 1, 2, 2, 3, and 4 via the scheduler.
Priority Arbiter
2 1 4 1 3 2 1 1 2 2 3 4
Priority 2 Queue
Priority 3 Queue
Priority 4 Queue
Preemptive Scheduler
If a high-priority interrupt occurs when a low-priority ISR is in execution, the scheduler lets the
high-priority ISR preempt the CPU resource except a higher priority interrupt occurs during scheduling.
The low-priority ISR will be executed after the high-priority ISR is completed. This action ensures that
more emergent interrupt is executed prior to the lesser one and allows the preemption operation; therefore,
this is called preemption system. If an OS has this mechanism, it is called preemption OS.
If a low-priority interrupt occurs when a high-priority ISR is in execution, the scheduler will continue
executing the high-priority ISR. The low-priority interrupt will be pended and kept in the queue until the
high-priority ISR is completed. This mechanism ensures that high-priority ISR will be executed earlier
than the low-priority interrupt.
link
lock
mask
func
The member link is a pointer pointing to the next interrupt object. Because this is a queue system, a single
link list is used to make queue accessible. In the single link list, every node has a pointer pointing to the
next object, by which the scheduler can use a first-in-first-out (FIFO) system easily. Furthermore, the
pointer points to the interrupt object with the same priority.
The member lock is a flag to identify if the interrupt object is put in the queue or not. After initialization,
this flag is set as 0xff. When this object is put into the queue, the flag is set as 0x00. When the object leaves
the queue, the flag is set as 0xff again.
The member mask is a variable to identify the priority of the interrupt object. It equals to priority powers
of number two. This means the mask will be set by 1 if the priority is 0. It is used to make a comparison
in scheduling.
The member func is function pointer to the dispatch function. If an interrupt object is selected to be
executed, the scheduler brings the program to a certain address by this function pointer. This function has
no input parameters or return value.
Priority X Head 1st Interrupt 2nd Interrupt (N-1)th Interrupt Nth Interrupt
Queue 0
link link link link link
Queue 1
tail lock lock lock lock
Queue N
N Pended Interrupts
Figure 7. Pended Interrupt Table
INT_sets
X X X X X X X X
INT_rdytab
Queue 2
Queue 3
Queue 4
Queue 5
Queue 6
INT_mask
X X X X X X X X
INT_lock
X X X X X X X X
link link
tail lock
mask
func
As shown in Figure 10, in removing operation, the first interrupt object is removed from the link list. The
link pointer of head is set to the link of the removed interrupt object. If the removed interrupt object is the
last interrupt object in the FIFO queue, the head will be set to initialization state, in which the link pointer
will point to NULL and the tail pointer will point to link.
link link
tail lock
mask
func
2.3 Implementation
The scheduler implementation code is divided into two parts, interrupt post code and interrupt execution
code. The former implements the First-In operation of FIFO queue and the latter implements the first-out
operation of FIFO queue. Figure 11 shows the scheduler work flow. The left is post procedure work flow
and the right is execution procedure work flow.
Yes
Set INT_sets
The Queue Empty?
Reset Queue
Enable Interrupt No
Execute ISR
Yes Scheduler
Interrupted?
No No
All Queue Empty?
Yes Higher ISR No
Interrupted?
Yes
End
End To Execution
Please see Appendix A, “Scheduler Code Lists” for more detailed code implementation.
The variable INT_objtab is a structure table containing all interrupt objects’ information. It must be
defined in short addressing mode scope for quick access. The defined macro INT_OBJ supports a shortcut
to define the table. The following code defines five interrupt objects.
...
INT_objtab:
INT_OBJ KBI_obj
INT_OBJ TPM_obj
INT_OBJ ADC_obj
INT_OBJ TIM_obj
INT_OBJ SCI_obj
INT_OBJEND:
The constant INT_inittab is a structure table that contains the initial map of interrupt objects. It must be
defined in flash memory because the initialization routine copies this information to interrupt objects in
RAM. The macro INT_INI supports a shortcut to define this table. This macro needs these three
parameters:
• The interrupt object name
• The priority of interrupt object
• The service routine of interrupt object
Regarding to this example, the following code presents an approach to define the table,
Example 3. Define Interrupt Object Initial Information
CONST: SECTION
INT_inittab:
INTTABEND:
Example 4 shows a simple way to use the interrupt service routine for a KBI interrupt job.
Example 4. Interrupt Service Routine Definition
; The real interrupt routine, but only INT_dispatch called to trigger the scheduler
KBI_int:
INT_dispatch KBI_obj
RTI ; use return interrupt here
; All jobs are written here, this routine will be called by the scheduler
; after FIFO operations
KBI_isr:
; write the indeed jobs here
...
; return
RTS ; use return subroutine here
3.3 Initialization
All variables used in the scheduler must be initialized before use. The software package supports a function
named INT_init to complete initialization. This function has no parameters or return value. Example 5
shows how to use this function in the program.
Example 5. Scheduler Initialization
_Startup:
JSR INT_init ; Interrupt Scheduler Initialized
4 Performance
The performance is the most important point to the scheduler. Three points restricts the real-time
performance of a tiny system, flash memory, RAM, and time.
Interrupt Object Interrupt Object Flash Memory Scheduler Flash Memory Total Flash Memory
Number Consumptions (Bytes) Consumptions (Bytes) Consumptions (Bytes)
1 13 330 343
2 26 330 356
3 39 330 369
4 52 330 382
5 65 330 395
6 78 330 408
7 91 330 421
8 104 330 434
Interrupt Object Interrupt Object RAM Scheduler RAM Total RAM Consumptions
Number Consumptions (Bytes) Consumptions (Bytes) (Bytes)
1 5 18 23
2 10 18 28
3 15 18 33
4 25 18 38
5 30 18 43
6 35 18 48
7 40 18 53
8 45 18 58
The longest latency of the scheduling is 205 CPU cycles. As a 20 MHz CPU clock system, it produces
about 10 μs latency. This is short enough for a real-time system. However, what we can get is to reduce
the high-priority interrupt latency when a low-priority interrupt routine is being executed. This is a big
improvement in many real-time based systems.
Table 3. Time Consumption
5 Miscellaneous Topics
5.1 Use ISR Not Supporting Scheduler
Programmers can still use pure ISRs that do not support the scheduler in their program. But the pure ISRs
are executed prior to the routines controlled by the scheduler. It is not recommended to enable the interrupt
in the pure ISRs, because it causes trouble.
;*******************************************************************
;* This stationery serves as the framework for a user application. *
;* For a more comprehensive program that demonstrates the more *
;* advanced functionality of this processor, please see the *
;* demonstration applications, located in the examples *
;* subdirectory of the "Freescale CodeWarrior for HC08" program *
;* directory. *
;*******************************************************************
; ******************************************************************
; * THIS CODE IS ONLY INTENDED AS AN EXAMPLE OF CODE FOR THE *
; * CODEWARRIOR COMPILER AND HAS ONLY BEEN GIVEN A MIMIMUM *
; * LEVEL OF TEST. IT IS PROVIDED 'AS SEEN' WITH NO GUARANTEES *
; * AND NO PROMISE OF SUPPORT. *
; ******************************************************************
;*******************************************************************
;*
;* Freescale reserves the right to make changes without further notice to any
;* product herein to improve reliability, function, or design. Freescale does
;* not assume any liability arising out of the application or use of any
;* product, circuit, or software described herein; neither does it convey
;* any license under its patent rights nor the rights of others. Freescale
;* products are not designed, intended, or authorized for use as components
;* in systems intended for surgical implant into the body, or other
;* applications intended to support life, or for any other application in
;* which the failure of the Freescale product could create a situation where
;* personal injury or death may occur. Should Buyer purchase or use Freescale
;* products for any such intended or unauthorized application, Buyer shall
;* indemnify and hold Freescale and its officers, employees, subsidiaries,
;* affiliates, and distributors harmless against all claims costs, damages,
;* and expenses, and reasonable attorney fees arising out of, directly or
;* indirectly, any claim of personal injury or death associated with such
;* unintended or unauthorized use, even if such claim alleges that Freescale
;* was negligent regarding the design or manufacture of the part. Freescale
;* and the Freescale logo* are registered trademarks of Freescale Ltd.
;*
;*******************************************************************
; export symbols
XDEF _Startup, main
; we export both '_Startup' and 'main' as symbols. Either can
; be referenced in the linker .prm file or from C/C++ later on
XREF __SEG_END_SSTACK ; symbol defined by the linker for the end of the stack
;*******************************************************************
;*
;* Macro Definition
;*
;*******************************************************************
MAX_INT_TAB EQU 5
;
; INT_OBJ
; Usage:
; INT_OBJ name,priority,function
; For example:
; INT_OBJ KBI_OBJ,3,KBI_isr
;
INT_OBJ MACRO
; XDEF \1 ; able to be accessed externally
\1:
DS.B INT_OBJ_SIZE
ENDM
INT_INI MACRO
; XREF \3 ; use function externally
\1_:
DCB.B 1,0 ; NULL -> link
DCB.B 1,-1 ; -1 -> lock
DCB.B 1,1 << \2 ; -1 -> mask
DCB.W 1,\3 ; function -> func
ENDM
;
; INT_DISPATCH
; Usage:
; INT_DISPATCH object
INT_dispatch MACRO
PSHH ; H -> stack
PSHX ; X -> stack
ENDM
;
; Left Most Bit Detection , 20 cycles for every calling
; 1xxxxxxx -> 7
; 01xxxxxx -> 6
; 001xxxxx -> 5
; 0001xxxx -> 4
; 00001xxx -> 3
; 000001xx -> 2
; 0000001x -> 1
; 00000001 -> 0
;
LMBD MACRO
\@LMBD:
CMPA #$10 ; #2 , a ?>= 16
BGE \@LMBD_7654 ; #3 , goto 7654
\@LMBD_3210: ; x x x x 3 2 1 0
CMPA #$04 ; #2 , a ?>= 4
BGE \@LMBD_32 ; #3 , goto 32
\@LMBD_10: ; x x x x x x 1 0
CMPA #$02 ; #2 , a ?>= 2
BGE \@LMBD_1 ; #3 , goto 1
\@LMBD_0: ; x x x x x x x 0
CLRA ; #1 , 0 -> A
BRA \@LMBD_exit ; #3 , exit
\@LMBD_1: ; x x x x x x 1 x
LDA #$01 ; #2 , 1 -> A
BRA \@LMBD_exit ; #3 , exit
\@LMBD_32: ; x x x x 3 2 x x
CMPA #$08 ; #2 , a ?>= 8
BGE \@LMBD_3 ; #3 , goto 3
\@LMBD_2: ; x x x x x 2 x x
LDA #$02 ; #2 , 2 -> A
BRA \@LMBD_exit ; #3 , exit
\@LMBD_3: ; x x x x 3 x x x
LDA #$03 ; #2 , 3 -> A
BRA \@LMBD_exit ; #3 , exit
\@LMBD_7654: ; 7 6 5 4 x x x x
CMPA #$40 ; #2 , a ?>= 64
BGE \@LMBD_76 ; #3 , goto 76
\@LMBD_54: ; x x 5 4 x x x x
CMPA #$20 ; #2 , a ?>= 32
BGE \@LMBD_5 ; #3 , goto 5
\@LMBD_4: ; x x x 4 x x x x
LDA #$04 ; #2 , 4 -> A
BRA \@LMBD_exit ; #3 , exit
\@LMBD_5: ; x x 5 x x x x x
LDA #$05 ; #2 , 5 -> A
BRA \@LMBD_exit ; #3 , exit
\@LMBD_76: ; 7 6 x x x x x x
CMPA #$80 ; #2 , a ?>= 128
BGE \@LMBD_7 ; #3 , goto 7
\@LMBD_6: ; x 6 x x x x x x
LDA #$06 ; #2 , 6 -> A
BRA \@LMBD_exit ; #3 , exit
\@LMBD_7: ; 7 x x x x x x x
LDA #$07 ; #2 , 7 -> A
\@LMBD_exit:
ENDM
;*******************************************************************
;*
;* Variable Definition
;*
;*******************************************************************
INT_RDYBEG:
INT_RDYEND:
INT_OBJBEG:
INT_objtab:
INT_OBJ KBI_obj
INT_OBJ TPM_obj
INT_OBJ ADC_obj
INT_OBJ TIM_obj
INT_OBJ SCI_obj
INT_OBJEND:
;*******************************************************************
;*
;* Constant Definition
;*
;*******************************************************************
CONST: SECTION
INTTABBEG:
INT_inittab:
INTTABEND:
;*******************************************************************
;*
;* Hardware Interrupt Entry Definition
;*
;*******************************************************************
ENTRANCE:
KBI_int:
INT_dispatch KBI_obj
RTI
TPM_int:
INT_dispatch TPM_obj
RTI
ADC_int:
INT_dispatch ADC_obj
RTI
TIM_int:
INT_dispatch TIM_obj
RTI
SCI_int:
INT_dispatch SCI_obj
RTI
;*******************************************************************
;*
;* Vector Table Definition
;*
;*******************************************************************
VECTOR_ROM: SECTION
ORG $FFD8
ORG $FFDA
ORG $FFE0
ORG $FFE6
ORG $FFF0
;*******************************************************************
;*
;* Main Entry
;*
;*******************************************************************
; variable/data section
MY_ZEROPAGE: SECTION SHORT ; Insert here your data definition
; code section
MyCode: SECTION
main:
_Startup:
LDHX #__SEG_END_SSTACK ; initialize the stack pointer
TXS
CLI ; enable interrupts
mainLoop:
; Insert your code here
NOP
feed_watchdog
BRA mainLoop
;*******************************************************************
;*
;* ISR definitions
;*
;*******************************************************************
CODE: SECTION
KBI_isr:
; input KBI jobs here
RTS
TPM_isr:
; input TPM jobs here
RTS
ADC_isr:
; input ADC jobs here
RTS
TIM_isr:
; input TIM jobs here
RTS
SCI_isr:
; input SCI jobs here
RTS
;*******************************************************************
;*
;* void INT_init(void)
;*
;*******************************************************************
CODE: SECTION
INT_init:
JSR Global_init ; Gloabal Initialize
RTS ; return
Global_init:
; INT_mask = 1;
; INT_sets = 0;
; INT_lock = -1;
RTS ; return;
Ready_init:
;
; for ( i = 0 ; i < MAX_RDY_TAB ; i++ )
; {
; INT_rdytab[i].link = 0;
; INT_rdytab[i].tail = INT_rdytab[i];
; }
;
Ready_loop:
; INT_rdytab[i].link = 0;
RTS ; return;
; End of Loop
Object_init:
; initialize stack
;
; high address
; INT_objtab low 4
; INT_objtab high 3
; INT_inittab low 2
; INT_inittab high 1
; low address
;
; INT_inittab
Object_loop:
; INT_inittab[i] -> A
AIX #1 ; i++
; A -> INT_inittab[i]
AIX #1 ; i++
; next loop
; uninitialize stack
; return;
RTS ; return;
;*******************************************************************
;*
;* void INT_post(swi)
;* {
;* if (swi->lock == 0)
;* {
;* return;
;* }
;*
;* swi->lock = 0;
;*
;* INT_lock++;
;*
;* INT_mask |= swi->mask;
;*
;* ready->tail.link = swi;
;*
;* ready->tail = swi;
;*
;* if ((INT_mask > INT_sets) || INT_lock)
;* {
;* INT_lock--;
;*
;* return;
;* }
;*
;* INT_exec();
;*
;* return;
;* }
;*
;*******************************************************************
;*******************************************************************
;
; If swi posted, 6 cycles
; If swi not posted but not executed, 95 cycles
; If swi not posted and executed, 233 cycles
;
;*******************************************************************
CODE: SECTION
INT_post:
; if (swi->lock == 0)
; 9 cycles
; {
; return;
; }
; 6 cycles
post:
; swi->lock == 0;
; 5 cycles
; INT_lock++;
; 5 cycles
; Disable Interrupts
; 1 cycle
; INT_sets |= swi->mask;
; 9 cycles
; priority = lmbd(mask);
; 23 cycles
; ready = INT_rdytab[priority];
; 3 cycles
; push(swi);
; 2 cycles
; push(ready);
; 2 cycles
; ready->tail->link = swi;
; ready->tail = swi;
; 18 cycles
; Enable Interrupts
; 1 cycle
; INT_exec();
; 3 cycles
;*******************************************************************
;*
;* void INT_exec(void)
;* {
;* for (;;)
;* {
;*
;* Push(INT_mask);
;*
;* priority = lmbd(1,INT_sets);
;*
;* rdytab = &SWI_D_rdytab[priority];
;*
;* swi = (INT_Obj *)ready->link;
;*
;* swi->lock = -1;
;*
;* rdytab->link = swi->link;
;*
;* if(swi->link == NULL)
;* {
;* SWI_D_curset ^= swi->mask;
;*
;* rdytab->tail = (PUINT)rdytab;
;*
;* rdytab->link = (PUINT)NULL;
;*
;* }
;* else
;* {
;* swi->link = NULL;
;* }
;*
;* INT_mask <<= 1;
;*
;* INT_lock = -1;
;*
;* (*func)();
;*
;* INT_lock = 0;
;*
;* INT_mask = Pop();
;*
;* if (INT_mask > INT_sets)
;* {
;* break;
;* }
;* }
;*
;* return;
;* }
;*
;*******************************************************************
; INT_exec();
INT_exec:
; INT_lock++;
; 5
; INT_run();
INT_run:
; push(INT_mask);
; 5 cycles
; priority = lmbd(INT_sets);
; 23 cycles
; swi->lock = -1;
; 5 cycles
; ready->link = swi->link;
; 9 cycles
; if (ready->link == 0)
; {
; ready->tail = (PUCHAR)ready;
; ready->link = (PUCHAR)0;
; INT_sets ^= swi->mask;
; }
; 26 cycles
; else
; {
; swi->link = 0;
; }
; 8 cycles
not_empty:
dispatch:
; pop();
; 2 cycles
; INT_lock = -1;
; 4 cycles
; (* func)();
; 20 cycles
PSHH ; push(H) #2
PSHX ; push(X) #2
LDHX FUNC,X ; swi->func -> H:X #5
JSR ,X ; (* func)(); #5
PULX ; X = pop(); #3
PULH ; H = pop(); #3
; INT_lock = 0;
; 4 cycles
; {
; break;
; }
; 3 cycles
; INT_lock--;
; 5 cycles
; return;
; 6 cycles
INT_post_exit:
RTS ; interrupt return #6 , total 143 cycles
;*******************************************************************
;* End Of File
;*******************************************************************
Web Support:
http://www.freescale.com/support Freescale Semiconductor reserves the right to make changes without further notice to
any products herein. Freescale Semiconductor makes no warranty, representation or
USA/Europe or Locations Not Listed: guarantee regarding the suitability of its products for any particular purpose, nor does
Freescale Semiconductor, Inc. Freescale Semiconductor assume any liability arising out of the application or use of any
Technical Information Center, EL516 product or circuit, and specifically disclaims any and all liability, including without
2100 East Elliot Road
Tempe, Arizona 85284 limitation consequential or incidental damages. “Typical” parameters that may be
+1-800-521-6274 or +1-480-768-2130 provided in Freescale Semiconductor data sheets and/or specifications can and do vary
www.freescale.com/support in different applications and actual performance may vary over time. All operating
parameters, including “Typicals”, must be validated for each customer application by
Europe, Middle East, and Africa: customer’s technical experts. Freescale Semiconductor does not convey any license
Freescale Halbleiter Deutschland GmbH under its patent rights nor the rights of others. Freescale Semiconductor products are
Technical Information Center not designed, intended, or authorized for use as components in systems intended for
Schatzbogen 7 surgical implant into the body, or other applications intended to support or sustain life,
81829 Muenchen, Germany
+44 1296 380 456 (English) or for any other application in which the failure of the Freescale Semiconductor product
+46 8 52200080 (English) could create a situation where personal injury or death may occur. Should Buyer
+49 89 92103 559 (German) purchase or use Freescale Semiconductor products for any such unintended or
+33 1 69 35 48 48 (French) unauthorized application, Buyer shall indemnify and hold Freescale Semiconductor and
www.freescale.com/support its officers, employees, subsidiaries, affiliates, and distributors harmless against all
claims, costs, damages, and expenses, and reasonable attorney fees arising out of,
Japan: directly or indirectly, any claim of personal injury or death associated with such
Freescale Semiconductor Japan Ltd. unintended or unauthorized use, even if such claim alleges that Freescale
Headquarters
ARCO Tower 15F Semiconductor was negligent regarding the design or manufacture of the part.
1-8-1, Shimo-Meguro, Meguro-ku,
Tokyo 153-0064 RoHS-compliant and/or Pb-free versions of Freescale products have the functionality
Japan and electrical characteristics as their non-RoHS-compliant and/or non-Pb-free
0120 191014 or +81 3 5437 9125
[email protected] counterparts. For further information, see http://www.freescale.com or contact your
Freescale sales representative.
Asia/Pacific:
Freescale Semiconductor Hong Kong Ltd. For information on Freescale’s Environmental Products program, go to
Technical Information Center
2 Dai King Street http://www.freescale.com/epp.
Tai Po Industrial Estate
Tai Po, N.T., Hong Kong Freescale™ and the Freescale logo are trademarks of Freescale Semiconductor, Inc.
+800 2666 8080 All other product or service names are the property of their respective owners.
[email protected]
© Freescale Semiconductor, Inc. 2007. All rights reserved.
For Literature Requests Only:
Freescale Semiconductor Literature Distribution Center
P.O. Box 5405
Denver, Colorado 80217
1-800-441-2447 or 303-675-2140
Fax: 303-675-2150
[email protected]