ESP32 Arduino Wire not working

Hi guys,

I recently switched to ESP32 and I am trying to connect an IMU with I2C.
I’ve read several issues that might be related, but I couldn’t figure it out.

I am running on a ESP32 S3 DevKit C Board.

platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino

There are the packages used

pio pkg list
Resolving esp32dev dependencies...
Platform espressif32 @ 6.5.0 (required: espressif32)
├── framework-arduinoespressif32 @ 3.20014.231204 (required: platformio/framework-arduinoespressif32 @ ~3.20014.0)
├── tool-cmake @ 3.16.4 (required: platformio/tool-cmake @ ~3.16.0)
├── tool-esptoolpy @ 1.40501.0 (required: platformio/tool-esptoolpy @ ~1.40501.0)
├── tool-mkfatfs @ 2.0.1 (required: platformio/tool-mkfatfs @ ~2.0.0)
├── tool-mklittlefs @ 1.203.210628 (required: platformio/tool-mklittlefs @ ~1.203.0)
├── tool-mkspiffs @ 2.230.0 (required: platformio/tool-mkspiffs @ ~2.230.0)
├── tool-ninja @ 1.9.0 (required: platformio/tool-ninja @ ^1.7.0)
├── tool-openocd-esp32 @ 2.1100.20220706 (required: platformio/tool-openocd-esp32 @ ~2.1100.0)
├── toolchain-esp32ulp @ 1.23500.220830 (required: platformio/toolchain-esp32ulp @ ~1.23500.0)
├── toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 (required: espressif/toolchain-riscv32-esp @ 8.4.0+2021r2-patch5)
└── toolchain-xtensa-esp32s3 @ 8.4.0+2021r2-patch5 (required: espressif/toolchain-xtensa-esp32s3 @ 8.4.0+2021r2-patch5)

Libraries
├── FastLED @ 3.6.0 (required: fastled/FastLED @ ^3.6.0)
├── Madgwick @ 1.2.0 (required: arduino-libraries/Madgwick @ ^1.2.0)
├── SCL3300 @ 3.3.1 (required: davidarmstrong/SCL3300 @ ^3.3.1)
└── TFT_eSPI @ 2.5.43 (required: bodmer/TFT_eSPI @ ^2.5.43)

and I am trying to connect LSM6DS3 IMU. I started with the Arduino library, but I moved that code to a custom class for testing.
I am initialising i2c with the following code:

    _wire->begin(static_cast<int>(SDA), static_cast<int>(SCL));
    if (!(readRegister(LSM6DS3_WHO_AM_I_REG) == 0x6C || readRegister(LSM6DS3_WHO_AM_I_REG) == 0x69))
    {
        end();
        return 0;
    }

This is the very same code as used in the original lib.

I am getting this error message, and I cannot understand why this is happening.

[   803][E][Wire.cpp:526] write(): NULL TX buffer pointer
[   804][E][Wire.cpp:448] endTransmission(): NULL TX buffer pointer

This seems to be strange, as the allocateWireBuffer method should output an error message similar to this, if it was not able to allocate memory log_e("Can't allocate memory for I2C_%d rxBuffer", num);

Any ideas?

And the full code of that class is?

Sorry, here it is:

#include "angle.h"

uint8_t Angle::begin()
{
    filter.begin(sensorRate);

    _wire = &Wire; // need the pointer to make it compatible with the original code

    _wire->begin(static_cast<int>(SDA), static_cast<int>(SCL));
    if (!(readRegister(LSM6DS3_WHO_AM_I_REG) == 0x6C || readRegister(LSM6DS3_WHO_AM_I_REG) == 0x69))
    {
        end();
        return 0;
    }

    // set the gyroscope control register to work at 104 Hz, 2000 dps and in bypass mode
    writeRegister(LSM6DS3_CTRL2_G, 0x4C);

    // Set the Accelerometer control register to work at 104 Hz, 4 g,and in bypass mode and enable ODR/4
    // low pass filter (check figure9 of LSM6DS3's datasheet)
    writeRegister(LSM6DS3_CTRL1_XL, 0x4A);

    // set gyroscope power mode to high performance and bandwidth to 16 MHz
    writeRegister(LSM6DS3_CTRL7_G, 0x00);

    // Set the ODR config register to ODR/4
    writeRegister(LSM6DS3_CTRL8_XL, 0x09);

    return 1;
}

uint8_t Angle::lsmAngle(double *angle)
{
    float xAcc, yAcc, zAcc;
    float xGyro, yGyro, zGyro;
    float roll, pitch, heading;
    if (accelerationAvailable() && gyroscopeAvailable())
    {
        readAcceleration(xAcc, yAcc, zAcc);
        readGyroscope(xGyro, yGyro, zGyro);
        filter.updateIMU(xGyro, yGyro, zGyro, xAcc, yAcc, zAcc);
        pitch = filter.getPitch();

        float pitchFiltered = 0.1 * pitch + 0.9 * pitchFilteredOld; // low pass filter
        pitchFilteredOld = pitchFiltered;
        *angle = pitchFiltered;
        return true;
    }

    return false;
}

uint8_t Angle::readRegisters(uint8_t address, uint8_t *data, size_t length)
{
    _wire->beginTransmission(_slaveAddress);
    _wire->write(address);

    if (_wire->endTransmission(false) != 0)
    {
        return -1;
    }

    if (_wire->requestFrom(_slaveAddress, length) != length)
    {
        return 0;
    }

    for (size_t i = 0; i < length; i++)
    {
        *data++ = _wire->read();
    }
    return 1;
}

int Angle::readRegister(uint8_t address)
{
    uint8_t value;

    if (readRegisters(address, &value, sizeof(value)) != 1)
    {
        return -1;
    }

    return value;
}

int Angle::gyroscopeAvailable()
{
    if (readRegister(LSM6DS3_STATUS_REG) & 0x02)
    {
        return 1;
    }

    return 0;
}

void Angle::end()
{
    writeRegister(LSM6DS3_CTRL2_G, 0x00);
    writeRegister(LSM6DS3_CTRL1_XL, 0x00);
    _wire->end();
}

int Angle::readAcceleration(float &x, float &y, float &z)
{
    int16_t data[3];

    if (!readRegisters(LSM6DS3_OUTX_L_XL, (uint8_t *)data, sizeof(data)))
    {
        x = NAN;
        y = NAN;
        z = NAN;

        return 0;
    }

    x = data[0] * 4.0 / 32768.0;
    y = data[1] * 4.0 / 32768.0;
    z = data[2] * 4.0 / 32768.0;

    return 1;
}

int Angle::accelerationAvailable()
{
    if (readRegister(LSM6DS3_STATUS_REG) & 0x01)
    {
        return 1;
    }

    return 0;
}

int Angle::readGyroscope(float &x, float &y, float &z)
{
    int16_t data[3];

    if (!readRegisters(LSM6DS3_OUTX_L_G, (uint8_t *)data, sizeof(data)))
    {
        x = NAN;
        y = NAN;
        z = NAN;

        return 0;
    }

    x = data[0] * 2000.0 / 32768.0;
    y = data[1] * 2000.0 / 32768.0;
    z = data[2] * 2000.0 / 32768.0;

    return 1;
}

int Angle::writeRegister(uint8_t address, uint8_t value)
{
    _wire->beginTransmission(_slaveAddress);
    _wire->write(address);
    _wire->write(value);
    if (_wire->endTransmission() != 0)
        return 0;

    return 1;
}

I am just calling the begin method, and I see the shown error.
That’s why I didn’t post the whole class …

Where is the _slaveAddress member set? Not in the .cpp code.

True, sorry, again.
It’s defined in the angle.h file

#ifndef ANGLE_H
#define ANGLE_H

#include <MadgwickAHRS.h>
#include <Math.h>
#include <Wire.h>

#define LSM6DS3_ADDRESS 0x6A

#define LSM6DS3_WHO_AM_I_REG 0X0F
#define LSM6DS3_CTRL1_XL 0X10
#define LSM6DS3_CTRL2_G 0X11

#define LSM6DS3_STATUS_REG 0X1E

#define LSM6DS3_CTRL6_C 0X15
#define LSM6DS3_CTRL7_G 0X16
#define LSM6DS3_CTRL8_XL 0X17

#define LSM6DS3_OUT_TEMP_L 0X20

#define LSM6DS3_OUTX_L_G 0X22
#define LSM6DS3_OUTX_H_G 0X23
#define LSM6DS3_OUTY_L_G 0X24
#define LSM6DS3_OUTY_H_G 0X25
#define LSM6DS3_OUTZ_L_G 0X26
#define LSM6DS3_OUTZ_H_G 0X27

#define LSM6DS3_OUTX_L_XL 0X28
#define LSM6DS3_OUTX_H_XL 0X29
#define LSM6DS3_OUTY_L_XL 0X2A
#define LSM6DS3_OUTY_H_XL 0X2B
#define LSM6DS3_OUTZ_L_XL 0X2C
#define LSM6DS3_OUTZ_H_XL 0X2D

class Angle
{
protected:
    float pitchFilteredOld;
    Madgwick filter;
    const float sensorRate = 104.00;

    TwoWire *_wire;
    int _slaveAddress = LSM6DS3_ADDRESS;

    uint8_t readRegisters(uint8_t address, uint8_t *data, size_t length);
    int readRegister(uint8_t address);
    int gyroscopeAvailable();
    void end();
    int readAcceleration(float &x, float &y, float &z);
    int accelerationAvailable();
    int readGyroscope(float &x, float &y, float &z);
    int writeRegister(uint8_t address, uint8_t value);

public:
    uint8_t begin();
    uint8_t lsmAngle(double *angle);
};

#endif

I noticed, that I am using LSM6DS3TR-C which seems to be important, as a few values are different.
The WHO_AM_I register has an expected value of 0x6A.

It’s working now. Never mind - thanks for your help :slight_smile:

1 Like