Monday 21 November 2022

Progress on the DIY Keyboard

As I have explained in recent blog posts, I am working on an alternate PCB design for the keyboard, with a couple of goals, the chief of which is to make it possible for folks to build their own MEGA65 keyboard at home for use with off-the-shelf FPGA development boards.  It also creates an insurance policy for us for production of the keyboard for the retail MEGA65s, because the design doesn't use any FPGAs that are impossible to source, but rather a bunch of easily sourced I2C IO expander chips. 


Previously I had gotten as far as getting the PCB designed and fabricated by PCBWay. The last week has been focussed on populating the PCB with keyswitches and the other vital components, and then adding support for it.

Assembly wasn't too tricky, as the surface-mount I2C IO expander chips are fairly easy to place using drag soldering, and then cleaning up the bridges after using solder braid. There are lots of YouTube tutorials on how to hand-solder SMD components in this way. If you are lucky enough to have a reflow oven, that would work fine, too, of course, but it isn't necessary.  

The key switches themselves are super easy to click into place (just make sure they click in all the way and sit flat on the PCB). Because they click into place, you can populate the whole board in one go, and only after flip it over to solder all their legs in place.

Apart from that, there is only the 10 pin hole-through header and some hole-through resistors to get the core of the keyboard working.  

That got things far enough that I could start trying to add support to the MEGA65 core for this.  After a frustrating couple of days where it looked like the rise-time on the I2C bus was ~50usec instead of ~500ns, I finally realised what I should have already remembered: The keyboard connector routes via the MAX10 auxilliary FPGA on the MEGA65 main board.  Once I remembered this, it was actually a good thing, as it meant that I could just resynthesise the MAX10 FPGA with support for the keyboard, rather than having to wait an hour or so each time to resynthesise the core for the main FPGA.  It also means that none of the existing cores will need modification to support this keyboard, as it is only the MAX10 FPGA program that needs updating.

With that problem out the way, it was time to actually pull it all together.  As the keyboard bus has proven a bit fiddly to work with in the past, I implemented unit tests that included the MAX10 FPGA, the keyboard FPGA on a MK-I keyboard, and the I2C IO expanders of the MK-II keyboard, as well as a simple representation of the Xilinx FPGA's side of the keyboard communications. This let me test the entire system -- including auto-detection of the keyboard type -- offline and quite quickly.

This meant that when I did synthesise an updated MAX10 FPGA bitstream, it actually worked first time -- the only outstanding problem was mapping problems with various keys (which I expected), and one last little I2C communications problem that didn't show up during simulation.  It really did make my life much easier.

Most of the IO Expander ports were backwards compared to what I had listed, which is probably just a transcription error on my part. But I did discover that I hadn't properly wired up the E and <- keys. Fortunately I did include a GPIO header with a couple of spare lines, so I have connected those keys to those, and then re-mapped the GPIO lines to where those keys were originally intended to go. This means that I can make these "revA" keyboards work with all keys, without introducing electrical differences in the "revB" that will include fixes to all the problems I have identified along the way.

The fixes for these two keys are the only changes that have required "bodge wire" as I call it on the revA PCBs:

Add some key caps I had laying around from an old mechanical keyboard to make testing easier, and I had something that more or less works:

Obviously you would want to get a proper set of keycaps for it if you were building it yourself -- but, again, if your goals was to spend just a little each time, and progressively improve your home-made setup, then you could totally do something like this.

With that I was able to use the MEGA65's on-screen-keyboard overlay to confirm that each and every key was working.  It did also show up that I still had one solder bridge to clean up, as the F and SPACE keys were both causing both to be pressed.  By cross-referencing back to the schematics I was able to quickly identify the location and clean it up, resulting in a completely working keyboard after that.

So, that now just leaves getting all the LEDs working, and confirming that the LOCK keys are doing their jobs.  SHIFT LOCK I know is already working fine, because I can see it toggle the SHIFT LOCK key on the on-screen-keyboard.  The CAPS LOCK key is trickier, because it also doubles as the "turbo" button: Hold it down, and the CPU goes full speed.  I have also still to confirm that any of the LEDs work, and that they are the right way around.  This goes for both the LOCK LEDs, as well as the power / drive LEDs at the top.

I'll start with the SHIFT LOCK LED, as that should be fairly easy to deal with.

The IO expander that drives the LEDs has to be switched from input to output mode, which happens only once when the MAX10 first detects the MK-II keyboard.  This means that if the keyboard is detached and re-attached, thus powering down the IO expanders in the meantime, that the LEDs won't work.  To avoid this situation, I just need to flash instead of program in the updated MAX10 bitstream, and not unplug the keyboard.

Having done all that, I'm still not seeing the LOCK LED get any voltage on it when I toggle the SHIFT LOCK key.  Ah, that could well be because I haven't yet fitted the 330 Ohm resistors for the LEDs :)

So now I have the SHIFT LOCK LED working, but its inverted: On when the LOCK if off, and vice-versa. Easy to fix in the VHDL. CAPS LOCK is the same, but it also has to do the tricky "cancel last CAPS LOCK toggle if held down for a long time" feature, that we use to make CAPS LOCK a convenient "TURBO" button.

All that's left now, is the power and drive LEDs. So far I only have one of the four fitted, and the resistors for one of them as well.  The logic is in theory all there for doing Pulse Width Modulation of the LEDs to allow brightness control of the R, G and B channels for each.  I have of course not fitted the matching LED to the resistors. I should really just fit the remaining LEDs and resistors, and then go from there. In theory the power LED should come on when the keyboard is connected, without further work, although I suspect I have the control sense of the LEDs inverted, i.e., off is on and on is off. We will soon see!

With resistors fitted, the LED that is currently fitted is working, and not emitting smoke from excess current, so I now feel safe to fit the other LEDs.  The colour selection is indeed inverted it seems, with the drive LED showing blue. I've now fitted the remaining LEDs. They are quite fiddly to hand-solder, but I think I have them in ok.  Certainly 3 of the 4 are nice and bright -- if not a little too bright. The 4th I think I just haven't got soldered down particularly well. I'll fix that a bit later.

It looks like I had the LED order reversed, and also the red and green channel of each reversed. This is not particularly hard to fix, so I'll deal with that now.

Meanwhile, the only feature this keyboard lacks compared with the MK-I, is the "ambulance light" mode when the main FPGA is not talking to it.  In fact, it would work even if the MAX10 FPGA was not talking to it.  However, for the MK-II keyboard, the MAX10 is doing the talking to the keyboard, so we can still detect the lack of communications from the main Xilinx FPGA, e.g., when there is no valid bitstream/core loaded on it, but not if the MAX10 is sad.  That's probably still a reasonable gain over not having it at all.  This of course won't work on other boards like the Nexys4 if we add support for this keyboard to it, because there will be no communications at all.

And after the usual fiddling of getting the RGB order "fixed" in a different wrong order, I now have it all back and working.  Also, because of the way the MAX10 is involved in driving the MK-II keyboard, it is also safe to return to having red and blue flashing lights for Ambulance Mode, which I think always looks nicer.

Before I wrap things up, I also wanted to make sure that this new keyboard handling code in the MAX10 correctly handles the original MK-I keyboard, still. This is where my "hot auto-detection" code is handy: I can switch the keyboards at will on a running machine (don't do this at home, as it isn't totally risk free), and the MEGA65 adapts to the appropriate keyboard, and I can keep typing merrily away on the switched keyboard within about 1 second of plugging it in.

Now I think its time for a video showing the whole thing together.  I've just done a live stream on twitch, which I'll embed in here once it's up on youtube. The audio is a bit quiet in the first few minutes, but I fix it, so persevere, or just jump to around the 5 minute mark.

With everything working, it's now safe for me to finish revising the PCB design, ready to get some more samples made, so that I can do a repeat assembly test, and confirm that everything is fine. I had a bit of a TODO list of items for that, including tweaking mounting hole positions, using larger resistor footprints, so that they can be soldered flat to the board, as well as adding the supports for the RETURN key and SPACE bar.  

Those are all done now, and I now just need to be able to confirm their correctness.  The best way would be to print at 1:1 scale, so that I can fit-test, but I've yet to find a way to get KiCad and my printer to come to an agreement on how to achieve this.  I've also ordered some keyboard stabilisers, so that I can confirm that I have the correct PCB mounts for them.  So that's it for now, until the stabilisers arrive, and I figure out a good way to fit-test the changes.

Wednesday 16 November 2022

Working around 74LVC165 supply problems for the MEGA65 Expansion Board

I mentioned in a previous blog post I mentioned that the expansion board was designed around using the 74LVC165 shift register for reading the IO lines. Unfortunately, they are a bit of Unobtainium right now, but the 74HC165 is available, and is 5V tolerant. 

However, if you run them on 3.3V VCC as I am doing to get 3.3V shift register output for input to the FPGA, then if the IO pins are at 5V, the voltage difference leads to current flowing continuously through.  

This can be solved by putting resistors in-line with the IO pins, to limit the current.  a 1K resistor will mean that with the 5V - 3.3V = 1.7V difference, that 1.7V / 1K = 1.7mA of current will flow -- well below the 50mA limit of the 74HC165s.

So the next step was to patch the boards to have these resistors in line.  This turned out to be a pain, so I instead just designed a little PCB that could be inserted into the 74LVC165 sockets, and have a socket on it for a 74HC165 and the resistors inline.  I made it a super simple 2-layer board, so that I could get it fabricated quickly by PCBWay. 

Those little boards arrived today, and I assembled three of them, and inserted them into the test expansion board I have been building:

So the next step will be to test this. But first, I want to finish working on the MK-II keyboard. I've got that mostly assembled now, and will do a blog post on my adventures and misadventures working on that.