Reviving an antique cnc router

August 7, 2019

TL;DR: This machine is very light duty as far as cutting goes, and the tolerances leave something to be desired (but it’s way WAY better than not being able to use one).  i3Detroit is currently in the middle of a fundraiser to help expand into the second half of our building, and part of that expansion involves buying some new tools that we now have space for.  We have decided that upgrading this machine beyond what I have listed at the end would be a waste as we could buy a new machine that would be more reliable, sturdier, could take bigger cuts, and is more precise for the money it would take to upgrade this one.  We are hoping to get at least $50k raised by October in our fundraiser, because if we do the Michigan Economic Development Corporation will match that $50k to help with out expansion.  Even though this machine will ideally be operating as a wood router for less than a year, it will likely live on as a CNC plasma cutter considering the side forces for that tool are pretty much zero.


I am classifying this one as an antique even though I have used hardware older than this when it was new.  The cnc router craze is relatively new as far as manufacturing processes go and this one is downright archaic compared to what I am used to seeing.  It uses steel cable and turnbuckles for the drive and quadrature encoders and ball chain for feedback.  Looking at the design was kinda surreal:




I’m a member of a makerspace known as i3Detroit, many of my previous hacks have been done either in service of them or at least using their facilities.  We recently received this old CNC router for free, but the catch was that it didn’t work.  There are several reasons it didn’t work, but the one I’m tackling is the electronics.  A CNC router is no good if the computer can’t talk to it, and that’s the problem we have here.


The computer we got with it is an old socket 7 box with a 2GB IDE hard drive, 16MB of ram, and a 110Mhz Cyrix 6×86.  The really odd thing is it has two BGA chips onboard, 4 PCI slots, 3 ISA slots, spots for SIMMs, DIMMs, and onboard IDE.  Happily enough it powered up and we were treated to Windows 95.  In the documentation there was talk of a licence for Engravelab and the number in he documentation matched what was plugged into the parallel port of the machine.  There were also two serial ports and one of them was occupied by a serial mouse, I couldn’t figure out which port the mouse was hooked up to but when I tried to talk out one of them the mouse stopped responding: mystery solved.  With the serial ports labeled we could now try to use the software on the machine to try to plot something on the CNC router.  That inevitably led us to our second problem: the CNC controller.


The controller for this particular machine was housed in an old AT computer case and the power supply was shot.  I have no doubt we could have brought it back, but for now we dropped in an ATX supply and I wired the green wire and a ground wire to the old alternate action switch which used to switch the mains.  We now have a functional power supply.  There are no indicators that it’s on however.  The case that was repurposed to hold this CNC controller still had the entire complement of front panel LEDs and buttons and only the power LED looked like it had been touched.


Let me take some time aside here to ask, why would anyone ever need to wrap the LED and button wires in a ferrite core? is the old computer that sensitive to interference picked up by a foot long wire?  It’s not like there are fast signals running to those LEDs.  Ok, back to the repair.


The power LED was burned out, but this manufacturer terminated the LED side of the header wire with a two pin polarized 0.1″ spacing jack (2 pin fan connector jack to me) and just slid the LED in.  I could see that the green LED was burned up, so I swapped in another one, added a current limiting resistor and now we have a power indicator.


“We applied the cortical electrodes but were unable to get a response from either patient”

The next issue is the controller itself, It is an 80c32 dev board by Blue Earth Research called the XPLOR 32 and has a frickin’ DC-37 connector for all of the I/O and power (I love them already…).  This controller has a rom on it labeled “ShopBotControls Ver. 8 0420980000204” and from their website it seems that Shop Bot has had many generations of controller that kept this DC-37 connector.  The board it’s attached to is a generic breakout and I have pinned it out entirely along with noting where the connections to the encoders and stepper drivers go.  In doing this I noticed that the DE-9 serial port that we had hooked directly up to our PC was passed straight to the 80c32 without a level translator.  Is that cool? I don’t know but that’s how it’s wired.  When trying to connect the software to this module it would do things on the correct serial port (we had an LED indicator on it) but we got no response.


The final mystery was the stepper controllers.  They’re not really controllers, more like drivers.  The SLA7026M have virtually no smarts in them except current regulation and take quadrature signals raw to drive the windings of the motors.  This means no step and direction signals which is what most CNC controllers want to output.  This was the part that took the longest and I kept double and triple checking the wiring each step of the way.  I borrowed a design for step and direction to quadrature from this post.  Even in the initial question he’s asking if there’s an easy way to make the circuit better, but for me it’s good enough to start cutting.  I was feeling a bit brain-dead so rather than staring at it for an hour and not being sure it would work I went on and modeled it.  I have to say, that was a very easy tool to prove to myself that the circuit would work.  I soldered in 5 sockets and then noticed that the chips wouldn’t fit that close together, so I belt sanded the chips to fit and kept on. 


I really like how the circuit works.  You’ve got two XOR gates and two D latches.  The output of each XOR is connected to the data pin of each latch, so whatever it evaluates will get read in when the circuit is stepped.  The step pin is connected to both clock pins on the latches so every step the circuit re-evaluates and the states change.  One input of each latch is connected to the direction pin, which swaps what polarity the other pin needs to trigger.  The other pin is connected to the output of the other latch, meaning that one latch only changes state a cycle after the opposite latch changes state.  For one of the XOR gates it’s connected the the Q output on the latch, but for the other it’s connected to !Q meaning that the state changes are always happening on the opposite polarity.  The normal and complementary outputs of each latch are used to drive the full quadrature so you don’t even need not gates on the output.  I find this quite a nice and compact circuit to solve this issue.  


they’re socketed, sure, but you’ll have to sand the new chip down to make it fit

With all the custom stuff done I just had to grab an arduino mega and flash it with grbl-mega, it then happily talked to me over GrblPanel.  Soldering up those step and direction wires to the shield I competed the custom electronics to make this thing drive.  Now, does it work?


Does it ever! There are of course remaining tasks to be done:

  1. Re-string the steel cable to make the X axis move
  2. Find a way to use the quadrature encoders on the X and Y axes
  3. Add endstops for homing
  4. Add endstops at the other end to prevent crashing
  5. speed control of the spindle?
  6. rebuild the spindle (bearings? brushes?)

That being said, the only thing that stops it from making cuts is the first point, so that’ll be the next one to tackle. And if I’m really feeling like a smartass I’ll put a max232 on that shield and you can use the controller just as it was originally (I think), but this time it’ll take straight g-code.

Portable arcade test rig

August 6, 2019

In working with arcade PCBs and trying to debug, diagnose, or just determine what they are it’s nice to have an arcade cabinet to plug them into.  Sometimes you want to set them up where having an arcade machine is difficult, or putting the board on a bench is most helpful.  In that case, a JAMMA harness and arcade monitor would be the usual prescription.  That is a little cumbersome to have to carry around all the time, and also can be fragile as monitor neck is exposed.  It’s possible to get a 15khz to 31khz converter to allow arcade boards on a regular computer monitor, but where’s the fun in that.  To solve this problem I packaged all the contents of an arcade machine in to a mini-ITX case and made it as portable as possible.


my dumb genesis controllers can be seen in their first application

To start the discussion of some choices, first I need to go over JAMMA.  JAMMA stands for Japan Amusement Machine and Marketing Association, Inc. and is the shorthand for a rough standard based around a 0.156″ pitch double sided 28 pin long card edge connector.  I say rough because I’ve found some variations and omissions that I will try to correct on this rig as time goes on.  I don’t intend to try to make this an everything tester initially, but if I need to test additional boards that use other unpopulated (or otherwise mapped) pins I’ll make revisions.  I compiled a ‘comprehensive’ set of pinouts for the JAMMA connector based on a lot of various incomplete or different variations (I almost said universal instead of comprehensive, but that’s a brand of arcade manufacturer with their own variation):


Here’s my explanation:

  • Some things are pretty constant, the top power rails, the video connections, and the  coin, joystick, and a few buttons
  • Some things have been omitted more and more like the lockout coils,  the coin counters, and whatever power rails a particular board doesn’t need
  • Other things get extended into unused or redundant pins, like buttons replacing grounds or test switches
  • Creating stereo sound seems to have been re-invented at least twice

MGD is the arcade incarnation of the dreamcast, and I’m not planning on hooking one of those up any time soon (but if I do I know it’ll mostly work.  I do like Neo-Geo, so having those buttons work would probably be nice (maybe I can get clever and mix the sound).  The rest of the issue is to try to populate things that are usually omitted and hope I don’t run into too many crazy things.  Right now I have populated everything the JAMMA connector I used had wires for, and ordered more crimps to populate the others.  I used the common L and 10 connections for mono sound out, even though that’s not supposed to need an amplifier.  As you can see this is pretty much all you would need for any arcade machine, not even just JAMMA compatible ones.  Using this interface and some adapter boards it is possible to connect just about anything to this tester, although it may require a special adapter to be made.  Some adapters may not be passive either, Nintendo had this thing that inverted the colors to their monitors, others may use different voltages, but all this can be made to work now that most of the items are in a nice compact case.


Interior shot

This lets me show the various things I’ve done to it so far.  the JAMMA connector goes out the I/O backplane hole, the DE-9 ports I have used for controller ports go out the PCI slots (the brackets already had DE-9 knockouts in them).  The power supply is a regular arcade power supply riveted through the immobile side of the computer case, it is hooked up to the back of a PC power supply that I cut the back plate off of.  That plate has the fan, power switch, 110/220 switch, and power connector on it and they all work.


The monitor is a Samtron 5″ monitor from here although their prices are not accurate any more.  The monitor chassis is mounted on the motherboard tray so I can access the tuning controls, and I cut away most of the 3.5″ bays to allow my hand to get back there.  The monitor came with a degauss coil, but no associated drive circuitry, I initially hooked it up with a button, but that blew up the first coil, apparently a “positor” or positive temperature coefficient device is used to open the circuit at the optimal time to fix the screen.  I pulled the device out of an old 15″ CRT monitor that came in with a Windows 95 era wood CNC.  The monitor has inputs for RGBI (although it appears no one has ever documented actually using one for that) and was converted to analog with help of a sync splitter and this guide.


Along the top in the last two pictures is a 5.25″ bay set of speakers, this is what really led me to this project, just throw it all in a PC case.  I do also remember an old website where someone crammed several small black and white portable TVs into a case and fed them with a modified video card to display at the right frequency.  He managed to drive three monitors from one signal, one color for each monochrome monitor.  Originally that set of speakers had a cord hardwired in the back, I took it upon myself to eliminate the cord and put a jack so the harness could plug into it (there was a footprint on the pcb for a jack I had).  After opening it I realized that the speakers were just grills and the real speakers were regular big 8R drivers sit at an angle and pointed up, not even any isolation between them.  There’s just this big cavity and the sound will eventually make it out the front.  Well.  If they can do that so can I.  We were looking for a design to fit the blankout plate that is to go over the USB and sound holes when I pointed out that the Vault Tec logo is about the right proportions.  That plus blue meant that it now needs yellow instead of white paint.  At the insistence of Mike who pointed out that it looks great, except for that crappy speaker grill, I decided to just bandsaw off the front and he’s make another acrylic piece that went all the way up.  Along the way I decided to eliminate the power indicator and the aux-in jack and switch to a more appropriate knob instead of a slider.


As you can see we borrowed a speaker grill off a thing and a knob off a guitar (it’s mono now, but it drives both speakers) to make the top audio section.  The text around the knob was cribbed from an HM audio generator.  The arcade coin buttons happen to perfectly fit in the floppy drive section and you can see the degauss button that’s actually bolted through the steel so it sits flush.  I bought real coin counters and added diodes to them to protect the arcade board, they are apparently low side drive so I hooked mine to the 12v line since they’re 12 coils.  The lockout coils I knew less about, I just assumed they’d go high with 5v and wired the other side of the LED to ground, but we’ll see once the terminals get here because that section wasn’t wired on this harness.  I added Tilt, Test, and Service switches even though Test wasn’t populated on my harness either.


I gave this thing a new coat of paint in almost the same colors it was already, just to cover up the scuffing that had gotten done to it over the years.  I still have handles to mount, additional pins to wire, and maybe a circuit to sit in the harness and talk to buttons 4, 5, and 6 after decoding real 6-button genesis controllers.  I also blew up the audio amp chip on the tetris board, oops.  Did you know that tetris by Atari has two power amp footprints on the PCB and only one populated? The schematic seems to imply that they are in parallel but I assure you the footprints are mutually exclusive.

EDIT: the tetris problem was because that mono output was supposed to be for an isolated speaker and I’ve now put a 1:1 audio transformer in the line to isolate my amp ground from speaker-.  Also some boards assume all the power and ground pins are hooked together in the harness, this isn’t true in mine yet but I added one bodge so far to bring up one board.  I may use vampire taps to join the remaining wires.

We picked up a jamma extension harness from china for super cheap, so far I’ve had to fix a bunch of stuff:

  • 12v was run with one wire and only connected to one side of the fingers, but both sides of the card edge female
  • 5v was run with one wire and only connected to one side of the fingers (two fingers), but both sides of the card edge female (all four pins)
  • -5v was not run
  • coin counters and lockout coils were not run
  • no key in female card edge
  • 7th pin not cutout of fingerboard

I can understand cheaping out by running fewer wires, and I can understand not using the coin counters and lockout coils.  The lack of -5v really shows that this was designed for a small target market.  The lack of joining the finger sides together also shows that it’s only really meant to work on ‘most’ machines.  The lack of a key and cutout, I don’t know any boards this would work on out of the box… That all being said, The cost of this harness was under $5 and well worth it after repairing it.

Scanning Electron Microscope reverse engineering- 8741A programmer/reader

June 7, 2019

The AMRAY 1845 FE EM we got is proving to be an interesting beast.  I has its own internal signaling network called NibbleNet.  This seems to be some variant on GPIB, but the hardware is slightly different.  We decided the best way to figure out how NibbleNet worked was to dump the program out of one of the NibbleNet control processors.  Since there are two, interchangeable instances of this IC in the microscope we think that they are generic in some way and can be helpful in figuring out the signaling protocol.  Once we’ve got an idea of the protocol we can build a sniffer and start logging data from the machine.


The NibbleNet processors this SEM is an 8741A, and at first it seemed like we would just be able to throw it into one of our many chip readers and read/program it but that was not the case.  The MCS-51 line of processor (the infamous 8051 line) has wide support to this day in all sorts of modern variants and vintage applications.  This is not one of that series.  The precursor to the MCS-51 is, of course, the MCS-48.  the one we have here is the 8741A (EPROM version of 8041) with 1K × 8 EPROM, 64 × 8 RAM.  Now before we get to building a reader, we should have a way to know if it read correctly.  To me, that means writing to a different processor and seeing if the board operates correctly.  We were unable to get an 8741a for this purpose, but we got an 8742 which is the double size EPROM version so it should be pretty compatible.


I started development using the datasheet and a small stack of 8742 chips, which worked out better than you might think.  Using this for a base I built a fairly complete hardware setup that was capable of sending all the right voltages to the right pins.  The code was written from scratch, because after being unable to get the other guy’s code to do a write/verify I didn’t trust it.  Following the datasheet for the 8742 wasn’t hard and eventually I got it to the point where I was confident in the programmer.  At this point we still only have two 8741a chips, both presumably the same and containing code we can’t get back from anywhere else if we accidentally blow it away.  Turns out the 8741a is slightly different in several important ways.


The first thing I wanted to do to ensure the integrity of the data was to install a hardware program/verify switch.  This physically interrupted the programming voltage from being sent to the chip so any rouge arduino couldn’t accidentally overwrite all or part of our precious chips.  I had only added the write functionality so I could validate the integrity of the tester.  The second thing that had to be done is add another switch that selected between the 8741a and the 8742 voltage on the EA pin.  On the 8742 it’s 18v, which is not the highest voltage in the system so I’m creating it with a linear regulator.  On the 8741a it’s 23v which is the highest voltage in the system so it’s coming straight off the input pins (and why I have the board labeled very carefully.  This also means that when going to the 8741a you have to run the whole board at two volts higher than when you run an 8742.


With EA sorted out it took Frank to determine that you have to bring Test0 low to reading the 8741a.  I didn’t get that from the datasheets, you can see that’s not the behavior on the 8742 and it’s not called out on the 8741a. He got it from the 8748 datasheet and it worked beautifully.  We now have the NibbleNet program memory dumped, but there’s an issue.  When we load this program into the top half of memory of the 8742, it doesn’t run correctly.  That being said, my validation of running correctly is that an LED is solid and not blinking so I’m not 100% sure here.  When we put the code into both pages of memory it seemed to work, but it may just be doing enough to keep the watchdog on the other (I’m assuming 80186) processor happy.


The pictures are here and all the rest of the documentation for this project is here.

Arduino control over Ham radio

June 6, 2019

This is not my idea, but I finally got around to setting up and testing it so I can show you what I did and why.  When I got my ham licence I got myself a decent radio, a Yaesu ft-60r.  That wasn’t cheap, but I trust it’ll be good for quite a while and is of a good quality.  What I eventually also got was a Baofeng UV-5RV2+ but this I got as a receive only radio.  I have no intention of breaking it or making any hardware modifications, but I just don’t intend to use it as a radio to talk on.  Some people think they create a ton of interference when they transmit, but mostly there’s a dislike of cheap radios because it’s a lower barrier to entry.  That’s not the point here.  The point here is long range control of a system with minimal hardware.


If you need to control something over a long distance (~2 miles away) you might choose to use wifi and the internet.  This is a reasonable choice and by far the cheapest, but it requires internet at both locations.  You might choose cellular radio modems, but those are expensive and you have to pay for a service to make them work.  You might even choose some purpose built radio modems, but those are usually unreasonably expensive and a lot of trouble to use.  I have a simple control scheme that requires no special hardware at the sending end and a cheap, small receiver using mostly commodity hardware.


My initial setup uses a Ramsey TT7 decoder kit and an arduino pro mini.  The decoder kit has a logic chip that decodes what button is pressed and triggers one output, but the arduino can do that in software and not require as many pins.  My modification to the kit was to piggyback a header that exposes power, ground, the binary decoded key and the latch signal that is enabled when the data on the bus is good.  The code I have is simple and is an example that can be modified for basically any use.  The initial idea was an RF remote control for a DSLR setting the photos to be taken, focus or not, number of photos and time between them, or video start and end (or set duration).  I still like this idea, but I don’t have a camera to use like that so I’ll have some other eventual use.

Modify genesis controllers for dumb operation (JAMMA)

May 30, 2019

In trying to build a small portable Jamma test rig around a little CRT the subject of controls came up.  The obvious answer to me was the genesis controller as it contains the joystick (d-pad) three buttons and start, which is the primary Jamma standard per player.  The 6 button controller could allow for the extended Jamma button set but for now I just needed to get Tetris going.


The genesis controllers have 8 buttons, which would allow for a simple pinout of 8 buttons and a ground, but they didn’t do that.  They seemed to adopt the standard that was the pinout for the Atari2600.  The problem with that as a standard meant onr pin was for 5v because the spinners were really potentiometers and they used all three pins of the pot instead of just having a variable resistance between two pins (I don’t blame them, I would have done the same).  The 5v line meant that in order for these controllers to not cause the 2600 problems when inserted that they couldn’t have a button there.  That leaves one too few lines for the classic genesis controller.


The solution was to put a logic chip in the controller to multiplex the buttons.  That meant using the existing 5v line to power the chip, but also using another line to take in the select signal for the multiplexer.  This means that the genesis controller presents the states of Up, Down, Left, Right, B, and C or Up, Down, A, and Start.  Don’t ask me why it doesn’t always show left and right, or why A isn’t in the default layout.  The 6 button controller is even more complex having Z, Y, and X replace Up, Down, and Left every third cycle.  Truthfully you can do a sort of detection using left and right to determine which cycle you are on but it’s hacky and doesn’t always work.

I decided to dumb down these controllers, breaking compatibility with the genesis, but making them good general purpose controllers for future projects.  That involved re-wiring the DE-9 ports to get rid of the crappy molded connectors and wiring around the multiplexer chips to make them 8 buttons and a common ground.  I ended up having two different style controller PCBs so I had to do the reverse engineering twice.  In the end I also had to do a lot of cleaning to the carbon pads and the PCB where they make contact but now the controllers seem to work well. All the pictures are located here.


Sony Sports Watchman FM-45A composite input

May 30, 2019

As part of this ‘real Pip Boy’ project I’ve started I decided I needed a real CRT for this to work.  The whole point is to have antique technology, not just the look and Sony made portable CRTs of about the right form factor.  I elected to buy one, but the classic Sony Watchman has a long skinny appearance that I never much liked.  I prefer to have something closer to the dimensions of a Pip Boy to start with, so I found what I thought was the compact model.  It says sport in the name and the ratio of case length to width was more what I liked so I bought one for only $20 shipped.  When I got it I found out my mistake: this isn’t the smallest one, it’s the biggest one.  They apparently called it the ‘sport’ because the whole case is waterproof, and as I disassembled it I tend to agree (they did a really good job designing it).  That being said, I now have a heavy plastic box as big as my forearm and bigger than any of my model Pip Boys, that’ll do.


The problem with getting something that isn’t what everyone else is hacking means that you have to blaze your own trail.  There isn’t a place to find easy instructions to inject composite video into this particular model so I had to figure it out.  Not really.  Someone else found the same chip in a different one and explained where to hook in.  Pin 8 of the QDIP  IC201 is the composite pin and pin 23 s your ground reference on the Sony CX20183.  But at least now all these keywords are in the same place for the next person.


I still need to tune the CRT, inject audio into the existing amplifier circuit, maybe remove some RF components for space, make sure the radio still works, add a rechargeable lithium pack to run the monitor and pi, and add more sensors/buttons/knobs/lights.  The keyboard is done.

Xbox360 Chat Pad to USB

May 30, 2019

I have been working on a Pip-Boy that uses a real CRT (more to come on that later) but I decided that for input it should really have a keyboard, this is similar to the Pip-Boy 2000 Mark VI found in Fallout 76. This is a deviation from all prior designs having simple interfaces of rotary knobs and buttons (although the 1.0 prototype seemed to have a calculator-style keypad). Having a keyboard will help with the interface, meaning it doesn’t need special software to start with and can be used with a linux computer out of the box. My intent in the future is to extra inputs and outputs, but the keyboard is the first step in making it usable.


The keyboard itself is an Xbox360 chatpad. I bought this because it was cheap, and I assumed it would be a simple arduino library or python script and I’d have it working. I ended up with a little more work on my hands, but not much. Had I voiced this thought about an hour earlier I would probably have bought this, but I would have always complained that it was wireless.


I spent a fairly long time working to get this driver working. It turns out that there are apparently subtle differences between the knock-off and legit chatpads and this driver was tuned for the knock off which I didn’t have. I eventually gave up, but this would also have been a sticking point with me about the lack of portability that the solution had. Next I take a look at this arduino driver. It was promising, but ultimately flawed. Whenever I programmed it the keyboard would work, but after unplugging it and plugging it back in again (normal use case for a keyboard) it would fail, constantly, all the time. It took me a while to find the issue with this and I would also caution anyone working with an atmega32u4 to limit the amount of spam you put out the virtual serial port, it can cause programming issues with the arduino bootloader.

// Only act if a full message is available.
if (_serial->available() >= 8) {
for (int i = 0; i < 8; i++) {
_buffer[i] = _serial->read();
if (_buffer[0] != 0xA5 && _buffer[0] != 0xB4) i–; //if it gets off by one it will keep throwing out bytes until it gets to the start of another message

// We expect “status report” packets beginning with 0xA5, but don’t know
// what to do with them — so we silently discard them.
if (_buffer[0] == 0xA5) return;

// We *do not* expect other types of packets. If we find one, complain
// to the user.
if (_buffer[0] != 0xB4) {
Serial.print(“Unexpected packet type: “);
Serial.println(_buffer[0], HEX);
delay(100); //this makes the arduino micro programmable, fast serial communication locks it up
if (_buffer[1] != 0xC5) {
Serial.print(“Unexpected second byte: “);
Serial.println(_buffer[1], HEX);
delay(100); //this makes the arduino micro programmable, fast serial communication locks it up

I have added my code in red, and I will describe what exactly is happening here. This parser is written so it fires when there are enough bytes in the buffer to constitute a packet. Then it transfers the bytes out of the buffer and evaluates them. If the first byte is not one we expect, it throws out all 8 and starts again. If the second byte is not what we expect, it throws out all 8 and starts again. Think about that, if the byte you think is the start of a packet does not match the packet starting byte, why do you throw away the next 8 bytes and expect a packet to start there? This is an example of a super, SUPER optimistic bit of code. What was happening was a byte was getting dropped, probably because the chatpad booted up before the arduino and then it was forever out of sync. My fix for this was to inject a check into the loop that transfers the data out of the buffer and into the packet that’s decoded. If the header byte is not correct, I simply decrement the counter in the loop and it keeps over-writing the header until a valid one is present. This theoretically means the following checks will never fire.


With the parsing fixed I was now able to implement the character tables the way I wanted. I suppose I could have done this in the library, but I like to have a light touch on other people’s code and use it as-is as much as possible (at least where libraries are concerned maybe I have hangups about that).

if (type == Chatpad::Down) {
char a = -1;
if(mode == 0 && caps == 0) a = mode0A;
else if(mode == 0 && caps == 1) a = capsA;
else if(mode == 1) a = mode1A;
else if(mode == 2) a = mode2A;
if(a != -1) Keyboard.print(a);

This picks which array to decode the keypress to, either mode0 which is normal, mode1 which is green, mode2 which is orange, or caps lock mode. All positions that are unprintable characters in those overlays have a value of -1 so if the variable 'a' falls through this while remaining '-1' then it's either a keypress that warrants no action or something that has to be handled below.

if (code == 132 && mode == 2) mode = 0;
else if (code == 132) mode = 2;
if (code == 130 && mode == 1) mode = 0;
else if (code == 130) mode = 1;
if (code == 85); //left
if (code == 81); //right
if (code == 113); //backspace
if (code == 131); //leftcontrol
if (code == 99); //enter
if (code == 38 && mode ==2); //up
if (code == 54 && mode ==2); //down
if (code == 55 && mode ==2); //left
if (code == 53 && mode ==2); //right

if(code == 129 && caps == 1) caps = 0;
else if(code == 129) caps = 1;

The first couple lines handle setting or un-setting the green and orange lock modes, they can only be unset by pressing the same key again. The next few are special keys (not characters) and the four arrow keys are a sort of easter egg to me. I implemented the same sort of WASD-to-arrows on the Commodore 64 matrix controller and revived it here because there are no proper up and down arrows. The last two lines let you turn caps lock off in any mode and turn it on in any mode (but as you will see, in some modes it acts as shift and only in the correct mode does it act as a lock).

if (type == Chatpad::Up) {
if (code == 129 && mode != 2) caps = 0;
if (code == 85) Keyboard.release(0xD8); //left
if (code == 81) Keyboard.release(0xD7); //right
if (code == 113) Keyboard.release(0xB2); //backspace
if (code == 131) Keyboard.release(0x80); //leftcontrol
if (code == 99) Keyboard.release(0xB0); //enter
if (code == 38 && mode ==2) Keyboard.release(0xDA); //up
if (code == 54 && mode ==2) Keyboard.release(0xD9); //down
if (code == 55 && mode ==2) Keyboard.release(0xD8); //left
if (code == 53 && mode ==2) Keyboard.release(0xD7); //right

The first line does what I said above, if it is not in orange mode then when you release shift it does not lock, if in orange mode it locks. The rest just release the special keys they pressed. The entire rest of the code is just housekeeping on the LED outputs for the mode indication, I could have used other I/O for encoders or buttons but right now I wanted to keep it simple. There were other things I could have done, including reprogramming the PIC (but seriously, fuck PICs) or just using another library, but this is the solution I ended on.

My code is here and my repaired driver is here.

Wahoo Fitness Bluetooth scale reverse engineering

April 6, 2019

I had a friend recently ask about putting his bluetooth scale on out IOT.  My first answer: just grab the serial lines and fuck bluetooth.  That turned out not to be completely correct in this case.

scale, with notes

The board included a footprint for a bluetooth board that was not present as well as a bunch of test points, that was useful.  Turns out the NRF8001 has a serial port but it’s not used in normal operation so the data from the scale was getting to the bluetooth controller some other way.  I probes the lines with a scope and leaned on the scale while monitoring the bluetooth connection, I knew that the bluetooth connection had changing data and that the data I wanted would be updating at that rate somewhere on the PCB.  eventually I found it to be SPI with simple clock and data lines, every time the bluetooth program updated the data bus had a spike.

clock and data

The connector is broken out to the exterior of the device because I should have no hope of battery powering an esp8266 for any reasonable amount of time so this will probably get an external box with an esp and regulator to power the scale as well so it doesn’t need batteries anymore.  Remaining reverse engineering to come later.

external power and data connector

Pinball 7-segment LED reverse engineering

April 6, 2019

Found in a box in the basement

This is a quick overview of an LED 7-segment driver board found in a box of arcade PCBs in Frank‘s basement.  We’ve been working on some of the low hanging fruit of his collection lately.  Osborne executive monitor repair (broken solder joint), although I still think we should burn new roms that have his name in them since that’s a service offered back in the day.  Commodore 1902 monitor repair (broken solder joint).  Verified the working status of a metamorphic force board I got out of a freecycle nintendo red tent (someone wanted to buy it from me).  Built a video cable for his commodore 64 and diagnosed it with a failing PLA.  There’s plenty more planned, but that’s the highlights for now.  On one expedition into his many boxes of random PCBs we came across this board.

back side

To me this looks like it could pretty easily be reverse engineered to drive with simple GPIO from, say, an esp8266.  The layout is as follows:

8-bit data bus for all the segments

4-bit address bus for the digits, last two select which board (player 1 or player 2)

7442N to decode the address bus for each clock input of the 74LS273

74LS273 for each digit to hold the display

ULN2003A to drive the displays (at 12v)

2n2222 to drive the decimal point on top (only 7 drivers in the darlington)

Resistor network for the LED segments

Interface board

There are also a few interesting notes I have on this board design:

The 2n2222 drives the decimal point through a 470R resistor, not using the resistor pack, but the resistor pack has a spare resistor because it has 8 and the darlington only has 7.  The values are the same so the board designer wasted two resistors on those decimal points as well as the labor to install them.

The bottom decimal points are not controllable, but could be by bodging a copy of the top circuit on the bottom.

Most strangely of all, the 7442N outputs are inverted from what the clock on the 74LS273 wants.  Here’s what I mean: the 7442N is a BCD to decimal decoder, meaning that on the 4 bit input you can count up from 0 to 9 and for each combination a different output pin will be enables, but note I didn’t say ‘will be high’.  The output of this chip is to have all the outputs high except the one being addressed, possibly for use as a low side driver for nixie tubes or something, but either way it means that when you switch to a digit you trigger a negative going pulse.  The 74LS273 latches in on a positive going pulse to the clock input, meaning for this relationship of chips you have to pick the segments you want to display and put it on the data bus while the location is selected on the address bus, then it is latched in when you switch away from that address.  This either means that you have to know which location you want to display next before writing the current one or, as I do, switch to an unused address (in retrospect this should be something out of range of the chip, like F, but I just picked one not used by my display).  I do this because processor cycles aren’t super important to my application and the ability to arbitrarily write to a certain location is.

If I were so inclined I might chop the traces between the clock and decoder chip and put in an inverter, but this project is an exercise of interfacing to the circuit without modifying it.  That being said I did modify it a bit by adding a connector for power that I had the mate to.

Interface board back side

On to the Howie did it section of the post.  The obvious solution to me was an esp8266, but they have nowhere near enough pins.  We’ve been using the MCP23017 as the go-to solution to this problem, especially as you can stack 8 on the same i2c bus without any collisions.  This also solves our level shifting problem going from 3.3v to 5v (although not really a problem because 3.3v is withing the ‘high’ range of just about all 5v chips).  I power the whole thing with a 12v barrel jack which runs unregulated into the 12v input on the power header (for the LED common lines only) and also run it into a 5v regulator board.  Now, these are rated at 2A.  I don’t know who rated them but I bet they’ll also tell you they caught a fish thiiiiiis big.  My design sags the voltage pretty bad under load, but not enough to cut out so whatever.  I chose that particular converter because it was thin and would fit between the PCB and the… other PCB (by this point I had avoided any components on the back and I wanted to keep that up).  For the esp8266 I used the d1mini despite having plenty of real estate and a bunch of boards I want to get rid of because I forgot I still had those kicking around.

Pin layout vs pin numbering in arduino library

Unusually for me I wired this up without testing anything (aside from testing if the i2c expander showed up on the bus before wiring the data and address lines).  This was a bit of a mistake as I guessed wrong about the direction the port goes on the expander and now my address bus is backward.  I also wired up jumpers for the address in case I wanted to change it… for some reason.  my main concern was getting the soldering wrapped up all at once so it would just be software after that.

Backwards bits for addressing

I spent a fair bit of time with the multimeter determining how the code mapped to the hardware and very little time actually coding the logic to drive the display.  The address bus being backward was confusing at first, but not more than the logic on the decimal decoder being inverted.  Throwing 0xFF on the data bus an latching it into each possible location made it easy to find where on the bus each display was located.  After that it wasn’t hard to count up on the data bus and continually latch it into one display to watch the segments count up like a binary counter.  That made decoding the segment locations easy.

Somewhat logical bit layout

I really like how the data bit layout ended up, kinda the opposite of the address bit layout.  You can see that the lower nibble controls the lower half of the digit and the upper nibble controls the mirrored upper half of the digit.   This means that it’s fairly easy to read the font, knowing what the bottom and top half each look like.

Now I’ll give a small explanation of my code (linked below).  The first section is the defines at the top:

//this is the lower 4 bits backward, to make more sense it would be wired the other way
uint8_t displays[] = {0x00, 0x08, 0x04, 0x0C};

//unused display output used as a state to send the latch to when not used
uint8_t neutral = 0x01;

//hand coded 7-segment font
uint8_t digits[] = {0xEE, 0x88, 0xD6, 0xDC, 0xB8, 0x7C, 0x7E, 0xC8, 0xFE, 0xFC};

//buffer that writeBuffer pulls from
uint8_t buffer[] = {1, 2, 3, 4};

//buffer that writeBufferRaw pulls from
uint8_t bufferRaw[] = {0xFA, 0xFE, 0x66, 0xEE};

The first section is the addresses of the displays, so I can refer to them as displays[2] instead of 0x08 for example.  The next one is just an unused display, for more correct code (and stuff compatible with a second board chained) it should be something like 0x0F.  I’ll also not here that it just needs to be in the lower 4 bits, the upper 4 aren’t used and could be inputs if you like.  The next section is the font table, like the first one it’s so I can say digits[3] instead of 0xDC and display a ‘3’.  If you wanted an alphanumeric font you could either do an ascii table with null or unique but wrong values for the unprintable stuff and bytes representing the font for all printable characters, or you could do key-value pairs and look them up while having a default value for anything not in that table.  The first one is easy, the second one probably takes less memory.  The last two sections are just buffers that you can update, then trigger functions to update all the displays at once.

uint16_t writeAddr(uint8_t high) {
uint16_t a = mcp.readGPIOAB();
a = high << 8 | (a & 0x00FF);
return a;
uint16_t writeDigit(uint8_t low) {
uint16_t a = mcp.readGPIOAB();
a = low | (a & 0xFF00);
return a;

Both of these are unashamedly stolen from some IOT code on the i3detroit github but I renamed them so you can tell what they actually control in this code.  All they do is take a byte and write it to half the expander, one for high and one for low.

void latchIn(uint8_t digit) {


Like I explained before, you latch in the data bus when you switch away from the address you currently have selected, this function just jumps from wherever it is (it’s at the neutral address most of the time) to the target address, waits a tiny bit, then goes and parks itself back at the neutral address.  This means if the neutral address were actually being displayed somewhere then it would always hold the last value written in because I set the data bus before this so both jumps latch in the data.

void writeBuffer()
for (int i = 0; i < 4; ++i) {

I broke this out into a function, but inside you can see how to write the digit.  This function iterates through the buffer, correlating it with the font table and writing those bits to the data bus.

void writeBufferRaw()
for (int i = 0; i < 4; ++i) {

Here is the last section of code but it’s important.  I have included a 0-9 font table, and right now that’s the only thing I intend to use this display for, but years from now I’d like to be able to do something else with it without having to rewrite the code, so I’m leaving raw access to the bits in (you can push animations or letters to the display via mqtt if you want).  This just writes the buffer of raw bits the same way the above one writes the buffer of numbers.  Raw also happens to be the only way to drive the decimal points (although I could have made 0-9 digits and 10-19 digits with decimal in the font table).

This is a pretty good example of how I tend to go about reverse engineering things so I’ll present it here.  First I name and number the connectors and chips if they aren’t already done.

Board layout has been numbered

Then I trace all the pins on a given connector, then the next, then the next.  Then I do the same for the chips, tracing how they interconnect until I can look at the whole picture and not have any further questions about how the board is wired up.

Address chip pinned out

Sometimes I deviate a bit from this for ease of readability (like in the case of the player select on this board or the bare transistors) but labeling things and having a convention to stick to while going back and forth is key.  I even wrote on the board to remind me which pin I declared pin 1 on the headers or where the clock input was on each latch.

Input pin header

That’s really all I needed, the latches and darlingtons are transparent, logically.  I have the whole album here as well as the code here.

printing on the board:



Ledia Grayhound Electronics Inc. © 1988

Now if anyone has one google should bring them here

Is it from a dart game?


Eurocom laptop backlight repair (bypass?)

February 20, 2019

So, there was a small issue with my laptop.  It was dirty.  I cleaned the screen with glass cleaner and wasn’t too careful about where the liquid got.  Later that night the screen fizzles out.  In summary The not-water part of the cleaner corroded on the LCD connector on the display and no matter how much I cleaned it I couldn’t get it all functional.  I ordered a replacement panel (LTN156FL02-101) and a replacement cable (6-43-P7501-022-1C) from ebay and aliexpress respectively.  The panel came in first and I was excited to install it, in that excitement I tried seating the old laptop cable on the new (used) panel a couple of times and eventually I stopped getting backlight and smelled electronics burning (oops).

eurocom backlight circuit

Luckily this is a Eurocom, which means it’s a rebranded Clevo, which means I can get the schematics for it.  I have the schematics for the P775DM2(-G) and mine is a P751DM2-G and this section is the same between them.  Above is the chip that I found charred and destroyed.  The MTS3572G6 was burnt to a crisp.  I tried to order one but ebay had none, digikey had none, aliexpress had none, it seems to be a very specialized part (N-channel P-channel pair, like a darlington).  I could have gotten some similar FETs and bodged them back in, but after reviewing the circuit it seems that all this does is turn on the backlight.  Before I did this I had no idea if this would mean that it would always have the backlight on when the lid was closed, or other un-intended consequences.  But I also saw this:

edp circuit.PNG

This shows that the panel handles the brightness on its own, and even has a backlight-on line, the part of the circuit that fried seems to let the video card turn off the power to the backlight to save power (I’m guessing).  Based on all this bridging PJ45 would seem to fix my issue.  But if it happens again I’ll break something upstream and I don’t want that.  I could install a fuse at the jumper, but what reating? The burnt chip is good for… 20A? That won’t do (and I don’t believe it).  What are the ratings on the panel then.


Looks like 900mA.  I picked the next up size polyfuse (1100mA) and got to soldering.  It’s not pretty.


That connector at the bottom is the graphics card socket, this all had to fit under the graphics card.  After re-assembling this thing for the tenth time in a week it boots up!  The new screen has a stuck pixel but that’s what I get for buying used instead of new.  The un-intended consequence is that I now have screen on boot every time.  Previously, when not in UEFI mode the screen would not light up if the laptop had been on recently (20 minutes or so).  I never found the root cause of this, but once windows 7 booted and the driver asserted the graphics card everything was fine.  Now it seems the display is always on for boot.  Don’t ask me why it used to have a cooldown time, I tried everything including removing the bios battery and resetting to factory defaults.  This jumper happened to fix all the problems I had with this laptop.