diff --git a/CHANGELOG.md b/CHANGELOG.md index 88022d6..7304d23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [0.5.2] - 2024-05-19 - Fix #40, add interrupt functions +- update **MCP23S17_registers.h** +- change return type of several functions + - e.g **bool enable/disableControlRegister()** +- update readme.md +- update keywords.txt ## [0.5.1] - 2024-03-02 diff --git a/MCP23S17.cpp b/MCP23S17.cpp index fef7b09..407a475 100644 --- a/MCP23S17.cpp +++ b/MCP23S17.cpp @@ -547,6 +547,136 @@ bool MCP23S17::getPullup16(uint16_t &mask) } +/////////////////////////////////////////////////// +// +// INTERRUPTS (experimental, see #40) +// +// TODO, catch writeReg errors +// TODO, MCP23S17_INT_MODE_ERROR? +// TODO, if register not changed no need to update? +// TODO, 8 bits optimize? more code vs speed? +// +// pin = 0..15, mode = { RISING, FALLING, CHANGE } +bool MCP23S17::enableInterrupt(uint8_t pin, uint8_t mode) +{ + if (pin > 15) + { + _error = MCP23S17_PIN_ERROR; + return false; + } + + // right mode + uint16_t intcon = readReg16(MCP23S17_INTCON_A); + if (mode == CHANGE) + { + // compare to previous value. + intcon &= ~(1 << pin); + } + else + { + uint16_t defval = readReg16(MCP23S17_DEFVAL_A); + if (mode == RISING) + { + intcon |= (1 << pin); + defval &= ~(1 << pin); // RISING == compare to 0 + } + else if (mode == FALLING) + { + intcon |= (1 << pin); + defval |= ~(1 << pin); // FALLING == compare to 1 + } + writeReg16(MCP23S17_DEFVAL_A, defval); + } + writeReg16(MCP23S17_INTCON_A, intcon); + + // enable interrupt + uint16_t value = readReg16(MCP23S17_GPINTEN_A); + value |= (1 << pin); + return writeReg16(MCP23S17_GPINTEN_A, value); +} + + +bool MCP23S17::disableInterrupt(uint8_t pin) +{ + if (pin > 15) + { + _error = MCP23S17_PIN_ERROR; + return false; + } + // disable interrupt + uint16_t value = readReg16(MCP23S17_GPINTEN_A); + value &= ~(1 << pin); + return writeReg16(MCP23S17_GPINTEN_A, value); +} + + +bool MCP23S17::enableInterrupt16(uint16_t mask, uint8_t mode) +{ + uint16_t intcon = 0, defval = 0; + // right mode + if (mode == CHANGE) + { + // compare to previous value. + intcon = ~mask; + } + else + { + if (mode == RISING) + { + intcon = mask; + defval = ~mask; // RISING == compare to 0 + } + else if (mode == FALLING) + { + intcon = mask; + defval = ~mask; // FALLING == compare to 1 + } + writeReg16(MCP23S17_DEFVAL_A, defval); + } + writeReg16(MCP23S17_INTCON_A, intcon); + + // enable the mask + writeReg16(MCP23S17_GPINTEN_A, mask); + return true; +} + + +bool MCP23S17::disableInterrupt16(uint16_t mask) +{ + return writeReg16(MCP23S17_GPINTEN_A, ~mask); +} + + +// which pins caused the INT? +uint16_t MCP23S17::getInterruptFlagRegister() +{ + return readReg(MCP23S17_INTF_A); +} + + +uint16_t MCP23S17::getInterruptCaptureRegister() +{ + return readReg(MCP23S17_INTCAP_A); +} + + +bool MCP23S17::mirrorInterrupts(bool on) +{ + if (on) return enableControlRegister(MCP23S17_IOCR_MIRROR); + return disableControlRegister(MCP23S17_IOCR_MIRROR); +} + + +bool MCP23S17::isMirroredInterrupts() +{ + return (readReg(MCP23S17_IOCR) & MCP23S17_IOCR_MIRROR) > 0; +} + + +///////////////////////////////////////////// +// +// MISC +// int MCP23S17::lastError() { int e = _error; @@ -555,31 +685,31 @@ int MCP23S17::lastError() } -void MCP23S17::enableControlRegister(uint8_t mask) +bool MCP23S17::enableControlRegister(uint8_t mask) { uint8_t reg = readReg(MCP23S17_IOCR); reg |= mask; - writeReg(MCP23S17_IOCR, reg); + return writeReg(MCP23S17_IOCR, reg); } -void MCP23S17::disableControlRegister(uint8_t mask) +bool MCP23S17::disableControlRegister(uint8_t mask) { uint8_t reg = readReg(MCP23S17_IOCR); reg &= ~mask; - writeReg(MCP23S17_IOCR, reg); + return writeReg(MCP23S17_IOCR, reg); } -void MCP23S17::enableHardwareAddress() +bool MCP23S17::enableHardwareAddress() { - enableControlRegister(MCP23S17_IOCR_HAEN); + return enableControlRegister(MCP23S17_IOCR_HAEN); } -void MCP23S17::disableHardwareAddress() +bool MCP23S17::disableHardwareAddress() { - disableControlRegister(MCP23S17_IOCR_HAEN); + return disableControlRegister(MCP23S17_IOCR_HAEN); } diff --git a/MCP23S17.h b/MCP23S17.h index f460568..b6bc306 100644 --- a/MCP23S17.h +++ b/MCP23S17.h @@ -88,6 +88,25 @@ class MCP23S17 bool getPullup16(uint16_t &mask); + // INTERRUPTS (experimental) + // pin = 0..15, mode = { RISING, FALLING, CHANGE } + bool enableInterrupt(uint8_t pin, uint8_t mode); + bool disableInterrupt(uint8_t pin); + + // mask = 0x0000..0xFFFF (overrides all earlier settings. + bool enableInterrupt16(uint16_t mask, uint8_t mode); + bool disableInterrupt16(uint16_t mask); + + // which pins caused the INT? + uint16_t getInterruptFlagRegister(); + uint16_t getInterruptCaptureRegister(); + + // merge INTA and INTB + bool mirrorInterrupts(bool on); + bool isMirroredInterrupts(); + + + // SPI // speed in Hz void setSPIspeed(uint32_t speed); uint32_t getSPIspeed() { return _SPIspeed; }; @@ -97,11 +116,11 @@ class MCP23S17 int lastError(); // set/clear IOCR bit fields (0.2.3 experimental) - void enableControlRegister(uint8_t mask); - void disableControlRegister(uint8_t mask); + bool enableControlRegister(uint8_t mask); + bool disableControlRegister(uint8_t mask); // 0.2.5 experimental - void enableHardwareAddress(); - void disableHardwareAddress(); + bool enableHardwareAddress(); + bool disableHardwareAddress(); private: diff --git a/MCP23S17_registers.h b/MCP23S17_registers.h index 4b12043..8c177b3 100644 --- a/MCP23S17_registers.h +++ b/MCP23S17_registers.h @@ -11,20 +11,20 @@ #define MCP23S17_DDR_B 0x01 // Data Direction Register B P18 #define MCP23S17_POL_A 0x02 // Input Polarity A P18 #define MCP23S17_POL_B 0x03 // Input Polarity B P18 -#define MCP23S17_GPINTEN_A 0x04 // NOT USED interrupt enable P19 -#define MCP23S17_GPINTEN_B 0x05 // NOT USED -#define MCP23S17_DEFVAL_A 0x06 // NOT USED interrupt def P19 -#define MCP23S17_DEFVAL_B 0x07 // NOT USED -#define MCP23S17_INTCON_A 0x08 // NOT USED interrupt control P20 -#define MCP23S17_INTCON_B 0x09 // NOT USED +#define MCP23S17_GPINTEN_A 0x04 // Interrupt enable P19 +#define MCP23S17_GPINTEN_B 0x05 // Interrupt enable P19 +#define MCP23S17_DEFVAL_A 0x06 // Interrupt default P19 +#define MCP23S17_DEFVAL_B 0x07 // Interrupt default P19 +#define MCP23S17_INTCON_A 0x08 // Interrupt control register P20 +#define MCP23S17_INTCON_B 0x09 // Interrupt control register P20 #define MCP23S17_IOCR 0x0A // IO control register P20 -#define MCP23S17_IOCR2 0x0B // NOT USED +#define MCP23S17_IOCR2 0x0B // NOT USED #define MCP23S17_PUR_A 0x0C // Pull Up Resistors A P22 #define MCP23S17_PUR_B 0x0D // Pull Up Resistors A P22 -#define MCP23S17_INTF_A 0x0E // NOT USED interrupt flag P22 -#define MCP23S17_INTF_B 0x0F // NOT USED -#define MCP23S17_INTCAP_A 0x10 // NOT USED interrupt capture P23 -#define MCP23S17_INTCAP_B 0x11 // NOT USED +#define MCP23S17_INTF_A 0x0E // Interrupt flag register P22 +#define MCP23S17_INTF_B 0x0F // Interrupt flag register P22 +#define MCP23S17_INTCAP_A 0x10 // Interrupt capture register P23 +#define MCP23S17_INTCAP_B 0x11 // Interrupt capture register P23 #define MCP23S17_GPIO_A 0x12 // General Purpose IO A P23 #define MCP23S17_GPIO_B 0x13 // General Purpose IO B P23 #define MCP23S17_OLAT_A 0x14 // NOT USED output latch P24 diff --git a/README.md b/README.md index 4273273..55eed91 100644 --- a/README.md +++ b/README.md @@ -175,13 +175,48 @@ Since 0.2.6 the reading and writing to registers have been performance optimized If there are problems please open an issue. +### Interrupts (experimental 0.5.2) + +Read the datasheet for the details, page 24,25. +Note: Error handling is limited. + +pin = 0..15 +mode = { RISING, FALLING, CHANGE } +- **bool enableInterrupt(uint8_t pin, uint8_t mode)** +Returns true if successful. +Returns MCP23S17_PIN_ERROR if pin > 15. +- **bool disableInterrupt(uint8_t pin)** +Returns true if successful. +Returns MCP23S17_PIN_ERROR if pin > 15. + + +16 pin interface, overrides all earlier settings. +Sets all pins to the same interrupt mode { RISING, FALLING, CHANGE }. +- **bool enableInterrupt16(uint16_t mask, uint8_t mode)** mask = 0x0000..0xFFFF. +- **bool disableInterrupt16(uint16_t mask)** + + +Determine which pins caused the Interrupt. (datasheet). +- **uint16_t getInterruptFlagRegister()** Reads all 16 pins. +- **uint16_t getInterruptCaptureRegister()** Reads all 16 pins. +Is used to detect if multiple pins triggered an interrupt. + + +Merge INTA and INTB into one signal so only one line handles all interrupts. +This reduces the number of interrupt lines to handle, however one has +to read more registers to find the changed ones. + +- **bool mirrorInterrupts(bool on)** enables / disables mirror mode. +- **bool isMirroredInterrupts()** returns set option. + + ### IO Control Register Since 0.2.3 the library supports setting bit fields in the IO control register. Read the datasheet carefully! -- **void enableControlRegister(uint8_t mask)** -- **void disableControlRegister(uint8_t mask)** +- **bool enableControlRegister(uint8_t mask)** +- **bool disableControlRegister(uint8_t mask)** | constant | mask | description | @@ -198,8 +233,8 @@ Read the datasheet carefully! Two dedicated functions are added since 0.2.5. -- **void enableHardwareAddress()** set IOCR_HAEN bit. -- **void disableHardwareAddress()** clear IOCR_HAEN bit. +- **bool enableHardwareAddress()** set IOCR_HAEN bit. +- **bool disableHardwareAddress()** clear IOCR_HAEN bit. ### Error codes @@ -241,6 +276,10 @@ See examples. - IOCON.HAEN, Hardware Address ENable. - should this be enabled in **begin()** by default? 0.3.0 - check address range in constructor. +- enhance INTERRUPTS, IOCON.ODR and IOCON.INTPOL to set polarity. + - **bool setInterruptPolarity(polarity)** + getter + HIGH LOW Open Drain? +- fix TODO's in code #### Could @@ -248,8 +287,6 @@ See examples. - check if bit mask changes. - what is performance gain vs footprint? - investigate and reimplement the INPUT_PULLUP for pinMode() ? -- RP2040 support for SPI, setGPIOpins() etc - - See MCP_DAC - AVR software SPI optimize - dao and clock - see fastShiftOut. diff --git a/keywords.txt b/keywords.txt index 961455d..fe47bc4 100644 --- a/keywords.txt +++ b/keywords.txt @@ -36,6 +36,16 @@ getPolarity16 KEYWORD2 setPullup16 KEYWORD2 getPullup16 KEYWORD2 +enableInterrupt KEYWORD2 +disableInterrupt KEYWORD2 +enableInterrupt16 KEYWORD2 +disableInterrupt16 KEYWORD2 +getInterruptFlagRegister KEYWORD2 +getInterruptCaptureRegister KEYWORD2 + +mirrorInterrupts KEYWORD2 +isMirroredInterrupts KEYWORD2 + setSPIspeed KEYWORD2 getSPIspeed KEYWORD2 usesHWSPI KEYWORD2