Tuesday, 3 March 2020

DebounceHAT: how to keep switches from killing a Raspberry Pi board

Back in 2018, I found myself volunteering to rework part of a local hackerspace's RFID locking and club status system. Until that point the system had consisted out of a converted ATX power supply and Raspberry Pi single-board computer (SBC) literally dangling from wires, with signal wires soldered onto the general-purpose input/output (GPIO) pins of the SBC. These signal wires connected to two switches, one which detected whether the lock in the door had been engaged, the other to a manual switch using which non-permanently powered outlets in the space could be turned on or off.

Replacing the active loop Python script that constantly polled the two inputs with something more elegant was fairly straightforward [1], employing a C++ solution that used interrupt-based events (ISRs). By using ISRs instead of constant polling, this did lose the 'advantage' of debouncing incoming switch signals through brute force, so instead debouncing had to be re-added in a more elegant fashion.

Here one has two options: a timer-based approach in software, where one registers that 'something' is happening on an input that is connected to a mechanical switch, but waits before reading out the value (low or high) on that input until a certain amount of time has expired and the fluctuating signal from the switch's contacts bouncing against each other has probably settled into the final signal.

The other approach is to do it in hardware, where the fluctuating signal from the mechanical switch passes through a hardware circuit, which essentially smooths it out so that on the software end one can always read the pin out as if it's a purely digital input. I previously covered the basic theory behind this type of circuit on my development blog [2].

This all led to a basic expansion board that could be put on top of the Raspberry Pi's GPIO pins, first in a basic (prototype) version, as seen on the left hand side in the below image, which later got reworked into the version that can be seen on the right. As one may note, the latter board has a lot more components on it, which leads to the next part of this story.




You see, with the basic debounce circuit, consisting out of an RC (resistor-capacitor) circuit and an inverse Schmitt trigger chip, the debouncing part worked great. The noisy signal from the switch's contacts bouncing against each other got practically eliminated by the RC filter, with any remaining noise that might have survived the RC filter getting dealt with by the Schmitt trigger, courtesy of its large dead-zone in between the trigger points.

Unfortunately, during the first winter period it was found that touching the door handle of the door that had the first switch connected it would disable the Raspberry Pi until restarted. A bit of research showed this to be due to the electrostatic discharge (ESD) from the person touching the (metal) door handle. This discharge would find its way from the door handle to the metal parts inside the frame, then to the metal parts of the micro switch that had been embedded into the frame. From there it would travel along the signal wire to the Raspberry Pi and zap the system.

The same effect could be observed when there was a surge in the 230V wiring running alongside this signal wire, inducing a current via electromagnetic coupling. Fortunately this current was low enough that it would only cause false positive trigger events, but it's conceivable that with the proper EM source, strong enough voltages and currents could be generated that would damage the connected hardware. As the Raspberry Pi and similar boards can only accept a voltage of 3.3V on their pins and can sink only a few milliamperes without damage, this would likely cause permanent damage in the long term.

Obviously a solution was needed to fix this.


This is where the second board was conceived: in order to completely isolate the SBC from its environment and especially the signal wires, it was decided to use opto-isolators and an isolated DC-DC voltage supply to provide a voltage source for use with the switches. This way, the signal wires were left completely electrically isolated, with any incoming signals being transferred via the opto-isolator's LED and photo diode instead of via a copper wire. In addition, spark gaps were added to the board and provision for an earth wire so that any surge would be safely carried away.

While a good start, a friend convinced me to take a look at further improvements and together we sat down to make more improvements. This is the board that is now featured on the Github repository [3] and which will also soon be featured in a CrowdSupply crowdfunding campaign [4] so that people can get their own.




Like its predecessor, this board is an official Raspberry Pi HAT, with the requisite EEPROM with configuration settings. Changes include better channel separation and surge protection on the 6 input channels, an isolated DC-DC supply with full class B EM compliance, isolation slots, improved spark gaps and about 4-5 kV AC surge isolation. All 6 input channels are rated at 3-12V. It also provides input protection when the Raspberry Pi is provided with power via this DebounceHAT board.

A number of prototype boards have been assembled of this current version for more testing the coming time while hunting down a company for assembly of the production boards.


Hopefully this board will save a lot of people from having to jump through the same hoops and painful discoveries that I did :)


Maya



[1] https://github.com/MayaPosch/ClubStatusService
[2] https://mayaposch.wordpress.com/2018/06/26/designing-an-rc-debounce-circuit/
[3] https://github.com/MayaPosch/DebounceHat
[4] https://www.crowdsupply.com/maya-posch/debounce-hat

No comments: