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.

Common Hall Effect Speed Sensor Modules
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.

ESP32 to Hall Effect Sensor Pinout
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.
Wiring Tip: If using an open-drain sensor like the bare A3144EUA, you must add a 10kΩ external pull-up resistor between the DO pin and the ESP32's 3.3V rail. Without it, the signal line will float, causing phantom interrupts and erratic RPM readings.

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).

  1. Convert Period to Frequency (Hz): f = 1,000,000 / T
  2. Convert Hz to Revolutions Per Second (RPS): RPS = f / N
  3. 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.