I believe your goal in this test is to check if sensor is solid and consistent. If you have other plans to build on, I am glad to pivot to your base work from that. But below is test I setup to start “small and expand” in my testing.
PS: I dug around and found .1u ceramic capacitor (104) and put it on bread board between pins 9 and 10. So each MCP has noted capacitor setup.
My foundation code that has solid test. where each of the 16 outputs with the sensor are solid and consistent.
#include <SPI.h>
// MCP23S17 SPI settings
const uint8_t CS_PIN = 2; // Chip select pin for Group 1 (CS0)
const uint8_t MCP_ADDR = 0x20; // Address 0 (A0=A1=A2=GND)
// MCP23S17 registers (for bank=0 mode)
#define IODIRA 0x00 // I/O direction for Port A (1=input, 0=output)
#define IODIRB 0x01 // I/O direction for Port B
#define GPPUA 0x0C // Pull-up enable for Port A
#define GPPUB 0x0D // Pull-up enable for Port B
#define GPIOA 0x12 // Input state for Port A
#define GPIOB 0x13 // Input state for Port B
// Track previous states for change detection
uint8_t lastStateA = 0xFF; // Assume all HIGH (no magnet) initially
uint8_t lastStateB = 0xFF;
void setup() {
Serial.begin(9600);
SPI.begin();
pinMode(CS_PIN, OUTPUT);
digitalWrite(CS_PIN, HIGH); // Deselect chip
// Initialize MCP23S17
writeRegister(IODIRA, 0xFF); // All GPA0-GPA7 as inputs
writeRegister(IODIRB, 0xFF); // All GPB0-GPB7 as inputs
writeRegister(GPPUA, 0xFF); // Enable pull-ups on GPA0-GPA7
writeRegister(GPPUB, 0xFF); // Enable pull-ups on GPB0-GPB7
}
void loop() {
// Read both ports
uint8_t stateA = readRegister(GPIOA); // GPA0-GPA7
uint8_t stateB = readRegister(GPIOB); // GPB0-GPB7
// Check for changes on Port A
for (int i = 0; i < 8; i++) {
bool currentBit = (stateA >> i) & 0x01; // Current state of GPA[i]
bool lastBit = (lastStateA >> i) & 0x01; // Previous state of GPA[i]
if (currentBit != lastBit) {
Serial.print("MCP000-GPA");
Serial.print(i);
Serial.print("-");
Serial.print(currentBit ? "1" : "0");
Serial.println(currentBit ? " - No Magnet" : " - Magnet Detected");
}
}
// Check for changes on Port B
for (int i = 0; i < 8; i++) {
bool currentBit = (stateB >> i) & 0x01; // Current state of GPB[i]
bool lastBit = (lastStateB >> i) & 0x01; // Previous state of GPB[i]
if (currentBit != lastBit) {
Serial.print("MCP000-GPB");
Serial.print(i);
Serial.print("-");
Serial.print(currentBit ? "1" : "0");
Serial.println(currentBit ? " - No Magnet" : " - Magnet Detected");
}
}
// Update previous states
lastStateA = stateA;
lastStateB = stateB;
delay(100); // Poll every 100ms for debouncing
}
// Write to MCP23S17 register
void writeRegister(uint8_t reg, uint8_t value) {
digitalWrite(CS_PIN, LOW);
SPI.transfer(MCP_ADDR << 1); // Write command (address + write bit)
SPI.transfer(reg); // Register address
SPI.transfer(value); // Data
digitalWrite(CS_PIN, HIGH);
}
// Read from MCP23S17 register
uint8_t readRegister(uint8_t reg) {
digitalWrite(CS_PIN, LOW);
SPI.transfer((MCP_ADDR << 1) | 0x01); // Read command (address + read bit)
SPI.transfer(reg); // Register address
uint8_t value = SPI.transfer(0x00); // Read data
digitalWrite(CS_PIN, HIGH);
return value;
}
Test Output Serial. Very consistent.
MCP000-GPA7-0 - Magnet Detected
MCP000-GPA7-1 - No Magnet
MCP000-GPA7-0 - Magnet Detected
MCP000-GPA7-1 - No Magnet
MCP000-GPA7-0 - Magnet Detected
MCP000-GPA7-1 - No Magnet
<snip other 14 tests>
MCP000-GPB0-0 - Magnet Detected
MCP000-GPB0-1 - No Magnet
MCP000-GPB0-0 - Magnet Detected
MCP000-GPB0-1 - No Magnet
##########
Upon that is my next phase of the test where I add the second “bank” of MCPs
# Wiring Diagram for t02
Arduino UNO R4 WiFi
+-------------------+
| D2 ---- CS0 ---- Group 1 (8x MCP23S17-E, Addr 0-7) --+-- A3144 Sensors (128)
| D3 ---- CS1 ---- Group 2 (8x MCP23S17-E, Addr 0-7) --+-- A3144 Sensors (128)
| D4 ---- CS2 ---- Group 3 (8x MCP23S17-E, Addr 0-7) --+-- A3144 Sensors (128)
| D5 ---- CS3 ---- Group 4 (8x MCP23S17-E, Addr 0-7) --+-- A3144 Sensors (128)
| D6 ---- CS4 ---- Group 5 (8x MCP23S17-E, Addr 0-7) --+-- A3144 Sensors (64 used)
| D11 ---- MOSI ----+------------------------------------+
| D12 ---- MISO ----+------------------------------------+
| D13 ---- SCK ----+------------------------------------+
| +5V ---- VDD, /RESET (via 10kΩ) ----------------------+
| GND ---- VSS -----------------------------------------+
+-------------------+
Group N (8x MCP23S17-E):
+-------------------+
| MCP23S17-E (Addr 0) | Pin 15 (A0)=GND, Pin 16 (A1)=GND, Pin 17 (A2)=GND
| MCP23S17-E (Addr 1) | Pin 15 (A0)=+5V, Pin 16 (A1)=GND, Pin 17 (A2)=GND
| ...
| MCP23S17-E (Addr 7) | Pin 15 (A0)=+5V, Pin 16 (A1)=+5V, Pin 17 (A2)=+5V
| Pin 9 (VDD) ---- +5V
| Pin 10 (VSS) --- GND
| Pin 18 (/RESET) -+-- 10kΩ -- +5V
| Pin 11 (/CS) ---- Arduino DN (CSN, e.g., D2 for Group 1)
| Pin 12 (SCK) ---- Arduino D13
| Pin 13 (SI) ----- Arduino D11 (MOSI)
| Pin 14 (SO) ----- Arduino D12 (MISO)
| GPA0-GPA7, GPB0-GPB7 ---- A3144 Sensors (open-collector, internal pull-ups)
+-------------------+
*Note: 0.1uF capacitor noted as required. Likely to keep voltage consistent as this is prone to noise for readings that are consistent. Need to RTFM a bit on this.
I wired up in diagram what would be bank CS1, MCP000. Pins on MCP 14-12 on same breadboard line as CS0, MCP000. MCP pin 18 over to same breadboard line to use common 10kohm resistor . In theory pin D2 is group CS0 with one MCP000, pin D3 is group CS1 with MCP000
#include <SPI.h>
// MCP23S17 SPI settings
const uint8_t CS_PINS[2] = {2, 3}; // CS pins: CP0 (D2), CP1 (D3)
const uint8_t MCP_ADDR = 0x20; // Address 0 (A0=A1=A2=GND) for both MCPs
const char* GROUP_NAMES[2] = {"CP0", "CP1"}; // Group identifiers
// MCP23S17 registers (for bank=0 mode)
#define IODIRA 0x00 // I/O direction for Port A (1=input, 0=output)
#define IODIRB 0x01 // I/O direction for Port B
#define GPPUA 0x0C // Pull-up enable for Port A
#define GPPUB 0x0D // Pull-up enable for Port B
#define GPIOA 0x12 // Input state for Port A
#define GPIOB 0x13 // Input state for Port B
// Track previous states for change detection (one per MCP)
uint8_t lastStateA[2] = {0xFF, 0xFF}; // Assume all HIGH (no magnet) initially
uint8_t lastStateB[2] = {0xFF, 0xFF};
void setup() {
Serial.begin(9600);
SPI.begin();
// Initialize CS pins
for (int i = 0; i < 2; i++) {
pinMode(CS_PINS[i], OUTPUT);
digitalWrite(CS_PINS[i], HIGH); // Deselect chip
}
// Initialize both MCP23S17 chips
for (int i = 0; i < 2; i++) {
writeRegister(i, IODIRA, 0xFF); // All GPA0-GPA7 as inputs
writeRegister(i, IODIRB, 0xFF); // All GPB0-GPB7 as inputs
writeRegister(i, GPPUA, 0xFF); // Enable pull-ups on GPA0-GPA7
writeRegister(i, GPPUB, 0xFF); // Enable pull-ups on GPB0-GPB7
}
}
void loop() {
// Read both MCPs
for (int chip = 0; chip < 2; chip++) {
uint8_t stateA = readRegister(chip, GPIOA); // GPA0-GPA7
uint8_t stateB = readRegister(chip, GPIOB); // GPB0-GPB7
// Check for changes on Port A
for (int i = 0; i < 8; i++) {
bool currentBit = (stateA >> i) & 0x01; // Current state of GPA[i]
bool lastBit = (lastStateA[chip] >> i) & 0x01; // Previous state
if (currentBit != lastBit) {
Serial.print(GROUP_NAMES[chip]);
Serial.print("-MCP000-GPA");
Serial.print(i);
Serial.println(currentBit ? " - No Magnet" : " - Magnet Detected");
}
}
// Check for changes on Port B
for (int i = 0; i < 8; i++) {
bool currentBit = (stateB >> i) & 0x01; // Current state of GPB[i]
bool lastBit = (lastStateB[chip] >> i) & 0x01; // Previous state
if (currentBit != lastBit) {
Serial.print(GROUP_NAMES[chip]);
Serial.print("-MCP000-GPB");
Serial.print(i);
Serial.println(currentBit ? " - No Magnet" : " - Magnet Detected");
}
}
// Update previous states
lastStateA[chip] = stateA;
lastStateB[chip] = stateB;
}
delay(100); // Poll every 100ms for debouncing
}
// Write to MCP23S17 register for specified chip
void writeRegister(uint8_t chip, uint8_t reg, uint8_t value) {
digitalWrite(CS_PINS[chip], LOW);
SPI.transfer(MCP_ADDR << 1); // Write command (address + write bit)
SPI.transfer(reg); // Register address
SPI.transfer(value); // Data
digitalWrite(CS_PINS[chip], HIGH);
}
// Read from MCP23S17 register for specified chip
uint8_t readRegister(uint8_t chip, uint8_t reg) {
digitalWrite(CS_PINS[chip], LOW);
SPI.transfer((MCP_ADDR << 1) | 0x01); // Read command (address + read bit)
SPI.transfer(reg); // Register address
uint8_t value = SPI.transfer(0x00); // Read data
digitalWrite(CS_PINS[chip], HIGH);
return value;
}
Serial.print(i);
Serial.println(currentBit ? " - No Magnet" : " - Magnet Detected");
}
}
// Update previous states
lastStateA = stateA;
lastStateB = stateB;
delay(100); // Poll every 100ms for debouncing
}
// Write to MCP23S17 register
void writeRegister(uint8_t reg, uint8_t value) {
digitalWrite(CS_PIN, LOW);
SPI.transfer(MCP_ADDR << 1); // Write command (address + write bit)
SPI.transfer(reg); // Register address
SPI.transfer(value); // Data
digitalWrite(CS_PIN, HIGH);
}
// Read from MCP23S17 register
uint8_t readRegister(uint8_t reg) {
digitalWrite(CS_PIN, LOW);
SPI.transfer((MCP_ADDR << 1) | 0x01); // Read command (address + read bit)
SPI.transfer(reg); // Register address
uint8_t value = SPI.transfer(0x00); // Read data
digitalWrite(CS_PIN, HIGH);
return value;
}
Everything is solid until I plug in CS1, MCP000 pin 11 (CSS) .. I don’t even have to plug it into anything. just wire in and wiggle it and I get outputs like
MCP000-GPB6 - Magnet Detected
MCP000-GPB7 - Magnet Detected
MCP000-GPA7 - Magnet Detected
MCP000-GPA0 - No Magnet
MCP000-GPA1 - No Magnet
MCP000-GPA2 - No Magnet
MCP000-GPA3 - No Magnet
MCP000-GPA4 - No Magnet
MCP000-GPA5 - No Magnet
if I pull wire out. I do still get consistent reads from CS0, MCP000.
So my question is:
-
You mentioned push based hall effect sensor. Can you give me RTFM location for this?
-
On paper the design of shared SO,SI,SCK with each channel having pin for each “group”, seems logical. scan would cycle through each MCP by address 0-7 from each CS “group” channel, and during that time slice. But peiece I am not sure on is if this is a “pull” how does it shut off/exclude the signals sent. I guess CS is pin to say “your my focus” (all others state low and go to sleep on outputs), then within that MCP group, cycle via ID through MCP0-7 and each sub 1-16 scans. So in theory.. this works… Hopeing this is just a wire / noise control adjustment I need to make vs scrap design.
Thanks as always for wisdom.