FastArduino v1.10
C++ library to build fast but small Arduino/AVR projects
Loading...
Searching...
No Matches
mcp23017.h
Go to the documentation of this file.
1// Copyright 2016-2023 Jean-Francois Poilpret
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
16
21#ifndef MCP23017_H
22#define MCP23017_H
23
24#include "mcp230xx.h"
25#include "../bits.h"
26#include "../functors.h"
27#include "../i2c_device.h"
28#include "../i2c_device_utilities.h"
29
30namespace devices::mcp230xx
31{
36 enum class MCP23017Port : uint8_t
37 {
39 PORT_A,
41 PORT_B,
52 };
53
55 namespace mcp23017_traits
56 {
57 template<MCP23017Port PORT_> struct Port_trait
58 {
59 using TYPE = uint8_t;
60 static constexpr uint8_t shift(uint8_t reg)
61 {
62 return reg;
63 }
64 };
65
66 template<> struct Port_trait<MCP23017Port::PORT_A>
67 {
68 using TYPE = uint8_t;
69 static constexpr uint8_t shift(uint8_t reg)
70 {
71 return reg;
72 }
73 };
74
75 template<> struct Port_trait<MCP23017Port::PORT_B>
76 {
77 using TYPE = uint8_t;
78 static constexpr uint8_t shift(uint8_t reg)
79 {
80 return reg + 1;
81 }
82 };
83
84 template<> struct Port_trait<MCP23017Port::PORT_AB>
85 {
86 using TYPE = uint16_t;
87 static constexpr uint8_t shift(uint8_t reg)
88 {
89 return reg;
90 }
91 };
92 }
94
101 template<typename MANAGER>
102 class MCP23017 : public i2c::I2CDevice<MANAGER>
103 {
104 private:
106 template<typename OUT, typename IN> using FUTURE = typename PARENT::template FUTURE<OUT, IN>;
107
108 template<MCP23017Port P> using TRAIT = mcp23017_traits::Port_trait<P>;
109 template<MCP23017Port P> using T = typename TRAIT<P>::TYPE;
110
111 // Forward declarations needed by compiler
112 template<MCP23017Port P, uint8_t REGISTER>
114 template<MCP23017Port P, uint8_t REGISTER>
116 template<MCP23017Port P, uint8_t... REGISTERS>
117 using TWriteMultiRegisterFuture = i2c::TWriteMultiRegisterFuture<MANAGER, T<P>, TRAIT<P>::shift(REGISTERS)...>;
118
119 // Base address of the device (actual address can be in 0x20-0x27)
120 static constexpr const uint8_t BASE_ADDRESS = 0x20;
121
122 // All registers addresses (in BANK 0 mode only)
123 static constexpr const uint8_t IODIR_A = 0x00;
124 static constexpr const uint8_t IODIR_B = 0x01;
125 static constexpr const uint8_t IPOL_A = 0x02;
126 static constexpr const uint8_t IPOL_B = 0x03;
127
128 static constexpr const uint8_t GPINTEN_A = 0x04;
129 static constexpr const uint8_t GPINTEN_B = 0x05;
130 static constexpr const uint8_t DEFVAL_A = 0x06;
131 static constexpr const uint8_t DEFVAL_B = 0x07;
132 static constexpr const uint8_t INTCON_A = 0x08;
133 static constexpr const uint8_t INTCON_B = 0x09;
134
135 static constexpr const uint8_t IOCON = 0x0A;
136
137 static constexpr const uint8_t GPPU_A = 0x0C;
138 static constexpr const uint8_t GPPU_B = 0x0D;
139
140 static constexpr const uint8_t INTF_A = 0x0E;
141 static constexpr const uint8_t INTF_B = 0x0F;
142 static constexpr const uint8_t INTCAP_A = 0x10;
143 static constexpr const uint8_t INTCAP_B = 0x11;
144
145 static constexpr const uint8_t GPIO_A = 0x12;
146 static constexpr const uint8_t GPIO_B = 0x13;
147 static constexpr const uint8_t OLAT_A = 0x14;
148 static constexpr const uint8_t OLAT_B = 0x15;
149
150 // IOCON bits (not all are used in this implementation)
151 static constexpr const uint8_t IOCON_BANK = bits::BV8(7);
152 static constexpr const uint8_t IOCON_MIRROR = bits::BV8(6);
153 static constexpr const uint8_t IOCON_SEQOP = bits::BV8(5);
154 static constexpr const uint8_t IOCON_DISSLW = bits::BV8(4);
155 static constexpr const uint8_t IOCON_HAEN = bits::BV8(3);
156 static constexpr const uint8_t IOCON_ODR = bits::BV8(2);
157 static constexpr const uint8_t IOCON_INTPOL = bits::BV8(1);
158
159 static constexpr uint8_t compute_address(uint8_t address)
160 {
161 return uint8_t((uint8_t(BASE_ADDRESS) | uint8_t(address & 0x07U)) << 1);
162 }
163
164 public:
172 MCP23017(MANAGER& manager, uint8_t address)
173 : PARENT{manager, compute_address(address), i2c::I2C_FAST, true} {}
174
175 // Asynchronous API
176 //==================
192 class BeginFuture : public TWriteRegisterFuture<MCP23017Port::PORT_A, IOCON>
193 {
195 public:
197 explicit BeginFuture(
198 bool mirror_interrupts = false,
200 : PARENT{build_IOCON(
201 mirror_interrupts, interrupt_polarity == InterruptPolarity::ACTIVE_HIGH)} {}
203 };
204
223 {
224 return this->async_write(future);
225 }
226
247 template<MCP23017Port P_>
248 class ConfigureGPIOFuture : public TWriteMultiRegisterFuture<P_, IODIR_A, IPOL_A, GPPU_A>
249 {
251 public:
253 ConfigureGPIOFuture(T<P_> direction, T<P_> pullup = T<P_>{}, T<P_> polarity = T<P_>{})
254 : PARENT{direction, polarity, pullup} {}
256 };
257
279 template<MCP23017Port P_> int configure_gpio(ConfigureGPIOFuture<P_>& future)
280 {
281 return this->async_multi_write(future);
282 }
283
305 template<MCP23017Port P_>
306 class ConfigureInterruptsFuture : public TWriteMultiRegisterFuture<P_, GPINTEN_A, DEFVAL_A, INTCON_A>
307 {
309 public:
311 ConfigureInterruptsFuture(T<P_> int_pins, T<P_> ref = T<P_>{}, T<P_> compare_ref = T<P_>{})
312 : PARENT{int_pins, ref, compare_ref} {}
314 };
315
337 template<MCP23017Port P_>
339 {
340 return this->async_multi_write(future);
341 }
342
357 template<MCP23017Port P_>
359
381 template<MCP23017Port P_> int values(SetValuesFuture<P_>& future)
382 {
383 return this->async_write(future);
384 }
385
398 template<MCP23017Port P_>
400
421 template<MCP23017Port P_> int values(GetValuesFuture<P_>& future)
422 {
423 return this->async_read(future);
424 }
425
439 template<MCP23017Port P_>
441
464 template<MCP23017Port P_> int interrupt_flags(InterruptFlagsFuture<P_>& future)
465 {
466 return this->async_read(future);
467 }
468
482 template<MCP23017Port P_>
484
509 template<MCP23017Port P_> int captured_values(CapturedValuesFuture<P_>& future)
510 {
511 return this->async_read(future);
512 }
513
514 // Synchronous API
515 //=================
531 bool begin(bool mirror_interrupts = false,
533 {
534 BeginFuture future{mirror_interrupts, interrupt_polarity};
535 if (begin(future) != 0) return false;
536 return (future.await() == future::FutureStatus::READY);
537 }
538
559 template<MCP23017Port P_> bool configure_gpio(T<P_> direction, T<P_> pullup = T<P_>{}, T<P_> polarity = T<P_>{})
560 {
561 ConfigureGPIOFuture<P_> future{direction, pullup, polarity};
562 if (configure_gpio(future) != 0) return false;
563 return (future.await() == future::FutureStatus::READY);
564 }
565
586 template<MCP23017Port P_>
587 bool configure_interrupts(T<P_> int_pins, T<P_> ref = T<P_>{}, T<P_> compare_ref = T<P_>{})
588 {
589 ConfigureInterruptsFuture<P_> future{int_pins, ref, compare_ref};
590 if (configure_interrupts(future) != 0) return false;
591 return (future.await() == future::FutureStatus::READY);
592 }
593
608 template<MCP23017Port P_> bool values(T<P_> value)
609 {
610 return this->template sync_write<SetValuesFuture<P_>>(value);
611 }
612
625 template<MCP23017Port P_> T<P_> values()
626 {
627 return get_value<GetValuesFuture<P_>, T<P_>>();
628 }
629
643 template<MCP23017Port P_> T<P_> interrupt_flags()
644 {
645 return get_value<InterruptFlagsFuture<P_>, T<P_>>();
646 }
647
663 template<MCP23017Port P_> T<P_> captured_values()
664 {
665 return get_value<CapturedValuesFuture<P_>, T<P_>>();
666 }
667
668 private:
669 template<typename F, typename T> T get_value()
670 {
671 T value;
672 if (this->template sync_read<F>(value))
673 return value;
674 else
675 return T{};
676 }
677
678 i2c::I2CLightCommand write_stop(uint8_t byte_count = 0) const
679 {
680 return this->write(byte_count, false, true);
681 }
682
683 static constexpr uint8_t build_IOCON(bool mirror, bool int_polarity)
684 {
685 return bits::ORIF8(mirror, IOCON_MIRROR, int_polarity, IOCON_INTPOL);
686 }
687 };
688}
689
690#endif /* MCP23017_H */
Create a future to be used by asynchronous method begin(BeginFuture&).
Definition: mcp23017.h:193
Create a future to be used by asynchronous method configure_gpio(ConfigureGPIOFuture.
Definition: mcp23017.h:249
Create a future to be used by asynchronous method configure_interrupts(ConfigureInterruptsFuture<P_>&...
Definition: mcp23017.h:307
I2C device driver for Microchip MCP23017 support.
Definition: mcp23017.h:103
bool configure_gpio(T< P_ > direction, T< P_ > pullup=T< P_ >{}, T< P_ > polarity=T< P_ >{})
Configure GPIO on one or both ports of this MCP23017 chip.
Definition: mcp23017.h:559
T< P_ > values()
Get levels of pins on one or both ports of this MCP23017 chip.
Definition: mcp23017.h:625
bool begin(bool mirror_interrupts=false, InterruptPolarity interrupt_polarity=InterruptPolarity::ACTIVE_HIGH)
Initialize the chip before operation.
Definition: mcp23017.h:531
bool configure_interrupts(T< P_ > int_pins, T< P_ > ref=T< P_ >{}, T< P_ > compare_ref=T< P_ >{})
Configure interrupts on one or both ports of this MCP23017 chip.
Definition: mcp23017.h:587
int interrupt_flags(InterruptFlagsFuture< P_ > &future)
Get the pins that generated the latest interrupt on one or both ports of the MCP23017 chip.
Definition: mcp23017.h:464
int values(SetValuesFuture< P_ > &future)
Set output levels of output pins on one or both ports of this MCP23017 chip.
Definition: mcp23017.h:381
T< P_ > captured_values()
Get captured levels, at the time an interrupt was triggered, of pins on one or both ports of this MCP...
Definition: mcp23017.h:663
int values(GetValuesFuture< P_ > &future)
Get levels of pins on one or both ports of this MCP23017 chip.
Definition: mcp23017.h:421
int begin(BeginFuture &future)
Initialize the chip before operation.
Definition: mcp23017.h:222
T< P_ > interrupt_flags()
Get the pins that generated the latest interrupt on one or both ports of the MCP23017 chip.
Definition: mcp23017.h:643
bool values(T< P_ > value)
Set output levels of output pins on one or both ports of this MCP23017 chip.
Definition: mcp23017.h:608
int configure_gpio(ConfigureGPIOFuture< P_ > &future)
Configure GPIO on one or both ports of this MCP23017 chip.
Definition: mcp23017.h:279
int configure_interrupts(ConfigureInterruptsFuture< P_ > &future)
Configure interrupts on one or both ports of this MCP23017 chip.
Definition: mcp23017.h:338
MCP23017(MANAGER &manager, uint8_t address)
Create a new device driver for an MCP23017 chip.
Definition: mcp23017.h:172
int captured_values(CapturedValuesFuture< P_ > &future)
Get captured levels, at the time an interrupt was triggered, of pins on one or both ports of this MCP...
Definition: mcp23017.h:509
Base class for all I2C devices.
Definition: i2c_device.h:84
static constexpr I2CLightCommand write(uint8_t write_count=0, bool finish_future=false, bool stop=false)
Build a write I2CLightCommand that can be later pushed to the I2C Manager for proper handling.
Definition: i2c_device.h:202
int async_write(F &future, bool stop=true)
Helper method that asynchronously launches I2C commands for a simple Future performing only one write...
Definition: i2c_device.h:357
int async_multi_write(F &future, bool stop=true)
Helper method that asynchronously launches I2C commands for a simple Future performing several regist...
Definition: i2c_device.h:379
MANAGER MANAGER
the type of I2C Manager that can handle this device.
Definition: i2c_device.h:87
int async_read(F &future, bool stop=true)
Helper method that asynchronously launches I2C commands for a simple Future performing one write foll...
Definition: i2c_device.h:309
Light atomic I2C command as prepared by an I2C device.
Generic Future that can be used to read an I2C device register.
Generic Future that can be used to write to several I2C device registers.
Generic Future that can be used to write to an I2C device register.
API to handle the MCP23008/23017 chips (8 & 16-Bit I/O Expanders with I2C interface).
static constexpr uint8_t BV8(uint8_t bit)
Create a uint8_t bitmask for the given bit number.
Definition: bits.h:41
static constexpr uint8_t ORIF8(bool flag1, uint8_t val1, bool flag2, uint8_t val2)
Create a uint8_t bitwise OR boolean operation between uint8_t operands, conditioned by bool flags.
Definition: bits.h:361
Defines the API for MCP23008/MCP23017 chips support.
Definition: mcp23008.h:30
MCP23017Port
The port(s) to use in MCP23017 API.
Definition: mcp23017.h:37
@ PORT_AB
Both A and B ports of MCP23017.
@ PORT_A
The A port of MCP23017.
@ PORT_B
The B port of MCP23017.
InterruptPolarity
The polarity of the MCP23008/MCP23017 INT pins.
Definition: mcp230xx.h:44
@ ACTIVE_HIGH
The INT pins shall be active high, ie they are low by default, and changed to high when an interrupt ...
Contains the API around Future implementation.
Definition: future.h:312
@ READY
The status of a Future once its output value has been fully set by a provider.
Define API to define and manage I2C devices.
Definition: i2c.h:51