If you want to use a hall effect sensor for direction sensing on a rotating shaft, a single digital switch won't cut it. You need a quadrature array: two linear analog Hall sensors mounted 90° apart, reading a diametrically magnetized ring. This setup outputs two sine waves phase-shifted by 90 degrees, allowing your microcontroller to calculate absolute angle, rotational speed, and exact direction of travel without the mechanical wear of a traditional potentiometer or optical encoder.
Below is the exact wiring, the raw-to-unit math, and the microcontroller code to make this work on 5V Arduinos and 3.3V ESP32 boards.
The Physics: How Linear Hall Sensors Measure Flux
When a current flows through a semiconductor and a magnetic field is applied perpendicular to that current, the Lorentz force deflects the charge carriers to one side of the material. This accumulation of charge creates a measurable transverse voltage known as the Hall voltage. In raw silicon, this voltage is in the microvolt range and highly susceptible to temperature drift.
Modern linear Hall ICs, like the Honeywell SS49E or TI DRV5055, integrate a precision amplifier and temperature compensation circuitry directly on the die. Instead of acting as a simple on/off switch, these ICs output a ratiometric analog voltage proportional to the magnetic flux density (measured in Gauss or milliTesla). At zero magnetic field, the output sits at exactly half the supply voltage (Vcc/2). A north magnetic pole pushes the voltage toward Vcc, while a south pole pulls it toward GND.
Wiring the Quadrature Hall Array
To detect direction, we treat the two sensors as the X and Y axes of a Cartesian plane. As the diametric magnet rotates, the X sensor reads the cosine of the magnetic field, and the Y sensor reads the sine.
| Parameter | Honeywell SS49E | Texas Instruments DRV5055 |
|---|---|---|
| Supply Voltage (Vcc) | 2.7V to 6.5V | 2.5V to 5.5V |
| Output Type | Ratiometric Analog | Ratiometric Analog |
| Sensitivity (at 5V) | 1.4 mV/Gauss | 23 mV/mT (approx 2.3 mV/G) |
| Zero-Field Offset | Vcc / 2 | Vcc / 2 |
| Pin 1 | Vcc | Vcc |
| Pin 2 | GND | GND |
| Pin 3 | Vout | Vout |
- Mount the Magnet: Press a diametrically magnetized ring magnet (e.g., 6mm x 2.5mm x 2mm) onto your motor shaft. Ensure it is seated flush to minimize axial runout.
- Position Sensor X: Mount the first SS49E as close to the magnet face as possible (1-2mm air gap) without physical contact. Wire Vout to your microcontroller's Analog Pin 0.
- Position Sensor Y: Mount the second SS49E exactly 90° mechanically from the first sensor around the magnet's circumference. Wire Vout to Analog Pin 1.
- Power and Ground: Wire both Vcc pins to a clean, regulated 5V (or 3.3V for ESP32) rail. Tie both GND pins to the microcontroller's common ground. Do not share this ground return path with high-current motor drivers.
The Math: Converting Raw ADC to Angle and Direction
The raw ADC reading is useless on its own. We must convert it to a voltage, subtract the zero-field offset, and divide by the sensor's sensitivity to get the magnetic flux density in Gauss. Once we have the X and Y flux vectors, we use the atan2() function to find the absolute angle.
Here is the exact math for an Arduino Uno (10-bit ADC, 5V reference) using the SS49E (1.4 mV/G sensitivity):
- Voltage:
V = ADC_raw * (5.0 / 1023.0) - Zero Offset:
V_offset = 2.5V(Calibrate this! See below) - Flux (Gauss):
B = (V - V_offset) / 0.0014 - Angle (Radians):
theta = atan2(B_y, B_x)
To determine direction, we calculate the change in angle over time (delta theta). Because atan2 wraps around from +π to -π, we must mathematically handle the discontinuity so the microcontroller doesn't think the motor instantly spun 360° backward when crossing the zero-degree mark.
// Direction Sensing Core Logic (Arduino C++)
float prev_theta = 0.0;
int direction = 0; // 1 = CW, -1 = CCW, 0 = Stopped
void calculateDirection(float Bx, float By) {
float current_theta = atan2(By, Bx);
float delta_theta = current_theta - prev_theta;
// Handle the +/- Pi wrap-around
if (delta_theta > PI) {
delta_theta -= 2 * PI;
} else if (delta_theta < -PI) {
delta_theta += 2 * PI;
}
// Determine direction based on delta threshold
// Threshold prevents noise jitter from registering as movement
if (delta_theta > 0.02) {
direction = 1; // Clockwise
} else if (delta_theta < -0.02) {
direction = -1; // Counter-Clockwise
} else {
direction = 0; // Stopped or below noise floor
}
prev_theta = current_theta;
}
Calibration and Beating Magnetic Interference
Theoretical math assumes your 5V USB rail is exactly 5.00V and your sensor's internal resistor divider is perfectly centered. In reality, a cheap USB hub might output 4.8V, shifting your zero-field offset from 2.5V down to 2.4V. If you don't calibrate, your atan2 circle will be offset, causing angular distortion.
The Calibration Routine: On bootup, before the motor spins, take 100 rapid ADC samples from both X and Y sensors with the magnet in a static position (or removed entirely). Average these samples to establish your true V_offset_x and V_offset_y. Use these dynamic offsets in your math instead of the hardcoded 2.5V.
1. Power Supply Ripple: Because linear Hall sensors are ratiometric, any noise on your Vcc line directly injects into your Vout signal. Always place a 100nF ceramic decoupling capacitor directly across the Vcc and GND pins of each sensor.
2. EMI from Stepper Drivers: High-frequency switching from motor drivers (like the A4988 or TMC2209) induces electromagnetic noise in the sensor leads. Keep sensor wires under 10cm, twist the signal and ground wires together, and physically separate them from motor phase wires.
3. Ferrous Metal Proximity: Mounting your PCB on a steel chassis will distort the magnetic field lines from the ring magnet, causing non-linear angle errors. Use plastic, aluminum, or brass standoffs for the sensor array.
For deeper technical specifications on ratiometric Hall sensor behavior and thermal drift compensation, refer to the Texas Instruments DRV5055 Datasheet. If you are debugging ESP32 ADC non-linearity issues that affect your offset calculations, consult the official Espressif ADC Oneshot Driver Documentation.
FAQ: Hall Effect Direction Sensing
Can a single digital hall effect sensor detect motor direction?
No. A standard digital Hall switch (like the A3144) only outputs a binary HIGH or LOW when a magnetic threshold is crossed. It can tell you a magnet is passing by, allowing you to calculate RPM, but it has no memory of the previous state's spatial relationship. To detect direction, you must use either two sensors in a quadrature arrangement (so one triggers before the other depending on rotation) or a single linear analog sensor paired with a complex multi-pole ring magnet and specialized decoder IC.
How do I wire a hall effect sensor for direction to an ESP32 without clipping the signal?
The ESP32 operates at 3.3V logic and its ADC will clip (max out) at roughly 3.1V to 3.2V depending on the specific silicon batch. If you power your SS49E sensors with 5V, the positive magnetic peaks will exceed 3.3V and destroy the ESP32 pin or severely distort your angle math. You must power the Hall sensors from the ESP32's 3.3V pin. This shifts your zero-field offset to 1.65V and scales the sensitivity down proportionally, keeping the entire analog waveform safely within the ESP32's readable ADC window.
Why is my hall sensor direction reading jittery at very low motor speeds?
Jitter at low RPM is almost always caused by ADC quantization noise or mechanical runout. When the motor moves slowly, the change in magnetic flux between microcontroller read cycles is tiny. If your ADC only has 10-bit resolution (1024 steps), a slight vibration might bounce the reading between two adjacent integer values, causing the delta_theta to rapidly flip between positive and negative. Fix this by implementing a software low-pass filter (like an exponential moving average) on the raw X and Y flux values before passing them into the atan2() function, or upgrade to a 12-bit external ADC like the ADS1115.






