All parts / MCP23008
MCP23008 register map
8-bit I2C I/O expander with interrupt output — Microchip Technology
Get it as a C header
pip install regforge
regforge gen MCP23008 --out ./src --driver --tests
Writes mcp23008_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 | IODIR | RW | 8 | 0xFF | Pin direction. 1 = input, 0 = output. All pins are inputs after reset. |
| 0x01 | IPOL | RW | 8 | 0x00 | Input polarity. 1 = the GPIO register reflects the inverted pin value. |
| 0x02 | GPINTEN | RW | 8 | 0x00 | Interrupt-on-change enable, per pin |
| 0x03 | DEFVAL | RW | 8 | 0x00 | Default comparison value, used when INTCON selects comparison mode |
| 0x04 | INTCON | RW | 8 | 0x00 | Interrupt control. 1 = compare against DEFVAL, 0 = compare against the previous value. |
| 0x05 | IOCON | RW | 8 | 0x00 | Device configuration. Note there is no BANK bit here -- with a single port there is nothing to re-bank. |
| 0x06 | GPPU | RW | 8 | 0x00 | 100 kOhm pull-up enable, per pin, on pins configured as inputs |
| 0x07 | INTF | RO | 8 | 0x00 | Interrupt flags. 1 = this pin caused the interrupt. Read-only. |
| 0x08 | INTCAP | RO | 8 | 0x00 | Port value captured at the time of the interrupt. Cleared by reading INTCAP or GPIO. |
| 0x09 | GPIO | RW | 8 | 0x00 | Port value. Reading returns the pin state; writing modifies the output latch. |
| 0x0A | OLAT | RW | 8 | 0x00 | Output latch. Reading returns the latch, not the pin. |
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 @ 0x05 — 5 fields
| Bits | Field | Access | Mask | Reset | Description |
|---|---|---|---|---|---|
| [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 MCP23008 writes for IOCON:
/* ------------------------------------------------------------------------ */
/* IOCON @ 0x05u rw 8-bit reset 0x00u */
/* Device configuration. Note there is no BANK bit here -- with a single port there is nothing to re-bank. */
/* ------------------------------------------------------------------------ */
#define MCP23008_IOCON 0x05u
#define MCP23008_IOCON_WIDTH 8u
#define MCP23008_IOCON_RESET 0x00u
/* SEQOP bits [5] rw reset 0x00u -- Sequential operation disable. 1 = the address pointer does not increment. */
#define MCP23008_IOCON_SEQOP_SHIFT 5u
#define MCP23008_IOCON_SEQOP_WIDTH 1u
#define MCP23008_IOCON_SEQOP_MASK 0x20u
#define MCP23008_IOCON_SEQOP_GET(reg) (((uint8_t)(reg) & 0x20u) >> 5u)
#define MCP23008_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 MCP23008_IOCON_DISSLW_SHIFT 4u
#define MCP23008_IOCON_DISSLW_WIDTH 1u
#define MCP23008_IOCON_DISSLW_MASK 0x10u
#define MCP23008_IOCON_DISSLW_GET(reg) (((uint8_t)(reg) & 0x10u) >> 4u)
#define MCP23008_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 MCP23008_IOCON_HAEN_SHIFT 3u
#define MCP23008_IOCON_HAEN_WIDTH 1u
#define MCP23008_IOCON_HAEN_MASK 0x08u
#define MCP23008_IOCON_HAEN_GET(reg) (((uint8_t)(reg) & 0x08u) >> 3u)
#define MCP23008_IOCON_HAEN_SET(reg, val) (((uint8_t)(reg) & (uint8_t)~0x08u) | (((uint8_t)(val) << 3u) & 0x08u))
/* ODR bits [2] rw reset 0x00u -- 1 = INT pin is open drain, overriding INTPOL */
#define MCP23008_IOCON_ODR_SHIFT 2u
#define MCP23008_IOCON_ODR_WIDTH 1u
#define MCP23008_IOCON_ODR_MASK 0x04u
#define MCP23008_IOCON_ODR_GET(reg) (((uint8_t)(reg) & 0x04u) >> 2u)
#define MCP23008_IOCON_ODR_SET(reg, val) (((uint8_t)(reg) & (uint8_t)~0x04u) | (((uint8_t)(val) << 2u) & 0x04u))
/* INTPOL bits [1] rw reset 0x00u -- INT pin polarity when ODR is 0. 0 = active low, 1 = active high. */
#define MCP23008_IOCON_INTPOL_SHIFT 1u
#define MCP23008_IOCON_INTPOL_WIDTH 1u
#define MCP23008_IOCON_INTPOL_MASK 0x02u
#define MCP23008_IOCON_INTPOL_GET(reg) (((uint8_t)(reg) & 0x02u) >> 1u)
#define MCP23008_IOCON_INTPOL_SET(reg, val) (((uint8_t)(reg) & (uint8_t)~0x02u) | (((uint8_t)(val) << 1u) & 0x02u))
Compared with
Related parts
Source
Transcribed from Microchip MCP23008/MCP23S08 datasheet (DS21919) (hand-transcribed) (hand-transcribed). Hand-authored seed entry, not machine-extracted. Check against Microchip MCP23008/MCP23S08 datasheet (DS21919) before trusting it, then mark it verified.