Wednesday, March 9, 2011

Assembly language routine written!

As I said yesterday, I decided that I needed to re-write my code in AVR assembly language in order to make it fast enough to be able to reliably detect the 4 microsecond bit cells send from the Apple 5.25" disk drive.

I now have ported both the bit detector function and the interrupt service routine (ISR) to assembly language. The ISR was the one that I was the most keen on optimizing because the C compiler added a bunch of wasteful stack pushes/pops that I didn't need, but I also benefited from optimizing the main loop also because I was able to move a global variable from memory into a register which saved a few cycles.. and when talking about microseconds at 14.7 MHz, a few cycles are worth a lot!

I am excited to test out my new routine on real hardware.

Here is the ISR routine below. As you can see, it's pretty short. It gets activated when a read pulse is received from the 5.25" disk drive.

// this interrupt is triggered when a pulse (connected to INT6 pin) starts (active low)
.global INT6_vect
INT6_vect:
in sreg_save, _SFR_IO_ADDR(SREG) ; preserve flags

; When we store this cycle value to the timer, it will be at most 1 cycle off so it is pretty accurate
; I got this value by counting cycles in the simulator/debugger.
; I want the timer to be relative to the start of the pulse so it's easier to visualize in my head.
; The timer will not overflow within the time that it is useful to us.
ldi u8Timer, 12
out _SFR_IO_ADDR(TCNT0), u8Timer

clr bPulseOccurred ; this register should already be 0 in every case but I want to be safe and this only uses 1 cycle
inc bPulseOccurred ; let main loop know that a pulse started

; we need to wait for the pulse to end or else this ISR will get triggered again immediately
wait_pulse_end:
sbis _SFR_IO_ADDR(PINE), 6
rjmp wait_pulse_end

out _SFR_IO_ADDR(SREG), sreg_save ; restore flags
reti

No comments:

Post a Comment