; ; 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: ; ; TOC0 - Timer output compare 0 is used to generate ; a square wave ; ; RTI - The Real Time Interrupt is used to vary ; the width of the square wave ; ; ; History: ; 09-15-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 ;****************************************************************** ;****************************************************************** ; 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 * ; This defines a block of tRtiDelay rmb 2 ; WORD sized variables that tEndOfTimers equ * ; interrupt handler wPeriodIncrement rmb 2 CHANGE_WAVE_INCR equ 50 PRINT_RATE equ 2000 ; Print every 2 seconds ;****************************************************************** ; 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 #strProgStart jsr outstr ; ; Enable the RTI interrupts. The $81 enables interrupts, and sets ; the period for the interrupts to 1.024 milliseconds on a system ; with a 8MHZ ECLOCK ; ldaa #$81 staa RTICTL ; ; Setup timer system ; ldaa #$80 ; Timer Enable staa TSCR ldaa #$01 ; Set to toggle bit on compare staa TCTL2 staa TIOS ; Set TC0 to be an output compare staa TMSK1 ldd #8192 ; Initial pulse width is 8192 clocks wide std wPeriodIncrement ; On a 8MHZ ECLOCK, that would be a pulse std TC0 ; width of approximately 1.024ms. There are ; two changes per cycle, which means a full ; cycle is 2.048ms. 1/.002048 is in the ; 488hz neighborhood, which is is a good ; frequency to start with on a peizo speaker ; ; Initialization is now complete. We can now enable interrupts! ; cli MainLoop: ldd #PRINT_RATE ; Delay approx 2 seconds std tRtiDelay MinorLoop: ; ; Insert whatever code you would like to put here. Once it is ; done, the code below will execute. Only if the countdown ; timer tRtiDelay is zero will it print then call the main ; loop. ; jsr getchar cmpa #'d' bne ML5 jsr putchar ldd wPeriodIncrement addd #CHANGE_WAVE_INCR std wPeriodIncrement bra ML6 ML5 cmpa #'u' bne ML6 jsr putchar ldd wPeriodIncrement subd #CHANGE_WAVE_INCR std wPeriodIncrement ML6 tst tRtiDelay bne MinorLoop ldx #strProgRunning jsr outstr bra MainLoop ;****************************************************************** ; The timer interrupt routine for TOC0 ; int_Timer_0 ; ; First thing, acknowledge the interrupt ; bset TFLG1,#$01 ; ; TC0 holds the 16 bit value that compared. Add the ; period to TC0 derives the next value to that needs an ; interrupt ; ldd TC0 addd wPeriodIncrement std TC0 rti ;****************************************************************** ; 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 RTI_END rti ;*************************************** ; Test program strings ; strProgStart: db 13,10 fcc "Timer Interrupt Routine Started" db 13,10,0 strProgRunning fcc "Still Running The Program!" db 13,10 fcc "Notice how the frequency doesn't change even while this is printing is" db 13,10 fcc "being done. The printing takes a very long time to process, but the" db 13,10 fcc "interrupt driven routines are doing a nice job of handling the work in" db 13,10 fcc "the background!" 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 ; ; getchar retrieves a character from serial port 0 ; Returns with character in A ; getchar ldaa #0 brclr SC0SR1,#$20,getchar2 ldaa SC0DRL getchar2 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 ;************************************************************************* ; ; 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 int_Timer_0 _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