Retrochallenge 2018/09

This time I am finally sitting down and (starting) to write the operating system for the Cat-644. (external link to hackday.io) The hardware is a 20 Mhz 8-bit homebrew computer built around an AtMega 644 microcontroller, and features VGA video output. Retrochallenge main page

[viewing Newest] . . . |Older >>| . . . |Oldest|
(view all as one document)

Keyboard and VGA working together AND a mystery!

September 19 2018

I had VGA and video working together a few days ago. I took the 'cheat' route and just had a pin change event blank out an entire scanline. It worked perfectly. At a 30 Khz screen, if the keyboard is up to 15 khz, and the clock has a 50% duty cycle, the routine should be able to sample the bits just fine if it looks once per scanline. And it worked just fine.

I tried to handle the keypress without blanking out the screen. I did this on the cat1 test program when it was all in C:

It did not work in this case. Then I remembered that the sampling has to be at the same time every scanline. If sometimes I sample at the beginning (for a blank line), or at the end (for an active line), the important bit transition may have been missed. Basically if the ps2 pin clock is 50% duty cycle, if I don't sample evenly, something will be missed. So, instead I changed it to sample at the beginning of the scnaline cycle, at hsync, exactly at the same clock every scanline. This also didn't work! So I went back to the simple version that blanks out a scanline. (Thanks git!). And I ran by sample-and-save code immediately after my load-and-act code, and it still didn't work. Why the hell not? Well I have two versions of the sampling code here, both almost identical, and in the AVR simulator do the exact same time. One works, one does not! I even padded the working one with a NOP to make the io timings the same!

in zl, io(PCIFR)		//read pin change flags
andi zl, 1<<PCIF0		//isolate the flag we are looking for
nop				//skip a step to line up with not-working version

out io(PCIFR), zl 		//write the flag back.  If it was 0, this does nothing.  If this was 1, writing a 1 here clears the flag	
in zh, io(KEY_PIN)		//read the ps2 port
andi zh, KEY_DATA | KEY_CLK	//isolate the clock and data bits  (bits 6 and 7)
or zh, zl			//add in the changed flag (bit 0)
out io(GPIOR0), zh		//store in GPIOR0, which is later read to get the captured ps/2 port snapshot, and the 'changed' flag
in zl, io(PCIFR)		//read the pin change flags
sbi io(PCIFR),PCIF0		//read the flags, set bit 0, and write back
				//technically this might clear other flags, But no other flags in this register are being used, and should be zero
				//also, clearing an already clear flag should do anything.  It doesn't in the atmel simulator!
andi zl, 1<<PCIF0		//isolate the pin change flag
in zh, io(KEY_PIN)		//read ps2 port
andi zh, KEY_DATA | KEY_CLK	//isolate the clock and data bits
or zh, zl			//add in the changed flag
out io(GPIOR0), zh		//store in GPIOR0

Now if you look at the not-working version there is a slight race condition. It is possible that after reading the pin change flag, the change can occur right before the next instruction SBI, and I'll have a pin change state that I haven't captured. But, this race condition is only vulnerable for 2 instruction cycles (.1 us out of every scanline), and if every keypress is magically hitting this, despite me plugging the keyboard in at a random time, that is very very unlucky. Or the pin change circuit of the AVR has large delay in it between a pin change and the flag appearing. Or writing a 1 to a non-set pin change flag causes some errant behavior, maybe suppressing the next up-and-coming pin change? The simulator doesn't seem to have any odd behavior here.

I plan to apply this fix to the complicated version, and then move on to the SD card.

[viewing Newest] . . . |Older >>| . . . |Oldest|
(view all as one document)