I am using a MCP2221 to talk I2C to a MCP23017. Using python3 to interface.

I had some trouble with the adafruit libraries, so have resorted to using the PyMCP2221A library. It works great for writing to the MCP23017. However, I don't know how to ensure I am reading the correct position of the MCP23017 registers.

For example in the MCP2221 I2C Terminal software I ran the following series of commands. If I read just one bit (say that is a bus error, emf issue, or other) then the buffer in the MCP23017 does not reset itself and the data becomes shifted and I will read the data in the incorrect register. enter image description here

Looking at the adafruit mcp23017 code it looks like they reset the transmission just before reading. This makes sense, but not sure how to do that in python or how to access this I2C stop function from the PyMCP2221A library or the upstream cython-hidapi library. Also not 100% sure it just requires a stop signal or something more.

* Reads a given register
uint8_t Adafruit_MCP23017::readRegister(uint8_t addr) {
  //read the current GPINTEN
  _wire->beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(addr, _wire);
  _wire->requestFrom(MCP23017_ADDRESS | i2caddr, 1);
  return wirerecv(_wire);

Any guidance is greatly appreciated!


2 Answers 2


Unlike reading, the writing process is quite simple:

  1. Send start
  2. Send device address on writing (0 1 0 0 A2 A1 A0 0)
  3. Send register address (for example: 00h)
  4. Send byte-by-byte (the register counter will increment automatically)

According to the pg.14-pg.15 of the datasheet on the MCP23017, for reading you shall:

  1. Send start
  2. Send device address on writing (0 1 0 0 A2 A1 A0 0)
  3. Send register address (this action set the register counter and determ the reading position, for example: 00h)
  4. Send stop
  5. Send start (again)
  6. Send device addres on reading (0 1 0 0 A2 A1 A0 1)
  7. Read sequentially all nessesary registers

enter image description here

  • \$\begingroup\$ You sir are a genius! I have no idea how you extracted that information from the datasheet. And it took a while to soak in to my mind. I tested it this evening and it worked perfectly resetting the address pointer to the zero register! Thank You! > I2C Write, Address = 32, Data: 0 Delay = 0 \$\endgroup\$
    – ericnutsch
    Commented Sep 3, 2020 at 6:24
  • \$\begingroup\$ A couple years ago I myself was looking for an answer to this question. No problems ;) \$\endgroup\$
    – Arseniy
    Commented Sep 3, 2020 at 6:27
  • \$\begingroup\$ Microchip support did reply, but essentially told me RTFM lol. Understanding that part was definitely not intuitive. Thanks again! \$\endgroup\$
    – ericnutsch
    Commented Sep 3, 2020 at 6:45

The accepted answer is great, but has an error. For the read sequence, step 4 (Send Stop) should not be issued. The highlighted diagram (red rectangles) actually shows no stop sent after address (ADDR) and before a restart (SR). Transmitting a stop at this point signals other masters that the bus is free and they are open to taking control of the bus. This could result in an arbitration error being generated when the start at point 5 in this example is issued.

The actual steps for a read are:

  1. Start (S)
  2. Transmit OP | W ((OP << 1) | 0)
  3. Transmit register (ADDR)
  4. Transmit restart (SR) [A restart is just a start without a previous stop)
  5. Transmit OP | R ((OP << 1) | 1)
  6. Wait for received byte (one or more bytes) - ACK tells slave expecting more bytes
  7. Once all bytes have been received the master needs to signal a NAK to the slave device
  8. Transmit stop (P)
  • \$\begingroup\$ This is correct. Feel free to edit the accepted answer; a moderator will then review and most likely accept your edit. \$\endgroup\$ Commented May 16, 2021 at 22:52

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.