Skip to content

Commit cc3100d

Browse files
add MCP23S17 expander
1 parent 67a95c2 commit cc3100d

File tree

2 files changed

+274
-0
lines changed

2 files changed

+274
-0
lines changed
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/*
2+
* Copyright (c) 2021 Collab
3+
* All rights reserved
4+
*/
5+
/*
6+
MultiPlexer_MCP23S17.cpp - Control MCP23S17 16-channel digital multiplexer over SPI.
7+
*/
8+
9+
#include "MultiPlexer_MCP23S17.h"
10+
11+
MultiPlexer_MCP23S17::MultiPlexer_MCP23S17(SPIClass *spi, int cs_pin, Method btn_callback, uint8_t addr) {
12+
address = addr;
13+
_btnCallback = btn_callback;
14+
15+
_mcp = new MCP23S17(spi, cs_pin, addr);
16+
}
17+
18+
void MultiPlexer_MCP23S17::begin() {
19+
_mcp->begin();
20+
}
21+
22+
void MultiPlexer_MCP23S17::init() {
23+
// set MCP23S17 pin modes and interrupt configurations
24+
// to set one pin: chip.pinMode(0, INPUT_PULLUP);
25+
setPins();
26+
27+
// clear the interrupt value variables
28+
_mcpAReading = 0;
29+
_mcpBReading = 0;
30+
_mcpReading = 0;
31+
}
32+
33+
void MultiPlexer_MCP23S17::setupInterruptHandler(uint8_t irq_pin, void (*ISR)(void), int value) {
34+
pinMode(irq_pin, INPUT_PULLUP);
35+
36+
attachInterrupt(digitalPinToInterrupt(irq_pin), ISR, value);
37+
}
38+
39+
/**
40+
* Runs the MCP Interrupt processing from the Arduino ISR
41+
* and then takes action (prints) on the MCP pins that went LOW.
42+
*/
43+
void MultiPlexer_MCP23S17::loop() {
44+
if (_flagMCPA > 0) {
45+
//Log.info(F("loop flagMCPA" CR));
46+
47+
// get the bit count and write the bits to byteBit[] array
48+
readByteBits(0);
49+
50+
// do some processing of each interrupted pin
51+
processPins(0);
52+
53+
_flagMCPA = 0;
54+
}
55+
56+
if (_flagMCPB > 0) {
57+
//Log.info(F("loop flagMCPB" CR));
58+
59+
readByteBits(1);
60+
61+
// do some processing of each interrupted pin
62+
processPins(1);
63+
64+
_flagMCPB = 0;
65+
}
66+
}
67+
68+
/**
69+
* Set all port expander pins to desired mode INPUT_PULLUP.
70+
* Set all port expander input pins interrupts
71+
*/
72+
void MultiPlexer_MCP23S17::setPins() {
73+
for (uint8_t ind = 0; ind <= totalPorts - 1; ind++) {
74+
_mcp->pinMode(ind, INPUT_PULLUP);
75+
_mcp->enableInterrupt(ind, FALLING);
76+
}
77+
78+
// set port expander interrupt configuratons
79+
_mcp->setMirror(false);
80+
_mcp->setInterruptOD(false);
81+
_mcp->setInterruptLevel(LOW);
82+
83+
// clear all interrupts on this port expander
84+
_mcpReading = _mcp->getInterruptValue();
85+
}
86+
87+
/**
88+
* Take action on new pin interrupt values
89+
*/
90+
void MultiPlexer_MCP23S17::interruptMCP(uint8_t port) {
91+
// read the Port Expander Interrupt pins
92+
readBankPortIntPins(port);
93+
94+
// read the Port Expander Interrupt values
95+
readBankPortIntVal(port);
96+
97+
// take action on new pin interrupt values
98+
if (port < 1) {
99+
// set flag that Port A interrupt occurred
100+
_flagMCPA = 1;
101+
} else {
102+
// set flag that Port B interrupt occurred
103+
_flagMCPB = 1;
104+
}
105+
}
106+
107+
/**
108+
* Process the port byteBits array of interrupted MCP pins
109+
*/
110+
void MultiPlexer_MCP23S17::processPins(uint8_t port) {
111+
uint8_t pin;
112+
if (port < 1) {
113+
// Port A
114+
// _byteACount = number of pins to process
115+
for (uint8_t ind = 0; ind < _byteACount; ind++) {
116+
// recover the bit number from sequential array
117+
pin = _byteABits[ind];
118+
119+
// notify listeners
120+
_btnCallback.callback3IntArg(address, port, pin);
121+
}
122+
} else {
123+
// Port B
124+
// _byteBCount = number of pins to process
125+
for (uint8_t ind = 0; ind < _byteBCount; ind++) {
126+
// recover the bit number from sequential array
127+
pin = _byteBBits[ind];
128+
129+
// notify listeners
130+
_btnCallback.callback3IntArg(address, port, pin);
131+
}
132+
}
133+
}
134+
135+
/**
136+
* Read all Port Expander port interrupt pins.
137+
* save set bit to byteBits arrays
138+
* byteBits array can be sequentially processed later
139+
*/
140+
void MultiPlexer_MCP23S17::readByteBits(uint8_t port) {
141+
if (port < 1) {
142+
// Port A
143+
_byteACount = 0;
144+
for (uint8_t ind = 0; ind < 8; ind++) {
145+
// ~ inverts bit values
146+
if (bitRead(~_mcpAReading, ind)) {
147+
// save the bit number to sequential array
148+
_byteABits[_byteACount] = ind;
149+
_byteACount = _byteACount + 1;
150+
//Log.info(F("Port A whichBit: %d" CR), ind);
151+
}
152+
}
153+
//Log.info(F("_byteACount: %d" CR), _byteACount);
154+
} else {
155+
// Port B
156+
_byteBCount = 0;
157+
for (uint8_t ind = 0; ind < 8; ind++) {
158+
// ~ inverts bit values
159+
if (bitRead(~_mcpBReading, ind)) {
160+
// save the bit number to sequential array
161+
_byteBBits[_byteBCount] = ind;
162+
_byteBCount = _byteBCount + 1;
163+
//Log.info(F("Port B whichBit: %d" CR), ind);
164+
}
165+
}
166+
//Log.info(F("_byteBCount: %d" CR, _byteBCount);
167+
}
168+
}
169+
170+
/**
171+
* Read all Port Expander port interrupt values
172+
*/
173+
void MultiPlexer_MCP23S17::readBankPortIntVal(uint8_t port) {
174+
if (port < 1) {
175+
// Port A
176+
_mcpAReading = _mcp->getInterruptAValue();
177+
//Log.info(F("Port A Interrupt Values: ")); print8Bits(_mcpAReading);
178+
} else {
179+
// Port B
180+
_mcpBReading = _mcp->getInterruptBValue();
181+
//Log.info(F("Port B Interrupt Values: ")); print8Bits(_mcpBReading);
182+
}
183+
}
184+
185+
/**
186+
* Read all Port Expander port interrupt pins
187+
*/
188+
void MultiPlexer_MCP23S17::readBankPortIntPins(uint8_t port) {
189+
if (port < 1) {
190+
// Port A
191+
_mcpAReading = _mcp->getInterruptAPins();
192+
} else {
193+
// Port B
194+
_mcpBReading = _mcp->getInterruptBPins();
195+
}
196+
}
197+
198+
void MultiPlexer_MCP23S17::print8Bits(uint8_t myByte) {
199+
for (uint8_t mask = 0x80; mask; mask >>= 1) {
200+
if (mask & myByte)
201+
Log.info(F("1"));
202+
else
203+
Log.info(F("0"));
204+
}
205+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright (c) 2021 Collab
3+
* All rights reserved
4+
*/
5+
/*
6+
MultiPlexer_MCP23S17.h - Control MCP23S17 16-channel digital multiplexer over SPI.
7+
*/
8+
#ifndef MultiPlexer_MCP23S17_h
9+
#define MultiPlexer_MCP23S17_h
10+
11+
#include <Arduino.h>
12+
#include <SPI.h>
13+
#include <Method.h>
14+
#include <MCP23S17.h>
15+
#include <ArduinoLog.h>
16+
17+
class MultiPlexer_MCP23S17
18+
{
19+
public:
20+
MultiPlexer_MCP23S17(
21+
SPIClass *spi,
22+
int cs_pin,
23+
Method btn_callback,
24+
uint8_t addr = 0
25+
);
26+
void begin();
27+
void init();
28+
void loop();
29+
void interruptMCP(uint8_t port);
30+
void setupInterruptHandler(uint8_t irq_pin, void (*ISR)(void), int value);
31+
32+
uint8_t address;
33+
const int totalPorts = 16;
34+
35+
private:
36+
MCP23S17* _mcp;
37+
uint8_t _address;
38+
Method _btnCallback;
39+
40+
/* 16-bit interrupt reading */
41+
volatile uint16_t _mcpReading = 0;
42+
/* 8-bit Port-A interrupt reading */
43+
volatile uint8_t _mcpAReading = 0;
44+
/* 8-bit Port-B interrupt reading */
45+
volatile uint8_t _mcpBReading = 0;
46+
47+
/* number of bits set in byte */
48+
uint8_t _byteACount = 0;
49+
/* number of bits set in byte */
50+
uint8_t _byteBCount = 0;
51+
/* set bit array */
52+
uint8_t _byteABits[8] = {0};
53+
/* set bit array */
54+
uint8_t _byteBBits[8] = {0};
55+
56+
volatile uint8_t _flagMCPA = 0;
57+
volatile uint8_t _flagINTA = 0;
58+
volatile uint8_t _flagMCPB = 0;
59+
volatile uint8_t _flagINTB = 0;
60+
61+
void setPins();
62+
void processPins(uint8_t port);
63+
void print8Bits(uint8_t myByte);
64+
void readByteBits(uint8_t port);
65+
void readBankPortIntVal(uint8_t port);
66+
void readBankPortIntPins(uint8_t port);
67+
};
68+
69+
#endif

0 commit comments

Comments
 (0)