Make a Custom Membrane Keypad for Arduino

My son got one of these Leap Frog toys a few years ago as a gift.  He enjoys playing with it very much.  I am not sure how much counting and learning he is doing but it makes funny noises and sings to him so its a lot of fun.

Recently the unthinkable happened.  It died.  Not the batteries but something else.  I took the back off to look at what might be wrong (which was very easy for a toy).  Unfortunately, other than the speaker, a switch, battery compartment, and a ribbon cable to the front, there wasn’t much to investigate.  A couple of glop tops and nothing else.  I fiddled a bit more with it but everything “external” seemed fine.

Did I mention my son really loves this toy?

It can’t be that hard to make something similar using the carcass of the old one, right?  It has all the external bits and pieces.  I just need to figure out how to take some input and play some sounds. Right?  So I spent a few hours figuring out the basics of what I wanted to change this thing into.  Audio driven from an atmega328.  A simple amplifier.  Make it power friendly (and run off of two AA batteries).

But what about that input?  The original toy had a very thin membrane keyboard basically.  I need a membrane keyboard of my own.  There are a few places that will make custom membrane keypads but that is too costly.  You can buy one of these hobbyist keypads cheaply ($3-$10 from Amazon and less than that from places like DXSoul).

That screams fun right?

What other options are there?

I decided to make my own.  There are a few tutorials on building membrane keypads. Most of the DIY keypads I’ve found don’t seem like they would be all that reliable nor resilient. I’m not looking for something to last forever but it should last long enough to warrant the 30 minutes of work needed to make it.

Future blog posts will cover more details of the final new “front panel” of the toy.  The rest of this post will cover a (boring) prototype I used to verify some thinking.

As mentioned earlier, there are sites out there that provide details of what a membrane keypad is and (more generally) what a matrix keypad is.  For my version, I’ll end up with four layers:

  • A “front decal” layer that has the images of the buttons.  This is what the user sees.
  • A “top foil” layer that contains the traces that link the rows of buttons together and provides “pads” onto which to connect wires.  The top foil layer is the opposite side of the front decal layer (i.e. the “inside” of the front of the keypad).
  • A “bottom foil” layer that contains the traces that link the columns of buttons together and provides pads.  The bottom foil layer is the “inside” of the back of the keypad.
  • A “cutout” layer.  This layer is sandwiched between the top and bottom foil layers and provides just enough separation to prevent the row and column traces from shorting when a button is not pressed.

I drew the four layers in Adobe Illustrator and printed them out.  The decal layer uses a 4×4 matrix arrangement with some “custom” graphics (thanks icons8.com).  After printing out the four layers separately, I had the templates to which I could attach my traces. (As soon as I figured out how to make the traces.)

There are a few options here but I ultimately need the keypad to be as thin as possible and as cheap as possible.  Using paper for the substrate covers those needs pretty well.  After a bit of searching around I came across copper foil tape that seems to be popular (or at least known) in the wearable electronics space.

This stuff is pretty cool.  It is tape so it is sticky on one side and thin conductive foil on the other.   It comes on a roll where there is a paper separating each winding.  You unroll some of the tape, cut it off with scissors, peel off the backing and stick it where you want.  To connect two traces you just overlap the tape.  It took a bit to get used to getting the backing off but it is very easy to work with.

In places where I needed multi-layer traces (!) I just used normal masking tape between the layers.  I’m sure this causes some subtle capacitive effect but everything seems to work out.

At the bottom, row and column traces are pulled off the keypad using jumper wires. They are attached using the same copper foil tape.

Top foil layer:

IMG_4590IMG_4592IMG_4594IMG_4595
IMG_4602

The bottom foil layer is simpler and once I was happy with it I glued the cutout layer directly onto it and attached leads there as well.

IMG_4596 IMG_4597
IMG_4600

Final construction of the keypad was to glue the decal layer to one side of a piece of cardstock (thicker paper) and the top foil layer to the other side.  Then I glued the bottom foil+cutout layers to another piece of cardstock.  Finally I glued the two assemblies together.

The final bit was to test out the keypad with an Arduino.  The breadboard and jumpers below are just for my convenience so the keypad could lay flat while I was testing.

IMG_3660

Driving the keypad is simple using the existing Arduino Keypad library.  I just had to plug in the right row and column pins.  The code follows (which is just the Keypad sample with the correct row and column information filled in).

#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
  {'1','2','3','S'},
  {'4','5','6','N'},
  {'7','8','9','P'},
  {'<','0','>','O'}
};
byte rowPins[ROWS] = {A0, A1, A2, A3}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 4, 3, 2}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup(){
  Serial.begin(9600);
}

void loop(){
  char key = keypad.getKey();

  if (key){
    Serial.println(key);
  }
}

In retrospect, I probably should have attached a ribbon cable of some sort to the pads instead of the jumper wire pigtails but this works.

This prototype version of a membrane matrix keypad isn’t necessarily cheaper to build than to buy one of the ones like linked above.  However, this approach has some benefits that are important to fixing the blue toy:

  • It is thin.  Total thickness is two pieces of cardstock paper.  You can make it pretty much as thin as you want it to be.
  • Custom decals.  While the layout of this is still a pretty boring 4×4 keypad, I got to choose my decals.  Some of the matrix keypads out there let you print out buttons and insert them but that would affect thickness and possibly reliability.
  • Custom layout.  I didn’t change the layout or size of the buttons in the example above but using the foil tape lets me effectively have any layout I want to.  Buttons can be arbitrarily placed and the traces can follow arbitrary decal shapes and sizes.  This is critical for replacing the blue toy’s front panel.  I’ll follow up more on this later.

(I’ll clean up the Illustrator files and post them as PDFs.  For some reason when I view the ones I uploaded, all layers are baked together.  When I view the local files I just uploaded they look correct.  Odd.)

Update on 1/25/2015

A few people have noted that I could just use off the shelf parts or try to mimic
the tactile feedback of membrane keyboards using domes for the buttons. In this case, I
was mainly going for a very thin keypad where there are no physical switches and the
circuitry is on the structure itself. The post is really about the prototype I made to
figure out how well this method works.

The original toy had this great “touch panel” feel. It recognized soft touches and there
was no tactile response. Even though it used a matrix keypad, the button shapes and thinness
helped give a nice feel to the toy that I want to replicate. I’ll write up the actual
replacement I made for the toy and hopefully it will make more sense why I wanted something
without off the shelf switches or domes.  For a sneak peek, here is the new keypad decal layer where each truck, person, etc… you see is a button that is shaped roughly like the sticker you see.

IMG_4583

 

Update on 2/4/2015

Here’s a Fritzing diagram for those curious what the circuit looks like.  This uses tact switches for the matrix keypad.

membrane_arduino

 

“Lab” Upgrades

For the longest time my home electronics projects have been done on a 60″ x 30″ folding table in one of our spare bedrooms.  My growing collection of project boxes, spare parts, and equipment finally started to put stress on my furniture – particularly my table.

The old lab table.

The old bowing table in its “clean” state.

I spent embarrassingly too long fretting over whether to buy a desk or build it.  If I bought something, what should I get?  Do I need an “electronics” workbench?  If I build it, what should I build it out of?  I probably spent five months going back and forth – all the while piling more junk on my table.

Spurred on by my better half (and Ministry of Finance), I swallowed my “I can build this” pride and just bought something.  I went with a Kennedy bench by BenchPro.  Specifically, I got a KF3696 which has the rounded front Formica top.  At 8′ x 3′ and well over 100 pounds, it is substantial.  It has a very sturdy feel which is exactly what I wanted.  I went with a cloudy gray top and black frame.  I like the looks very much.  I also went with the adjustable legs and set the height at 36″.

New bench.

The bench in its new home.

I couldn’t be more pleased with the ordering & delivery.  I got a quote from BenchDepot over email and called to confirm the order.  The bench came on a 9′ palette delivered to my home by the freight company.

While switching out the table for the bench, I took the opportunity to clean things up a bit and get organized. All of my project and spare parts boxes now fit neatly under the left half of the bench.  Power strips and what not are neatly along the back (both on top and bottom of the bench).

More space, better organization.

More space, better organization.

I have a few additions left that are on their way – a 4′ x 2′ dissipative rubber mat for the left half of the bench for example.  That hasn’t prevented taking the new configuration for a few test drives.  My daughter used the “new lab” to do one of her science experiments (a homemade accelerometer).

IMG_2099

Homemade accelerometer.

So far, so good.

UPDATE: The rubber mat arrived from All-spec.  I really dig this over the previous setup.  Very sturdy and is great to work on.

photo

 

Ancient History

Found a link to one of the many “big huge awesome” projects that we started in ACM@UIUC back in the day. I’m pretty sure this page is the only thing that actually came out of this project. :) I think (hope?) that I’ve gotten a little better at completing things (retro pc project and this blog not withstanding).

These big huge unfinished projects were not really failures. Many of the people who worked on projects like these at ACM@UIUC are now veterans of the startup scene or leaders behind the scenes at the hot tech shops around. I look back at these projects as ambitious and a great learning experience.

A Simple Remote-Controlled Arduino Tank

A little while ago my son was showing some interest in robotics. His birthday was coming up and we were having trouble deciding between a beginner robot kit focused more on construction or lots of bits and pieces.

The kit we looked at was the Elenco OWI ATR – All Terrain Robot:

The alternative was to build a robot based around Arduino. There are many robotics kits out there but I liked the idea of investing in Arduino as the basis for exploring robotics. I figured we would get the Arduino Uno, a few shields to control motors and sensors and whatnot, throw some wheels on it, and blammo, have a robot.

Then the shopping set in. There is a multitude of places to buy a multitude of robot stuff. I was tempted by RobotShop’s DFRobotShop Rover. Arduino compatible, everything we need to get started. And it was on sale at the time I was looking.

In the end, we bought our son the OWI ATR kit mentioned above for his birthday and I ordered a bunch of bits and pieces instead of the RobotShop Rover to build something more advanced with him. He really enjoyed the OWI ATR kit – he likes to build with his hands so it was the right balance of technology and construction.

For the Arduino robot project, I decided to start with a simple remote controlled tank. I really had no specific plan though I had searched around a bit on YouTube and such to see that others had managed to throw something together. I ordered everything from Amazon though not everything was fulfilled by Amazon so I paid shipping for a few things. Otherwise, I tried to spend as little as possible.

For the mechanicals, I used cheap Tamiya plastic bits. The instructions on these are not the most verbose but my son and I managed to stumble through without any damage to ourselves or the parts.

For the brains behind the operation, I went with a fairly stock setup with an Arduino Uno and a Motor Shield from DFRobot.

Additionally, I wanted to use a wireless PS3 controller for the remote control. I picked up a used Logitech wireless PS2 controller from my local Gamestop (since closed). You can find them on Amazon as well.

I allowed myself a bit of luxury by buying jumper wires.

A battery pack to hold four AA batteries seemed like enough power.

Assembly of the chassis was straightforward…

Tank Chassis

Assembled tank chassis with motors.

After building the chassis, the motor, and doing a quick test with the battery pack connected directly to the motors, I moved on to attaching the Uno and motor shield, I had some 1.5 inch nylon standoffs with screws that I used to mount the Arduino complex to the chassis. I did another quick test controlling the motors using the Arduino + Motor Shield.

Mounted Uno and Motor Shield

Mounted Arduino Uno and Motor Shield

//Arduino PWM Speed Control for DFRobot Motor Shield
//

int E1 = 6;
int M1 = 7;
int E2 = 5;
int M2 = 4;

void setup()
{
    pinMode(M1, OUTPUT);
    pinMode(M2, OUTPUT);
}

void loop()
{
  int value;
  for(value = 0 ; value <= 255; value+=5)
  {
    digitalWrite(M1,HIGH);
    digitalWrite(M2, HIGH);
    analogWrite(E1, value);   //PWM Speed Control
    analogWrite(E2, value);   //PWM Speed Control
    delay(30);
  }
}

Finally, I tore apart the wireless dongle for the PS2 controller, soldered on some jumper pigtails and connected it to the Arduino. Using PS2X from Bill Porter, I got basic remote control working pretty quickly.

Wireless PS2 Controller Dongle

Wireless controller dongle hanging off the back of the tank.

// Glue together PS2X controller code with DFRobot Motor Shield code
//
#include <PS2X_lib.h>  //for v1.6

PS2X ps2x; // create PS2 Controller Class

//right now, the library does NOT support hot pluggable controllers, meaning
//you must always either restart your Arduino after you conect the controller,
//or call config_gamepad(pins) again after connecting the controller.
int error = 0;
byte type = 0;
byte vibrate = 0;

//Arduino PWM Speed Control for DFRobot Motor Shield (default pins)
int E1 = 6;
int M1 = 7;
int E2 = 5;
int M2 = 4;
int lmotor = 0;
int rmotor = 0;

void setup()
{
  Serial.begin(57600);

  // set pin modes for DFRobot Motor Shield
  pinMode(M1, OUTPUT);
  pinMode(M2, OUTPUT);

  error = ps2x.config_gamepad(13,11,10,12, true, true);   //setup pins and settings:  GamePad(clock, command, attention, data, Pressures?, Rumble?) check for error

  if(error == 0)
  {
    Serial.println("Found Controller, configured successful");
    Serial.println("Try out all the buttons, X will vibrate the controller, faster as you press harder;");
    Serial.println("holding L1 or R1 will print out the analog stick values.");
    Serial.println("Go to www.billporter.info for updates and to report bugs.");
   }
   else if(error == 1)
   {
     Serial.println("No controller found, check wiring, see readme.txt to enable debug. visit www.billporter.info for troubleshooting tips");
   }
   else if(error == 2)
   {
     Serial.println("Controller found but not accepting commands. see readme.txt to enable debug. Visit www.billporter.info for troubleshooting tips");
   }
   else if(error == 3)
   {
     Serial.println("Controller refusing to enter Pressures mode, may not support it. ");
   }

   type = ps2x.readType();
   if (type != 1)
   {
     Serial.println("warning: DualShock Controller Not Found!");
   }
}

void loop()
{
 if(error == 1) //skip loop if no controller found
  return;
 if (type == 1)
 {
    ps2x.read_gamepad(false, vibrate);          //read controller and set large motor to spin at 'vibrate' speed

   lmotor = 0;
   if (ps2x.Button(PSB_L1))
     lmotor = 255;
   if (ps2x.Button(PSB_L2))
     lmotor = -255;

   rmotor = 0;
   if (ps2x.Button(PSB_R1))
     rmotor = 255;
   if (ps2x.Button(PSB_R2))
     rmotor = -255;

 }
 else
 {
   lmotor = 0;
   rmotor = 0;
 }

 // update motors
   if (lmotor < 0)
   {
    digitalWrite(M1, LOW);
    analogWrite(E1, -lmotor);   //PWM Speed Control
   }
   else
   {
    digitalWrite(M1, HIGH);
    analogWrite(E1, lmotor);   //PWM Speed Control
   }

   if (rmotor < 0)
   {
    digitalWrite(M2, LOW);
    analogWrite(E2, -rmotor);   //PWM Speed Control
   }
   else
   {
    digitalWrite(M2, HIGH);
    analogWrite(E2, rmotor);   //PWM Speed Control
   }

 delay(30);
}

Overall, the little tank worked pretty well and we had fun building it. I think the four AA batteries aren’t really enough to power the system as I couldn’t drive both motors in opposite directions simultaneously (or there is a bug in my code which is equally possible).

Assembled Tank

Assembled tank with battery pack.

Since we built this, I’ve used the Arduino for a number of projects (yet to be posted) and picked up an Ultrasonic sensor that we’ve yet to put into use on the tank. That’ll have to be a future post.

Updated: A Mostly Complete Parts List

Here’s the items I used with links to Amazon (based on looking at my order history).

From Breadboard to Protoboard

The time has come to clear some space on my breadboard so I can continue to build out the remainder of the system. I’ve collected a few prototype boards from Futurlec by tossing a few in each order over a few months. I bought a few different flavors of boards (PROTO777, PRBRDLG, and EXPBRD) to see which worked best for my random projects.

Step one was to create a few more bundles of jumper wires to use. I don’t buy jumper wire kits, instead I keep a roll of CAT5 cable and cut off lengths I need, strip off the casing, and make my own jumpers. I’ve gone through about 40 feet of cable so far on the retro pc project. Fry’s usually has 25, 50, and 100′ bulk cat5 bundles in their networking aisles for reasonable prices (definitely cheaper than the jumper kits in the components aisle ).

Another bundle of jumpers.

Next, I took a few boards and laid out sockets for all of the components that are currently on the breadboard. I taped them to the board temporarily with labels for what each part was. This let me get an idea of how many boards I would need, what parts should be located near each other, etc…

Examples of placement.

And then the soldering begins…

Debugging stuck bits

I’ve been blocked on making progress on the retro pc project due to bad reads from the ROM. The seemingly simple snippet of boot code should light an led wired to to the i/o ports (any port).

section .text
resb 0x7F0
org 0x7F0

start:
mov al, 0x1

again:
out 0x10, al
jmp again

When assembled, this turns into the following x86 bits:

00007f0: b0 01 e6 10 eb fc

Unfortunately, when I tried to boot the bundle of wires on the breadboard, I got the following while looking at AD[0:7] on the 8088.

00007f0: b0 01 e2 10 ...

Hmm… that isn’t going to work very well at all. Looking at this more closely, bit 2 (the third bit) is zero when it should be one. What could be causing this bit to be zero instead of one?

  1. It’s possible that the bits in the ROM are simply incorrect and the circuit is reading what is there. If that is the case the fix is easy, burn a new EPROM.
  2. Since this is the low 8 bits of address lines, it is multiplexed with the 8-bits of data. To demultiplex the address and data lines, a 74LS245 is used to control the direction of these 8 lines. It is possible that the ‘245 is driving the troublesome bit to zero even when it should be passing data from the ROM (or RAM) to the 8088. If this is the case, the ‘245 is likely bad.
  3. The RAM and ROM are both connected to the ‘245 and some glue logic to ensure only the RAM or ROM is enabled at any given moment. If the glue logic is wrong, both could be driving the ‘245 at the same time which would be bad.
  4. Finally, there is an 8-bit latch attached to the ‘245 to hold the data written to any 8088 i/o port whose bit 0 is connected to an led. Since this is used as output only, it is bad wiring if this is driving the ‘245.

Debugging the stuck bit is a matter of incrementally testing the potential issues above. Testing the values in the EPROM was easy, I just plopped the EPROM in the USB programmer, read the bits back out and dumped them. They all looked correct.

Testing a bad ‘245 was easiest by replacing it with a different one since I had plenty of backups. I tried two different replacements which behaved similar to the first. Seems likely that it would be a circuit problem not something wrong with the chip itself.

Next, I decided to verify the EPROM was working properly in-circuit by disconnecting the wire connecting the EPROM D2 bit to the ‘245 and monitored the 8-bit outputs of the EPROM. The value read as expected (E6 was E6, not E2). While the EPROM was disconnected, I used another channel of the LogicPort to monitor the B3 (pin 16) of the ‘245 to validate the fact that it was continually driven low — this would confirm that the EPROM was not the issue. Yup pin 16 was stuck low.

So someone else connected to pin 16 of the ‘245 must be driving it low. I disconnected the RAM’s output data bit 2 at the ‘245 and repeated the test. Still driven low. Wha? That implies that the 8-bit output port is driving the ‘245 low? That would be odd. I followed pin 16 to the output port latch … and it was connected to the bit 2 output (Q2) instead of the bit 2 input. Whoops.

The funny thing is that the first thing I did when I saw the “E2″ value is that I double and triple checked all of the connections between the 8088, ‘245, ‘373 address latches, memory glue logic, RAM, and EPROM. I ignored the ‘output port’ many times in the process.

In the end, I managed to get a good boot sequence and I feel pretty confident that the breadboard 8088 is running!

x86 boot sequence that lights an led. You can see the code coming from the ROM and the write to the IO port in the sequence.

Using Ultrascope for Rigol DS1052E

I’ve become more and more annoyed at having to export images from my Rigol scope to a flash drive plugged into the device. I’d much prefer to capture signals and images directly from my Macbook. Unfortunately, the PC software that comes with the Rigol — Ultrascope — does not run on Mac OS X. Boo. Over the last couple nights, I’ve played with the idea of writing a Cocoa app to pull data from the scope. USBTMC + Cocoa seems like a pretty good path to go.

I also run Windows 7 x64 in Parallels on the Macbook. This works great for a handful of geek related Windows-only tools I use such as the Logicport application as well as the software for my GQ eeprom programmer. I could never get Ultrascope to run properly under Windows 7 x64 on my Thinkpad laptop though so I’ve generally ignored it since shortly after I got the Rigol scope.

Tonight I had to try again while debugging the latest evolution of my retro pc project. I really wanted to capture some waveforms and decided to give it another go.  A post on the rigol_scope Yahoo group had some helpful pointers on getting things to work. After following those directions, things work!

Ultrascope is kind of crappy software in general but it allows me to leave the flash drive plugged into my Xbox 360. :)

Sometimes it is a bad part… sometimes.

I’ve spent the last few weeks working on my retro pc project. The first step with the 8284 seemed to go well but the trouble began when I tried wiring up the 8088. I wasn’t getting anything remotely close to the expected boot sequence. According to the datasheet and
The 8088 Project Book
a few clocks after dropping RESET back to zero, the 8088 should raise ALE after placing 0xFFFF0 on the address lines.

No such luck.

I tried debugging to the best of my limited abilities and could not seem to get the 8088 to behave. I dropped by EEVblog forums to get some help. Turns out those older CPUs were / are pretty sensitive to the clock levels and the 8284 was not producing a valid clock. After a bit more debugging I decided to punt and order a new 8284 — this time from arcadecomponents.com. After the new 8284 arrived, I dropped it in as a replacement for the 8284 from Jameco I previously used. Success! Good looking CLOCK, READY, and RESET signals from the 8284. But still no good ALE, address lines, or boot sequence from the 8088. Tonight I decided to move the 8088 from one breadboard to another and rewire the 8088.

Breadboarded 8088 (on the left) and 8284.

I’m not sure whether it was using the different breadboard or just the rewiring but I was able to get a good boot sequence. Joy! A shot of the signals via an Intronix LogicPort.

8088 Reset Sequence

The 8088 post-reset sequence!

Next stop… adding some address decoders, a ROM, and some SRAM.

Starting a Retro PC using The 8088 Project Book

Several months ago, I purchased a copy of Robert Grossblatt’s classic The 8088 Project Book in hopes of building a retro 8088 computer. My plan was to scavenge the parts from craigslist, ebay, and a couple Seattle area used computer junk stores. My adventures locally didn’t result in many parts though I did have much fun finding all those old ISA cards. I did manage to buy quite a few intel parts (8259s, 8255s, etc…) and a bunch of 74xx TTL parts from a gentleman in the area who was clearing out old stuff. But I still didn’t have an 8088 and a couple other necessary support parts. My queries to craigslist resulted in offers to sell me old 8088 PCs for crazy prices. Eventually, I gave up on finding the parts locally and started adding the remaining pieces to various digikey and futurlec purchases. This past weekend the final piece – the 8284 – arrived which is good because it is pretty important being that it drives the clock for the entire system.

Saturday afternoon I gathered all the various parts, my handy breadboard, and started building the clock driving circuit — the first thing in the book beyond the power supply. There isn’t much to the circuit – a couple caps, resistors, a 14Mhz crystal, etc… However, it didn’t take long to figure out that I was a 4.7uF cap short and couldn’t manage to fake one with the parts I did have on hand.

I was going to place yet another futurlec order but I gave up tonight and stopped by Radio Shack and got the missing cap, wired up everything again, and … nothing. Noise on the 8284’s CLK output. Boo. Double checked everything with the meter and still nothing.

Clock driver circuit.

After a moment I noticed that the bench supply showed no current on its meter. Aha! I’ve never had a proper current limiting bench supply before — turns out it limits the current. Further, when you turn the current limit down to zero, the 8284 doesn’t seem to want to function. Duh. Turn the current limit up to non-zero and … bam! Functioning clock circuit.

Mmm... current & voltage!

CLK and PCLK from the 8284

Next stop is to actually hook up the 8088!

MSP430 LaunchPad arrived today

I ordered one of the $4.30 LaunchPad eval kits from TI a few weeks ago. It was immediately on backorder but to TI’s credit, when they had them, they shipped them quick — overnight FedEx from what I can tell. Nice.

I’ve only downloaded the tools – Code Composer Studio and IAR Embedded Workbench – which I’ve never used before. Should be interesting. I’ll check all this out once I work through my current (and ongoing) PIC32 composite video problems.