; ; intr.asm - Interrupt source code file ; ; This file contains several useful interrupt routines that ; you might find useful to adapt. These routines are written ; for the 68HC812A4, but should also work on most versions ; of the 68HC12. ; ; Interrupts currently serviced include: ; RTI - Real Time Interrupt - includes example of how a ; countdown timer mechanism can be established ; and how a set of routines can be called on a ; regular basis without needing your main code ; to poll for appropriate times to call. This ; example implements a 'heartbeat' on PORTA bit 0 ; ; ; History: ; 10-01-98 KevinRo@nwlink.com ; Initial version written. ; ; ; The following are port definitions. You can save them to a ; file and use them in your own programs. I recommend using a ; file called hc12regs.inc that you can include with the following ; ; #include hc32regs.inc ; ; I stuck them into this file to keep the number of files ; low ; ;****************************************************************** PORTA equ $00 ;Port A Data PORTB equ $01 ;Port B Data DDRA equ $02 ;Port A Data Direction DDRB equ $03 ;Port B Data Direction PORTC equ $04 ;Port C Data PORTD equ $05 ;Port D Data DDRC equ $06 ;Port C Data Direction DDRD equ $07 ;Port D Data Direction PORTE equ $08 ;Port E Data DDRE equ $09 ;Port E Data Direction PEAR equ $0A ;Port E Assigment MODE equ $0B ;Mode PUCR equ $0C ;Pull Up Control RDRIV equ $0D ;Reduced Drive INITRM equ $10 ;RAM Position INITRG equ $11 ;Register Position INITEE equ $12 ;EEPROM Position MISC equ $13 RTICTL equ $14 ;Real Time Interrupt Control RTIFLG equ $15 ;Real Time Interrupt Flag COPCTL equ $16 ;COP Control COPRST equ $17 ;Arm/Reset COP Timer ITST0 equ $18 ;Internal Test 0 ITST1 equ $19 ;Internal Test 1 ITST2 equ $1A ;Internal Test 2 ITST3 equ $1B ;Internal Test 3 INTCR equ $1E ;Interrupt Control HPRIO equ $1F ;Highest Priority Interrupt KWIED equ $20 ;Key Wakeup Port D Interrupt Enable KWIFD equ $21 ;Key Wakeup Port D Flag RES22 equ $22 ;Reserved on 812A4 RES23 equ $23 ;Reserved on 812A4 PORTH equ $24 ;Port H Data DDRH equ $25 ;Port H Data Direction KWIEH equ $26 ;Key Wakeup Port H Interrupt Enable KWIFH equ $27 ;Key Wakeup Port H Flag PORTJ equ $28 ;Port J Data DDRJ equ $29 ;Port J Data Direction KWIEJ equ $2A ;Key Wakeup Port J Interrupt Enable KWIFJ equ $2B ;Key Wakeup Port J Flag KPOLJ equ $2C ;Key Wakeup Port J Polarity PUPSJ equ $2D ;Key Wakeup Port J Pull-up / Pull-down Select PULEJ equ $2E ;Key Wakeup Port J Pull-up / Pull-down Enable RES2F equ $2F ;Reserved on 812A4 PORTF equ $30 ;Port F Data PORTG equ $31 ;Port G Data DDRF equ $32 ;Port F Data Direction DDRG equ $33 ;Port G Data Direction DPAGE equ $34 ;Data Page PPAGE equ $35 ;Program Page EPAGE equ $36 ;Extra Page WINDEF equ $37 ;Window Definition MXAR equ $38 ;Memory Expansion Assignment RES39 equ $39 ;Reserved on 812A4 RES3A equ $3A ;Reserved on 812A4 RES3B equ $3B ;Reserved on 812A4 CSCTL0 equ $3C ;Chip Select Control 0 CSCTL1 equ $3D ;Chip Select Control 1 CSSTR0 equ $3E ;Chip Select Stretch 0 CSSTR1 equ $3F ;Chip Select Stretch 1 LDV equ $40 ;Loop Divider LDVL equ $41 ;Loop Divider Low Byte RDV equ $42 ;Reference Divider RVDL equ $43 ;Reference Divider Low Byte CLKCTL equ $47 ;Clock Control ; $48-$5F are all reserved on the 812A4 ATDCTL0 equ $60 ;Reserved ATDCTL1 equ $61 ;Reserved ATDCTL2 equ $62 ;ATD Control 2 ATDCTL3 equ $63 ;ATD Control 3 ATDCTL4 equ $64 ;ATD Control 4 ATDCTL5 equ $65 ;ATD Control 5 ATDSTAT equ $66 ;ATD Status ATDSTATL equ $67 ;ATD Status Low Byte ATDTEST equ $68 ;ATD Test ATDTESTL equ $69 ;ATD Test Low Byte PORTAD equ $6F ;Port AD Data Input ; $6A - $6E are all reserved on the 812A4 ADR0 equ $70 ;A/D Converter Result0 RES71 equ $71 ;Reserved on 812A4 ADR1 equ $72 ;A/D Converter Result 1 RES73 equ $73 ;Reserved on 812A4 ADR2 equ $74 ;A/D Converter Result 2 RES75 equ $75 ;Reserved on 812A4 ADR3 equ $76 ;A/D Converter Result 3 RES77 equ $77 ;Reserved on 812A4 ADR4 equ $78 ;A/D Converter Result 4 RES79 equ $79 ;Reserved on 812A4 ADR5 equ $7A ;A/D Converter Result 5 RES7B equ $7B ;Reserved on 812A4 ADR6 equ $7C ;A/D Converter Result 6 RES7D equ $7D ;Reserved on 812A4 ADR7 equ $7E ;A/D Converter Result 7 RES7F equ $7D ;Reserved on 812A4 TIOS equ $80 ;Timer Input Capture/Output Compare Select CFORC equ $81 ;Timer Compare Force OC7M equ $82 ;Output Compare 7 Mask OC7D equ $83 ;Output Compare 7 Data TCNT equ $84 ;Timer Counter TCNTL equ $85 ;Timer Counter Low Byte TSCR equ $86 ;Timer System Control TQCR equ $87 ;Reserved TCTL1 equ $88 ;Timer Control 1 TCTL2 equ $89 ;Timer Control 2 TCTL3 equ $8A ;Timer Control 3 TCTL4 equ $8B ;Timer Control 4 TMSK1 equ $8C ;Timer Interrupt Mask 1 TMSK2 equ $8D ;Timer Interrupt Mask 2 TFLG1 equ $8E ;Timer Interrupt Flag 1 TFLG2 equ $8F ;Timer Interrupt Flag 2 TC0 equ $90 ;TIC/TOC 0 TC0L equ $91 ;TIC/TOC 0 Low Byte TC1 equ $92 ;TIC/TOC 1 TC1L equ $93 ;TIC/TOC 1 Low Byte TC2 equ $94 ;TIC/TOC 2 TC2L equ $95 ;TIC/TOC 2 Low Byte TC3 equ $96 ;TIC/TOC 3 TC3L equ $97 ;TIC/TOC 3 Low TC4 equ $98 ;TIC/TOC 4 TC4L equ $99 ;TIC/TOC 4 Low Byte TC5 equ $9A ;TIC/TOC 5 TC5L equ $9B ;TIC/TOC 5 Low Byte TC6 equ $9C ;TIC/TOC 6 TC6L equ $9D ;TIC/TOC 6 Low Byte TC7 equ $9E ;TIC/TOC 7 TC7L equ $9F ;TIC/TOC 7 Low Byte PACTL equ $A0 ;Pulse Accumulator Control PAFLG equ $A1 ;Pulse Accumulator Flag PACNT equ $A2 ;Pulse Accumulator Count PACNTL equ $A3 ;Pulse Accumulator Counter Low Byte ; $A4 - AC are reserved on 812A4 TIMTST equ $AD ;Timer Test PORTT equ $AE ;Timer Port T Data DDRT equ $AF ;Timer Port T Data Direction ; $B0 - BF are reserved on 812A4 SC0BD equ $C0 ;SCI 0 Baud Rate SC0BDL equ $C1 ;SCI 0 Baud Rate Low Byte SC0CR1 equ $C2 ;SCI 0 Control 1 SC0CR2 equ $C3 ;SCI 0 Control 2 SC0SR1 equ $C4 ;SCI 0 Status 1 SC0SR2 equ $C5 ;SCI 0 Status 2 SC0DR equ $C6 ;SCI 0 Data SC0DRL equ $C7 ;SCI 0 Data Low Byte SC1BD equ $C8 ;SCI 1 Baud Rate SC1BDL equ $C9 ;SCI 1 Baud Rate Low Byte SC1CR1 equ $CA ;SCI 1 Control 1 SC1CR2 equ $CB ;SCI 1 Control 2 SC1SR1 equ $CC ;SCI 1 Status 1 SC1SR2 equ $CD ;SCI 1 Status 2 SC1DR equ $CE ;SCI 1 Data SC1DRL equ $CF ;SCI 1 Data Low Byte SP0CR1 equ $D0 ;SPI 0 Control 1 SP0CR2 equ $D1 ;SPI 0 Control 2 SP0BR equ $D2 ;SPI 0 Baud Rate SP0SR equ $D3 ;SPI 0 Status SP0DR equ $D5 ;SPI 0 Data RESD4 equ $D4 ;Reserved on 812A4 PORTS equ $D6 ;Port S Data DDRS equ $D7 ;Port S Data Direction ; $D8 - EF are reserved on 812A4 EEMCR equ $F0 ;EEPROM Module Configuration EEPROT equ $F1 ;EEPROM Block Protect EETST equ $F2 ;EEPROM Test EEPROG equ $F3 ;EEPROM Control ; $F4 - $1FF are reserved ;****************************************************************** HEART_BEAT_RATE equ 1000 ;****************************************************************** ; Declaring some storage space. Using the 'ds' instruction allocates ; the bytes, but doesn't try to initialize them like the 'db' or 'dw' ; instructions. This is mighty important since you don't want to ; initialize RAM variables! If you do, they will not be valid when ; you try to use them after power cycling. Worse yet, if you do ; and you are trying to program Flash EEPROM, you will crash the ; little RAM based program that writes the Flash! ; ; RAM is mapped from $0800 - $0BFF ; ORG $0800 tStartOfTimers equ * tRtiDelay rmb 2 tHeartBeat rmb 2 tEndOfTimers equ * ;****************************************************************** ; The ORG statement is set to $F000, which is the default starting ; address for the 4k of EEPROM on the 68HC812A4. ; ORG $F000 Start: ; ; Set the top of the stack. Using $0C00 is OK, because the 68HC12 ; decrements BEFORE pushing. Many people set it to $BFF, but having ; a word aligned stack is better. ; lds #$0C00 ; ; The 68HC12, unlike the 68HC11, defaults with the COP turned on. ; The COP is a timer function that requires the software to ; periodically write a specific pair of values to a register. If ; this isn't done in time, the processor will reset every 1.04 ; seconds or so. ; ; For this module, the COP is going to be disabled. The following ; line disables the COP by setting the COP Watchdog Rate to zero ; clr COPCTL ; Store zero in COP Control Register jsr serial_init ldx #ProgStart jsr outstr ; ; Enable the RTI interrupts. The $81 enables interrupts, and sets ; the period for the interrupts to 1.024 milliseconds ; ldaa #$81 staa RTICTL ; ; Initialize the timers used in this example ; ldd #HEART_BEAT_RATE std tHeartBeat ldaa #$01 staa DDRA ; ; Initialization is now complete. We can now enable interrupts! ; cli MainLoop: ldd #2000 ; Delay approx 2 seconds std tRtiDelay MinorLoop: tst tRtiDelay bne MinorLoop ldaa #'R' jsr putchar bra MainLoop ;*************************************** ; Test program strings ; ProgStart: fcc "Interrupt Test Program Started" db 13,10,0 CRLF: db 13,10,0 ;************************************************************************* ; ; Some serial port routines. serial_init: ; ; To use the serial port, one must set the baud rate. The 68HC12 ; is capable of speeds up to 38400. Here, we set it to 19200 ; baud. The value here is a 16 bit divisor. ; ldd #26 ; Value from Baud Rate Generation Table std SC0BD ldaa #$0C ; Enable transceiver staa SC0CR2 rts ; ; putchar outputs a character to serial port 0 ; Call with character in register A ; putchar: brclr SC0SR1, #$80 putchar staa SC0DRL rts ; ; ; outstr outputs a NULL terminated character string ; On input, register X points to string in memory. Note the use of ; the index auto post increment addressing mode! ; outstr0: jsr putchar outstr: ldaa 1,X+ ; Auto increment X by one bne outstr0 ; If not a NULL character, send it rts ; ; HeartBeat is called on a regular basis by the RTI routine. Its function ; is to toggle the low bit on the A port, to indicate that the program is ; still running. ; HeartBeat ldd #HEART_BEAT_RATE ; Setup for the next beat std tHeartBeat ldaa #$01 eora PORTA ; Toggle the heartbeat bit staa PORTA ; ; Note that heartbeat is called from another function. ; Though it is called during an interrupt, we need to ; use the RTS function since we aren't trying to restore ; an interrupt state on exit ; rts ; ; The Real Time Interrupt is serviced by walking the list of timers ; found starting at tStartOfTimers. For each timer, which is a word ; in length, decrement the counter by one unless the timer is already ; zero ; int_Real_Time_Int bset RTIFLG,#$80 ; Acknowledge Interrupt ldx #tStartOfTimers RTI_LOOP cpx #tEndOfTimers beq RTI_ROUTINES ldd 2,x+ ; Notice the autoincrement beq RTI_LOOP subd #1 ; Decrement the value by 1 std -2,x ; Store at the previous location bra RTI_LOOP ; ; Some of the timers represent routines that need to be called ; on a regular basis. We have already counted down these ; timers. Now, for each timer that is zero, call the subroutine ; that handles the function. This is very useful if you need ; to have some function handled on a regular basis ; RTI_ROUTINES ldd tHeartBeat bne RTI_END jsr HeartBeat RTI_END rti ;************************************************************************* ; ; Interrupt vectors. When the CPU starts, or encounters an interrupt, it ; will read this table to determine where to jump to in the code. ; ; Note: If you are using the 5G18E pre production mask, there was an ; error in the addressing of the interrupt vectors. Get a newer part, as ; there were plenty of other errors on that chip as well. ; vec_Unexpected: bgnd ldx _int_Reset jmp [0,x] ; Must start at this specific address ORG $FFCE _int_Key_Wakeup_H dw vec_Unexpected _int_Key_Wakeup_J dw vec_Unexpected _int_ATD dw vec_Unexpected _int_SCI1 dw vec_Unexpected _int_SCI0 dw vec_Unexpected _int_SPI_STC dw vec_Unexpected _int_PAIE dw vec_Unexpected _int_PAO dw vec_Unexpected _int_Timer_Overflow dw vec_Unexpected _int_Timer_7 dw vec_Unexpected _int_Timer_6 dw vec_Unexpected _int_Timer_5 dw vec_Unexpected _int_Timer_4 dw vec_Unexpected _int_Timer_3 dw vec_Unexpected _int_Timer_2 dw vec_Unexpected _int_Timer_1 dw vec_Unexpected _int_Timer_0 dw vec_Unexpected _int_Real_Time_Int dw int_Real_Time_Int _int_IRQ_Key_Wakeup_D dw vec_Unexpected _int_XIRQ dw vec_Unexpected _int_SWI dw vec_Unexpected _int_UIT dw vec_Unexpected _int_COP_Failure dw vec_Unexpected _int_COP_Clock_Monitor_Fail dw vec_Unexpected _int_Reset dw Start end