In part 5 I touched on some ideas about my overall architecture for interfacing the Flight Simulator with the Raspbery Pi. In this post I look into GPIOs, the basic mechanism by which the Raspberry Pi can communicate with the real world.

GPIO stands for General-Purpose Input/Output ... and is a common feature found in most microcontrollers that is used to interface software with the real world of electronics. When used as an input, it allows the microcontroller to sense if an input signal is high or low voltage. When used as an output, it lets the microcontroller emit a high or low voltage on a pin connected to other components. Because GPIOs can be sensed and controlled by software running on the microcontroller, it allows software to interact with the real world.

GPIOs at their most basic can be used to sense toggle switches, or control LEDs. But they can also be used to communicate with electronic components such as rotary encoders and servos, or even other integrated circuit chips, such as shift registers and Digit Display controllers.

The Raspiberry Pi Model B+ that I am using for my overhead panel features 26 GPIO pins. With the overhead panel having over a hundred switches and annunciators, and gauges and digital displays, this is hardly sufficient. Fortunately, I had experimented with Adding the MCP23017 GPIO Expander to the Raspberry Pi earlier. Quick Summary: The MCP23017 is a IC that adds 16 general-purpose I/O ports to any microcontroller. It connects to the Pi using the i2C bus, and you can add up to 8 of these chips to a Pi by assigning each chip a unique address, for a total of 128 additional GPIOs. Definite useful!

Perfboard and Layout

In my earlier experiments, I had used breadboards to test circuits with the MCP23017. Breadboards allow you to rapidly prototype a circuit by plugging in ICs and using wires to form temporary connections, but they are not suitable for actual use. So if I was to use the MCP23017, I knew I would need to build my own circuit board for the actual overhead panel.

Breadboards (not my work or photo)

I started with using perfboard (aka Universal PCB). These are boards with holes and pads on them that come in various sizes, to which you can solder through-hole-components. Unlike a breadboard, which has internal connections across all pins across the board, with a perfboard you are expected to link the components yourself, using short lengths of wire or solder bridges on the underside. This is a more flexible solution, allowing you to lay out the components in the best possible way that suits your needs. This is what the it ends up looking like:

Solder Bridges on a Perfboard (not my work or photo)

Jumper wires on a Perfboard (Not my work or photo)

Well, it turns out I'm pretty useless at this.

While I've gained enough experience that soldering components to pads is now quite easy work, despite my best efforts the wires and bridges would end up as a right mess, and I gave up just trying to do all the connections to get a single MCP23017 going, not to mention eight of them. Laying out wiring is pretty much an art, and you need to constantly think of the logical design of your overall circuit while also trying to solve the physical design aspect of it. You can't just work on part of a circuit on a perfboard and grow your design, rather you have to have the big picture in mind at all times. Given I don't really have much clue of where I'm headed, my attempts at building a single perfboard solution with 8 MCP23017s did not take off.

I decided to break the problem into smaller manageable chunks and focus on smaller goals: make a modular "add-on" for a single MCP23017. It would need to be a flexible solution where I could add additional MCP23017s as I needed. This would be useful not just for this 737 Overhead project, but potentially anything else I was working on that needed extra GPIOs.

I started by writing down my basic requirements:

  • The I2C bus consists of two pair of pins on the Raspberry Pi, SDA and SCL, that each MCP23017 would need to connect to. To achieve modularity, I decided that my MCP23017 module should have a set of I2C "in" pins, and also I2C "out" pins, to allow me to easily daisychain as many modules as I needed.
  • Power (5VDC and GND) should also be distributed the same way.
  • The MCP23017's signals are 5V (since I'm powering it using 5V). The Raspberry Pi's I/O pins however have a limit of 3.3V on then. For the I2C bus, this is not an issue as the nature of the I2C bus signalling is that the Pi (master) side raises the voltage on the line to High (3.3V), and the MCP23017 (slave) side will either leave the signal as it is or lower it to GND. Since the MCP23017 never raises it's end of the bus to 5V, there's no risk of damanging the Pi's IO pins.
  • The MCP23017 has a the ability to raise a signal whenever one of the pins change state. By connecting this pin to the Pi, it would be possible for the code on the Pi to be triggered automatically, without having to continuously poll the IC. However, the MCP23017 (in my case) outputs this at 5V, whereas the Pi is not supposed to receive more than 3.3V. To solve this, I created a voltage-divider using a 1K ohm resistor (R1) and a 1.5K ohm resistor (R2) which results in a 3V signal.
  • To allow up to 8 MCP23017s to sit on the same I2C bus, each one needs to be assigned a unique address. There are 3 pins on the MCP23017 that need to be set to a unique combination of high and low. I decided to expose this as header pins on the module, so that I can use jumpers to set the unique address.
  • GPIOs often need current limiting resistors on their pins, to prevent too much current from being drawn out of hte MCP23017, or to limit the current to some component (such as a LED) connected to the GPIO. I decided my MCP23017 module should have standard points to add in a resistor for each GPIO. These could be bypassed with wire if the resistors weren't needed.
  • In the MCP23017, GPIOs are usually channeled to GND, i.e when used as an input (with the built-in pull-up resistors) or as an output (for example, when connecting an LED). I decided it would be useful to make many ground pins avaiable to connect to on my module.
  • Sometimes it is useful for multiple wires to be connected to a GPIO, therefore, it would be useful if extra pins to connect to a GPIO could be made available.
  • There should be mounting holes so I could stack multiple modules using spacers.

This looked like a tall order even for a single MCP23017 on a perfboard. I needed a logical schematic of the circuit drawn out. So I started looking at design tools to help me with this. There are a number of them out there, but the one I ended up using was which is a totally web-based design tool, i.e. you don't have to install anything on your PC. You can select from a library of existing components or add your own, and link them with tracks. I decided for each MCP23017 I need to do something like this:

EasyEDA allows you to go from a logical layout like above to a physical layout, where you can physically lay the components out on a surface and plan how to route the wires from one point to another.

Finally, and the most useful part of all, is that I found EasyEDA has an auto-router function, which will lay out the connections automatically, making use of multiple layers. It's said that machine routing is never as good as human routing, but one look at the autogenerated output and it was obvious that it was way ahead of my skill.

So after playing around bit I came up with something like this:

From the number of connections required I could see that this was way beyond my skill level to layout on perfboard physically. However, with a few more clicks EasyEDA can also manufacture the Printed Circuit Boards (PCBs) based on your design in a factory in China, and ship the boards to you. Now printed circuit boards are a lot easier to work with as the tracks are already laid out on them, all I have to do is solder the components to the pads. PCBs are also more flexible as they can be made in multiple layers, allowing tracks to criss-cross at different layers without connecting to each other.

The prices were actually quite reasonable. I could get twenty of the above boards for USD21 (MYR 88.51) + USD10.90 (MYR45) for shipping. That works out to about USD1.50 (MYR 6.32) per board. Given my perfboard layout skills, it was an easy decision to proceed.

It took about 2 weeks to arrive. Here's what it looks like:

I purchased the MCP23017 from Element14 and sourced the headers and resistors from eBay. Here's what the board looks like when populated:

Wooh ... Stuff just got REAL! And way neater than anything I could have come up with using perfboard. ๐Ÿ˜Ž


  1. In hindsight I would have optimized it for space and made it smaller, and matched the holes to the ones on the Raspberry Pi so that they can be stacked together.
  2. You can find my designs for the MCP23017 Breakout Board here Feel Free to modify it as per the license terms. You can also download the gerber files and have them fabricated yourself, or get easyeda to fabricate and ship them to you.
  3. All this happened around Jul 2016 ... the blog is still catching up with real life ... 8-)