All parts / MCP23017
MCP23017 register map
16-bit I2C I/O expander with interrupt output — Microchip Technology
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.
Registers
| Addr | Register | Access | Width | Reset | Description |
|---|---|---|---|---|---|
| 0x00 | IODIRA | RW | 8 | 0xFF | Pin direction. 1 = input, 0 = output. All pins are inputs after reset. (port A) |
| 0x01 | IODIRB | RW | 8 | 0xFF | Pin direction. 1 = input, 0 = output. All pins are inputs after reset. (port B) |
| 0x02 | IPOLA | RW | 8 | 0x00 | Input polarity. 1 = the GPIO register reflects the inverted pin value. (port A) |
| 0x03 | IPOLB | RW | 8 | 0x00 | Input polarity. 1 = the GPIO register reflects the inverted pin value. (port B) |
| 0x04 | GPINTENA | RW | 8 | 0x00 | Interrupt-on-change enable, per pin (port A) |
| 0x05 | GPINTENB | RW | 8 | 0x00 | Interrupt-on-change enable, per pin (port B) |
| 0x06 | DEFVALA | RW | 8 | 0x00 | Default comparison value, used when INTCON selects comparison mode (port A) |
| 0x07 | DEFVALB | RW | 8 | 0x00 | Default comparison value, used when INTCON selects comparison mode (port B) |
| 0x08 | INTCONA | RW | 8 | 0x00 | Interrupt control. 1 = compare against DEFVAL, 0 = compare against the previous value. (port A) |
| 0x09 | INTCONB | RW | 8 | 0x00 | Interrupt control. 1 = compare against DEFVAL, 0 = compare against the previous value. (port B) |
| 0x0A | IOCON | RW | 8 | 0x00 | Device configuration, shared by both ports. Also readable and writable at 0x0B; the two addresses are the same physical register. |
| 0x0C | GPPUA | RW | 8 | 0x00 | 100 kOhm pull-up enable, per pin, on pins configured as inputs (port A) |
| 0x0D | GPPUB | RW | 8 | 0x00 | 100 kOhm pull-up enable, per pin, on pins configured as inputs (port B) |
| 0x0E | INTFA | RO | 8 | 0x00 | Interrupt flags. 1 = this pin caused the interrupt. Read-only. (port A) |
| 0x0F | INTFB | RO | 8 | 0x00 | Interrupt flags. 1 = this pin caused the interrupt. Read-only. (port B) |
| 0x10 | INTCAPA | RO | 8 | 0x00 | Port value captured at the time of the interrupt. Cleared by reading INTCAP or GPIO. (port A) |
| 0x11 | INTCAPB | RO | 8 | 0x00 | Port value captured at the time of the interrupt. Cleared by reading INTCAP or GPIO. (port B) |
| 0x12 | GPIOA | RW | 8 | 0x00 | Port value. Reading returns the pin state; writing modifies the output latch. (port A) |
| 0x13 | GPIOB | RW | 8 | 0x00 | Port value. Reading returns the pin state; writing modifies the output latch. (port B) |
| 0x14 | OLATA | RW | 8 | 0x00 | Output latch. Reading returns the latch, not the pin. (port A) |
| 0x15 | OLATB | RW | 8 | 0x00 | Output 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
| Bits | Field | Access | Mask | Reset | Description |
|---|---|---|---|---|---|
| [7] | BANK | RW | 0x80 | 0x00 | Register addressing mode. 0 = A/B registers interleaved (the mapping transcribed here), 1 = ports in separate banks. |
| [6] | MIRROR | RW | 0x40 | 0x00 | 1 = INTA and INTB are internally connected |
| [5] | SEQOP | RW | 0x20 | 0x00 | Sequential operation disable. 1 = the address pointer does not increment. |
| [4] | DISSLW | RW | 0x10 | 0x00 | Disable slew-rate control on SDA |
| [3] | HAEN | RW | 0x08 | 0x00 | Hardware address enable. No effect on the I2C part; present for the SPI variant. |
| [2] | ODR | RW | 0x04 | 0x00 | 1 = INT pin is open drain, overriding INTPOL |
| [1] | INTPOL | RW | 0x02 | 0x00 | INT 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
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.