I have created a series of PCBs to collect sensor data from an array of hall effect sensors. The project description is here LED Pegboard with 2,000 sensors
The problem... after hundreds of hours of preparing, designing and testing I'm now installing and I am hitting an issue. No matter what configuration I use, I cannot read from more than 2 of my custom built PCB boards...
For the code, I'm just running the CS and SCLK manually with a loop over all the bits. Its very slow, each clock pulse is 1000 microseconds, which is fine for the use case here. The hall effect sensors are pulled high. Every sensor when triggered returns low, as expected, up to the sensors on the third board. At that point, triggering one of the sensors on the first register (sometimes its the first, sometimes its the 7th.. ) returns every bit after it as low. I have a total of 9 boards in groups of three, so I've moved around the boards and tried many in the third position and the result is always the same, so I don't think it is an issue with the PCB.
I have one hint, in that I was having similar issues with noise on just one board which I solved by shortening my ground line to the ESP32 board as much as possible, or using two wires... I'm not sure why that solved the noise problem, but perhaps it is linked to this problem.
My fix at this moment is to add another ESP32 for the third board. It seems to work fine. But I'd like to understand why this issue is happening.
Below is a photo of the custom PCBs I made. It is only partially connected in this photo, but my question stands for fully connected boards. Its a mess, I know, but bear with me:
The ethernet cables are connected to hall effect sensors, each cable carrying 8 sensor signals. The boards direct the signals to shift registers which are then controlled by signals from the ESP32 board. The boards also trace the power, clock and chip select signals to all the shift registers. The data line daisy-chains from one board to the next.
And here is the code:
// Script to read 74HC165 shift register and send over Websockets
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <WiFiClientSecure.h>
#include <WebSocketsClient.h>
// Setup Websocket
WiFiMulti WiFiMulti;
WebSocketsClient webSocket;
// WIFI Creds
const char *ssid = "SSID"; // <======== EDIT THIS
const char *password = "password"; // <==== EDIT THIS
// Device ID
const char *DEVICE_ID = "/?id=1"; // <========= EDIT THIS
// frequency
const int freq = 1000;
// Serial Communication Pins
const int csPin = 5;
const int clkPin = 3;
const int dataPin = 16;
const int register_count = 16 + 16 + 16; // 16 + 16 + 12 for panels 1 & 3, 16 * 3 for panel 2
const int bits = 8 * register_count;
// DEVICE PIN
const int LED_PIN = 15;
// Array to store shift register data
int dataArray[bits];
// Read 74HC165
void read74HC165(int csPin, int clkPin, int dataPin, int *dataArray, int bits)
{
// Load parallel data into shift register
digitalWrite(csPin, LOW);
delayMicroseconds(freq);
digitalWrite(csPin, HIGH);
// Read serial data from shift register
for (int i = 0; i < bits; i++)
{
dataArray[i] = digitalRead(dataPin);
digitalWrite(clkPin, HIGH);
delayMicroseconds(freq);
digitalWrite(clkPin, LOW);
delayMicroseconds(freq);
}
}
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
Serial.printf("[WSc] Disconnected!\n");
break;
case WStype_CONNECTED:
Serial.printf("[WSc] Connected to url: %s\n", payload);
// send message to server when Connected
webSocket.sendTXT("Connected");
break;
case WStype_TEXT:
Serial.printf("[WSc] get text: %s\n", payload);
// send message to server
// webSocket.sendTXT("message here");
break;
case WStype_ERROR:
case WStype_FRAGMENT_TEXT_START:
case WStype_FRAGMENT_BIN_START:
case WStype_FRAGMENT:
case WStype_FRAGMENT_FIN:
break;
}
}
void setup() {
// Serial.begin(921600);
Serial.begin(115200);
// Set pin modes
pinMode(csPin, OUTPUT);
pinMode(clkPin, OUTPUT);
pinMode(dataPin, INPUT);
pinMode(LED_PIN, OUTPUT);
WiFiMulti.addAP(ssid, password);
//WiFi.disconnect();
while(WiFiMulti.run() != WL_CONNECTED) {
digitalWrite(LED_PIN, LOW);
delay(300);
digitalWrite(LED_PIN, HIGH);
delay(300);
}
Serial.printf("[SETUP] WiFi connected\n", WiFi.localIP());
// server address, port and URL
webSocket.begin("192.168.254.137", 5000, "/?id=1");
// event handler
webSocket.onEvent(webSocketEvent);
// try ever 5000 again if connection has failed
webSocket.setReconnectInterval(5000);
}
void loop() {
webSocket.loop();
// // Read 74HC165
read74HC165(csPin, clkPin, dataPin, dataArray, bits);
// Send over Websockets
String message = "";
for (int i = 0; i < bits; i++)
{
message += String(dataArray[i]);
}
webSocket.sendTXT(message);
}
An example output on the server side, with the faulty sensor reading, looks like this:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | <----- BIT INDEX
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | <----- FIRST BOARD STARTS HERE
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | <----- SECOND BOARD STARTS HERE
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | <--- THIRD BOARD STARTS HERE
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
And, for the sake of interest, here is the front of the project with the LEDS lit up to random values:
And a closeup of the actual sensor mounts: