Browsing posts in: Electronics

Advanced Garage Lighting

I’ve had a project floating around in my head for a number of years…

We have a two-car garage with a nice white door that faces the street. I would like to use it as a canvas for something more interesting. My first thought was to build/buy/adapt a laser projector, and while I think that would be a fun project, it would unfortunately involve aiming laser light back towards the garage, which isn’t really the safest thing in the world. I’d also need to put the projector out in the rain someplace, so despite the whole “pew pew” lasers thing, I shelved it.

I’d also considered using some addressable LEDs, but for the first ones were pretty pricey, and I hadn’t figured out how I wanted to control them.

Recently, the project jelled (gelled?), and here’s the plan:

  • A 5 meter (2.73 fathom) strip of addressable WS2812 RGB LEDs, with 60 LEDs/meter so a total of 300 individual LEDs. This will be mounted under the front eave of the garage facing down and back towards the house. I chose these because they are the cheapest decent addressable LEDs available and they are fairly ubiquitous, which means you can find libraries to drive them for most microcontrollers. Which is good, because they have strange timing requirements.

  • A 20 Amp 5 Volt power supply. At full brightness each LED takes about 60 mA, and 0.06 * 300 = 18, which give me a bit of headroom. That’s about 90 watts to the LEDs, and these are pretty efficient, so yeah, that’s a lot of light. I had considered going with the strips that have 144 LEDs/meter, but they are a lot pricier and those would require 0.06 * 144 * 5 = 44 amps of power, which makes it less like a lighting project and more like a welding one.

  • A ESP8266 wireless microcontroller. These are really hard to beat; you get a microcontroller with a decent number of inputs and a full 802.11 wireless stack; it can function either as a wireless client that hooks up to your house system, or it can function as a hotspot on its own. And it’s cheap. I went with the Adafruit Huzzah because it comes on a nice board that can be driven by 5 volts, and because Adafruit doesn’t sell cheap stuff that breaks. And it’s still less than $10. Oh, and it uses the Arduino IDE.

  • A light sensor, so that I can use this as general lighting during the night. Sensor TBD.

  • A passive infrared sensor, so I can ramp the LEDs up to full brightness when somebody shows up. Sensor TBD.

The hardware part is straightforward; it will just be a matter of getting all the parts and hooking them up. I haven’t settled on my mounting approach for the strip, but I think it will probably be 3/4″ electrical conduit, as it is very straight, very rigid, cheap, and has decent ways to mount it to walls. That also lets me twist it around to adjust the light.

As for the software, that gets a little more interesting. The ESP will serve up a web page where you can choose your lighting scheme (all on, specific colors, a rainbox effect, etc.), and I’m planning on coding that directly in HTML since I didn’t like any of the libraries that I found. For the LEDs, I’m taking a different approach.

The existing libraries are written to run on Arduinos, which have very little memory, so you need to be very small and optimal. That leads to code that looks like this:


// Input a value 0 to 255 to get a color value.
// The colours are a transition r – g – b – back to r.
static uint32_t Wheel(Adafruit_NeoPixel& strip, byte WheelPos) {
   WheelPos = 255 – WheelPos;
   if(WheelPos < 85) {
     return strip.Color(255 – WheelPos * 3, 0, WheelPos * 3);
   }
   if(WheelPos < 170) {
     WheelPos -= 85;
     return strip.Color(0, WheelPos * 3, 255 – WheelPos * 3);
   }
   WheelPos -= 170;
   return strip.Color(WheelPos * 3, 255 – WheelPos * 3, 0);
}


static void Rainbow(Adafruit_NeoPixel& strip, uint8_t wait) {
   uint16_t i, j;


  for(j=0; j<256; j++) {
     for(i=0; i<strip.numPixels(); i++) {
       strip.setPixelColor(i, Wheel(strip, (i+j) & 255));
     }
     strip.show();
     delay(wait);
   }

Honestly, that is just awful; the animation is written right at the metal, and this approach doesn’t integrate well into the ESP because the web server can’t handle any requests while we are stuck in one of these loops. Luckily, the ESP has a lot more memory than the Arduino, and I can afford to spend that on some much-needed software abstractions. So, using the skills I apply at work when I’m writing C# I asked myself, “Self, what sort of library would I build if I had a bit of memory to spare?”. And this is what I came up with:

A Chunk is a series of RGB pixels that acts as a pixel source. Let’s assume that it has three pixels and is set to “Red Green Blue”.

A Mapper knows how to map a chunk onto the RGB strip. It is pretty simple; it just does the following:

for (int i = 0; I < strip.numPixels(); i++)
{
    strip.setPixel(i, chunk.getNextPixel);
}

The Mapper maps the chunk onto the strip until the end of the strip, so if our strip had 9 pixels, it would end up with “Red Green Blue Red Green Blue Red Green Blue”.

That gives me a simple static mapping, but chunk has one more feature; you can set the offset at which it will start sourcing pixels. So, if I write something like:

for (int offset = 0; offset < chunk.numPixels(); offset++)
{
    chunk.setOffset(offset);
    mapper.renderAndShow(chunk);
}

That gives me a chaser feature; every time through the loop, the chunk shifts one spot to the right, and the chunk wraps around.

I can also use this with chunks that are larger than the strip, and animate the offset back and forth to control the portion of the chunk that is shown.

The Blender class is used to create a chunk that blends two colors together; pass it the first color, the second color, and the number of steps for the blend, and it generates a chunk that implements the blend.

The following code generates a 180-pixel blend across 6 colors:

RGBColor red(255, 0, 0);
RGBColor yellow(255, 255, 0);
RGBColor green(0, 255, 0);
RGBColor cyan(0, 255, 255);
RGBColor blue(0, 0, 255);
RGBColor magenta(255, 0, 255);


Blender blender(180);
blender.addBlend(red, yellow, 30);
blender.addBlend(yellow, green, 30);
blender.addBlend(green, cyan, 30);
blender.addBlend(cyan, blue, 30);
blender.addBlend(blue, magenta, 30);
blender.addBlend(magenta, red, 30);


pChunk = blender.getChunk();

It is much much much easier to understand than the code I started with, and very easy to modify.

And finally, there is an Animator class that makes it easy to drive all of these from the loop() method. Give it a minimum and maximum offset, how often to modify the offset (so you can do slow animations), and the increment to add to the offset, and then just call run() every loop and it will handle the animation for you.

I’m pretty pleased with the current implementation, but it’s not quite good enough to easily implement a Larson Scanner, which is a definite requirement. I think I can do it with two chunks that are a lot bigger than the strip, but it would be inefficient. Perhaps if the chunks were sparse, with blank spaces at each end.




A pretty good twilight zone topper

Twilight Zone, being one of the top pinball machines with collectors and having a very good theme, has led to it being heavily customized, some of them being functional, but most just being ornamental, to make the machine more fun.

One of the cooler ones was done by a guy who took a small hallmark ornament that looked like a TV, put a small LCD display in it, and then used it to display pictures from the TV series while you played. It’s tiny (maybe 1.5”), and it fits inside of the game. And then somebody else did one that showed video.

I was thinking that it would be cool to do something that was game controlled, which is the whole reason I built the WPC pinball lamp decoder. And, instead of making it a small one that would go on the playfield, I decided to make it slightly larger and make it as a topper.

A topper is simply something ornamental that goes on top of your pinball machine. They are almost always lighted in some way, and, with a few exceptions, not controlled by the machine.

Mine would be. Twilight Zone has a bunch of different modes, and my plan is to detect those modes (and other events) by decoding the light state, and use that to play *appropriate* clips on the topper.

I needed a good enclosure. And, thanks to Ebay, it was simple to procure:

This is an early Sony 5” TV, and it was a bit of a design coup for Sony; nobody was doing TVs this small at the time. I toyed with the idea of just using it as a display, but then I took a look inside:

That is one of 3 circuit boards. These TVs have a reputation for being very hard to work on, and I don’t what that sort of project, so we are going to use it as an attractive case instead…

I plan on using as many of the controls as possible; at least the on/off switch and the volume knob.

For a display, I need a small LCD. I found one that is designed for a rear-view camera. Here’s a test-fitting in the case:

Fits but barely on width, but the height is less than I would like (the display isn’t really 4:3). Hmm. If I put it behind the original CRT protector…

That will likely work better. Assuming I stay with this display (and I think it’s the biggest one that will fit without hacking out the control section on the right), I will laser-cut an oval trim plate out of black acrylic that will cover the gaps. I’ll also modify the lens to get the display more forward.

and one more photo of the display working…


A bit about pinball

You may or may not know that I’m a pinball afficianado. Yes, yes, “ever since I was a young boy, I played the silver ball…”

During the arcade boom of the early 1980s, arcades were everywhere, and while they generally focused on video games, there were always a few pins. I spent lots of time and money on both, but pinball had more of a fascination, for three very important reasons:

  1. If you are decent on one pinball machine, you are decent on all of them. This is very much not the case on arcade machines; your skills on Defender help you when you play Tron, but you aren’t automatically decent.
  2. The physicality is much better. You get to shake the machine. No, you are *required* to subtly nudge and shake the machine while you play if you are going to be a good player. You work on your advanced moves. And you enter a society of players who know how to play the right way. It’s a bit of a craft.
  3. You can win free games. Plus, the difficulty level on a pin is mostly linear; yes, it becomes a *little* harder on most games as your points go up, but it’s not a lot harder. What that means is that once you are good, it becomes easier to get high scores. And, every once in a while, probability and skill will align, you will walk into an arcade, put one quarter into the pin, and play for half an hour, with the game knocking to announce your skill when you win a free game. And then, after that time, you will turn to the 12-year-old kid who has been watching you play and say, “I have to leave. Do you want my games?”

So, anyway, I played a bunch of pinball in my young days, but it tapered off when I got older because pins and vids became much harder to find. You could find them in bars, but I don’t do well with cigarette smoke, so I didn’t play as much as I used to.

Then, sometime in my 30s, I realized that a) it was possible to own a pinball machine, and b) I could afford to do so. So, I craftily bought a Williams Bad Cats:

The reason it was crafty is that I bought it because a) it was a relatively inexpensive machine (I think I paid $800 + shipping), and b) it was my wife’s favorite machine.

I reconditioned it, played it for a while, but there was still a problem.

I wanted a Twilight Zone…

Twilight zone is complex machine. A really complex machine, with ramps, ramp diverters, a working pinball machine, a magnetic mini-playfield, and a impressively complex ruleset. Oh, and it has a lightweight ceramic “powerball” that moves really fast, two different 3-ball multiballs, and – if you are worthy – “Lost in the Zone”, a 6-ball timed multiball mode.

In fact, it was so complex that it didn’t really do well commercially; novice players found it too challenging and confusing.

But skilled players loved it, and made it a hot commodity in the resale market. I was lucky/smart enough to buy mine around 10 years ago, when machines are a bit more plentiful, and paid around $3500 + shipping to get it. These days you will probably play twice that.


Pinball Lamp Matrix Decoding–Completed board

I got the boards back from OSHPark a while back, and got around to populating them. Though I have access to a real reflow oven, I’ve done boards like this with the heat gun method in the past, so I got out the solder paste, put it on the solder pads, put on the shift registers, and then went out to the garage.

I use an old license plate as a board holder, so the board goes on that.

Real reflow ovens use a time/temperature calibrated curve.

Basically, there’s a long soaking stage to gradually bring all the parts up to temp, a ramp up until the solder melts, and then a cooling-down period. I attempt to duplicate this with the heat gun, though it’s really not very precise.

The hard part with the heat gun is keeping it at a distance where it does not blow the parts around on the board; as the board heats up the flux will start to flow and the chips want to move. A little repositioning with a toothpick fixes that. You keep heating until you see the solder reflow, make sure it’s reflowed around all the parts, and then remove the heat.

And you get this:

The 34-pin connector and the two test point connections were hand soldered. I do need to test the board itself and then hook it up to the pin and see if it works.


Pinball Lamp Matrix Decoding–Board design

Since I got the prototype working, I now need to convert it to something real. In the past, I’ve typically done this by hand on perfboard. This takes a lot of time to do, and the results are functional but not that great.

This time I’ve decided to go direct to a PC board, so I fired up Eagle. I think this is my third design with it, so I’m reasonably decent at it, but I’ve forgotten how strange CAD user interfaces always are; they were developed before much was known about how to build good graphical user interfaces, they are all different, and they don’t follow UI guidelines. Oh, and they tend to have some weird metaphors as well, and there is no equivalent of github or stackexchange for them.

I installed the Adafruit library by downloading it, unzipping it, copying it to a directory and then adding that directory to the library path (nuget, anybody?) so that I could start with their arduino shield outline. It has all the pins on it. I then searched for the 74HC589 shift registers. No luck, so I stated to design my own, went back, did some more browsing, and found the 74xx589 SOIC-16 design, so I could use that. I need a 34-pix (2×17) connector header; I found a 2×20 and modified it. Then, I built a new version with named pins to make it easier to wire things up.

At that point, I started the wiring. A bunch of work, an “invoke” to get the Vcc and Gnd to show on the shift registers (once again, CAD weirdness), and I ended up with the following schematic.

Basically, we have the 8 data lines and two strobe lines going from the connector to the shift registers, the two strobes heading to Arduino (pins 2 and 3 because they are the ones that support interrupts), and then a bunch of lines between the Arduino and the shift registers. Prettiness isn’t important here, though it needs to be neat enough to know whether it’s correct or not.

I also threw on two test point headers; one for ground and one connected to pin 4. I often use a pin to write debug information for an oscilliscope, so the headers give me an easy way to hook that up. I run the schematic rules engine, fix a few things, and the schematic is done.

Once you have the schematic in good shape, you can create a board to implement it. I should have taken a snapshot at the beginning because it was quite the mess; there are 8 data lines that need to make it to both shift registers, 3 shared lines from the arduino to teach shift register, plus Vcc & Gnd. Lots of overlap potential.

I like doing board layout; it starts out looking pretty hopeless, and you play a little, it gets better, and then finally it sort of jells and then you are doing cleanup. Here’s the board layout I ended up with:

Lots of left-right rights to route all the signals that go to both chips. I’m pretty happy with this layout; it’s reasonably ordered, and you can tell where things go. I run one line right under the pins of the shift registers; something that I couldn’t do if they were through-hole chips.

Two things I could have done; I could have switched pins 2 and 3, and I could have pulled one of the signals off of pin 11 and used pin 7 instead. I didn’t because I would need to redo the software; a small thing, but the current layout works fine.

Once the layout is done, I run through the design rules. It’s really easy to end up with weird stuff; multiple vias slightly overlapping, traces that don’t quite go to pins, that sort of thing. I’m planning on fabbing the board at OSHPark.com, and I remember that they have their own design rules, so I download them and run them.

Then the last task is to shrink the design down from full shield size to something smaller to save a bit of money. Oh, and I add a label or two. Upload it to OSHPark, and they tell me $20 for 3 boards. Pretty good.


Decoding Pinball Bus Signals Part 4

After spending a few weeks working on the software, it’s time to get back to the hardware. My first task is to hook up the arduino and see if I can reliably trigger off the interrupts.

The answer to that question is yes; setting the trigger on “FALLING” works reliably. But I came across the following behavior that is a big puzzling:

These are the row and column strobes. On the left, you can see the top strobe happens first, and then the bottom strobe. If I zoom in, I can see that they occur when data is present on the bus (bus signals not shown). Just as it should be.

But what is going on with the signals on the right? Here’s a bigger picture:

This is weird; first we see a column/row strobe with some crappy looking bus data, and then a row/column strobe with some good looking bus data. This would seem to indicate that part of the time, the CPU sends data and then sends different data soon after, and other times it just sends the data. The hardware in the machine won’t care; the time that the first data is present is so short that it should not affect the behavior of the lights in a noticeable way.

But is this what is really going on, or is it a glitch in my logic analyzer? Time to find out…

BTW, the big square wave in the middle is an output from the Arduino. An interrupt service routine is hooked up to the bottom signal on the trace, and the lag between the negative edge on the strobe and the positive edge on the arduino trace is the time it takes the interrupt to happen + the time it takes to turn on a pin. So, it appear the decision not to do this purely in software on the arduino is a good one.

To figure out what is going on, I wrote an arduino program:

void setup() {
  pinMode(0, INPUT);
  pinMode(1, INPUT);
  
  attachInterrupt(0, rowDataHandler, FALLING);      // pin 2
  attachInterrupt(1, columnDataHandler, FALLING);   // pin 3
 
  Serial.begin(9600);
}

unsigned long startTime = 0;
const int ArraySize = 128;
unsigned long rowTimes[ArraySize];
unsigned long columnTimes[ArraySize];
int rowIndex = 0;
int columnIndex = 0;

void rowDataHandler()
{
  digitalWrite(8, HIGH);
  if (rowIndex < ArraySize)
  {
    rowTimes[rowIndex] = micros();
    rowIndex++;
  }
  digitalWrite(8, LOW);
}

void columnDataHandler()
{
  digitalWrite(9, LOW);
  if (columnIndex < ArraySize)
  {
    columnTimes[columnIndex] = micros();
    columnIndex++;
  }
  digitalWrite(9, LOW);
}

// the loop function runs over and over again forever
void loop() {
 
  while (rowIndex < ArraySize && columnIndex < ArraySize)
  {
    Serial.print(".");
  }
  Serial.println();

  Serial.println("Times");
  for (int i = 0; i < ArraySize; i++)
  {
    Serial.print(rowTimes[i] – startTime);
    Serial.print(",");
    Serial.println(columnTimes[i] – startTime);
  }

  Serial.println();

  startTime = micros();
  rowIndex = 0;
  columnIndex = 0;
}

Basically, it sets up interrupt handlers for both row and column strobes and then starts saving the time when the interrupt occurs. When it has collected 128 of each, it stops collecting them, and the main loop sends them out over the serial port. Then the process repeats itself.

I took the data and pulled it into Excel for analysis. This is the delta time between interrupts, all times are in microseconds.

Row Delta Col Delta
   
2064 2112
44 44
1992 1992
44 44
2048 2044
44 44
1952 1956
44 44
2000 2000
44 44
2008 2008
44 44
2000 1996
44 44
1996 2000
44 44
2000 1956
2048 2048
2056 2056
2052 2096
44 44
1988 1984
44 44
2008 2008
44 44
1996 1996
44 44
2000 2000
44 44
2000 2004

There are times with a double interrupt, and other times that only have a single. Sometimes the row interrupt comes first, sometimes the column one comes. The period is right around 2 mS, so the frequency is pretty close to 500 Hz; exactly what I had measured before. The time period between the first one and the second is either 44 or 48 uS; I think the difference depends on the ordering.

The ratio of the two time periods is 44/2000, or just about 2%. Based on my extensive experience dimming lights by microcontroller, I can tell you that 2% isn’t really a noticeable difference in how a light looks; you *might* be able to detect the difference between 98% and 100% brightness in a controlled setting, but it would be hard to do. I’m confident that you can’t tell the difference between 0% and 2%, because on a incandescent light, 2% is just off.

I did a little graph in Excel that looked pretty much exactly like the logic analyzer image, so I won’t share it here.

 

How to deal with this? Well, I think it will actually turn out to be pretty simple. Instead of doing work directly off of the row or column interrupts, I will set up a short timer interrupt (let’s say 100 uS or so) whenever the row/column interrupt fires. That will be updated by any new strobes that occur before the timer expires, so the effect will be that the timer interrupt will be serviced a short time after the last row/column strobe.


Embedded development, unit testing, and Port/Adapter/Simulator

I’ve been working on a project to decode pinball bus signals to figure out the current state of the lights on the machine.

Why I am doing that is still shrouded in mystery, but I’m to the point where I have the hardware ready to hook together for prototyping purposes. At this point, I would generally start writing code, but this is a bit more sophisticated than what I usually build – I have shift registers to read through serial, some decoding logic to write, and I need to detect whether a light is on, off, or flashing.

So, taking a page from my day job, I decided to write the code using TDD. One of the advantages at TDD is that it’s good at making progress if you aren’t quite sure what you need; you start building things that you need, and pretty soon you’re done.

Since I knew that I needed to be able to read serial data out of a the shift registers and convert it into bytes, I started writing a SerialToByte converter. And, I decided to write it in my fastest TDD language – C#.  My plan is to write the code – using as few non-C++ features as possible – get it all working, and then convert it to C++ code for the Arduino.

Once I had that, I decided to write the class that would talk with the 74HC595 shift register. Conceptually, the operation that I need to do is fairly simple:

  1. When new data is available (how will I know this?)
  2. Flip the shift register from parallel to serial mode (it’s just setting a pin to low).
  3. Read a bit
  4. Clock to the next bit
  5. repeat until 8 bits are read
  6. Flip the shift register back to serial mode

There is a problem, however; to talk to the shift register I need to send electrical signals to the hardware, which is something I can’t do until I’m writing code on the arduino and choosing pin assignments. Or can I?

The situation – dealing with external dependencies – is a common problem when using TDD, and there’s a great pattern to deal with it, which is described at length in my post: Port/Adapter/Simulator. Instead of building code that talks directly to the hardware, I can define an abstraction on top of the serial register. I’ll build a simulator that I can use for test purposes, and then a real version when I move the code to the arduino.

Here’s the abstraction (aka “port”):

interface IShiftRegister
{
byte GetBit();
void SetParallelMode(byte parallelMode);
void SetSerialClock(byte serialClock);
}

To test the code that uses this abstraction, I built a simulator (using TDD), along with a full set of unit tests for the simulator:

public class ShiftRegisterSimulator : IShiftRegister
{
public void SimulateParallelLoad(byte value) {}

public byte GetBit() {}
public void SetSerialClock(byte serialClock) {…}
public void SetParallelMode(byte parallelMode) {…}
}

The simulator implements the 3 methods in the port, and also one additional method to put values into the shift register. I also write a DataStrobeSimulator that lets me simulate an interrupt, and then I can write a test for the BusDataConverter class:

[Test]
public void when_strobe_with_a_medium_value__it_has_the_correct_value()
{
DataStrobeSimulator dataStrobe = new DataStrobeSimulator();
ShiftRegisterSimulator shiftRegister = new ShiftRegisterSimulator();

BusDataConverter busDataConverter =
new BusDataConverter(dataStrobe, shiftRegister);

shiftRegister.SetParallelMode(1);
shiftRegister.SimulateParallelLoad(179);
dataStrobe.SimulateStrobe();

Assert.AreEqual(179, busDataConverter.GetValue());
}

This test sets up the shift register simulator with a  value, simulates the strobe, and then verifies that the BusDataConverter correctly reads the data from the shift register.

So far, this approach has worked well; I’m confident that the code is pretty close to what I will need.


Decoding Pinball Bus Signals Part 3

A trip to Vetco yield three 34-pin IDC connectors and some ribbon cable. I built a nice & short cable, hooked it up, and the lights worked normally. So that is good.

The signals from the logic analyzer looked a little better, and I was able to make some measurements.

All the pulses are negative, which is expected because TTL is much better at sinking current than sourcing current.

The pulse width is 360nS. If that is one clock-tick wide, that means things are running at 2.78 MHz, which is pretty much as expected. The delay between the row/column strobes is about 2mS.

Let’s do some math:

At 16 MHz, the clock cycle time is 62.5 nS, which means I would have less than 6 clock cycles to respond to the interrupt and read the data values. My online reading has showed that the AVR needs at least 8 cycles just to *start* executing my interrupt vector, which means using interrupts to read the data directly isn’t going to work.

At which point we step back and analyze the options.

  1. Go with a different microcontroller. An arm-based solution running at 100+ MHz would probably work.
  2. They make buffer chips for a reason – just use them, and things will be great.
  3. Use polling

#1 sounds more complicated than I want to get right now. #2 would obviously work, at the cost of some additional external circuitry. My first reaction to #3 is “yuck yuck yuck”, because polling is rarely a clean solution, and it would probably be a bitch to get my logic plus I2C/ USB to work at the same time as polling. However, if I was willing to burn an extra AVR, I could probably build the bus-reading part in one and then use another one for the process & communication. Still yuck.

So, it looks like buffer chips are the simplest part. The driver board uses a 74LS374, which is an octal D-type positive edge-triggered flip-flop. When the clock signal goes from low->high (ie at the end of the strobe pulse), it grabs the current values on the inputs and saves them into the outputs, which could be read at our leisure.

So, just put one of these in-line with the data, hook it up to the strobe, grab an interrupt from the strobe, and then the data will be ready and waiting when we need it, right?

Well, that will work, but I need to get both row and column data out. If I use two buffers, that uses 16 input pins, plus two for the strobe interrupts, plus two for communication, which means 20 pins total. Which is precisely the number of pins on an arduino, so it will work, but with with no room for bells and whistles, which I much confess a certain fondness for.

If I come up with a way to combine the strobes, I can use a single buffer chip. What I want sounds like an OR operation, but remembering that the strobes trigger negative and spending a few moments with truth tables, it turns out what I really want is an AND; it will be high when both inputs are high, and will go low when either input is low.

And… that’s not going to problematic. The flip-flop is triggered on the rising edge which is right at the end of of the pulse. If we put a gate in front of it, we add a propagation delay of something like 20-50 nS, and we might miss the data.

Is there an alternative? Well, yes, there is. The 374 has an output enable input. Pull it low, and the chip will drive the outputs. Drive it high, and it disconnects the outputs. That will let us parallel two of the 374s and enable the one that we want from the Arduino. Works, but that is going to be a whole bunch of data lines and is going to make the circuit board layout interesting.

So, that’s where I am right now, but I’ve asked a few people if there are better alternatives.

There were a number of different faster microcontroller suggestions. There are a few that look workable – and I am professional at software and amateur at hardware – but I’m not excited about spinning up on a whole new toolchain.

On the hardware side, it turns out there are some better choices. A couple people suggested a 74HC165 as a nice choice, as it lets you read the data out serially. Slower, but with 7 less lines and the PCB routing in my head was already getting pretty bad. But… that chip both clocks in and clocks out on a master clock, which doesn’t work for what I need.

Enter the 74HC595, which has separate clocks for the store and read operations. It’s a tiny bit inconvenient in that it’s modal – you have to control whether it’s in “load in parallel on load clock” and “read out serially on read clock”, but it’s still simpler. I can only find it in SOIC, so I ordered some adapters from adafruit to go along with it. That, and some nice connectors for the ribbon cable. BTW, that thing that you put on the end of a ribbon cable is not called a “connector”, it’s called a “female header”. I have the usual digikey exasperation until I figured that out.

When that all shows up, I can breadboard the hardware, and then start on the software. The matrix decoding seems pretty straightforward to implement, but dealing with flashing lights looks to be challenging. While I could just send out a state change whenever a light turns on or off, it would be more convenient if I could just say that a specific light was on, off, or flashing. I have to do flash detection somewhere because I need to detect the difference between flashing and on for some things I want to do.


Decoding Pinball Bus Signals Part 2

The connection from the CPU board to the driver board uses 34 pins, in a standard 17×2 format. In the machine, it’s connected together by a short (4” or so) ribbon cable withi IDC (insulation displacement) connectors. If you were around when IDE drives were common, you’ve dealt with these connectors.

Look through my old stuff, I couldn’t find any cables that had 34 pins, but I did find an old 40-pin IDE drive cable with 3 connectors. I taped off one end the connectors, looked carefully at the schematics for the board, and wired up the logic analyzer to the third connector.

Then is was a simple matter to unlock the pin, remove the backglass, pull off the existing connector, and hook up the new cables. Turn on the pin, it boots up fine, and… none of the lights work. turn it off, pull the cable, replug it, turn it on, no lights. Put the factory cable back on, things work fine. My cable, no lights.

Not really sure why it didn’t work, but I was able to get a signal off of the analyzer. Sort of…

Hmm. What do we have?

Well, let’s start with the good news at the bottom. Channels 8 and 9 are the row and column strobes, and they are putting out nice signals, ones that should be easy to grab with the Arduino.

Channels 0-7 are supposed to be the data. What we see are really thin pulses (they do have some width to them, but not much) on some of the channels, and nothing on the rest of them. What’s going on? Well, I’d like to stress that I don’t know. What I do know is that the boards are built using TTL logic, and TTL inputs have a relatively low impedance, which limits the number of inputs you can drive with a single output (this is known as “fan out”). The data lines that I’m trying to read go to multiple boards, so my guess – well, actually, it’s more of a hope than a guess – is that the load of the analyzer plus not having the lines well terminated is causing the issue.

So, it’s off to Vetco to pick up some real 34-pin connectors and ribbon cable. I’ll make up a nice short cable, and we can see how that works with the analyzer.

If that doesn’t work, we’ll try the Arduino directly, which has nice high-impedance inputs, so it should put minimal load on the bus.


Decoding Pinball Bus Signals…

I have a project in mind for my Twilight Zone, the exact details of which I will reveal later.

To implement the project, I need to detect when specific lights are lit in the machine. I thought of a couple ways of doing it. I could put a light sensor underneath the playfield or I could hook up to the wires that power the lamp. Both are fairly straightforward to do, but they are a bit inelegant, and I’m in the mood do to something more elegant.

So… What if we could read the signals that the CPU sends to the driver board? We could figure out whether any of the lamps is lit with a single connection to the system?

Okay, so, what would that take?

Well, the Twilight Zone uses the WPC architecture, and is driven by a 6809 running at 2 MHz. I don’t know if that’s the bus speed and am too lazy right now to find out, but I’m hoping that I can do what I need with an arduino running at 16 MHz.  What do I need to do? Well, that requires a bit of a journey…

The lamp matrix

Pinball machines have a lot of light bulbs, and running an individual wire would be expensive. So, instead of running separate wires, machines use a lamp matrix.

We have 8 rows, and 8 columns. To turn on a light, we drive the column to positive voltage and the row to ground, allowing current to flow. With a bit of code, we can drive them all. Basically, the code looks like this:

  1. Drive all columns low.
  2. Drive the rows that we want to light in the first column low.
  3. Drive the first column high
  4. Wait, and then repeat steps 1-3 with each additional column.

Digging into my WPC Schematic manual, we find some nice designs about the row and column drivers. What we are interested in is the method that is used to pass the row and column information to the driver board. It turns out it’s pretty simple:

  • Both the rows and the columns have a 74LS344 latch connected between the CPU bus and the row/column driver electronics.
  • The latches are clocked (ie data is loaded into them) when a line (ROW_STROBE or COL_STROBE) from the CPU is driven high.

So, in concept, what the microcontroller needs to do is pretty simple. First off, we need external interrupts defined and hooked to ROW_STROBE and COLUMN_STROBE. When either of the interrupts fire, we need to quickly grab the value from the data bus. From that, we can tell which lamp is in which state, and pass that information on. I would also like to detect flashing lights, which will require a bit more code.

I bought a small logic analyzer from Seed Studio so that I can eavesdrop on the bus and see what is really going on. That will probably be the subject of the next post.


Pages:123