ADXL345 3-Axis Accelerometer

The Adxl345 component provides an interface to the ADXL345 accelerometer, which is a small, thin, low-power, 3-axis accelerometer with high resolution (13-bit) measurement at up to ±16 g. It can be used in various applications such as motion detection, orientation sensing, and gesture recognition.

API Reference

Header File

Classes

class Adxl345 : public espp::BasePeripheral<>

Class for the ADXL345 I2C 3-axis accelerometer.

The ADXL345 is a 3-axis accelerometer with 10-bit to 13-bit resolution measurement at up to ±16g. Digital output data is formatted as 16-bit twos complement and is accessible through either a SPI (3- or 4-wire) or I2C digital interface.

The ADXL345 can support SPI up to 5 MHz and I2C up to 400 kHz. It has a programmable interrupt system that can be used to signal events such as data ready, free-fall, activity, inactivity, and tap detection.

The datasheet can be found here: https://www.analog.com/media/en/technical-documentation/data-sheets/adxl345.pdf

ADXL345 Example

  // I2C configuration
  espp::I2c i2c({
      .port = I2C_NUM_0,
      .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
      .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
  });

  std::error_code ec;


  // Create the ADXL345 instance
  // NOTE: auto_init defaults to true, so we don't have to call initialize ourselves.
  espp::Adxl345 accel(espp::Adxl345::Config{
      .device_address = espp::Adxl345::DEFAULT_ADDRESS,
      .range = espp::Adxl345::RANGE_2G,
      .data_rate = espp::Adxl345::RATE_100_HZ,
      .write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
                         std::placeholders::_3),
      .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1, std::placeholders::_2,
                        std::placeholders::_3),
      .log_level = espp::Logger::Verbosity::WARN,
  });

  // Disable measurement mode initially, so we can configure interrupts and such
  accel.set_measurement_mode(false, ec);

  // Configure the ADXL345
  accel.set_fifo_mode(espp::Adxl345::FifoMode::STREAM, ec); // discard old data when FIFO is full
  accel.set_fifo_num_samples(1, ec); // set FIFO to trigger watermark interrupt on every sample
  accel.set_low_power(false, ec);    // disable low power mode
  accel.set_sleep_mode(false, ec);   // disable sleep mode
  accel.set_auto_sleep(false, ec);   // disable auto sleep mode
  bool active_high = false;
  accel.set_interrupt_polarity(active_high, ec); // set interrupt polarity to active high
  // configure the interrupt to trigger on watermark on INT1 pin
  accel.set_interrupt_mapping(espp::Adxl345::InterruptType::WATERMARK,
                              espp::Adxl345::InterruptPin::INT1, ec);
  // enable the watermark interrupt
  accel.configure_interrupt(espp::Adxl345::InterruptType::WATERMARK, true, ec);


  static auto start = std::chrono::high_resolution_clock::now();
  auto callback = [&](const espp::Interrupt::Event &event) {
    std::error_code ec;
    // clear the interrupt source
    [[maybe_unused]] auto interrupt_status = accel.get_interrupt_source(ec);
    if (ec) {
      logger.error("Error getting interrupt source: {}", ec.message());
    }
    auto now = std::chrono::high_resolution_clock::now();
    // we got a data ready interrupt, read the data and print it
    auto data_vec = accel.read_all(ec);
    if (ec) {
      fmt::print("Error reading ADXL345: {}\n", ec.message());
      return;
    }
    for (int i = 0; i < data_vec.size(); ++i) {
      auto &data = data_vec[i];
      // get the offset in time from now that hte sample was taken
      auto sample_time = now - 10ms * (data_vec.size() - i - 1);
      // convert to seconds
      auto elapsed = std::chrono::duration<float>(sample_time - start).count();
      // Print the data in g's
      fmt::print("{:.3f}, {:.4f}, {:.4f}, {:.4f}\n", elapsed, data.x, data.y, data.z);
    }
  };

  espp::Interrupt::PinConfig accel_int = {
      .gpio_num = (gpio_num_t)CONFIG_EXAMPLE_ALERT_GPIO,
      .callback = callback,
      .active_level = espp::Interrupt::ActiveLevel::LOW,
      .interrupt_type = espp::Interrupt::Type::FALLING_EDGE,
      .pullup_enabled = true,
      .pulldown_enabled = false,
      .filter_type = espp::Interrupt::FilterType::PIN_GLITCH_FILTER,
  };

  espp::Interrupt interrupt({
      .isr_core_id = 1,
      .interrupts = {accel_int},
      .task_config =
          {
              .name = "Interrupt task",
              .stack_size_bytes = 6192,
              .priority = 5,
          },
      .log_level = espp::Logger::Verbosity::WARN,
  });


  // Print CSV header
  fmt::print("%time (s), x (g), y (g), z (g)\n");

  // Enable measurement mode
  accel.set_measurement_mode(true, ec);

  // Keep the main function running to allow the example to run
  while (true) {
    auto start_time = std::chrono::high_resolution_clock::now();
    auto active_states = interrupt.get_active_states();
    logger.info("Instantaneous state of pins: {}", active_states);
    auto interrupt_status = accel.get_interrupt_source(ec);
    if (ec) {
      logger.error("Error getting interrupt source: {}", ec.message());
    } else {
      logger.info("Interrupt source: 0x{:02X}", interrupt_status);
    }
    auto data_vec = accel.read_all(ec);
    if (ec) {
      logger.error("Error reading all data: {}", ec.message());
    } else {
      logger.info("Read {} samples from ADXL345: {}", data_vec.size(), data_vec);
    }
    interrupt_status = accel.get_interrupt_source(ec);
    if (ec) {
      logger.error("Error getting interrupt source: {}", ec.message());
    } else {
      logger.info("Interrupt source: 0x{:02X}", interrupt_status);
    }
    std::this_thread::sleep_until(start_time + 100ms);
  }

Public Types

enum Range

Range of the accelerometer.

Values:

enumerator RANGE_2G

±2g

enumerator RANGE_4G

±4g

enumerator RANGE_8G

±8g

enumerator RANGE_16G

±16g

enum DataRate

Output data rate.

Values:

enumerator RATE_0_10_HZ

0.10 Hz

enumerator RATE_0_20_HZ

0.20 Hz

enumerator RATE_0_39_HZ

0.39 Hz

enumerator RATE_0_78_HZ

0.78 Hz

enumerator RATE_1_56_HZ

1.56 Hz

enumerator RATE_3_13_HZ

3.13 Hz

enumerator RATE_6_25_HZ

6.25 Hz

enumerator RATE_12_5_HZ

12.5 Hz

enumerator RATE_25_HZ

25 Hz

enumerator RATE_50_HZ

50 Hz

enumerator RATE_100_HZ

100 Hz

enumerator RATE_200_HZ

200 Hz

enumerator RATE_400_HZ

400 Hz

enumerator RATE_800_HZ

800 Hz

enumerator RATE_1600_HZ

1600 Hz

enumerator RATE_3200_HZ

3200 Hz

enum InterruptPin

Interrupt Pin.

Values:

enumerator INT1

INT1 pin.

enumerator INT2

INT2 pin.

enum InterruptType

Interrupt type.

Values:

enumerator OVERRUN

FIFO overrun interrupt.

enumerator WATERMARK

FIFO watermark interrupt.

enumerator FREE_FALL

Free fall interrupt.

enumerator INACTIVITY

Inactivity interrupt.

enumerator ACTIVITY

Activity interrupt.

enumerator DOUBLE_TAP

Double tap interrupt.

enumerator SINGLE_TAP

Single tap interrupt.

enumerator DATA_READY

Data ready interrupt.

enum class FifoMode

FIFO Mode.

Values:

enumerator BYPASS

Bypass mode.

enumerator FIFO

FIFO mode.

enumerator STREAM

Stream mode.

enumerator TRIGGER

Trigger mode.

typedef std::function<bool(uint8_t)> probe_fn

Function to probe the peripheral

Param address:

The address to probe

Return:

True if the peripheral is found at the given address

Public Functions

inline explicit Adxl345(const Config &config)

Constructor.

Parameters:

config – Configuration for the ADXL345

inline bool initialize(std::error_code &ec)

Initialize the ADXL345.

Parameters:

ec – Error code to set if an error occurs

Returns:

True if initialization was successful, false otherwise

inline bool set_range(Range range, std::error_code &ec)

Set the range of the accelerometer.

Parameters:
  • range – New range

  • ec – Error code to set if an error occurs

Returns:

True if setting range was successful, false otherwise

inline bool set_data_rate(DataRate rate, std::error_code &ec)

Set the output data rate.

Parameters:
  • rate – New data rate

  • ec – Error code to set if an error occurs

Returns:

True if setting data rate was successful, false otherwise

inline bool set_low_power(bool enable, std::error_code &ec)

Enable/Disable low power mode.

Parameters:
  • enable – Whether to enable or disable low power mode

  • ec – Error code to set if an error occurs

Returns:

True if setting low power mode was successful, false otherwise

inline bool set_auto_sleep(bool enable, std::error_code &ec)

Enable/Disable the auto-sleep mode.

Parameters:
  • enable – Whether to enable or disable auto-sleep

  • ec – Error code to set if an error occurs

Returns:

True if setting auto-sleep was successful, false otherwise

inline bool set_measurement_mode(bool enable, std::error_code &ec)

Enable/Disable the measurement mode.

Parameters:
  • enable – Whether to enable or disable measurement mode

  • ec – Error code to set if an error occurs

Returns:

True if setting measurement mode was successful, false otherwise

inline bool set_sleep_mode(bool enable, std::error_code &ec)

Enable/Disable the Sleep mode.

Parameters:
  • enable – Whether to enable or disable sleep mode

  • ec – Error code to set if an error occurs

Returns:

True if setting sleep mode was successful, false otherwise

inline bool set_fifo_mode(FifoMode mode, std::error_code &ec)

Set the FIFO mode.

Parameters:
  • mode – New FIFO mode

  • ec – Error code to set if an error occurs

Returns:

True if setting FIFO mode was successful, false otherwise

inline FifoMode get_fifo_mode(std::error_code &ec)

Get the current FIFO mode.

Parameters:

ec – Error code to set if an error occurs

Returns:

Current FIFO mode

inline bool set_fifo_num_samples(std::uint8_t num_samples, std::error_code &ec)

Set the FIFO Num Samples.

Note

Num Samples is meaningless for FifoMode::BYPASS.

Note

The FIFO can store up to 32 samples.

Note

Num Samples specifies how many FIFO entries are needed to trigger a InterruptType::WATERMARK interrupt in FifoMode::FIFO, and FifoMode::STREAM.

Note

Num Samples specifies how many FIFO entries are retained in the FIFO before an InterruptType::TRIGGER interrupt is triggered.

Parameters:
  • num_samples – Number of samples to store in FIFO

  • ec – Error code to set if an error occurs

Returns:

True if setting FIFO num samples was successful, false otherwise

inline std::uint8_t get_fifo_num_samples_available(std::error_code &ec)

Get the number of samples available in the FIFO.

Parameters:

ec – Error code to set if an error occurs

Returns:

Number of samples available in the FIFO (0-32)

inline std::uint8_t get_fifo_status(std::error_code &ec)

Get the current FIFO status.

Note

The FIFO status byte contains the following bits:

  • Bit 7: FIFO trigger

  • Bit 6: unused (always 0)

  • Bits 5-0: Number of entries in FIFO (0-32)

Parameters:

ec – Error code to set if an error occurs

Returns:

Current FIFO status as a byte

inline Data read(std::error_code &ec)

Read the accelerometer data.

Parameters:

ec – Error code to set if an error occurs

Returns:

Accelerometer data in g

inline std::vector<Data> read_all(std::error_code &ec)

Read all accelerometer data from the FIFO.

Note

This function reads all available data from the FIFO. The data is returned as a vector of Data structures.

Note

If the FIFO is empty, an empty vector is returned.

Parameters:

ec – Error code to set if an error occurs

Returns:

Vector of accelerometer data in g

inline bool set_interrupt_polarity(bool active_high, std::error_code &ec)

Set the interrupt polarity.

Parameters:
  • active_high – Whether the interrupt should be active high (true) or active low (false)

  • ec – Error code to set if an error occurs

Returns:

True if setting interrupt polarity was successful, false otherwise

inline bool disable_all_interrupts(std::error_code &ec)

Disable all interrupts.

Parameters:

ec – Error code to set if an error occurs

Returns:

True if disabling all interrupts was successful, false otherwise

inline bool configure_interrupt(InterruptType type, bool enable, std::error_code &ec)

Configure an interrupt.

Parameters:
  • type – Type of interrupt to configure

  • enable – Whether to enable or disable the interrupt

  • ec – Error code to set if an error occurs

Returns:

True if configuring interrupt was successful, false otherwise

inline std::uint8_t get_interrupt_source(std::error_code &ec)

Get the interrupt source.

Parameters:

ec – Error code to set if an error occurs

Returns:

Bitmap of active interrupts

inline bool set_interrupt_mapping(InterruptType type, InterruptPin pin, std::error_code &ec)

Set the interrupt mapping.

Parameters:
  • type – Type of interrupt to map

  • pinInterrupt pin to map to

  • ec – Error code to set if an error occurs

Returns:

True if setting interrupt mapping was successful, false otherwise

inline bool probe(std::error_code &ec)

Probe the peripheral

Note

This function is thread safe

Note

If the probe function is not set, this function will return false and set the error code to operation_not_supported

Note

This function is only available if UseAddress is true

Parameters:

ec – The error code to set if there is an error

Returns:

True if the peripheral is found

inline void set_address(uint8_t address)

Set the address of the peripheral

Note

This function is thread safe

Note

This function is only available if UseAddress is true

Parameters:

address – The address of the peripheral

inline void set_probe(const probe_fn &probe)

Set the probe function

Note

This function is thread safe

Note

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

Note

This function is only available if UseAddress is true

Parameters:

probe – The probe function

inline void set_write(const write_fn &write)

Set the write function

Note

This function is thread safe

Note

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

Parameters:

write – The write function

inline void set_read(const read_fn &read)

Set the read function

Note

This function is thread safe

Note

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

Parameters:

read – The read function

inline void set_read_register(const read_register_fn &read_register)

Set the read register function

Note

This function is thread safe

Note

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

Parameters:

read_register – The read register function

inline void set_write_then_read(const write_then_read_fn &write_then_read)

Set the write then read function

Note

This function is thread safe

Note

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

Parameters:

write_then_read – The write then read function

inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)

Set the delay between the write and read operations in write_then_read

Note

This function is thread safe

Note

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

Note

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

Parameters:

delay – The delay between the write and read operations in write_then_read

inline void set_config(const Config &config)

Set the configuration for the peripheral

Note

This function is thread safe

Note

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

Parameters:

config – The configuration for the peripheral

inline void set_config(Config &&config)

Set the configuration for the peripheral

Note

This function is thread safe

Note

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

Parameters:

config – The configuration for the peripheral

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns:

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters:

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns:

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters:

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters:

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns:

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters:

rate_limit – The rate limit to use for the logger

Public Static Attributes

static constexpr std::uint8_t DEFAULT_ADDRESS = 0x53

Default I2C address of the ADXL345.

struct Config

Configuration for the ADXL345.

Public Members

std::uint8_t device_address = DEFAULT_ADDRESS

I2C address of the device.

Range range = RANGE_2G

Range of the accelerometer.

DataRate data_rate = RATE_100_HZ

Output data rate.

bool auto_init = true

Automatically initialize the device on construction.

BasePeripheral<std::uint8_t, true>::write_fn write

Function to write to the device.

BasePeripheral<std::uint8_t, true>::read_fn read

Function to read from the device.

espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}

Verbosity for the logger.

struct Data

Data structure for accelerometer readings.

Public Members

float x

X-axis acceleration in g.

float y

Y-axis acceleration in g.

float z

Z-axis acceleration in g.