The Physics and Output Types of Hall Effect Speed Sensors
When a magnetic field passes perpendicular to a semiconductor wafer inside the sensor, the Lorentz force deflects charge carriers to one side of the material, creating a measurable transverse voltage differential known as the Hall voltage. In speed sensing applications, a small neodymium magnet mounted on a rotating shaft passes the sensor once per revolution, triggering this voltage shift. The sensor's internal circuitry amplifies this microvolt-level shift into a usable logic or analog signal.
The output of hall effect speed sensors is strictly divided into two distinct categories: digital (switch) and analog (linear). Digital sensors (like the ubiquitous A3144) feature an internal Schmitt trigger and output a clean 0V/3.3V square wave, acting as a simple tachometer for counting pulses. Analog sensors (like the SS49E) output a continuous voltage proportional to the magnetic field strength (e.g., 1.0V to 3.0V), which requires ADC reading and software thresholding to detect a "pass" event. Never conflate the two in your circuit design; digital is for high-speed RPM counting, while analog is for proximity mapping or measuring field degradation.
Module Specifications and ESP32 Wiring Matrix
Selecting the right sensor depends on your operating voltage, temperature environment, and whether you need raw field data or simple pulse counting. Below is a specification matrix of the most common hall effect modules used in embedded projects.
| Module / IC | Output Type | Supply Range (VCC) | Output Stage | Best Application |
|---|---|---|---|---|
| KY-024 (LM393) | Digital + Analog | 4.5V - 5.5V | Push-Pull / Analog | Breadboard prototyping, dual-mode testing |
| A3144EUA | Digital Only | 4.5V - 24.0V | Open-Drain (Needs Pull-up) | High-temp automotive, industrial tachometers |
| SS49E | Analog Only | 2.7V - 6.5V | Push-Pull Linear | Joystick positioning, gear tooth mapping |
| DRV5055 (TI) | Analog Only | 2.5V - 5.5V | Push-Pull Linear | Low-noise precision BLDC commutation |
When wiring a digital hall effect speed sensor (like the KY-024 or A3144) to an ESP32 DevKit V1, you must respect the ESP32's 3.3V logic limits and ADC constraints. Below is the definitive wiring matrix.
| Sensor Pin | ESP32 Pin | Notes & Constraints |
|---|---|---|
| VCC | 3V3 (or VIN/5V) | Use 3V3 for A3144/DRV5055. KY-024 requires 5V (VIN) for its onboard LM393 comparator. |
| GND | GND | Ensure a common ground plane; avoid daisy-chaining grounds through high-current motor paths. |
| DO (Digital Out) | GPIO 15 | Must be an interrupt-capable pin. GPIO 15 supports hardware interrupts and has no boot-strapping conflicts. |
| AO (Analog Out) | GPIO 34 | GPIO 34 is input-only and tied to ADC1. Do not use ADC2 (e.g., GPIO 25) if WiFi is active. |
Signal Math: Converting Raw Pulses to RPM
Hall effect speed sensors do not output RPM directly; they output a frequency (Hz) or a pulse period. To display a physical speed unit, you must apply conversion math in your firmware. The most accurate method for microcontrollers is measuring the time interval between consecutive rising edges (the period) rather than counting pulses over a fixed time window, as period measurement provides instant updates even at very low speeds.
The Raw-to-Unit Math:
Let T be the time between two consecutive magnet passes in microseconds (µs).
Let N be the number of magnets mounted on the shaft (usually 1).
- Convert Period to Frequency (Hz):
f = 1,000,000 / T - Convert Hz to Revolutions Per Second (RPS):
RPS = f / N - Convert RPS to RPM:
RPM = RPS * 60
Combined Formula:
RPM = (60,000,000 / T) / N
Calibration and Scaling for Analog Sensors:
If you are forced to use an analog sensor (like the SS49E) for speed counting via the ESP32's 12-bit ADC (0-4095), you cannot simply read the raw value. The output is a sine-like wave peaking when the magnet is closest. You must establish a baseline (VCC/2, roughly ADC value 2048) and implement software hysteresis. Set a high threshold (e.g., 2800) to register a "pass" and a low threshold (e.g., 1500) to reset the state. This prevents the ADC from registering multiple false triggers as the voltage slopes across the threshold.
Interference Mitigation and Interrupt-Driven Code
When measuring speed near motors, hall effect speed sensors are highly susceptible to environmental noise. Understanding these interference sources is critical for stable readings.
- Brushed Motor EMI: Brush arcing generates high-frequency electromagnetic interference that couples into the sensor's signal wire, causing double-counting. Fix: Solder a 100nF ceramic decoupling capacitor directly across the sensor's VCC and GND pins, and use shielded cable for the signal run.
- Mechanical Bounce / Jitter: If measuring a ferrous gear tooth instead of a dedicated magnet, the magnetic field distortion can cause the Schmitt trigger to chatter at the threshold boundary. Fix: Implement a software debounce in the ISR, ignoring any pulses that arrive less than 2,000µs apart (limits max readable RPM to 30,000, which is sufficient for most applications).
- Magnetic Hysteresis: If the shaft stops with the magnet parked directly over the sensor, the output may remain latched LOW. This is normal behavior for unipolar switches like the A3144. Ensure your mechanical design allows the magnet to pass fully out of the sensor's detection zone.
Below is the complete, production-ready ESP32 Arduino code. It utilizes hardware interrupts via attachInterrupt and the IRAM_ATTR directive to ensure the interrupt service routine (ISR) executes from RAM, bypassing flash cache latency. For deeper details on ESP32 GPIO interrupt handling, refer to the official Espressif GPIO API documentation. For more on the underlying physics of these ICs, see the Texas Instruments Hall Effect Sensor overview.
/*
* ESP32 Hall Effect Speed Sensor (Digital Tachometer)
* Target: ESP32 DevKit V1 / Sensor: KY-024 or A3144
* Author: ElectricalFlux
*/
#define SENSOR_PIN 15 // Hardware interrupt capable pin
#define MAGNETS_PER_REV 1 // Number of magnets on the rotating shaft
#define DEBOUNCE_US 2000 // Ignore pulses faster than 2ms (30k RPM limit)
// Volatile variables modified inside the ISR
volatile unsigned long lastPulseMicros = 0;
volatile unsigned long pulseIntervalMicros = 0;
volatile bool newPulseAvailable = false;
// ISR must be in IRAM for ESP32 to prevent cache faults during WiFi/BLE ops
void IRAM_ATTR magnetPassISR() {
unsigned long currentMicros = micros();
// Software debounce to filter EMI noise spikes
if ((currentMicros - lastPulseMicros) > DEBOUNCE_US) {
pulseIntervalMicros = currentMicros - lastPulseMicros;
lastPulseMicros = currentMicros;
newPulseAvailable = true;
}
}
void setup() {
Serial.begin(115200);
delay(500); // Allow serial monitor to connect
// INPUT_PULLUP is safe for KY-024. Mandatory for bare A3144 if no external resistor.
pinMode(SENSOR_PIN, INPUT_PULLUP);
// Attach interrupt on RISING edge
attachInterrupt(digitalPinToInterrupt(SENSOR_PIN), magnetPassISR, RISING);
Serial.println("Hall Effect Tachometer Initialized.");
}
void loop() {
if (newPulseAvailable) {
// Critical section: disable interrupts briefly to read 32-bit variable safely
noInterrupts();
unsigned long interval = pulseIntervalMicros;
newPulseAvailable = false;
interrupts();
// Prevent divide-by-zero on initialization
if (interval > 0) {
// Math: RPM = (60,000,000 / T_us) / Magnets
float rpm = (60000000.0 / interval) / MAGNETS_PER_REV;
Serial.print("Interval: ");
Serial.print(interval);
Serial.print(" us | RPM: ");
Serial.println(rpm, 1);
}
}
// Handle stalled motor (no pulse for > 1 second)
noInterrupts();
unsigned long timeSinceLast = micros() - lastPulseMicros;
interrupts();
if (timeSinceLast > 1000000 && pulseIntervalMicros != 0) {
pulseIntervalMicros = 0; // Reset to prevent stale data
Serial.println("Motor Stalled | RPM: 0.0");
}
delay(100); // Non-blocking yield for ESP32 watchdog
}
By combining proper hardware decoupling, strict digital/analog separation, and microsecond-level interrupt math, you can achieve laboratory-grade tachometer readings using a $2 hall effect module and an ESP32.






