Designing a control panel - pt2
Now that I’m done designing a housing for these buttons that fits in well with my Ender 3’s existing control panel, I’m considering the wiring and electronics of this box. I have a few obvious options.
- 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, generic USB cable to a controlling RPIZW
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 the simplest solution, but a waste of a perfectly good microprocessor. I’m only processing inputs and 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 to make interrupts 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. I need more than 4 pins if I want an interrupt line. Interrupts will be essential for reducing CPU usage and increasing responsiveness by avoiding polling. This is important since the controlling RPIZeroW is also streaming a live video feed - this easily consumes 50-80% of the CPU. I think my next best bet is going to be the method recommended here - slice a black ethernet cable up. These cables are easy to acquire and since I plan on placing the control box a very short distance from the controlling Pi, it should be sufficient. I had wondered if I needed to pair a ground with the data and clock lines, so this makes a lot of sense to me. This is why my keyboard IIC has a lot of… trouble with noise, it’s not a fault tolerance protocol as it’s designed for circuitboard communication where there is (hopefully) low interference and resistance.
The method is 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
sudo raspi-config to enable I2C, I rebooted and saw address 20 populated correctly with
i2cdetect -y 1. Great! This cable is stable enough to carry an I2C signal when wired as described. Considering these cables are designed for much higher frequency transmissions, it’s not a great surprise, but I2C is notoriously vulnerable to noise.
After a long time writing Go code to interface with the I2C device, correctly configure the pullup resistors, make one of the pins a current sink and configure the 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 what I’m doing.
I then spent more time integrating someone’s Octoprint library, and programmed the buttons to perform various printer actions. One button checks Octoprint for a printer connection and sends a command to a mains relay based on if the printer is connected/on or not. There’s a few others for some favored heating, cooling and jog commands that were cumbersome when accessed via an Octoremote app or the Ender 3’s annoying LCD.
I’d call this project a great success, and I learnt that I could shove I2C along an ethernet cable, if needs be.