I'm working on a custom sensor that is wired to a couple of MCP23S17 gpio expanders, which are in term connected to a Raspberry Pi 4 via the SPI pins i.e. SPI_MOSI, SPI_MISO, SPI_SCLK and CE0 pin.

I'm trying to read/write to these expanded pins via some python code, preferably using 'wiringpi' but I can't seem to find any information about using these expander boards with SPI, all the tutorials I can find talk about connecting it via I2C in stead.

More specifically, I'd like to use SPI to address the expander pins and read analog voltages. I'll include an example of my Python code for clarity's sake:

selectorPins = [65, 66, 67, 68, 69, 70, 71, 72]
analogReadPins = [89, 90, 91, 92]

i2c1_pin_base = 65
i2c1_address = 0b001
i2c2_pin_base = 81
i2c2_address = 0b000

wiringpi.mcp23017Setup(i2c1_pin_base, i2c1_address)
wiringpi.mcp23017Setup(i2c2_pin_base, i2c2_address)

for x in selectorPins:
    wiringpi.pinMode(x, 1)
for x in analogReadPins:
    wiringpi.pinMode(x, 0)

# select sensor
wiringpi.digitalWrite(selectorPins[0], 0)
wiringpi.digitalWrite(selectorPins[1], 1)
# ...

sensorValue = wiringpi.analogRead(analogReadPins[2])
# ...

Though this obviously doesn't work since the expanders are connected via SPI and I'm not using I2C at all. Indeed If i try to run this I just get an error

Unable to open I2C device: No such file or directory

I'm running raspbian buster lite and have SPI set up properly (I hope) as I can do

pi@mySensorPi:~ $ ls -l /dev/spi*
crw-rw---- 1 root spi 153, 0 Oct 15 11:59 /dev/spidev0.0
crw-rw---- 1 root spi 153, 1 Oct 15 11:59 /dev/spidev0.1

I'm not sure if I'm missing something, I haven't worked with gpio expanders before. Any help and info is welcome!

P.S. the wiring is embedded in a custom board for this sensor so changing the pins is a costly option I'd like to avoid if possible.

  • 1
    Have you tried to search the web? There is a lot of info around. For analogue inputs you will need an A/D converter and there is loads of info about mc23s17 on Pi when searching for 'mcp23s17 python raspberry pi'.
    – Dirk
    Oct 15, 2020 at 12:39
  • 1
    @Dirk can the MCP23S17 not read analog inputs directly? If not I'm afraid our chip designer has messed up
    – WARdd
    Oct 15, 2020 at 13:11
  • @WARdd, Some years back, I successfully used Rpi IDLE python to play with SPI MCP23S08 and MCP23S17, using through hole chips. Afterwards I found almost everybody is playing with I2C MCP23017 for the lazy reason that there is cheapy assembled module using I2C MSP23017 but unluckily almost no module for MSP23S17 (very expensive or hard to find). So I switched to I2C MCP23017. As you might have already noticed, S17 and 017 have the same internal architecture, and only difference is the communication interface SPI, or I2C. / to continue, ...
    – tlfong01
    Oct 15, 2020 at 13:56
  • I forgot if I followed AdaFruit or Mag Pi magazine's tutorial on MCP23S08 or MCP23S17. A useful trick for newbies is (1) Do python SPI loop back test, to make sure software and hardware (wiring) setup is OK. (2) Use SPI to access some registers, usually address 0x00 config register. One you have have done (1) and (2), then you can borrow Arduino or Rpi's S17 or 017 library's functions to do the tasks you want.
    – tlfong01
    Oct 15, 2020 at 14:04
  • Another useful or time saving trick is try to write you read/write register functions/methods as high level as possible, because you will find that those functions can be shared between S17 and 017. Now a warning to newbies. MCP23S17/017 has very steep learning curve, because the register naming is very complicated. My advice is NOT to start with S08 or 008, because the S08 functions are very tedious to scale up to 017/S17. So you might like to start one through hole S17 and use a bread board to experiment.
    – tlfong01
    Oct 15, 2020 at 14:09

1 Answer 1


So I managed to find out a lot of valuable info on this topic. First of all I made the mistake of confusing MCP23S17 (which uses SPI) with MCP23017 (which uses I2C). There is a python library for this exact board: https://pypi.org/project/RPiMCP23S17/ which has only digital functions because this board has no analog capabilities. For this reason, we redesigned our circuits with MCP3008 analog to digital converter chips, which also have a relevant python library: https://github.com/adafruit/Adafruit_CircuitPython_MCP3xxx/. The new code using these looks something like this:

import busio
import digitalio
import board
from adafruit_mcp3xxx.mcp3008 import MCP3008
from adafruit_mcp3xxx.analog_in import AnalogIn 
from MCP23S17 import MCP23S17

selectorPins = [0, 1, 2, 3, 4, 5, 6, 7]
analogReadPins = [0, 1, 2, 3]

#adc boards
spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)
dio = digitalio.DigitalInOut(board.SCL)
adc = MCP3008(spi, dio)

#open adc channels
chan = []
for x in range(0, 4):
    chan.append(AnalogIn(adc, analogReadPins[x]))

#ioe board
ioe = MCP23S17(bus=0x00, pin_cs=0x00, device_id=0x00)
for x in range(0, 8):
    ioe.setDirection(x, ioe.DIR_OUTPUT)

# select sensor
ioe.digitalWrite(selectorPins[0], MCP23S17.LEVEL_LOW)
ioe.digitalWrite(selectorPins[1], MCP23S17.LEVEL_HIGH)
# ...

sensorValue = chan[0].value
# ...

This code seems to work...


this solution turns out to be useless since the relevant python libraries are far too slow for our application. It involves writing several pins and reading analog values at a rate of around 180.000 per second, which is pressing the hardware limits and as far as we can tell even cython won't quite cut it. So to complete the project we have decided to switch the code to c, and simply use libraries available there for SPI MCP23S17 and MCP3008 boards.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.