RegForge

All parts / MCP23017

MCP23017 register map

16-bit I2C I/O expander with interrupt output — Microchip Technology

21 registers I2C I²C 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 8-bit reg addresses 88% bit coverage not yet human-verified
I²C address conflict. On its default address(es) this part collides with MCP23008 (0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27). You cannot put them on the same bus without changing a strap pin, using an I²C multiplexer, or moving one to a second bus. See the full address map.

Get it as a C header

pip install regforge
regforge gen MCP23017 --out ./src --driver --tests

Writes mcp23017_regs.h with every address, mask and shift below, a bus-agnostic driver skeleton, and a file of compile-time assertions that make your compiler check the bit arithmetic. No API key needed — this part ships inside the package.

Not yet human-verified. Transcribed and mechanically validated — no overlapping fields, no out-of-range bits, reset values consistent with their fields — but not yet checked line-by-line against the datasheet. Verifying it is a useful half hour.

Registers

AddrRegisterAccessWidthResetDescription
0x00IODIRARW80xFFPin direction. 1 = input, 0 = output. All pins are inputs after reset. (port A)
0x01IODIRBRW80xFFPin direction. 1 = input, 0 = output. All pins are inputs after reset. (port B)
0x02IPOLARW80x00Input polarity. 1 = the GPIO register reflects the inverted pin value. (port A)
0x03IPOLBRW80x00Input polarity. 1 = the GPIO register reflects the inverted pin value. (port B)
0x04GPINTENARW80x00Interrupt-on-change enable, per pin (port A)
0x05GPINTENBRW80x00Interrupt-on-change enable, per pin (port B)
0x06DEFVALARW80x00Default comparison value, used when INTCON selects comparison mode (port A)
0x07DEFVALBRW80x00Default comparison value, used when INTCON selects comparison mode (port B)
0x08INTCONARW80x00Interrupt control. 1 = compare against DEFVAL, 0 = compare against the previous value. (port A)
0x09INTCONBRW80x00Interrupt control. 1 = compare against DEFVAL, 0 = compare against the previous value. (port B)
0x0AIOCONRW80x00Device configuration, shared by both ports. Also readable and writable at 0x0B; the two addresses are the same physical register.
0x0CGPPUARW80x00100 kOhm pull-up enable, per pin, on pins configured as inputs (port A)
0x0DGPPUBRW80x00100 kOhm pull-up enable, per pin, on pins configured as inputs (port B)
0x0EINTFARO80x00Interrupt flags. 1 = this pin caused the interrupt. Read-only. (port A)
0x0FINTFBRO80x00Interrupt flags. 1 = this pin caused the interrupt. Read-only. (port B)
0x10INTCAPARO80x00Port value captured at the time of the interrupt. Cleared by reading INTCAP or GPIO. (port A)
0x11INTCAPBRO80x00Port value captured at the time of the interrupt. Cleared by reading INTCAP or GPIO. (port B)
0x12GPIOARW80x00Port value. Reading returns the pin state; writing modifies the output latch. (port A)
0x13GPIOBRW80x00Port value. Reading returns the pin state; writing modifies the output latch. (port B)
0x14OLATARW80x00Output latch. Reading returns the latch, not the pin. (port A)
0x15OLATBRW80x00Output latch. Reading returns the latch, not the pin. (port B)

Bit layouts

Drawn MSB-first, the way the datasheet draws them. [7:5] means shift 5, width 3, mask 0xE0 — this is the notation that costs people a day when they read it backwards.

IOCON  @  0x0A  —  7 fields
BANK[7]
MIRROR[6]
SEQOP[5]
DISSLW[4]
HAEN[3]
ODR[2]
INTPOL[1]
—0
BitsFieldAccessMaskResetDescription
[7]BANKRW0x800x00Register addressing mode. 0 = A/B registers interleaved (the mapping transcribed here), 1 = ports in separate banks.
[6]MIRRORRW0x400x001 = INTA and INTB are internally connected
[5]SEQOPRW0x200x00Sequential operation disable. 1 = the address pointer does not increment.
[4]DISSLWRW0x100x00Disable slew-rate control on SDA
[3]HAENRW0x080x00Hardware address enable. No effect on the I2C part; present for the SPI variant.
[2]ODRRW0x040x001 = INT pin is open drain, overriding INTPOL
[1]INTPOLRW0x020x00INT pin polarity when ODR is 0. 0 = active low, 1 = active high.

Generated C header

What regforge gen MCP23017 writes for IOCON:

/* ------------------------------------------------------------------------ */
/* IOCON @ 0x0Au  rw  8-bit  reset 0x00u */
/* Device configuration, shared by both ports. Also readable and writable at 0x0B; the two addresses are the same physical register. */
/* ------------------------------------------------------------------------ */

#define MCP23017_IOCON                                 0x0Au
#define MCP23017_IOCON_WIDTH                           8u
#define MCP23017_IOCON_RESET                           0x00u

/*   BANK bits [7] rw reset 0x00u -- Register addressing mode. 0 = A/B registers interleaved (the mapping transcribed here), 1 = ports in separate banks. */
#define MCP23017_IOCON_BANK_SHIFT                      7u
#define MCP23017_IOCON_BANK_WIDTH                      1u
#define MCP23017_IOCON_BANK_MASK                       0x80u
#define MCP23017_IOCON_BANK_GET(reg)                   (((uint8_t)(reg) & 0x80u) >> 7u)
#define MCP23017_IOCON_BANK_SET(reg, val)              (((uint8_t)(reg) & (uint8_t)~0x80u) | (((uint8_t)(val) << 7u) & 0x80u))

/*   MIRROR bits [6] rw reset 0x00u -- 1 = INTA and INTB are internally connected */
#define MCP23017_IOCON_MIRROR_SHIFT                    6u
#define MCP23017_IOCON_MIRROR_WIDTH                    1u
#define MCP23017_IOCON_MIRROR_MASK                     0x40u
#define MCP23017_IOCON_MIRROR_GET(reg)                 (((uint8_t)(reg) & 0x40u) >> 6u)
#define MCP23017_IOCON_MIRROR_SET(reg, val)            (((uint8_t)(reg) & (uint8_t)~0x40u) | (((uint8_t)(val) << 6u) & 0x40u))

/*   SEQOP bits [5] rw reset 0x00u -- Sequential operation disable. 1 = the address pointer does not increment. */
#define MCP23017_IOCON_SEQOP_SHIFT                     5u
#define MCP23017_IOCON_SEQOP_WIDTH                     1u
#define MCP23017_IOCON_SEQOP_MASK                      0x20u
#define MCP23017_IOCON_SEQOP_GET(reg)                  (((uint8_t)(reg) & 0x20u) >> 5u)
#define MCP23017_IOCON_SEQOP_SET(reg, val)             (((uint8_t)(reg) & (uint8_t)~0x20u) | (((uint8_t)(val) << 5u) & 0x20u))

/*   DISSLW bits [4] rw reset 0x00u -- Disable slew-rate control on SDA */
#define MCP23017_IOCON_DISSLW_SHIFT                    4u
#define MCP23017_IOCON_DISSLW_WIDTH                    1u
#define MCP23017_IOCON_DISSLW_MASK                     0x10u
#define MCP23017_IOCON_DISSLW_GET(reg)                 (((uint8_t)(reg) & 0x10u) >> 4u)
#define MCP23017_IOCON_DISSLW_SET(reg, val)            (((uint8_t)(reg) & (uint8_t)~0x10u) | (((uint8_t)(val) << 4u) & 0x10u))

/*   HAEN bits [3] rw reset 0x00u -- Hardware address enable. No effect on the I2C part; present for the SPI variant. */
#define MCP23017_IOCON_HAEN_SHIFT                      3u
#define MCP23017_IOCON_HAEN_WIDTH                      1u
#define MCP23017_IOCON_HAEN_MASK                       0x08u
#define MCP23017_IOCON_HAEN_GET(reg)                   (((uint8_t)(reg) & 0x08u) >> 3u)
#define MCP23017_IOCON_HAEN_SET(reg, val)              (((uint8_t)(reg) & (uint8_t)~0x08u) | (((uint8_t)(val) << 3u) & 0x08u))

Compared with

Related parts

MCP23008
Microchip Technology
11 registers
ADXL345
Analog Devices
30 registers
DS1307
Analog Devices
8 registers

Source

Transcribed from Microchip MCP23017/MCP23S17 datasheet (DS20001952) (hand-transcribed) (hand-transcribed). Hand-authored seed entry, not machine-extracted. Transcribed for IOCON.BANK = 0, the power-on default; the BANK = 1 address map is not covered. Check against the datasheet before trusting it, then mark it verified.

Raw JSON · Report an error