Attitude Estimation· Live
Home / Chapter 2 / 2.3b

ESP32: I2C and the first WHO_AM_I

Lesson 2.3b · ESP32 · free

Video coming soon

This is lesson 2.3 again, on the Arduino Nano ESP32: the Wire library sets up I2C on pins A4 and A5, no CubeMX needed. We write the register number, read one byte back, and check the answer.

In this lesson · 4 steps
  1. Wiring (Arduino Nano ESP32 → IMU breakout)
  2. New sketch
  3. Read WHO_AM_I once
  4. Upload and check

1Wiring (Arduino Nano ESP32 → IMU breakout)

  1. 3V3 → VIN / VCC (not VBUS: that is 5 V)
  2. GND → GND
  3. A4 → SDA
  4. A5 → SCL
  5. Most breakouts already have pull-up resistors on SDA and SCL. The address pin left open gives the default address.

2New sketch

  1. File → New Sketch, save it as ch2_who_am_i
  2. Tools → Board: Arduino Nano ESP32, Tools → Port: your board

3Read WHO_AM_I once

ch2_who_am_i.ino · replace everything

We tell the sensor which register we want, then read one byte back.

#include <Wire.h>

/* IMU: change these three lines for your sensor
 *
 *   sensor          I2C address    WHO_AM_I register   expected answer
 *   ISM330DHCX      0x6A (0x6B)    0x0F                0x6B
 *   LSM6DSOX        0x6A (0x6B)    0x0F                0x6C
 *   MPU-6050        0x68 (0x69)    0x75                0x68
 *   MPU-9250        0x68 (0x69)    0x75                0x71
 *   ICM-20948       0x69 (0x68)    0x00                0xEA
 *   ICM-42688-P     0x68 (0x69)    0x75                0x47
 *   (in brackets: the address when the address pin is pulled the other way)
 */
#define IMU_ADDR          0x6A   /* 7-bit I2C address */
#define IMU_WHO_AM_I      0x0F   /* WHO_AM_I register */
#define IMU_WHO_AM_I_VAL  0x6B   /* expected answer   */

void setup()
{
  Serial.begin(115200);
  delay(10000);             /* 10 s: time to connect the serial plotter */

  Wire.begin();             /* Nano ESP32: SDA = A4, SCL = A5 */
  Wire.setClock(400000);    /* 400 kHz, like on the STM32 */

  /* 1. tell the sensor which register we want */
  Wire.beginTransmission(IMU_ADDR);
  Wire.write(IMU_WHO_AM_I);
  uint8_t error = Wire.endTransmission(false);   /* false: keep the bus, a read follows */

  /* 2. read one byte back */
  if (error != 0 || Wire.requestFrom(IMU_ADDR, 1) != 1)
  {
    Serial.println("No answer: check the wires and the address");
    return;
  }
  uint8_t who_am_i = Wire.read();

  if (who_am_i == IMU_WHO_AM_I_VAL)
    Serial.printf("WHO_AM_I = 0x%02X: sensor found!\n", who_am_i);
  else
    Serial.printf("WHO_AM_I = 0x%02X: unexpected value\n", who_am_i);
}

void loop()
{
}
Why?
The three values are the same as on the STM32; my sensor answers at 0x6B, so change IMU_ADDR if you get No answer. Wire uses the 7-bit address directly, no shift. endTransmission(false) keeps the bus for the read that follows. The 10 second delay gives us time to connect the plotter, because the message is printed only once.

4Upload and check

  1. Upload, then connect our web serial plotter (serial.steppeschool.com, chapter 1), 115200 baud
  2. Missed the line? It is printed once at start: press reset, then connect within 10 s (the USB port restarts too)
Check & troubleshoot

What you should see

  • WHO_AM_I = 0x6B: sensor found! in the serial plotter console

If it doesn't work

  • Compile error: every Arduino sketch needs a loop() function, even an empty one
  • No message: it is printed once at start. After the upload the USB port restarts, so connect the plotter within the 10-second delay
  • No answer: check A4/A5 and the address (hex 6A or 6B, set by the SDO pin)
  • Use the 3V3 pin, not 5 V

Next: Lesson 2.4: we turn this test code into one library that works on any board.