I have a MCP23017 GPIO expansion chip connected to a Pi via the I2C bus.

I want to be able to treat the pins of the chip like the GPIO pins of the PI – turning them on and off individually. Unfortunately I haven't been able to find a method in the Python smbus2 (or any other) library that allows me to set the value of a single pin. Instead I'm forced to read the value of an entire register (read_byte_data), save it to a variable, change the bit in question, and then write the entire byte (write_byte_data) back.

The problem is that when the value of other pins have changed between the reading and the writing, these changes then get overwritten. Does anyone know of a way to simply set the value of a single bit while disregarding the rest of the byte?

  • This is not the role of the bus protocol, it is about the device. See this datasheet on page 16: "Writing to the GPIOn register actually causes a write to the latches (OLATn). Writing to the OLATn register forces the associated output drivers to drive to the level in OLATn. Pins configured as inputs turn off the associated output driver and put it in high-impedance." By my reading, if there is voltage on an input pin, the state of the pin will reflect that, not the value that would have been written were it an output.
    – goldilocks
    Commented Jul 13, 2018 at 11:37
  • I do not understand what you are asking. It is your job as a programmer to keep track of the levels written to each bit and set the output byte accordingly.
    – joan
    Commented Jul 13, 2018 at 11:58
  • @goldilocks if it's about the device and not the protocol, I'd think I'd be able to find a method in the libraries for setting a single byte, as the libraries are protocol- not device-specific. But I haven't. Maybe no one has gotten around to writing that method yet or maybe someone already has and I just haven't found it... I was hoping it was the later and someone could point me in the right direction... Commented Jul 16, 2018 at 11:36

1 Answer 1


Why the other pins value may change? If it is input pin, you not need to worry, because you can write only output pins, input stay untouched (they are masked internally). If it is output pin and other part of your project can also change the state by writing to expander, then you should be able to solve this problem in your code or you need to redesign solution.

  • It is not input, it's all my code setting the values (either configuring the polarity to output or turning the output on and off). The values of the other pins are changing when multiple threads are instantiating objects. Each pin is being treated as a Switch. When a Switch is instantiated the polarity of the pin needs to be set as an output and the output with a value dependent on whether the actual switch attached to the pin (a relay) is Active High or Active Low – it should start off. The code using multiple threads to do the instantiation from a config file is outside of my control. Commented Jul 16, 2018 at 11:17
  • github.com/toomanydaves/mcp23017_gpio Commented Jul 16, 2018 at 11:39
  • When more then one thread share object, in this case GPIO expander, then you need to introduce some kind of locking feature. In this case writing to pin may look like that: 1. Check if lock is true. 2. if no then: set lock to true, read state, write new state, release lock. 3. If lock is true then: wait until lock is false and do (2). Of course every threads must handle locks without exception, and most be single lock variable for every register accessible for every thread. Commented Jul 17, 2018 at 7:49
  • This could be useful: docs.python.org/3.6/library/threading.html#lock-objects Commented Jul 17, 2018 at 8:26
  • Thanks so much for the explanation! That looks like exactly the mechanism I need to introduce into my code to deal with the issue! Commented Jul 17, 2018 at 9:20

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.