@Chromatix
Quote:
I suspect he's trying to learn by doing, rather than by following a recipe.
Indeed I am. I just began writing this MIDI player by reading the MIDI implementation. It worked out very quickly and very well, but I must admit that I have a hard time to make sense of what happens when the code in the interrupt routine takes more time than it’s given for one interrupt period. Especially when there is more than one interrupt involved.
Quote:
The interrupt mask register on your UART is not a read-modify-write register...
OK, that’s what BDD also said about the MRxx registers, I just have forgotten to implement it. However, that made no difference. It still loses events and stalls.
Quote:
You should be resetting the timer interrupt very soon after entering the timer ISR
Done that.
Quote:
That MIDI events are lost indicates that your send buffer is overrunning itself.
I tried your suggestion but it made no difference, events still got lost. So I tried this to stop the program if the buffer would get full.
Code:
midiout: ldx wr_ptr ;start with a containing the byte to put in the buffer.
sta buffer,x ;get the pointer value and store the data where it says,
inx
cpx rd_ptr ;wait for space in the buffer,
beq +
stx wr_ptr ;then increment the pointer for the next write.
rts
+ stp
...but it doesn’t stop, so the buffer isn’t overrun???
I suspect that my UART interrupt routine is not functioning well in conjunction with the timer routine.
I think I’ll revisit the "better timer" routines you suggested, because I haven’t implemented or even understood them.
@BDD
I replaced the TxD IRQ on and off with disabling / enabling the transmitter with:
Code:
lda #%00000101 ;enable Tx enable Rx
sta crb
lda #%00001010 ;disable Tx disable Rx
sta crb
Unfortunately no change.
Quote:
I've given you working code in the past, Marco, on how to correctly handle this stuff—you should refer to it
Yes you did, but back then I got it working on MARC-2 by copy and paste. A few months back I tried to get it working on MARC-4 but I failed. Perhaps I should give it another try. I’m rather new to the interrupt thing, I got several things working on a VIA handshake interrupt, the VDP scanline interrupt and the DUART timer interrupt. But I’ve still got to figure out the UART interrupt a bit more.
Quote:
A timer IRQ is cleared by issuing a "stop timer" command.
As far as I know I’m doing that by reading register “duart_base + $f”, right?
Quote:
subroutines in interrupt service handlers are not advisable
That’s definitely an easy thing to do next, but I don’t think it will save the day.
Here is how I initialize the timer and UART interrupt:
Initialize the MIDI UART channel B:
Code:
acia_b_init
lda #%10110000 ;set MR pointer to 0
sta crb
lda #%00000000 ;MR0 Normal mode
sta mr0b
lda #%00010011 ;No parity, 8 bits per char.
sta mr1b
lda #%00001111 ;Stop bit length 2.000
sta mr2b
lda #%11101110 ;receiver clock select IP5-16X transmitter clock select IP5-16X
sta csrb
lda #%00000101 ;enable Tx enable Rx
sta crb
rts
Setup the interrupts:
Code:
SetupDUARTInterrupt
sei ;disable interrupts
lda #<interrupt ;set interrupt vector
sta $fffe ;RAM on MARC-4
lda #>interrupt
sta $ffff
lda #>$1000 ;set c/t for 192Hz or 5208us
sta ctpu
lda #<$1000 ;deviser = 3.6864MHz / (2*192) = 9600 = $2580
sta ctpl
lda #%01100000 ;enable timer (square wave) X1 mode
sta acr ;clear bit 4 and set bits 6 & 5
lda #%10110000 ;set MRB pointer to 0
sta crb
lda #%00000000 ;MR0[5] MR0[4] Transmitter FIFO Interrupt Fill Level
sta mr0b ;8 bytes empty TxEMPTY
lda #%00011000 ;enable counter ready interrupt and transmitter interrupt
sta imr
lda sop12 ;start timer by reading register 14
cli ;enable interrupts
rts
The interrupt routine itself:
Code:
interrupt
pha
phx
phy
lda isr
and #%00010000 ;check if interrupt is caused by C/T
beq HandleTimer ;no? goto uart irq
jmp HandleUart
HandleTimer
lda rop12 ;clear counter ready interrupt status bit
lda tc ;is binvlq = tc?
cmp binvlq
bne IncTc ;no, increment tc and end irq
lda tc+1
cmp binvlq+1
bne IncTc
lda tc+2
cmp binvlq+2
bne IncTc
lda tc+3
cmp binvlq+3
bne IncTc
ExEv jsr DecodeEvent ;yes, decode a track event (midi/sysex/meta)
jsr GetVarLength ;get variable length quantity
lda binvlq ;is binvlq zero?
ora binvlq+1 ;no, reset tc and end irq
ora binvlq+2
ora binvlq+3
bne ResetTickCounter
bra ExEv
IncTc
inc tc ;increment tick counter tc
bne +
inc tc+1
+ bne +
inc tc+2
+ bne +
inc tc+3
+
bra EndTimerIrq
ResetTickCounter
stz tc ;Reset Tick Counter tc and end irq
stz tc+1
stz tc+2
stz tc+3
EndTimerIrq
jsr buf_dif ;are there bytes to send?
beq ClearCountReady ;no, exit
lda #%00000101 ;enable Tx enable Rx
sta crb
ClearCountReady
ply
plx
pla
rti
HandleUart
lda isr
and #%00010000 ;check if interrupt is caused by transmitter buffer empty
beq EndIrq ;no? exit irq
- jsr buf_dif ;are there bytes to send?
beq + ;no, disable TxEMT interrupt, exit
jsr rd_buf ;read next character to send
sta txfifob ;put character to port
lda srb ;get status reg B
and #%00000010 ;is transmit buffer full?
bne EndIrq ;yes, exit
bra -
+
lda #%00001010 ;disable Tx enable Rx
sta crb
EndIrq
ply
plx
pla
rti
Thanks for all the patience, I hope it isn’t getting too boring.