Designing a control panel


In the last episode, I complained about OpenSCAD and designed a control panel in FreeCAD.

This control panel fits in front of the Ender 3’s existing control panel, providing two rows of 8 buttons. This is more of a build log of the electronics and wiring of this box. A few options come to mind.

  • ESP32 wired to buttons, sends MQTT message upon press
  • MCP23017 wired to buttons, USB cable run to a controlling Raspberry Pi Zero W
  • Arduino Pro Micro wired to buttons, serial over USB to a controlling Pi

While an ESP32 would be a simple solution, it adds another wireless device to my already cluttered local network. An Arduino Pro Micro would certainly be a simple solution, but a waste of a perfectly good microprocessor. I’m only listening for input. I already have two devices in the same room with GPIO capabilities. MCP23017 it is.

I’ll add code to my HMQTT library to accept input from an MCP23017. The code will be designed around a single-pin-per-button setup so interrupts might work. Unlike in my recent keyboard project, Dactyl, there’s no need to save pins by utilising an input matrix. We only want to read 10 buttons and the MCP23017 has 16 inputs. The left side of the button will be wired to a shared voltage? ground? line, the right side of the button will be wired to a specific GPIO pin on the MCP23017.

To connect to the MCP23017, I will destroy a black USB cable and- oh. I’m using IIC/I2C. This lets microprocessors (black chips with lots of legs) talk to each other, but I need more than 4 pins if I want interrupt lines. Interrupts are essential for reducing CPU usage and increasing responsiveness by avoiding polling - a GPIO bank on the Pi processor can listen for changes and let us ignore the MCP23017 until it has information for us. This is important since the controlling Pi is also streaming a live video feed which consumes 50-80% of the CPU. The only other shielded high quality copper cabling I have to hand is an ethernet cable. It seems like someone’s done it before.. I plan on placing the control box a very short distance from the controlling Pi, so it should be sufficient. Pairing ground with the data and clock lines makes a lot of sense to me.

The method suggested was as follows

  • ORANGE / WHITE: GROUND
  • ORANGE: SDA
  • GREEN / WHITE: 3v
  • BLUE: 5v
  • BLUE / WHITE: 5v
  • GREEN: 3v
  • BROWN / WHITE: SCL
  • BROWN: GND

The pins are in connector order. I connected them up and powered the Pi. After the usual raspi-config && reboot to enable I2C, address 20 was populated correctly after i2cdetect -y 1. Great! This cable is stable enough to carry an I2C signal. Considering these cables are designed for much higher frequency ethernet frames, it’s not a great surprise, but I2C is notoriously vulnerable to noise since it’s designed for circuitboards.

After a long time writing Go code to interface with the I2C device, and correctly configure the Pi GPIO bus with interrupt pins, I was able to press buttons and have the Raspberry Pi receive the interupt signal, clear it, and act on the returned button state. There’s some code to prevent triggering buttons that were triggered in the last call. This is good enough for now but it might annoy me if I’m repeatedly pressing one button.

I then spent more time integrating someone’s Octoprint library, and programmed the buttons to perform various printer actions. Favored heating, cooling, jog and job cancel commands were added, removing the need to use apps or the Ender 3’s slow dial.

I’m happy with how this turned out and I learnt I2C will go along an ethernet cable, if needs be.