# Do the MCP23S17 GPIO pins need protection against latch up ESD within this circuit?

I have an SPI based system in which a Raspberry talks with a GPIO expender device using SPI communication. The chip reads and/or writes '0'/'1' and send it to the Raspberry by bus.

The expander GPIOs circuit is a very simple circuit, but somedays a dangerous overconsumption/overheating (it almost burns) is triggered randomly after hours of correct operation. This stops when I reset the device. After this, the device has normal behaviour and normal consumption. Nowadays system is being connected and tested on a protoboard. So, wiring or lab material may be affecting a little or a lot.

Some people suggest that this behaviour seems to be a "latch up" caused by ESD. Otherwise it could be caused by voltage spikes, positives spikes or negatives GND ones. So, they told me that my GPIOs need to be protected with resistors, diodes and capacitors. But I don't see any example with diodes, Cs and Rs protecting inputs/outputs in other microcontroller or microprocessor based projects. The most I have seen are series resistors at some of the GPIO pins.

My circuit is too much simpler than those I have seen:

1. 8 expander pins will be inputs. The rest will be outputs.

2. Expander outputs will be writing '0', never '1'.

3. Expander inputs has an internal Rpull up that put input at 3.3V when not connected.

4. I put a wire at every output and this wire could be connected directly to the inputs or not. So when read the 8 input pins, those who are connected to the inputs will read '0', and the rest, will read '1'.

5. An input would read these 3 scenarios:

• '1' (when not connected),
• '0' output writing (if they are connected)
• '0' = GND (if a GND point makes direct contact with an input).

A particular characteristic of this system is that GPIOs will not be configured as inputs or output for the rest of the times. So during one execution a pin can be configured as an input during initialization, but at the next execution the same pin could be configured to be an output.

This overheating phenomena doesn't happens more than once or twice per day. But I'm afraid that once would be enough to destroy the system.

At final PCB design GPIOs pins will be traced through the board achieving a 64-pin connector. Input and output will be connected through a wire that will connect -or not- two of the 64-pin connector pins by human connection during execution. This way, a circuit between one input and one output could be closed. But there could also be open circuits between the rest of inputs and outputs.

I have added 10K Rs at every device GPIO and I'm using a 100nF between VDD and GND. It seems not to happen anymore two days ago, but I would like to ensure my GPIOs if the circuit really needs.

Does this circuit need GPIO protection? Are these resistor enough?

• If you did not have any bypass caps over the supply pins at the chip, that alone can cause all kinds of issues. But since you tried so many things at once, it is impossible to know what will help and what does not. I would have tried to figure out whether the two pins were accidentally set both to outputs, as then it is not a latchup caused by ESD, but maybe programming or communication error. – Justme Jul 29 at 12:16
• There seems some confusion. Let me clarify. (1) ESD usually destroys components when a human handling the components (a) before the component is inserted into the circuit, AND (b) the human is not earthed and he at the same time carries electrostatic charge. If your components are already in circuit, then there is no ESD problem. / to continue, ... – tlfong01 Jul 29 at 13:24
• Using 10K is OK if your GPIO is to control a MOS device with high impedance input. But if the device is BJT, then the biasing resistance is usually 220R to 1k, then using 10k series to protect GPIO is a bit overdoing. Just casually talking aloud, my apologies for the typos. Ah, bed time. See you tomorrow. – tlfong01 Jul 29 at 14:03
• Ah, I forgot that your Rpi also uses GPIO pins to set the address pins (A0 to A2) of the MCP23S17, but that should not cause any problem. A safe way is just tie those A0 to A2 pins direct to Vcc and/or Ground. Cheers. – tlfong01 Jul 29 at 14:09
• (1) One more thing, about the MCP23x17 reset pin. When playing with MCP23x17, I found that the chip from time to time go crazy, and I need to push the manual reset button which I install because I find very useful in debugging. I do suspect that MCP23x17 is very noise sensitive, so might go crazy if your SPI/I2C connecting wires are very long (> 60cm). (2) Another thing is that I find it a good idea of not connecting MCP23x17's interrupt pin direct to Rpi. Instead you use Rpi to loop the MCP23s17 interrupt status registers. Cheers. – tlfong01 Jul 30 at 1:35

Question

How come my MCP23S17 GPIO extender gets very hot and goes crazy?

/ to continue, ...

Part 1 - Test setup

I would suggest to start with a smaller version of the user requirements. For example, instead of making things very flexible, any pin can be input or output, you can in the testing phase, let 8 pins input only, and another pins output only.

PA0~7 set to input mode

PB0~7 set to output mode

Only when find the fixed input/output mode of the pins OK in testing, then you generalize the program.

mcp23017_test_v0.2_2020aug0101 PUBLIC

Part 2 - Clarification on ESD and Latching up

You might have noticed that the vendors usually ship components in metallic plastic bags, and also on metallic sponges. That is for anti static.

The operators in the assembly and testing factories wear antistatic writs bands like this:

I am a hobbyist playing with cheap components, and I never bother, because the chances of catching the ESD virus is very very small.

It is in the old days when electronic components were expensive that people bothered. Or you stay in a very dry country, wearing poly/plastic/nylon clothes then you need to bother. Of course everybody has a chance of struck by lighting. Perhaps you should google further for a piece of mind.

Part 3 - Recommendation to use external power supply for MCP23S17

I always recommend newbies NOT to use the Rpi's 5V or 3V rail to power MCP23S17 or other peripheral devices, but use an external power supply, at least for prototyping stage.

This way, if MCP23S17 gets crazy, the Rpi still sits happily. So I just manually reset MCP23S17 and no need to reset Rpi, the shows goes on.

Part 4 - Possible causes of overheating

What you are saying about overheating is a bit worrying.

MCP23S17 cannot handle big currents. I usually use buffer chips to handle big currents. If you are overloading all the 16 GPIO output pins with big current, then you will be in big trouble.

I skimmed the datasheet and made a summary:

(1) Total power = 700 mW

(2) Max current VSS pin = 150 mA

(3) Max current into VDD pin = 25 mA

(4) Input clamp current = ±20 mA

(5) Output clamp current = ±20 mA

(6) Max output current sunk by any output pin = 25 mA

(7) Max output current sourced by any output pin = 25 mA

So you see, if you load 6 GPIO pins with 25mA, then total current is over the Vss pin 150mA limit. I usually the 8 big guy chip ULN2803A to do all the heavy work. Each of the 8 big guys can handle 500mA, ...

You seem to use 10Ω for series limiting/protecting resistor. You might like to do the calculations to make sure the individual GPIO and total Vcc current limit is not exceeded.

Part 5 - Pair/Swap Testing and Programming

It is often a good idea to use more than two samples to do pair/swap testing. Often a component might be bad on arrival and or damaged by careless wiring or testing. So often is only by swap comparing and contrast you find careless wiring mistakes. You can use MCP23s08 or MCP23017 for cross testing. It is only the setup part that is different in the I2C and SPI verions of MCP23x17. The main operation functions are identical for MCp23SS17 and MCP23017 017. Taking pictures from time to time is a good documentation for later reference.

/ to continue, ...

References

Part A - Datasheets and articles

Part B - Forum Discussions

Part C - Schematics

Appendices

Appendix A - Bypass and Decoupling Capacitors - Robert Keim, AAC

Introduction

It is not inconceivable that a dedicated, successful engineering student would graduate from college knowing almost nothing about one of the most pervasive and important components found in real circuits: the bypass capacitor. Even experienced engineers may not fully understand why they include 0.1 µF ceramic capacitors next to every power pin of every IC in every circuit board they design.

This article provides information that will help you to understand why bypass capacitors are necessary and how they improve circuit performance, and a follow-up article will focus on details related to choosing bypass capacitors and the PCB layout techniques that maximize their efficacy.

Solution

it is convenient that such a serious problem can be effectively resolved with a simple, widely available component. But why the capacitor? A straightforward explanation is the following: A capacitor stores charge that can be supplied to the IC with very low series resistance and very low series inductance.

Thus, transient currents can be supplied from the bypass capacitor (through minimal resistance and inductance) instead of from the power line (through comparatively large resistance and inductance). To better understand this, we need to review some basic concepts related to how a capacitor affects a circuit.

First, though, a brief note about terminology: The components discussed in this article are regularly referred to as both “bypass capacitors” and “decoupling capacitors.”

There is a subtle distinction here—“decoupling” refers to reducing the degree to which one part of a circuit influences another, and “bypass” refers to providing a low-impedance path that allows noise to “pass by” an IC on its way to the ground node.

Both terms can be correctly used because a bypass/decoupling capacitor accomplishes both tasks. In this article, however, “bypass capacitor” is favored in order to avoid confusion with a series decoupling capacitor used to block the DC component of a signal.

A Standard Approach

The foregoing analysis helps us to understand a classic bypassing scheme:

a 10 µF capacitor within an inch or two of the IC, and

a 0.1 µF ceramic capacitor as close to the power pin as possible:

The larger capacitor smooths out lower-frequency variations in the supply voltage, and the smaller capacitor more effectively filters out high-frequency noise on the power line.

If we incorporate these bypass capacitors into the 8-inverter simulation discussed above, the ringing is eliminated and the magnitude of the voltage disturbance is reduced from 1 mV to 20 µV, ...

Appendix B - Grounding Problem and Solution

Appendix C - Old MCP23S17/ MCP23017 Proto Board for Testing

I am thinking of using my old MCP23S17 or MCP23017 to do some tests. Looking at the messy wiring of my old MCP23017 board, now I remember why last time I gave up working on SPI MCP23S17 and switched to I2C MCP23017, because the DIY wiring is very messy, and difficult to do hardware troublshoot. For I2C MCP23S17, there are cheapy breakout borads, sayhing me much time doing wiring.

Appendix D - MCP23s17 protoboard setting up notes

Appendix E - Testing SPI 00, 01, 10, 11, 12 Loopback and repeat send one byte OK

# Program:
#   spi_loopback_v55.py  tlfong01  2020aug03hkt1220
#
# Function:
#   1. SPI one byte loopback
#   2. SPI repeatedly send one byte
#
# System Config:
#   Rpi4B buster (r2020may23), python 3.7.3 (r2019dec20), thonny v3.2.7 (r2020jan22)
#   $date Thu 25 Jun 2020 04:36:13 PM HKT #$ uname -a Linux raspberrypi 4.19.118-v7l+ #1311 SMP Mon Apr 27 14:26:42 BST 2020 armv7l GNU/Linux
#   $ls /dev/ttyUSB* /dev/ttyUSB0 #$ ls /dev/ttyS0 /dev/ttyS0
#   $ls /dev/ttyAMA0 /dev/ttyAMA0 # Test Function Definitions: # # Test 1 - loopBackTest() - SPI port send and receive one byte. # Function - Send one byte to MSOI and read it back from MISO.? # Setup - Connet MOSI pin to MISO pin to form a loop. # # Test 2 - repeatSendByte() - SPI port repeatedly send out single bytes. ? # Function - Repeat many times sending a byte, pause after each byte. # 1. SPI ports setup notes # To enable SPI and setup SPI 10, 11, 12 ports, add these two lines to /boot/config.txt # dtparam=spi=on # dtoverlay=spi1-3cs # To list SPI devices # pi@raspberrypi:~$ ls /dev/spi*
#   /dev/spidev0.0  /dev/spidev0.1  /dev/spidev1.0  /dev/spidev1.1  /dev/spidev1.2

# 2. Notes of loopback function
#   Call example - testLoopbackOneByte(spiPort00)
#   Function     - send byte 0x5b to SPI MOSI and read byte from MISO
#   Setup        - must connect MOSI pin to MISO pin to loop back
#   Note         - 1. Only checks if MISO echoes MOSI, CS0, CS1, CS2 is not checked
#                  2. To check if SPI 0, CS0, CS1, or SPI1 CS0, CS1, CS2, need a scope to display repeat send bytes

from time import sleep
import spidev

# *** Setup SPI Ports ***

spiPort00 = spidev.SpiDev()
spiPort00.open(0,0)
spiPort00.max_speed_hz = 100000

spiPort01 = spidev.SpiDev()
spiPort01.open(0,1)
spiPort01.max_speed_hz = 100000

spiPort10 = spidev.SpiDev()
spiPort10.open(1,0)
spiPort10.max_speed_hz = 100000

spiPort11 = spidev.SpiDev()
spiPort11.open(1,1)
spiPort11.max_speed_hz = 100000

spiPort12 = spidev.SpiDev()
spiPort12.open(1,2)
spiPort12.max_speed_hz = 100000

# *** Define SPI Functions ***

def spiSendRecvOneByte(spiPort, sendByte):
sendByteArray = [sendByte]
recvByteArray = spiPort.xfer(sendByteArray)
return recvByteArray

def loopBackOneByte(spiPort, sendByte):
recvByteArray = spiSendRecvOneByte(spiPort, sendByte)
recvByte      = recvByteArray[0]

print('\nBegin testLoopbackOneByte(),....')
#print('')
print('   sendByte = ', hex(sendByte))
print('   recvByte = ', hex(recvByte))
#print('')
print('End testLoopbackOneByte(),....')
return

def repeatSendOneByte(spiPort, sendByte, pauseTimeBetweenBytes, repeatCount):
print('\nBegin repeatSendByte(),....')
print('  Now use a scope to display the SPI signals, MOSI, MISO, CSn, ...')
for i in range(repeatCount):
spiSendRecvOneByte(spiPort, sendByte)
sleep(pauseTimeBetweenBytes)
print('End   repeatSendByte().')
return

# *** Test Funtions ***

def testLoopbackOneByte(spiPort, dataByte):
loopBackOneByte(spiPort, dataByte)
return

def testRepeatSendOneByte(spiPort, dataByte, pauseSeconds, repeatTimes):
repeatSendOneByte(spiPort, dataByte, pauseSeconds, repeatTimes)
return

# *** Main ***

# *** Test SPI Loopback Functions, Comment out not required tests ***

print('\n*** testLoopbackOneByte(spiPort00, 0x5b) ***', end = '')
testLoopbackOneByte(spiPort00, 0x5b)

#print('\n*** testLoopbackOneByte(spiPort01, 0x5b) ***', end = '')
#testLoopbackOneByte(spiPort01, 0x5b)

#print('\n*** testLoopbackOneByte(spiPort10, 0x5b) ***', end = '')
#testLoopbackOneByte(spiPort10, 0x5b)

#print('\n*** testLoopbackOneByte(spiPort11, 0x5b) ***', end = '')
#testLoopbackOneByte(spiPort11, 0x5b)

#print('\n*** testLoopbackOneByte(spiPort12, 0x5b) ***', end = '')
#testLoopbackOneByte(spiPort12, 0x5b)

# *** Test SPI Repeat Send One Byte Functions, Comment out not required tests ***

# *** SPI 00, 01 Repeat Send One Byte ***

#print('\n*** testRepeatSendOneByte(spiPort00, 0x5b, 0.001, 200000) ***', end = '')
#testRepeatSendOneByte(spiPort00, 0x5b, 0.001, 200000)

#print('\n*** testRepeatSendOneByte(spiPort01, 0x5b, 0.001, 200000) ***', end = '')
#testRepeatSendOneByte(spiPort01, 0x5b, 0.001, 200000)

# *** SPI Repeat Send One Byte 10, 11, 12 ***

#print('\n*** testRepeatSendOneByte(spiPort10, 0xb5, 0.001, 200000) ***', end = '')
#testRepeatSendOneByte(spiPort10, 0xb5, 0.001, 200000)

#print('\n*** testRepeatSendOneByte(spiPort11, 0xb5, 0.001, 200000) ***', end = '')
#testRepeatSendOneByte(spiPort11, 0xb5, 0.001, 200000)

#print('\n*** testRepeatSendOneByte(spiPort12, 0xb5, 0.001, 200000) ***', end = '')
#testRepeatSendOneByte(spiPort12, 0xb5, 0.001, 200000)

# End of program

''' Smple output tlfong 01 2020aug03hkt1219

>>> %Run spi_loopback_v54.py

*** testLoopbackOneByte(spiPort00, 0x5b) ***
Begin testLoopbackOneByte(),....
sendByte =  0x5b
recvByte =  0x5b
End testLoopbackOneByte(),....

*** testLoopbackOneByte(spiPort01, 0x5b) ***
Begin testLoopbackOneByte(),....
sendByte =  0x5b
recvByte =  0x5b
End testLoopbackOneByte(),....

*** testLoopbackOneByte(spiPort10, 0x5b) ***
Begin testLoopbackOneByte(),....
sendByte =  0x5b
recvByte =  0x5b
End testLoopbackOneByte(),....

*** testLoopbackOneByte(spiPort11, 0x5b) ***
Begin testLoopbackOneByte(),....
sendByte =  0x5b
recvByte =  0x5b
End testLoopbackOneByte(),....

*** testLoopbackOneByte(spiPort12, 0x5b) ***
Begin testLoopbackOneByte(),....
sendByte =  0x5b
recvByte =  0x5b
End testLoopbackOneByte(),....
>>>

Python 3.7.3 (/usr/bin/python3)
>>> %Run spi_loopback_v54.py

*** testRepeatSendOneByte(spiPort00, 0x5b, 0.001, 200000) ***
Begin repeatSendByte(),....
Now use a scope to display the SPI signals, MOSI, MISO, CSn, ...

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Python 3.7.3 (/usr/bin/python3)
>>> %Run spi_loopback_v54.py

*** testRepeatSendOneByte(spiPort01, 0x5b, 0.001, 200000) ***
Begin repeatSendByte(),....
Now use a scope to display the SPI signals, MOSI, MISO, CSn, ...

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Python 3.7.3 (/usr/bin/python3)
>>> %Run spi_loopback_v54.py

*** testRepeatSendOneByte(spiPort10, 0xb5, 0.001, 200000) ***
Begin repeatSendByte(),....
Now use a scope to display the SPI signals, MOSI, MISO, CSn, ...

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Python 3.7.3 (/usr/bin/python3)
>>> %Run spi_loopback_v54.py

*** testRepeatSendOneByte(spiPort11, 0xb5, 0.001, 200000) ***
Begin repeatSendByte(),....
Now use a scope to display the SPI signals, MOSI, MISO, CSn, ...

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Python 3.7.3 (/usr/bin/python3)
>>> %Run spi_loopback_v54.py

*** testRepeatSendOneByte(spiPort12, 0xb5, 0.001, 200000) ***
Begin repeatSendByte(),....
Now use a scope to display the SPI signals, MOSI, MISO, CSn, ...
End   repeatSendByte().
>>>

'''

# *** End ***


Appendix F - Repeat send byte scope screen captures

Appendix G - Dual MCP23S17 Proto Boards Setup