Skip to content
Get started

MT6701 14-Bit Magnetic Angle Sensor

The mt6701 sensor platform lets you use your MT6701 (datasheet) 14-bit absolute magnetic angle sensor / rotary encoder with ESPHome. The chip reports the shaft angle of a diametrically magnetized magnet placed over it and can be read over either the I²C or the SSI (SPI-compatible) interface.

This is a minimal driver: it reports the absolute angle and, over I²C, lets you configure the chip’s ABZ / UVW / analog outputs. Higher-level quantities such as multi-turn position or rotational speed are left to you to compute in YAML from the angle it exposes (see Deriving Position and Speed).

MT6701 chip with a diametrically magnetized magnet above it
MT6701 with its magnet; pressing the magnet down is reported as a push button

Pick one interface and add the matching hub, then add individual sensors with the MT6701 Sensor Platform.

Capabilitymt6701_i2cmt6701_spi (SSI)
Absolute angle / raw countyesyes
CRC-validated framesnoyes
Field status / push button / track lossnoyes
Write chip configurationyesno
Save configuration to EEPROMyesno

If five reads in a row fail (a bus error, or over SSI a CRC mismatch), the hub raises a warning status. It clears on the next good read.

To use the encoder over I²C, first set up the I²C Bus and connect the sensor to the pins specified there.

mt6701_i2c:
id: my_encoder
  • address (Optional, int): The I²C address of the sensor. Defaults to 0x06. The chip can be programmed to the alternate address 0x46.

    NOTE

    0x06 is in the I²C reserved address range, which a bus scan skips, so the MT6701 will not appear in the scan: output even though it responds to direct reads.

  • direction (Optional, string): The rotation direction in which the angle increases. Follows the datasheet’s DIR bit (clockwise writes DIR = 1). If your encoder counts the wrong way, flip this. Not written unless specified.

    • clockwise
    • counterclockwise
  • zero_offset (Optional): The angle reported as 0. Accepts a raw 12-bit count (0-4095), an angle (45deg, 90°) or a percentage of a full turn (12.5%).

  • hysteresis (Optional, float): Output hysteresis window in LSBs of the 12-bit output. One of 0 (off), 0.25, 0.5, 1, 2, 4, 8.

  • output_mode (Optional, string): Selects the incremental output format on the shared output pins.

    • abz
    • uvw
  • abz (Optional): ABZ incremental output settings.

    • pulses_per_revolution (Optional, int): AB pulses per turn, 1-1024.
    • z_pulse_width (Optional, string): Width of the Z index pulse. One of 1lsb, 2lsb, 4lsb, 8lsb, 12lsb, 16lsb, 180deg.
  • uvw (Optional): UVW output settings.

    • pole_pairs (Required, int): Emulated motor pole pairs, 1-16.
  • out_pin (Optional): Analog / PWM output pin settings.

    • mode (Required, string): Output-pin mode, analog or pwm.
    • pwm_frequency (Optional, string): 994.4hz or 497.2hz.
    • pwm_polarity (Optional, string): high or low.
    • analog_start / analog_stop (Optional): Start/stop angles of the analog or PWM output range (12-bit, same units as zero_offset).
  • id (Optional, ID): Manually specify the ID for this MT6701 hub.

  • All other options from I²C Bus.

The hub does not poll on its own: the sensors below read the encoder at their own update_interval.

NOTE

Configuration options are applied on every boot and take effect immediately in RAM. They are not written to EEPROM unless you explicitly call the mt6701_i2c.save_eeprom action.

NOTE

The I²C pins double as the ABZ outputs, and on the SOP-8 package also as the UVW outputs; the chip’s MODE pin selects which of the two they carry. To use ABZ or UVW output that you configure here, save it to EEPROM first and then switch the MODE pin. The analog / PWM output has a pin of its own.

The SSI interface is SPI-compatible and read-only, but it also reports the magnetic-field status, push button and track-loss flags that are not available over I²C. Each 24-bit frame is CRC-checked. First set up the SPI Bus.

mt6701_spi:
id: my_encoder
cs_pin: GPIOXX
  • cs_pin (Required, Pin): The chip-select (CSN) pin.

  • id (Optional, ID): Manually specify the ID for this MT6701 hub.

  • All other options from SPI Bus. The bus needs a miso_pin; the component defaults to SPI mode 1 at 1 MHz, so you normally do not need to change data_rate or spi_mode.

The hub does not poll on its own: the sensors below read the encoder at their own update_interval, and every read refreshes the status flags.

NOTE

A disconnected or stuck-low data line reads as all-zero frames, which pass the CRC. When every frame at boot reads zero the hub logs a warning, but keeps working, since an encoder resting at exactly 0 looks the same.

The mt6701 sensor publishes the absolute angle (and, optionally, the raw count) from your MT6701. Set up an I²C or SSI/SPI hub first, then add this platform.

sensor:
- platform: mt6701
mt6701_id: my_encoder
name: Encoder Angle
  • name (Required, string): The name of the angle sensor, in degrees (0-360).

  • mt6701_id (Optional, ID): The ID of the hub to read from.

  • raw_count (Optional): The raw 14-bit count, 0-16383.

    • All other options from Sensor.
  • update_interval (Optional, Time): The publish interval. Each poll also triggers a fresh read of the encoder. Defaults to 60s.

  • All other options from Sensor.

The mt6701_spi binary sensors expose the status flags carried in the SSI frame. They are only available on the SSI/SPI hub.

binary_sensor:
- platform: mt6701_spi
mt6701_spi_id: my_encoder
push_button:
name: Encoder Button
track_loss:
name: Encoder Track Loss
  • push_button (Optional): On when the magnetic push-button gesture is detected.

  • track_loss (Optional): On when the encoder reports a tracking loss / overspeed condition.

  • mt6701_spi_id (Optional, ID): The ID of the SSI/SPI hub.

  • update_interval (Optional, Time): How often the flags are read. A push has to be seen between two reads, so this is short. Defaults to 50ms.

The mt6701_spi text sensor exposes the magnetic-field status. It is only available on the SSI/SPI hub.

text_sensor:
- platform: mt6701_spi
mt6701_spi_id: my_encoder
name: Encoder Field Status

The reported value is one of:

  • OK: the magnet distance is fine.
  • TOO_STRONG: the magnet is too close / the field is too strong.
  • TOO_WEAK: the magnet is too far / the field is too weak.
  • UNKNOWN: the reserved status code.
  • mt6701_spi_id (Optional, ID): The ID of the SSI/SPI hub.
  • update_interval (Optional, Time): How often the field status is read. Defaults to 60s.
  • All other options from Text Sensor.

Writes the current configuration registers into the chip’s EEPROM so they survive a power cycle. Only available on the mt6701_i2c hub. The hub stops reading the encoder while the chip programs its EEPROM.

The chip loads its EEPROM at power-up, so the datasheet verifies the programming by power-cycling the chip and reading the registers back. To check it, remove the options from your configuration (so they are not written again at boot), power-cycle the device and confirm the outputs behave as programmed.

button:
- platform: template
name: Save Encoder Config
on_press:
- mt6701_i2c.save_eeprom: my_encoder
  • id (Required, ID): The mt6701_i2c hub to program.

CAUTION

The MT6701 EEPROM has a limited number of write cycles. Never call this action from a periodic automation; trigger it only manually. The datasheet also requires the supply voltage to be 4.5-5.5 V during the programming window of more than 600 ms, so a 3.3 V-powered sensor should not be programmed.

The MT6701 is an absolute angle sensor: it reports where the shaft points right now (0-360°), not how many turns it has made or how fast it spins. Those are easy to derive in YAML with a couple of globals and template sensors, which keeps them under your control (initial value, reset, units, filtering).

globals:
- id: enc_position # accumulated multi-turn angle, in degrees
type: double
restore_value: false
initial_value: "0"
- id: enc_prev_angle
type: float
restore_value: false
initial_value: "-1"
- id: enc_prev_us
type: uint32_t
restore_value: false
- id: enc_rpm
type: float
restore_value: false
sensor:
- platform: mt6701
mt6701_id: my_encoder
id: encoder_angle
name: Encoder Angle
update_interval: 100ms
on_value:
then:
- lambda: |-
const float angle = x;
const uint32_t now = micros();
if (id(enc_prev_angle) >= 0.0f) {
float diff = angle - id(enc_prev_angle);
if (diff > 180.0f) diff -= 360.0f;
else if (diff < -180.0f) diff += 360.0f;
id(enc_position) += diff;
const uint32_t dt = now - id(enc_prev_us);
if (dt > 0)
id(enc_rpm) = (diff / 360.0f) / (dt / 60000000.0f);
}
id(enc_prev_angle) = angle;
id(enc_prev_us) = now;
- platform: template
name: Encoder Position
unit_of_measurement: °
accuracy_decimals: 1
update_interval: 100ms
lambda: "return id(enc_position);"
- platform: template
name: Encoder Velocity
unit_of_measurement: RPM
accuracy_decimals: 1
update_interval: 100ms
lambda: "return id(enc_rpm);"
filters:
- sliding_window_moving_average:
window_size: 5

NOTE

Both values are inferred from the change between two angle samples, so their accuracy depends on how often the angle sensor updates: the shaft must move less than half a turn between samples, or the wrap detection guesses the wrong direction. At update_interval: 100ms that ceiling is ~300 RPM; lower the interval for faster shafts.