|
| 1 | +#pragma once |
| 2 | + |
| 3 | +#include <Adafruit_BusIO_Register.h> |
| 4 | +#include <Adafruit_I2CDevice.h> |
| 5 | +#include <cstdint> |
| 6 | + |
| 7 | +class MCP23008T { |
| 8 | + public: |
| 9 | + static constexpr uint16_t REG_IODIR_ADDR = 0x00; |
| 10 | + static constexpr uint16_t REG_IPOL_ADDR = 0x01; |
| 11 | + static constexpr uint16_t REG_GPINTEN_ADDR = 0x02; |
| 12 | + static constexpr uint16_t REG_DEFVAL_ADDR = 0x03; |
| 13 | + static constexpr uint16_t REG_INTCON_ADDR = 0x04; |
| 14 | + static constexpr uint16_t REG_IOCON_ADDR = 0x05; |
| 15 | + static constexpr uint16_t REG_GPPU_ADDR = 0x06; |
| 16 | + static constexpr uint16_t REG_INTF_ADDR = 0x07; |
| 17 | + static constexpr uint16_t REG_INTCAP_ADDR = 0x08; |
| 18 | + static constexpr uint16_t REG_GPIO_ADDR = 0x09; |
| 19 | + static constexpr uint16_t REG_OLAT_ADDR = 0x0A; |
| 20 | + |
| 21 | + static constexpr uint8_t ONE_BYTE = 1; |
| 22 | + |
| 23 | + MCP23008T(uint8_t address, TwoWire *wire = &Wire) : device(address, wire) {} |
| 24 | + |
| 25 | + bool begin() { |
| 26 | + if (!device.begin()) { |
| 27 | + return false; |
| 28 | + } |
| 29 | + |
| 30 | + return true; |
| 31 | + } |
| 32 | + |
| 33 | + /** |
| 34 | + * @details When a bit is set, the corresponding pin becomes an input (1). |
| 35 | + * When a bit is clear (0), the corresponding pin becomes an output. |
| 36 | + * |
| 37 | + * @returns Returns true on success, false otherwise |
| 38 | + */ |
| 39 | + inline bool setIODir(uint32_t value) { return regIODIR.write(value); } |
| 40 | + |
| 41 | + /** |
| 42 | + * @details If a bit is set, the corresponding GPIO register bit will |
| 43 | + * reflect the inverted value on the pin. |
| 44 | + * |
| 45 | + * @returns Returns true on success, false otherwise |
| 46 | + */ |
| 47 | + inline bool setInputPolarity(uint32_t value) { |
| 48 | + return regIPOL.write(value); |
| 49 | + } |
| 50 | + |
| 51 | + /** |
| 52 | + * @details If a bit is set, the corresponding pin is enabled for |
| 53 | + * interrupt-on-change. The DEFVAL and INTCON registers must also be |
| 54 | + * configured if any pins are enabled for interrupt-on-change. |
| 55 | + * |
| 56 | + * @returns Returns true on success, false otherwise |
| 57 | + */ |
| 58 | + inline bool setIntOnChange(uint32_t value) { |
| 59 | + return regGPINTEN.write(value); |
| 60 | + } |
| 61 | + |
| 62 | + /** |
| 63 | + * @details The default comparison value is configured in the DEFVAL |
| 64 | + * register. If enabled (via GPINTEN and INTCON) to compare against the |
| 65 | + * DEFVAL register, an opposite value on the associated pin will cause an |
| 66 | + * interrupt to occur. |
| 67 | + * |
| 68 | + * @returns Returns true on success, false otherwise |
| 69 | + */ |
| 70 | + inline bool setDefaultCompVal(uint32_t value) { |
| 71 | + return regDEFVAL.write(value); |
| 72 | + } |
| 73 | + |
| 74 | + /** |
| 75 | + * @details The INTCON register controls how the associated pin value is |
| 76 | + * compared for the interrupt-on-change feature. If a bit is set, the |
| 77 | + * corresponding I/O pin is compared against the associated bit in the |
| 78 | + * DEFVAL register. If a bit value is clear, the corresponding I/O pin is |
| 79 | + * compared against the previous value. |
| 80 | + * |
| 81 | + * @returns Returns true on success, false otherwise |
| 82 | + */ |
| 83 | + inline bool setIntOnChange(uint32_t value) { |
| 84 | + return regINTCON.write(value); |
| 85 | + } |
| 86 | + |
| 87 | + /** |
| 88 | + * @details The IOCON register contains several bits for configuring the |
| 89 | + * device: |
| 90 | + * - The Sequential Operation (SEQOP) controls the incrementing function of |
| 91 | + * the Address Pointer. If the Address Pointer is disabled, the Address |
| 92 | + * Pointer does not automatically increment after each byte is clocked |
| 93 | + * during a serial transfer. This feature is useful when it is desired to |
| 94 | + * continuously poll (read) or modify (write) a register. • The Slew Rate |
| 95 | + * (DISSLW) bit controls the slew rate function on the SDA pin. If |
| 96 | + * enabled, the SDA slew rate will be controlled when driving from a high |
| 97 | + * to a low. |
| 98 | + * - The Hardware Address Enable (HAEN) control bit enables/disables the |
| 99 | + * hardware address pins (A1, A0) on the MCP23S08. This bit is not used on |
| 100 | + * the MCP23008. The address pins are always enabled on the MCP23008. |
| 101 | + * - The Open-Drain (ODR) control bit enables/disables the INT pin for |
| 102 | + * open-drain configuration. |
| 103 | + * - The Interrupt Polarity (INTPOL) control bit sets the polarity of the |
| 104 | + * INT pin. This bit is functional only when the ODR bit is cleared, |
| 105 | + * configuring the INT pin as active push-pull. |
| 106 | + * bit 7-6 Unimplemented: Read as ‘0’ |
| 107 | + * bit 5 SEQOP: Sequential Operation Mode |
| 108 | + * 1 = Sequential operation disabled, Address Pointer does not increment |
| 109 | + * 0 = Sequential operation enabled, Address Pointer increments |
| 110 | + * bit 4 DISSLW: Slew Rate Control Bit for SDA Output |
| 111 | + * 1 = Slew rate disabled |
| 112 | + * 0 = Slew rate enabled |
| 113 | + * bit 3 HAEN: Hardware Address Enable (MCP23S08 only) |
| 114 | + * Address pins are always enabled on MCP23008. |
| 115 | + * 1 = Enables the MCP23S08 address pins |
| 116 | + * 0 = Disables the MCP23S08 address pins |
| 117 | + * bit 2 ODR: This bit configures the INT pin as an open-drain output |
| 118 | + * 1 = Open-drain output (overrides the INTPOL bit) |
| 119 | + * 0 = Active driver output (INTPOL bit sets the polarity) |
| 120 | + * bit 1 INTPOL: This bit sets the polarity of the INT output pin |
| 121 | + * 1 = Active-high |
| 122 | + * 0 = Active-low |
| 123 | + * bit 0 Unimplemented: Read as ‘0’ |
| 124 | + * |
| 125 | + * @returns Returns true on success, false otherwise |
| 126 | + */ |
| 127 | + inline bool setConfig(uint32_t value) { return regIOCON.write(value); } |
| 128 | + |
| 129 | + /** |
| 130 | + * @details The GPPU register controls the pull-up resistors for the PORT |
| 131 | + * pins. If a bit is set and the corresponding pin is configured as an |
| 132 | + * input, the corresponding PORT pin is internally pulled up with a 100 k |
| 133 | + * resistor |
| 134 | + * |
| 135 | + * @returns Returns true on success, false otherwise |
| 136 | + */ |
| 137 | + inline bool setPullUp(uint32_t value) { return regGPPU.write(value); } |
| 138 | + |
| 139 | + /** |
| 140 | + * @details The INTF register reflects the interrupt condition on the |
| 141 | + * PORT pins of any pin that is enabled for interrupts via |
| 142 | + * the GPINTEN register. A ‘set’ bit indicates that the |
| 143 | + * associated pin caused the interrupt. |
| 144 | + * |
| 145 | + * This register is ‘read-only’. Writes to this register will be |
| 146 | + * ignored. |
| 147 | + * |
| 148 | + * @returns Returns 0xFFFFFFFF on failure, value otherwise |
| 149 | + */ |
| 150 | + inline uint32_t readIntFlag(void) { return regINTF.read(); } |
| 151 | + |
| 152 | + /** |
| 153 | + * @details The INTCAP register captures the GPIO port value at the time the |
| 154 | + * interrupt occurred. The register is ‘read-only’ and is updated only when |
| 155 | + * an interrupt occurs. The register will remain unchanged until the |
| 156 | + * interrupt is cleared via a read of INTCAP or GPIO. |
| 157 | + * |
| 158 | + * @returns Returns 0xFFFFFFFF on failure, value otherwise |
| 159 | + */ |
| 160 | + inline uint32_t readIntCap(void) { return regIntCap.read(); } |
| 161 | + |
| 162 | + /** |
| 163 | + * @details The GPIO register reflects the value on the port. Reading from |
| 164 | + * this register reads the port. Writing to this register modifies the |
| 165 | + * Output Latch (OLAT) register. |
| 166 | + * |
| 167 | + * @returns Returns true on success, false otherwise |
| 168 | + */ |
| 169 | + inline bool setGPIO(uint32_t value) { return regGPIO.write(value); } |
| 170 | + |
| 171 | + /** |
| 172 | + * @details The OLAT register provides access to the output latches. A read |
| 173 | + * from this register results in a read of the OLAT and not the port itself. |
| 174 | + * A write to this register modifies the output latches that modify the pins |
| 175 | + * configured as outputs. |
| 176 | + * |
| 177 | + * @returns Returns true on success, false otherwise |
| 178 | + */ |
| 179 | + inline bool setOLAT(uint32_t value) { return regOLAT.write(value); } |
| 180 | + |
| 181 | + private: |
| 182 | + Adafruit_I2CDevice device; |
| 183 | + |
| 184 | + Adafruit_BusIO_Register regIODIR = Adafruit_BusIO_Register( |
| 185 | + &device, REG_IODIR_ADDR, ONE_BYTE, LSBFIRST, ONE_BYTE); |
| 186 | + Adafruit_BusIO_Register regIPOL = Adafruit_BusIO_Register( |
| 187 | + &device, REG_IPOL_ADDR, ONE_BYTE, LSBFIRST, ONE_BYTE); |
| 188 | + Adafruit_BusIO_Register regGPINTEN = Adafruit_BusIO_Register( |
| 189 | + &device, REG_GPINTEN_ADDR, ONE_BYTE, LSBFIRST, ONE_BYTE); |
| 190 | + Adafruit_BusIO_Register regDEFVAL = Adafruit_BusIO_Register( |
| 191 | + &device, REG_DEFVAL_ADDR, ONE_BYTE, LSBFIRST, ONE_BYTE); |
| 192 | + |
| 193 | + Adafruit_BusIO_Register regINTCON = Adafruit_BusIO_Register( |
| 194 | + &device, REG_INTCON_ADDR, ONE_BYTE, LSBFIRST, ONE_BYTE); |
| 195 | + Adafruit_BusIO_Register regIOCON = Adafruit_BusIO_Register( |
| 196 | + &device, REG_IOCON_ADDR, ONE_BYTE, LSBFIRST, ONE_BYTE); |
| 197 | + Adafruit_BusIO_Register regGPPU = Adafruit_BusIO_Register( |
| 198 | + &device, REG_GPPU_ADDR, ONE_BYTE, LSBFIRST, ONE_BYTE); |
| 199 | + Adafruit_BusIO_Register regINTF = Adafruit_BusIO_Register( |
| 200 | + &device, REG_INTF_ADDR, ONE_BYTE, LSBFIRST, ONE_BYTE); |
| 201 | + |
| 202 | + Adafruit_BusIO_Register regIntCap = Adafruit_BusIO_Register( |
| 203 | + &device, REG_INTCAP_ADDR, ONE_BYTE, LSBFIRST, ONE_BYTE); |
| 204 | + Adafruit_BusIO_Register regGPIO = Adafruit_BusIO_Register( |
| 205 | + &device, REG_GPIO_ADDR, ONE_BYTE, LSBFIRST, ONE_BYTE); |
| 206 | + Adafruit_BusIO_Register regOLAT = Adafruit_BusIO_Register( |
| 207 | + &device, REG_OLAT_ADDR, ONE_BYTE, LSBFIRST, ONE_BYTE); |
| 208 | +}; |
0 commit comments