Electronic – How to read from an accelerometer through i2c/spi for ~1 second at frequency>2kHz with precise distancing between measures

accelerometeresp32i2cspi

Context

goal

My final goal is to perform an fft on acceleration signals with specs at least:

  • band between ~10 and ~1000 Hz
  • spectral resolution ~1Hz

on a portable, cheap, low-power device.

hardware

I'd like to do this with cheap portable low power hardware so I opted for an adxl345 as accelerometer connected via i2c (but also spi would be viable) to an esp32-wrover as micro-controller, powered by a 18650 lipo battery. Of course there is no problem, if necessary, to opt for more expensive hardware staying around ~100 euros/dollars.

software

I know and like python more than I know and like C, so I decided to use micropython on the microcontroller to acquire data from the sensor and push it via wifi to a computer that will actually perform the fft.

Question

My question is very focused on how to pass acceleration signals from the accelerometer to the micro-controller via I2C: I have implemented a loop that lasts for the desired acquisition time (say 1 second) and on each iteration tests how much time has passed since the beginning and if it's a multiple of the desired frequency it read a value from the accelerometer via i2c

start = ticks_ns()
while ticks_ns() - start < acquisition_time * 1000000000:
    curr_time = ticks_ns()
    if curr_time - start < (n_act_meas * 999999999. / sampling_rate):
        continue
    buf[n_act_meas * 6:n_act_meas * 6 + 6] = i2c_read_bytes(address, regAddress, length=6)  # 6bytes = 2bytes * 3 signals (xyz)
    T[n_act_meas] = ticks_ns()
    n_act_meas += 1

but this approach is not very precise on the interval between measures (~10% relative error) and has a top frequency of 2kHz in my implementation (below the max frequency of the accelerometer).

I feel like I'm doing something wrong: is it possible to read via i2c the last n measures from the accelerometer (where n~1000 in my case) so that the problem of the timing is relegated to the accelerometer that should have a system that is precise enough to guarantee the nominal max sampling frequency, and a precise distancing between measures?

Best Answer

ADXL345 Datasheet.

The most interesting section is on the FIFO. See page 21:

The ADXL345 contains technology for an embedded memory management system with 32-level FIFO that can be used to minimize host processor burden. This buffer has four modes: bypass, FIFO, stream, and trigger (see FIFO Modes)

It sounds like you should set the FIFO mode to "stream". Set the "watermark" level to something suitable (e.g. half the FIFO depth, 16) and the sample speed (BW_RATE register). Then the device will tell the MCU when it is ready, and you simply repeatedly read the data registers (note that you need to do a multi-byte read to get all the axes properly), until you have 16 values. Those will be the values sampled from the last 16 time periods.