Using BLDC Hall Sensors as Position Encoders – Part 3

Using a Teensy 3.5 microcontroller to calculate position, direction, and distance

The following information is intended to assist in interpreting Hall sensor logical output for the purposes of determining position, direction and speed. Although the output can be used for motor commutation, that aspect of BLDC motor operation is not explained here.

See Part 1 and Part 2 of this blog series to review this project up to this point.


When the three Hall effect sensor outputs in a BLDC are fed into a microcontroller, the signals can be processed like a three-channel encoder. The data can be displayed or used to determine a pulse count, rotation direction and average revolutions per minute (RPM). The RPM is averaged to create a smooth progression in displayed values.

PJRC Teensy 3.5 Development board

The PJRC Teensy 3.5 Development Board by SparkFun (1568-1464-ND) has more than enough digital interrupts to handle the three signal inputs from the Hall sensors and it comes with soldered-in headers. The Teensy 3.5 is powerful enough to execute many additional tasks due to an ample amount of additional I/O channels and may be used for data logging using the built-in SD card.

Figure 1: The SparkFun Electronics Teensy 3.5 evaluation board. (Image source: SparkFun Electronics)

Breadboarding the Sensor Output and PJRC Teensy 3.5

Using a breadboard (438-1045-ND or similar), position the Teensy 3.5 with the USB connector to the right and the upper header pins inserted into the first row of breadboard holes above the partition (Figure 2). This will allow room for connection of the sensor outputs to the Teensy I/O.

Figure 2: Breadboard with Teensy 3.5 Dev Board and jumper connections. (Image source: Digi-Key Electronics)

Use solid jumper wires (BKWK-3-ND) to make all breadboard connections. Connect the positive (+) lead of a 5 V, 1 A power supply to the upper or lower power positive rail of the breadboard; then connect the negative (-) supply lead to the upper or lower negative power rail. Connect the positive (red) and negative (black) leads of the hall sensor connector to the positive and negative rails of the breadboard respectively; then connect the three sensor leads of the connector to the Teensy 3.5 at pins 2, 3 and 4 in any order.

The sensor output is active low meaning when triggered, the output is connected to the negative power rail. When not triggered, the sensor output needs to be pulled up to the positive power rail to establish two defined logic states. Insert three 4 KΩ – 8 KΩ resistors into the breadboard to be used as pull-ups for the sensor output (Figure 2).

Connect the Teensy 3.5 to a computer using a USB micro B to standard A cable.


The Teensy 3.5 is compatible with the Arduino Integrated Development Environment (IDE) for programming purposes. The IDE and Teensyduino add-on are available online. Follow the installation procedures at to continue.

The programming example code supplied below uses three hardware interrupts to monitor any change (rising and falling edges) of the Hall sensor outputs. Once an interrupt occurs, the elapsed time clock of the Teensy 3.5 and two of the three input pins are read. The sensor values are compared to determine rotation direction; then other calculations are made to determine pulse count and average RPM. The time between interrupts is calculated by comparing the current clock value to the stored clock value from the previous interrupt.

Four values are available to serial print inside the void loop. Comment or uncomment lines of code to deactivate or activate the serial print function; then download the code to the Teensy and launch the serial monitor to see the live data. Spin the BLDC motor to observe the changes in values in the print monitor.

Note: Serial print functions slow down the microcontroller. The I/O interrupts cause halting and jumping of displayed values as, by definition, the serial print process is interrupted each time an input pin changes state. If the display function is not used, assure all serial print functions are commented out of the code.

Copy/* BLDC Hall Sensor read and calculation program for Teensy 3.5 in the Arduino IDE (Ver.1). Digi-Key Electronics*/

/***************************** Variables *********************************/

#define CW             1			// Assign a value to represent clock wise rotation
#define CCW           -1			// Assign a value to represent counter-clock wise rotation

bool HSU_Val = digitalRead(2);		// Set the U sensor value as boolean and read initial state
bool HSV_Val = digitalRead(3);		// Set the V sensor value as boolean and read initial state 
bool HSW_Val = digitalRead(4);		// Set the W sensor value as boolean and read initial state 

int direct = 1;				// Integer variable to store BLDC rotation direction
int pulseCount;				// Integer variable to store the pulse count

float startTime;				// Float variable to store the start time of the current interrupt 
float prevTime; 				// Float variable to store the start time of the previous interrupt 
float pulseTimeW; 			// Float variable to store the elapsed time between interrupts for hall sensor W 
float pulseTimeU; 			// Float variable to store the elapsed time between interrupts for hall sensor U 
float pulseTimeV; 			// Float variable to store the elapsed time between interrupts for hall sensor V 
float AvPulseTime; 			// Float variable to store the average elapsed time between all interrupts 

float PPM;				// Float variable to store calculated pulses per minute
float RPM; 				// Float variable to store calculated revolutions per minute

/***************************** Setup *********************************/

void setup()
// Set digital pins 2, 3 and 4 as inputs
  pinMode(2, INPUT);			
  pinMode(3, INPUT);			
  pinMode(4, INPUT);

// Set digital pins 2, 3 and 4 as interrupts that trigger on rising and falling edge changes. Call a function (i.e. HallSensorU) on change
  attachInterrupt(digitalPinToInterrupt(2), HallSensorU, CHANGE);      
  attachInterrupt(digitalPinToInterrupt(3), HallSensorV, CHANGE);
  attachInterrupt(digitalPinToInterrupt(4), HallSensorW, CHANGE);

// Initialize the print monitor and set baud rate to 9600 

/*************************** Main Loop ******************************/

void loop()
  if ((millis() - prevTime) > 600) RPM = 0;                                     			// Zero out RPM variable if wheel is stopped

  //Serial.print(HSU_Val); Serial.print(HSV_Val); Serial.println(HSW_Val);      	// Display Hall Sensor Values
  //Serial.println(direct);                                                    				// Display direction of rotation
  //Serial.println(pulseCount);                                                 			// Display the pulse count
  Serial.println(RPM);                            		      			// Display revolutions per minute

/************************ Interrupt Functions ***************************/

void HallSensorW()
  startTime = millis();						// Set startTime to current microcontroller elapsed time value
  HSW_Val = digitalRead(4);					// Read the current W hall sensor value
  HSV_Val = digitalRead(3);						// Read the current V (or U) hall sensor value 
  direct = (HSW_Val == HSV_Val) ? CW : CCW;			// Determine rotation direction (ternary if statement)
  pulseCount = pulseCount + (1 * direct);				// Add 1 to the pulse count
  pulseTimeW = startTime - prevTime;				// Calculate the current time between pulses
  AvPulseTime = ((pulseTimeW + pulseTimeU + pulseTimeV)/3);	// Calculate the average time time between pulses
  PPM = (1000 / AvPulseTime) * 60;					// Calculate the pulses per min (1000 millis in 1 second)
  RPM = PPM / 90;						// Calculate revs per minute based on 90 pulses per rev
  prevTime = startTime;						// Remember the start time for the next interrupt

void HallSensorV()
  startTime = millis();
  HSV_Val = digitalRead(3);
  HSU_Val = digitalRead(2);					// Read the current U (or W) hall sensor value 
  direct = (HSV_Val == HSU_Val) ? CW : CCW;
  pulseCount = pulseCount + (1 * direct);
  pulseTimeV = startTime - prevTime;				
  AvPulseTime = ((pulseTimeW + pulseTimeU + pulseTimeV)/3);		
  PPM = (1000 / AvPulseTime) * 60;					
  RPM = PPM / 90;
  prevTime = startTime;

void HallSensorU()
  startTime = millis();
  HSU_Val = digitalRead(2);
  HSW_Val = digitalRead(4);					// Read the current W (or V) hall sensor value		
  direct = (HSU_Val == HSW_Val) ? CW : CCW;
  pulseCount = pulseCount + (1 * direct);
  pulseTimeU = startTime - prevTime;				
  AvPulseTime = ((pulseTimeW + pulseTimeU + pulseTimeV)/3);		
  PPM = (1000 / AvPulseTime) * 60;					
  RPM = PPM / 90;
  prevTime = startTime;

Note: Programmers may be tempted to break out repetitive interrupt function code into an additional function to simplify the overall program. Doing so may result in the additional function being interrupted and values being changed between calculations resulting in data errors. As noted in the breadboarding steps and the code, the order of sensor input only effects the determination of rotation direction. Uncomment the serial print line related to the variable “direct” to see the value in the display monitor. Verify the value stays as 1 or -1 depending upon which way you turn the wheel. If it deviates, flip the “CW” and “CCW” in the ternary code in the corresponding interrupt function to correct the output.


The BLDC Hall sensors are now configured as a three channel, low resolution, encoder capable of delivering accurate data to aid in navigation and wheel position sensing without hindering their primary motor control function. Some BLDC controllers use only back EMF for determining coil and magnet position leaving the Hall sensor outputs available solely for navigation and position sensing. Either way, the sensors have more value to the user than just motor control.

Additional Resources:

Arduino IDE:


About this author

Image of Don Johanneck

Don Johanneck, Technical Content Developer at Digi-Key Electronics, has been with the company since 2014. Recently moving into his current position, he is responsible for writing video descriptions and product content. Don earned his Associate of Applied Science degree in Electronics Technology & Automated Systems from Northland Community & Technical College through the Digi-Key scholarship program. He enjoys radio control modeling, vintage machine restoration and tinkering.

More posts by Don Johanneck