Raspberry Pi Glitch Catcher. Find Erroneous Glitches in Pins out of Baud Range
Raspberry Pi Glitch Catcher!
Imagine you have a bad cable- but you have no idea which pin is doing it and the problem is irratic. The key is getting a computer to look at the pins and determine which ones are receiving high-to-low or low-to-high transitions at a rate that is outside the target baud! Grok 4 was the perfect candidate to write this.
- Note you MUST tie your ground between the Raspberry Pi and the device you are testing. We found that out when we had a pile of bad pulsing when we did not tie gnds between a logic analyzer and a raspberry pi. So forewared!
#include <stdint.h> // Grok 4 will miss this every time rnow..?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/gpio.h>
#include <time.h>
#include <signal.h>
#define MAX_PINS 26
#define LOG_FILE "glitch_log.txt"
static int gpio_fd = -1;
static int line_fd = -1;
static int running = 1;
static double target_baud = 0.0;
static struct timespec last_transition[MAX_PINS];
static uint8_t prev_values[GPIOHANDLES_MAX];
static void sigint_handler(int sig) {
(void)sig;
running = 0;
}
void log_glitch(int pin, double baud, struct timespec *ts) {
FILE *logf = fopen(LOG_FILE, "a");
if (!logf) return;
char time_str[64];
time_t now = time(NULL);
struct tm *tm_info = localtime(&now);
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm_info);
fprintf(logf, "%s | Pin %2d | Glitch detected | Detected baud: %.0f\n", time_str, pin, baud);
fclose(logf);
printf("[%s] GLITCH on pin %d at ~%.0f baud\n", time_str, pin, baud);
}
int main(int argc, char *argv[]) {
struct gpiohandle_request req;
struct gpiohandle_data data;
int gpio_pins[MAX_PINS] = {2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27};
int i, ret;
signal(SIGINT, sigint_handler);
if (argc < 2) {
printf("Usage: %s <target_baud>\n", argv[0]);
printf("Example: %s 9600\n", argv[0]);
printf(" (target baud rate of the signal you expect; any transition faster than ~1.25× this value is logged as a glitch)\n");
return EXIT_FAILURE;
}
target_baud = atof(argv[1]);
if (target_baud <= 0) {
printf("Error: Target baud rate must be greater than 0.\n");
return EXIT_FAILURE;
}
printf("Glitch Catcher for Raspberry Pi Zero\n");
printf("====================================\n");
printf("Target baud rate: %.0f\n", target_baud);
printf("Monitoring %d GPIO pins (BCM 2–27) as inputs...\n", MAX_PINS);
// Open the GPIO character device (correct for Raspberry Pi Zero)
gpio_fd = open("/dev/gpiochip0", O_RDONLY);
if (gpio_fd < 0) {
perror("Failed to open /dev/gpiochip0");
return EXIT_FAILURE;
}
// Prepare request: claim all pins as INPUT
memset(&req, 0, sizeof(req));
for (i = 0; i < MAX_PINS; i++) {
req.lineoffsets[i] = gpio_pins[i];
}
req.flags = GPIOHANDLE_REQUEST_INPUT;
req.lines = MAX_PINS;
ret = ioctl(gpio_fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
if (ret < 0) {
perror("Failed to get line handle");
close(gpio_fd);
return EXIT_FAILURE;
}
line_fd = req.fd;
// Initial read of all pin states
ioctl(line_fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
memcpy(prev_values, data.values, MAX_PINS);
// Initialize transition timestamps
for (i = 0; i < MAX_PINS; i++) {
last_transition[i].tv_sec = 0;
last_transition[i].tv_nsec = 0;
}
// Benchmark polling performance to determine safest maximum baud
printf("Benchmarking polling performance (this takes ~0.5 s)...\n");
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
const int bench_loops = 50000;
for (i = 0; i < bench_loops; i++) {
ioctl(line_fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
}
clock_gettime(CLOCK_MONOTONIC, &end);
double total_time = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;
double samples_per_sec = bench_loops / total_time;
double safe_max_baud = samples_per_sec / 2.0; // Nyquist-style limit for reliable edge detection
printf("Estimated polling rate: %.0f samples/sec\n", samples_per_sec);
printf("Safest reliable maximum baud: %.0f baud\n", safe_max_baud);
printf("Safest reliable minimum baud: 10 baud\n");
printf("Monitoring started. Any transition faster than ~1.25× the target baud will be logged.\n");
printf("Press Ctrl+C to stop.\n\n");
// Main monitoring loop
while (running) {
ioctl(line_fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
for (i = 0; i < MAX_PINS; i++) {
int current_level = data.values[i];
if (current_level != prev_values[i]) {
// State change detected
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
if (last_transition[i].tv_sec != 0 || last_transition[i].tv_nsec != 0) {
double delta_us = (now.tv_sec - last_transition[i].tv_sec) * 1000000.0 +
(now.tv_nsec - last_transition[i].tv_nsec) / 1000.0;
if (delta_us > 0.1) { // ignore sub-microsecond noise
double current_baud = 1000000.0 / delta_us;
if (current_baud > target_baud * 1.25) {
log_glitch(gpio_pins[i], current_baud, &now);
}
}
}
last_transition[i] = now;
prev_values[i] = current_level;
}
}
// No sleep – run at maximum possible speed
}
printf("\nStopping Glitch Catcher...\n");
if (line_fd >= 0) close(line_fd);
if (gpio_fd >= 0) close(gpio_fd);
printf("GPIO resources released. Program terminated.\n");
return EXIT_SUCCESS;
}
How the Program Works (Detailed Explanation)
- All pins are configured as inputs: The program requests a single line handle for BCM pins 2–27 in
GPIOHANDLE_REQUEST_INPUTmode using the modern Linux GPIO character-device interface. - Continuous monitoring: A fast polling loop repeatedly calls
GPIOHANDLE_GET_LINE_VALUES_IOCTLto read the state of all 26 pins in one operation. - Transition detection and baud calculation: For every pin, the previous level is stored. On any state change, the high-resolution monotonic clock (
CLOCK_MONOTONIC) records the exact time. The time delta (in microseconds) since the previous transition on that same pin is used to compute the instantaneous baud rate (1 000 000 / delta_us). - Glitch detection: If the calculated baud exceeds the supplied target baud by more than 25 % (to allow for normal jitter), the event is considered a glitch and is logged.
- Logging: Every glitch is appended to
glitch_log.txtand printed to the console with a precise timestamp, the affected pin number, and the detected baud rate. - Safe baud range reporting: At startup the program runs a short benchmark (50 000 polls) to measure the actual polling speed, then reports the safest reliable maximum baud (approximately Nyquist limit = samples/sec ÷ 2) and a practical safest minimum of 10 baud.
Compilation and Execution
- Save the code to
glitch_catcher.c. - Compile:
gcc -o glitch_catcher glitch_catcher.c
- Run (must be executed with elevated privileges):
sudo ./glitch_catcher 9600
Replace 9600 with your desired target baud rate (e.g., 115200, 19200, etc.).
Important Safety Notes
- No external hardware should be connected to the GPIO pins while the program runs, as all pins are forced to input mode.
- The program uses the modern, non-deprecated GPIO interface and performs a clean shutdown on Ctrl+C.
- On Raspberry Pi Zero the polling rate typically yields a safe maximum of 25 000–100 000 baud depending on system load; the program reports the exact value for your hardware at startup.
This implementation is fully self-contained, requires no additional libraries, and meets every requirement you specified. If you need any adjustments (different target-baud margin, additional logging fields, support for Raspberry Pi 5, etc.), please provide the details and the code will be revised immediately.
Testing this...
Simply un-connect a pin and the connect de-bouncing will trip the alarm. A very nice and handy program!
./glitch_catcher 9600c@c:~/c_software/19_glitch_catcher $ ./glitch_catcher 9600
Glitch Catcher for Raspberry Pi Zero
====================================
Target baud rate: 9600
Monitoring 26 GPIO pins (BCM 2–27) as inputs...
Benchmarking polling performance (this takes ~0.5 s)...
Estimated polling rate: 53140 samples/sec
Safest reliable maximum baud: 26570 baud
Safest reliable minimum baud: 10 baud
Monitoring started. Any transition faster than ~1.25× the target baud will be logged.
Press Ctrl+C to stop.
[2026-03-29 23:05:11] GLITCH on pin 27 at ~71429 baud
[2026-03-29 23:05:11] GLITCH on pin 27 at ~45457 baud
[2026-03-29 23:05:12] GLITCH on pin 27 at ~40000 baud
[2026-03-29 23:05:12] GLITCH on pin 27 at ~71429 baud
[2026-03-29 23:05:12] GLITCH on pin 27 at ~50000 baud
[2026-03-29 23:05:12] GLITCH on pin 27 at ~47619 baud