65C22 Timer1 in free run mode and interrupts.

Programming the 6502 microprocessor and its relatives in assembly and other languages.
Post Reply
DRG
Posts: 66
Joined: 19 Sep 2021

65C22 Timer1 in free run mode and interrupts.

Post by DRG »

In my ongoing exploits to develop my understand of 65C02 related hardware and software (which is an enjoyable pastime in itself!), I've been improving my routines for the Hitachi 20x4 LCD HD44780U module which is connected in 4-bit mode to PORTB of the 65C22. As part of my approach, I had already created an 80 byte buffer in RAM which allows the LCD to act as a pseudo memory mapped device. I would make multiple writes to the buffer then call a subroutine to update the LCD with the buffer contents which also took into account the non-linear mapping of the LCD display. This way, the "memory mapped display" in RAM was contiguous which made for an easier programming model.

Then I came across this forum post which made me think of emulating the same interrupt driven approach to LCD updating. This would be a nice project as I hadn't done any real interrupt handling code. After some initial teething and troubleshooting, it worked. I am aware, however, this may be despite my coding rather than because of it. So, I'd be grateful if you can comment on my code and highlight where improvements could be made or where best practices should be adopted.

Basic concept is to get Timer1 to generate an interrupt every 10 ms and to count 16 of those interrupts, at which point, the LCD will be updated with the buffer contents, everything reset and the process to start again. Using my logic analyser, I can see that IRQB is indeed going low every 10 ms and that data burst activity to the LCD in 4-bit mode is lasting around 4.8 ms (I'd pre-calculated that, according to the HD44780U datasheet, this would take a minimum of 3.1 ms for LCD execution time alone). The whole cycle takes around 160.04 ms, equating to an LCD refresh rate of 6.25 Hz. The MPU load for doing this equates to around 3% (I think, as I worked it out like this -> 4.8/160 = 3.0% - is that the right way to do it?). My phi2 clock runs at 3.6864 MHz. I've not included the code that does the LCD/buffer transfer but I can post it if required.

Code: Select all

                .org $0480
start_0480:     ; Set up Timer1 on 65C22 VIA in free run mode to generate an interrupt every 10ms (0.01s).
                lda #$10                                        ; Sets the counter to track number of interrupts (16 no.). 
                sta TIMER1_COUNT + 1                            ; Hold this as a constant to reset to. Like a latch.
                sta TIMER1_COUNT                                ; This will decrement then be reset with the above value.
                lda #%01000000
                sta ACR                                         ; Places Timer1 into continuous interrupts (free run mode).
                lda #$FE                                        ; 0.01s @ 3.6864 Mhz (-2 cycles) = 36,862 ($8FFE).
                sta T1LL
                lda #$8F
                sta T1LH
                lda #$FE                                        ; 0.01s @ 3.6864 Mhz (-2 cycles) = 36,862 ($8FFE).
                sta T1CL
                lda #$8F
                sta T1CH

                lda #%11000000                                  ; Sets interrupts for Timer1.
                sta IER

                cli                                             ; Clear Interrupt Disable i.e. enable interrupts.
                rts

                
; ---------------------------------
; Includes
; ---------------------------------

                .include 4-bit_lcd.h.a65

; ---------------------------------
; Interrupt Handler(s)    
; ---------------------------------

                .org $0700
irq:
                pha                                             ; A, X & Y -> stack.
                phx
                phy
                lda T1CL                                        ; Clears the interrupt flag just by reading from T1CL.

                dec TIMER1_COUNT                                ; Decrement counter.
                bne irq_exit                                    ; Are we at Zero? No -> nothing more to do, so exit.

                ; We have counted the number of interrputs required at this point.
                lda TIMER1_COUNT + 1                            ; Get the reset value.
                sta TIMER1_COUNT                                ; Update.

                jsr lcd_prbuff                                  ; Update the lcd display with the contents of the lcd buffer.

irq_exit:
                ply
                plx
                pla                                             ; Y, X & A <- stack.
                rti
Thanks.

Dave
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: 65C22 Timer1 in free run mode and interrupts.

Post by GARTHWILSON »

What I have found, at least for some brands of '22, is that you have to write to the counters first to get T1 going, and then you can write to the latches after that.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Post Reply