Friday, 28 June 2019

Getting the keyboard working with the MEGA65 R2 main board

Ok, so now that I can program the three FPGAs that are in the MEGA65 R2 board and keyboard, it is time to try to get the keyboard working.

The keyboard has an 8-pin interface, which we can define however we like.  The same pins are also used for the JTAG interface when programming the keyboard's FPGA.  So to simplify things, I'll use the same pin names as with JTAG.

The protocol will be a simple bit-shifter that shifts out the state of the 70 keys on the keyboard, and also allows shifting in of bits of data/control from the MEGA65 itself, e.g., to control the LEDs.  This can be done easily with four lines, just like JTAG: Clock, synchronisation signal, data in and data out. The MEGA65 will simply run the clock, and periodically assert the synchronisation signal, and then read in the bits of keyboard matrix, and at the same time on each clock tick send out the bits for the LED control.

The keyboard will provide the state of the 70 keys, complete with simulating the held status of the caps and shift-lock keys -- that is, the keyboard will internally keep track of the state of those two keys.

To plumb this through I am moving the layer that handles the widget board that we designed for the Nexys4 boards from deep down to the outermost layer of the VHDL, so that it can be replaced with alternatives.  The new keyboard will then be implemented by creating such an alternative.

This has now been done, but I now have to debug it all, because not surprisingly, it didn't work first time.  Main problem is we don't have an oscilloscope here in the cellar.   So a bit of frantic searching was required for one that was: (a) near by; and (b) not too expensive.  There were some nice ones for <100 Euro, but not near by, and since we don't have that long with me being here, we didn't really want to have to rely on multiple days of postal delivery. We did in the end find a nice 1987-vintage Tektronix 2430A from a University student here in Darmstadt, and with a new probe ("Tastkopf" is my new German word for the day) we now have a suitable setup for probing pins for 220 Euro:

So, the keyboard protocol should have a clock of ~2MHz and syncrhonisation pulses at ~10KHz or so on the keyboard connector, but neither are visible.  This makes me suspect that the plumbing through from the Xilinx FPGA through the MAX10 to the keyboard connector is not right.

To verify this, I have created a test bitstream for the MAX10 that routes the keyboard clock signal from the Xilinx to one of the two on-board LEDs, and then another for the Xilinx FPGA that puts at 40MHz clock on that line, without any conditional logic that could be messing things up.  Hopefully with that I should see the 40MHz signal on the LED pin.

After a bit of fiddling, I have come to the conclusion that going through 2 FPGAs and a cheap oscilloscope probe and into 1987-era oscilloscope is not that conducive to seeing a 40MHz clock. So I instead made the MAX10 wiggle the line at varying speeds, which confirmed up to about 10MHz is easy enough to see, and there is a weak signal at higher speeds. So then it was a case of adjusting the Xilinx test bitstream to produce a signal in the right frequency range, and tada! I had a nice signal.

So now the next step is to pull the new keyboard controller into the Xilinx test bitstream, so that I can see if I can see the signals being produced by that. Okay, so have that in, and pleasingly, I can see a signal.  However, it is only about 20Hz, instead of ~2MHz. Ah, no, actually it is in fact ~1MHz, which is fine:

To give an idea how tricky this scope is in the wrong time-base, here is exactly the same signal, but shown at the wrong time base.  The only real hint that something is wrong is the ripple in the signal.  Of course, someone who was actually educated in electronics rather than picked it up as they went along would probably have spotted that, but oh well. I just have to get used to this oscilloscope not giving a clear indication when it is showing low frequency harmonics if the time base is way out.

Ok. So that's one problem down. Now to see if that signal shows up on the relevant pin of the keyboard connector: Yes, nice clear 1MHz clock on pin 3.  Probing around the connector, I can also see a signal on pin 5, that looks to me like the LED control signal from the computer to the keyboard, which is also in the right place.  The synchronisation pulse is also visible on pin 4, and there are signals on pins 7 and 6, although I am not yet sure if they are correct. It is possible that they are wrong way around.

To check that pins 6 and 7 are correct, I have disconnected the keyboard.  That way only the signals from the FPGA should be visible.  Doing so leaves the signal on pin 6 visible, and the signal on pin 7 disappears: This is correct. So it looks like we now have communications with the keyboard possible, from a physical sense.  So now to debug the communications.

First step is to see if the synchronisation signal on pin 4 is being captured or not.  This signal has a pulse width of only ~1usec. This SHOULD be enough, because the keyboard FPGA runs its internal clock at about 12MHz, so it should see the signal for several clock-cycles.  To test that it is being captured, I have configured one of the LEDs to increase in brightness each time a TMS signal is seen.  It seems that it is not captured.

Since the signal should be wide enough to be captured, I am now wondering if the pin assignment is wrong, or some other similar problem.  To test this, I will have the keyboard FPGA route the TMS signal back out onto the TDO line, so that I can see what it thinks it is directly.  If it comes through fine, then I know that there is a problem with the VHDL logic, rather than the clock capturing per se.

Well, a lot of fiddling around has established that I don't seem to be able to read the JTAG pins as inputs from in the Lattice CPLD.  I have made sure JTAGEN is low, so that the JTAG interface is not being taken over by the JTAG system, but I still seem to only read fixed values from the JTAG input pins.  Apparently this is the default behaviour according to So I can apparently set a flag to make them usable, but I need to make sure that doing so doesn't effectively permanently disable JTAG, thus preventing me from ever re-flashing the things.  That would be bad.   Anyway, it does at least explain the behaviour I am seeing.

There are a few potential solutions here:  First, I try to figure out how to switch the JTAG pins safely. Or alternatively, we do have 3 true GPIO lines on the connector, and so I could just write a protocol that uses only 3 pins instead of 4 to communicate with the keyboard.  Then it is a question of what protocol to use.

Probably the easiest is to switch to a 3 wire protocol, and use a stretched clock signal as the sync signal. That is, if the clock pulse is longer than, say, 2usec, then it is a sync signal.  That way the rest of the protocol can remain unchanged.
We can have the keyboard read and write bits on the rising edge of the clock, and the Xilinx FPGA can read and write on the falling edge, so that everything stays nice and simple. 

As with everything VHDL, this has taken a little longer than expected, and involved the usual cycle of me thinking I can get away without a test harness, and then eventually making one anyway, when I hit some inscrutible bug.  But I now have a 3-wire interface that uses a stretched clock pulse to mark the synchronisation.

One fun thing I found while doing this, is that having the keyboard protocol running on the keyboard cable while trying JTAG program the keyboard generates enough cross-talk to cause trouble with the JTAG verification process. So mental note to de-configure the Xilinx FPGA (or have it stop the keyboard protocol) before trying to flash the keyboard FPGA.

Better would be to make the dip switch that connects the keyboard to JTAG to also stop relaying the keyboard protocol pins through.  That means programming the MAX10 again, which is usually not much trouble now.  This time however, it tried to claim that the programming cable was not connected, when in fact it was. The problem turned out to be that jtagd got confused, which was fixed by killing jtagd, so that it would restart on the next programming attempt.

Excellent! I now have a blinking keyboard led (which is what the test Xilinx bitstream is supposed to do), and I can stop it blinking by enabling JTAG to the keyboard (which is what I just attacked), so I should now be able to easily flash the keyboard again.

Now, I said the LED is blinking, and it is blinking. However it should be the drive LED, not the power LED that is blinking (which is oddly the one nearest the drive).  Also, it should only be flashing RED, not with the occasional flash of blue.  And the other LED should be staying off.  However, such naughty things are happening.

Swapping which LED blinks should be nice and easy.  Working out the cause of the flashing is another thing altogether.  My best guess is that there is some clock glitching due to crossing clock domains etc.  This should be fixable by debouncing the clock.  Indeed, debouncing for a single cycle seems to be enough to fix it.

Now the colours are stable, but the LEDs are appearing green instead of the red that they are being instructed to be, so I'll need to look into that.  But first, I want to have a clear indication of when the computer is or isn't connected to the keyboard.  So I'll implement a bit of disco lights, maybe in police light style, that indicate when the computer isn't talking to the keyboard.  This should only ever happen in the first fraction of second at boot, which I will mask.  So basically if the police lights come on, you have a problem and need to pull over and sort it out.

Right, now back to the important business of getting the LEDs functioning properly for normal purposes, and working out if there is still any funny clock stuff going on. The reason I suspect clock funniness is because the wrong colour, which makes me worry that the clocks are being counted at half rate or so on the keyboard side, since red is in the first 8 bits, and green in the second. Or alternatively there are 8 bits being stuffed in at the beginning of each round of communications, which is causing the shift. I'll have tthink about it for a bit.

See: The LEDs can blink, just in the wrong colour.

But what is also nice now, is that the keyboard is responding with information about which keys are being pressed. This should be super responsive, because we get a complete update of the keyboard state every ~0.1 milliseconds, so the delay of the keyboard protocol should be really negligible.

So now to plumb it all in, so that the MEGA65 starts trying to use the keyboard. We know that the matrix will all be messed up initially, but that's okay.  First step is simply to get the key presses received and interpreted.

Okay, so, now I can detect when some keys are being pressed, but not all of them.  A bit of hunting found a stupid bug in the code that handles the key presses, which was causing all key presses to be interpreted as only one of the first 8 keys in the matrix.

Ok, fixed that, and now the keyboard decode accelerator at $D610 shows various ASCII codes of keys I am pressing (all messed up, because the matrix is not correct, yet), but our OpenROM BASIC is behaving as though there is no keyboard. A bit of poking around has found that this is because it thinks the joystick is active on all 5 inputs.  We had this problem with the R1 board due to lack of pull-up resistors, but that was supposed to be fixed.  What is weird, is that it is only one of the joystick ports doing this. I am now trying to work out which joystick port it is, and whether it is missing pull-ups or something else.

Hmm.. Oscilloscope is claiming that there is 0V on every pin of both ports. This new PCB does have a "5V enable" for the joysticks, which is controlled by the MAX10 FPGA, so I'll have to take a look at that. After some chasing around, I found and fixed a couple of stupid typos on my part, that mean that I was enabling on the wrong pin.  This was complicated slightly by the fact that the voltage control for the joystick port on the R2 boards already has a small patch on it.  Also we confirmed that the pull-up resistors were forgotten from the joystick lines, which is a bit annoying, but easy enough for us to fix. It's just a nuisance, because all 25 series boards will need to have ten surface-mount resistors fitted, and then tied to VCC.  That's quite a few hours work, in all likelihood.

Now, back to the keyboard, all that fuss about the joysticks was so that I could stop the joystick lines interfering with the keyboard scanning.  I'll have to implement a register that lets us connect and disconnect the joystick ports internally.  I had done this previously for the R1 PCBs, and it is just a case of resurrecting it.

Ok, so I have done that, can can see the joystick inputs disappear -- but there are still some funny things to solve: Pressing keys doesn't reliably set the bits in the bytes, and indeed the bits float around a bit.  This took quite a while for me to realise that I had de-glitched clock edges only partially. Once I realised that, I was able to sort that out.

Then the next funny problem is that some of the first few bits are still coming through as though keys are pressed -- even though I can see on the oscilloscope that the input line stays steadily high. Also, there seems to be a synchronisation problem with the LED colour receiving.  I think that it is probably reading one clock or one edge early or late.  The two problems may even be related directly, but that will require some investigation.

I am now invetigating the LED problems.  First, I have fixed a problem with the PWM brightness control.  Now I am trying to work out if there is a shift in the bits of data compared to where they should be.  The data consists of 4 x 24 bits for 8-bit RGB channels for each of the LEDs.  This is 96 bits in total.

The first 8 bits should be the red channel for the first LED, but seemingly do nothing.  So now I am working my way through systematically to figure out what is going on.  This requires about 3 - 4 minutes as I test each byte to see what it is being mapped to.  Ok, so the second 8 bits are also not seeming to do anything.  Ok, finally hitting where bits are doing something:

Bits 0 - 31 = nothing
Bits 32 - 39 = Blue channel for the second LED from the left.
Bits 40 - 47 = Green channel for the second LED from the left.
bits 48 - 55 = Red channel for the second LED from the left.

Hmmm,  it seems to be backwards.  Also note that 128 bits (total frame length) - 96 bits = 32 bits, which is suspiciously the size of the region which does nothing.  A closer look reveals that I am sending the bits indeed in reverse order.

Ok, time to reverse the bit order then, and see if that fixes it.
Hmm... Closer, but still something odd. I requested a red solid LED for power and blinking green drive led, and I have instead a blinking red LED and solid green one. They are also on the wrong LEDs, but that is really easy to fix.  I'm trying now to make the power led solid purple, and we will see what that does.  Most strange: I now have a blinking purple LED, even though the logic for the purple LED should have it solid on.  Found the cause of this: I had for some deranged reason in my test harness decided to make the power LED blink and the drive LED solid. Anyway, it's nice that that is now out the way.  The LED control is now all perfect, with C65-style green power and drive LEDs.

Now, back to the keyboard. Plenty of fun adventures to be had here, as I have chased down a variety of fun bugs. The bit order was being reversed here as well, but then the big problem was that initialising signal values doesn't seem to work on the Lattice CPLD we are using. It's probably a known situation, but it wasn't known to me until now.

So FINALLY I have the keyboard communications more or less working, and now just have to map the ~80 keys to the correct matrix order.  I have the schematic for the keyboard, as well as the C65 keyboard matrix from section 2.1.2 of the Commodore 65 Specifications, and I just have to match them all up.  Unfortunately the keyboard schematic for the MEGA65r2 doesnt show (or at least I couldn't find) the key number to keyboard position mappings, so I have to figure these out for myself.

I've started with SHIFT LOCK, because the lock keys are clearly marked on the schematic, and then with RUN/STOP and ESC because I can also deduce where they are.  If my hunches are confirmed, I will be able to fairly quickly match up more keys.  So, this worked in so far as I could indeed tell that I am pressing the correct keys.  However the matrix mappings seem to be wrong.

Fortunately I implemented the on-screen-keyboard for the MEGAphone, which lets me see in real-time exactly which keys are being pressed.  While this wasn't its original purpose, we can always pretend it was made for this purpose, for which it works fantastically, and looks pretty nice while doing it.

RUN/STOP should be key 63, but pressing it causes D to be pressed, as can be seen above, which is key 18 (column 2, row 2).
ESC should be key 71, but works as A, which is key 10.
SHIFT LOCK (key 15) works as key 66

Ah, in all cases they add up to 81! That means that the bit order is just reversed, which we can easily fix.  Oddly, trying to reverse the bit order didn't fix it, but making the key numbers be 81-(key number) has worked, so I am not going to worry too much for now.  So now to implement more of the keys.

Getting the vast majority of the keys correctly assigned took about 2 hours of iterating through, but in the end, we have most of the keys right. So we can finally type some things in, and even load programs again.  However there are a number of keys that are behaving oddly, which we will have to fix up.  But as this post is already half a mile long, I'll stop here for the moment.


  1. Wow, this was an exhausting read :-) I'm amazed at how much perseverance you have here, when faced with so many hurdles and obstacles. Just curious, did all of this happen over the course of one day? If so, what an exhausting day this must've been. I think I wluld've thrown in the towel for the day after the 4th or 5th issue :-)