Final talk on encoders: AS5600 vs MT6701 vs TMAG5273
Hi! If you have been following the previous logs, you already know the ending of this story - the TMAG5273 won. But I never wrote down the full journey of HOW it won, side by side, with the same motor and the same expectations. A few of you asked for exactly this, so here it is. ♥️
Why am I even comparing encoders?
Ariwoo is a self-balancing robot. That one sentence decides everything about what I need from a wheel encoder:
- I need to know exactly how far each wheel has turned (position).
- I need to know how fast it is turning (velocity), for the outer control loops.
- I have two wheels, so whatever I pick has to live twice on the same I2C bus (or give me another clean way out).
- My mechanical layout forces a side-shaft / radial orientation with a small rectangular magnet on the D-flat of an N20 shaft. I do NOT have the luxury of a perfectly centred diametric magnet on the end of the shaft. (See my axial vs radial log if you want the full drama on orientations.)
Every sensor in this shootout was judged against those four points. Not against a datasheet. Against MY requirement.
Quick note as always: I use Arduino for rapid prototyping because it gives me conceptual clarity faster. Production firmware will be ESP-IDF.
The contenders:
| AS5600 | MT6701 | TMAG5273 | |
|---|---|---|---|
| Resolution | 12-bit (4096 counts) | 14-bit (16384 counts) | Raw field + on-chip CORDIC angle |
| What it gives you | Finished angle | Finished angle (I2C, SSI, ABZ, PWM) | Bx, By, Bz raw field over I2C (+ optional angle) |
| I2C address | Fixed (0x36) | Fixed (0x06) | Four factory-selectable addresses (usually at x35) |
| Expected magnet | Diametric, on-axis | Diametric, on-axis | Whatever you can calibrate out |
On paper, the MT6701 looks like the obvious winner. 14 bits! ABZ output straight into the ESP32’s PCNT peripheral! No I2C polling in the hot loop! I genuinely thought this log would end differently.
AS5600 - the one that taught me everything
The AS5600 is where I started, and honestly, I don’t regret it. It is cheap, it is everywhere, and every tutorial on the internet uses it. If you are learning what a magnetic encoder even is, start here. But, I always had a thought that it was used for knobs, which means at lower speeds it should be pretty much accurate. But, for it to be accurate, I had to follow data sheet. I tried fixing the distortion too, but I was not entirely convinced.
But for Ariwoo it failed on two of my four requirements:
-
The fixed I2C address.
One address, 0x36, no options. Ariwoo has two wheels. That means two encoders on one bus, and the AS5600 simply cannot do it without adding an I2C multiplexer - which is another chip, more board space, more firmware, more things to go wrong. For a hobby bench test, fine. For a production PCB where I am fighting for every GPIO on the ESP32-S3? No. Either I need to have more pins or I have to software bit bang. probably I will do the same with TMAG5273 as well, but I will figure that out as I go.
-
It really, really wants a diametric magnet on-axis.
The official documentation expects a diametric circular magnet, perfectly centred on the axis of rotation, at the end face of the shaft. My earlier experiments confirmed it: the AS5600 only gave trustworthy position tracking in the two “correct” magnet/orientation pairings. With my rectangular magnet on the side of the shaft, the geometry is just wrong for it. The chip computes the angle internally and there is no way to reach in and un-warp what it decided.
That last point is the real killer, and it becomes the theme of this entire log: when the chip computes the angle for you, you inherit the chip’s assumptions about your magnet.
MT6701 - the lovely one that I am not going to use
The MT6701 is a genuinely lovely part. 14-bit resolution, angle computed on-chip, and the ABZ quadrature output means the ESP32’s PCNT hardware can count edges with zero CPU involvement. You ask it “what angle?” and it hands you a finished number.
Yes. I accidentally killed my only MT6701 on the bench. noooooo. I ordered more, but by the time replacements were on the way, the TMAG5273 experiments were already giving me results I could not ignore.
Even setting aside my own clumsiness, the MT6701 shares the AS5600’s deeper problem: the angle is computed on-chip, calibrated for an on-axis diametric magnet. In my radial, rectangular-magnet setup, the reported angle is warped, and there is nothing I can do about it from firmware because the raw field never leaves the chip. Also - fixed I2C address again. Two wheels, one bus, same wall.
Here is the code: this code is recommended for using using the magnet in axial orientations only.
#include <Wire.h>
#define MT6701_ADDR 0x06 // MT6701 default I2C address (7-bit)
#define ANGLE_H 0x03 // ANGLE[13:6]
#define ANGLE_L 0x04 // ANGLE[5:0] (in bits 7:2)
const float COUNTS_PER_REV = 16384.0; // 2^14
const int SAMPLE_INTERVAL_US = 100; // 0.1ms
// State
int16_t lastAngle = 0;
unsigned long lastTime = 0;
// Revolution period RPM
float rpm = 0.0;
unsigned long lastRevTime = 0;
bool revStarted = false;
int16_t prevAngle = 0;
long accumDelta = 0; // accumulated counts since last full rev
int16_t readRawAngle() {
Wire.beginTransmission(MT6701_ADDR);
Wire.write(ANGLE_H);
Wire.endTransmission(false);
Wire.requestFrom(MT6701_ADDR, 2);
uint8_t high = Wire.read(); // ANGLE[13:6]
uint8_t low = Wire.read(); // ANGLE[5:0] in bits [7:2]
return ((uint16_t)high << 6) | (low >> 2); // 0..16383
}
void setup() {
Serial.begin(115200);
while (!Serial);
delay(1000);
Wire.begin(8, 9);
Serial.println("Scanning I2C...");
for (byte addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) {
Serial.print("Device found at 0x");
Serial.println(addr, HEX);
}
}
Serial.println("MT6701 Ready.");
Serial.println("timestamp_us,angle_deg,rpm");
lastAngle = readRawAngle();
prevAngle = lastAngle;
lastTime = micros();
lastRevTime = micros();
revStarted = true;
}
void loop() {
unsigned long now = micros();
if (now - lastTime >= SAMPLE_INTERVAL_US) {
int16_t currentAngle = readRawAngle();
// Angle in degrees
float degrees = (currentAngle / COUNTS_PER_REV) * 360.0;
// Revolution period RPM
int16_t delta = currentAngle - prevAngle;
if (delta > 8192) delta -= 16384; // wraparound CW
if (delta < -8192) delta += 16384; // wraparound CCW
accumDelta += delta;
// Detect full revolution:
// +16384 counts = 1 full CW rev
// -16384 counts = 1 full CCW rev
if (accumDelta >= 16384) {
unsigned long revPeriodUs = now - lastRevTime;
rpm = 60000000.0 / revPeriodUs; // CW positive
lastRevTime = now;
accumDelta -= 16384;
} else if (accumDelta <= -16384) {
unsigned long revPeriodUs = now - lastRevTime;
rpm = -60000000.0 / revPeriodUs; // CCW negative
lastRevTime = now;
accumDelta += 16384;
}
// Log
Serial.print(now);
Serial.print(",");
Serial.print(degrees, 2);
Serial.print(",");
Serial.println(rpm, 2);
prevAngle = currentAngle;
lastTime = now;
}
}
logs for experiments done in all orientations: m1 indicates test with slow speed motor. log1 to log5 was done in one sensor that I actually burned down and had to wait for the new one to arrive.
- log1.txt
- log2.txt
- log3.txt
- log4.txt
- log5.txt
- log6_202607012150.txt
- log7_202607012157_m1.txt
- log8_202607012230.txt
- log9_202607012243_m1.txt
- log10_202607012245_m1_fullload.txt
- log11_202607012251.txt
- log12_202607012252.txt
- log13_202607012254.txt
- log14_202607012257.txt
- log15_202607012311.txt
Round 3: TMAG5273 - the one that hands you the raw field
Most magnetic encoders give you an answer. The TMAG5273 gives you the question: the raw Bx, By, Bz field components, straight over I2C, and lets you decide what to do with them.
That sounds like more work, and honestly, it is. But it flips the fundamental problem of the other two sensors on its head:
- With the AS5600 and MT6701, the magnet imperfections are baked into an angle you cannot fix.
- With the TMAG5273, the imperfections arrive as raw data in MY firmware, where I can see them, measure them, and calibrate them out.
And the practical wins kept stacking up:
-
Four factory I2C addresses.
Two encoders, one bus, no multiplexer, no extra parts. This quietly solved the problem that killed the AS5600 on day one.
-
Axis selection matters - a lot.
My first attempts used Bx/By, and one axis was degenerate in my side-shaft orientation - barely 0.22 mT of swing. Switching to By/Bz gave me a healthy ~4 mT on both axes. Same sensor, same magnet, same gap - just the right pair of axes for the geometry. You only discover this because the raw field is exposed. The other two chips would never have told me.
-
The on-chip CORDIC angle is genuinely good.
Once the right axes are selected, the sensor’s own angle calculation is excellent - see my previous log where log5.txt gave me goosebumps.
-
Self-calibration closed the gap.
The remaining distortion (my magnet is never perfectly seated) gets learned online by the firmware: a 128-bin correction that accumulates over the first revolution, gated by revolution duration, with zero-mean enforcement so it can never drift the absolute angle. No per-device factory calibration, no stored LUT, nothing to maintain in production. Every robot calibrates itself on its own magnet, every time.
The result: 0.38° RMS after a single revolution of self-calibration, against my target of 0.5°. With no stored calibration data at all.
Head-to-head, against my four requirements:
| Requirement | AS5600 | MT6701 | TMAG5273 |
|---|---|---|---|
| Accurate position in MY radial/rectangular setup | ❌ warped, unfixable | ❌ warped, unfixable | ✅ 0.38° RMS after self-cal |
| Usable velocity | ⚠️ per-revolution timing only | ✅ ABZ into PCNT is genuinely great | ✅ per-revolution timing, warp-immune |
| Two sensors, one I2C bus | ❌ fixed address | ❌ fixed address | ✅ four factory addresses |
| Survives my magnet geometry | ❌ | ❌ | ✅ raw field = firmware fixes it |
[PLACEHOLDER: measured comparison table - timestamp / angle / rpm extracts for all three sensors, same motor, same battery, same-ish RPM. Same format as the axial/radial log.]
Results and conclusions:
What I learned from this whole shootout:
- The datasheet resolution number means almost nothing if the magnet geometry is wrong. The 14-bit MT6701 in the wrong orientation is worse than a 12-bit anything in the right one.
- Chips that compute the angle for you also compute their assumptions for you. If your mechanical layout matches the datasheet’s imagined magnet, great. Mine does not, and only the TMAG5273 let me do anything about it.
- The boring stuff kills more time than the hard stuff. Missing pull-ups, STOP vs repeated-start, a burnt IC. None of these were the sensor’s fault, all of them cost me days.
- A good estimator is never a substitute for getting the hardware right - but exposed raw data is a substitute for a perfect magnet. That is the TMAG5273’s superpower.
The verdict:
The TMAG5273 goes on the production PCB. Two of them, two factory addresses, one bus, By/Bz axes, on-chip CORDIC angle, self-calibrating correction in firmware. 0.38° RMS with nothing stored in flash.
The MT6701 deserves an honourable mention - if your magnet is diametric and on-axis, and you only need ONE encoder, the ABZ-into-PCNT path is beautiful and I would pick it without hesitation. And the AS5600 remains the right first encoder for anyone learning - it just cannot follow Ariwoo where Ariwoo needs to go.
[PLACEHOLDER: your date/time-of-writing sign-off, e.g. “I started writing this log at … and finished at …”]
Thank you for reading! ♥️