Change A31301 I²C address via EEPROM

The Allegro A31301 is a high-precision magnetic angle sensor that communicates via I²C. One of the great advantages of the A31301 sensor is that its I²C address is configurable (16 with external resistors and 127 with programming). By default, it uses the I²C EEPROM address 0x6F, but in some applications you may want to change this — for example, if you have multiple A31301 sensors on the same I²C bus.

This guide explains how to change the I²C address stored in the EEPROM of the A31301 using an ESP32 and the Wire library.

Wiring

The following has been made on a breadboard with an ESP32 Firebettle 2 and a small home made breakout board for the A31301.

Bread board with the ESP32 and the 3D magnetic position sensor A31301

Here is how the A31301 has been wired on the ESP32:

A31301 magnetic position sensor wiring

First, the A31301 must be powered. Since the sensor is a low power device powered in 3.3V, it can be connected to the ESP32 regulator without any problem. Pins SA0 and SA1 have to be connected to VCC, so the device will respond to the peripheral address stored in the EEPROM.

How the A31301 Stores Its I²C Address?

The A31301 stores its configuration, including the I²C address, in an internal EEPROM. To modify EEPROM values, you must use indirect access registers, following the device’s EEPROM write procedure:

  1. Unlock the EEPROM read/write access with a two-step access code
  2. Set the indirect write address (EEPROM location)
  3. Load the data to be written
  4. Trigger the write command
  5. Wait until the write-done (WDN) flag is set

The EEPROM address that stores the I²C address is found in the device datasheet (page 35): 0x0015.

Source code

Here’s a complete example sketch that performs the I²C address change sequence:

#include <Wire.h>

#define A31301_ADDR 0x6F  // Default I²C address

// Read two bytes from a register
uint8_t read(uint8_t address, uint8_t reg_addr, uint8_t* msb, uint8_t* lsb) {
  Wire.beginTransmission(address);
  Wire.write(reg_addr);
  if (Wire.endTransmission(false) != 0) { 
    Serial.println("ERROR NACK ?"); 
    return 1; 
  }
  Wire.requestFrom(address, (uint8_t)2);
  if (Wire.available() != 2) { 
    Serial.println("ERROR: Should read 2 bytes"); 
    return 2; 
  }
  *msb = Wire.read();
  *lsb = Wire.read();
  return 0;
}

// Write two bytes to a register
uint8_t write(uint8_t address, uint8_t reg_addr, uint8_t msb, uint8_t lsb) {
  Wire.beginTransmission(address);
  Wire.write(reg_addr);
  Wire.write(msb);
  Wire.write(lsb);
  if (Wire.endTransmission() != 0) { 
    Serial.println("ERROR NACK ?"); 
    return 1; 
  }
  return 0;
}

void setup() {
  Serial.begin(115200);
  delay(1000); // Secure power-on delay
  Serial.println("\n\n\n ::::: Change EEPROM I²C address :::::");
  Wire.begin();

  // 1. Write Access Code
  Serial.println("1. Write Access Code");
  write(A31301_ADDR, 0x3E, 0x43, 0x55);
  write(A31301_ADDR, 0x3E, 0x53, 0x54);

  // 2. Load EEPROM target address (0x0015 = I2C address location)
  Serial.println("2. Load INDIRECT_WR_ADDR with EEPROM target address");
  write(A31301_ADDR, 0x02, 0x00, 0x15);

  // 3. Load EEPROM data to be written (new I2C address)
  // Example: new address = 0x2A
  Serial.println("3. Load INDIRECT_WR_DATA registers with new address");
  write(A31301_ADDR, 0x04, 0x00, 0x01);   // Data MSB
  write(A31301_ADDR, 0x06, 0x2A, 0x00);   // Data LSB (0x2A = new I2C addr)

  // 4. Invoke extended write
  Serial.println("4. Start EEPROM write");
  write(A31301_ADDR, 0x08, 0x80, 0x00);   // Set EXW bit = 1

  // 5. Wait until write completes (poll WDN bit)
  Serial.println("5. Waiting for EEPROM write to complete...");
  uint8_t WDN = 0;
  do {
    uint8_t msb, lsb;
    read(A31301_ADDR, 0x08, &msb, &lsb);
    WDN = lsb & 0x01;
  } while (!WDN);

  Serial.println("EEPROM write complete. Address changed.");
  Serial.println("Power-cycle the device for the new I2C address to take effect.");
}

void loop() {}

Step-by-Step Explanation

  1. Unlock EEPROM write access The two writes to register 0x3E send the required access codes (CUST):
0x3E ← 0x43 0x55  
0x3E ← 0x53 0x54  

This sequence unlocks EEPROM writes.

  1. Select target EEPROM address The target EEPROM word address (here 0x0015) is loaded into INDIRECT_WR_ADDR (register 0x02).

  2. Load data to write The new I²C address value (e.g., 0x55) is written into the INDIRECT_WR_DATA_MSB and LSB registers (0x01 and 0x2A).

  3. Trigger the write Writing 0x80 0x00 to INDIRECT_WR_STATUS (register 0x08) sets the EXW bit, which starts the EEPROM write.

  4. Poll the WDN bit The write-done bit (WDN) indicates when the operation has completed. The code polls this bit until it becomes 1.

  5. Power cycle the sensor After completion, the new I²C address takes effect only after a full power cycle.

🔍 Verifying the Change

Once the device restarts, you can scan your I²C bus (using an I²C scanner sketch) to confirm that the A31301 now appears at its new address:

#include <Wire.h>

void setup() {
  Wire.begin();
  Serial.begin(115200);
  Serial.println("Scanning I2C bus...");

  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.print("Found device at 0x");
      Serial.println(addr, HEX);
      delay(5);
    }
  }
}

void loop() {}

Notes & Best Practices

Summary

Step Action Register Description
1 Write access codes 0x3E Unlock EEPROM write
2 Set EEPROM address 0x02 Target = 0x0015
3 Write data 0x04 / 0x06 New I²C address
4 Trigger write 0x08 Set EXW bit
5 Wait for completion 0x08 Poll WDN bit

After this sequence and a power cycle, your A31301 sensor will respond to the new I²C address you programmed into its EEPROM.

Download

See also


Last update : 11/06/2025