LIS3DH sampling at 5000Hz

Hello Everyone,

We are organizing a school project with crash simulation for school students. I was able to follow the instructions to hook up the LIS3DH to an Arduino board and get acceleration readings on the serial monitor, thank you. The insturctons are on this page: https://learn.sparkfun.com/tutorials/li … okup-guide

We are in particular intersted to get high sampling rates as we are intrested in the impact data that takes place in a very short time i.e. 200 to 300 mili-seconds. Therefore, we need to run the accelerometer at the 5000Hz sampling rate. There is a line for this option in the code, please see below:

myIMU.settings.accelSampleRate = 10; //Hz. Can be: 0,1,10,25,50,100,200,400,1600,5000 Hz

However, we are not getting data any faster when this number is changed to 5000 or 1600 Hz. As a matter of fact, it seems that we are always getting 100 samples per second regardless of this setting in the code.

It is critical that we receive data at 5000 Hz due to the short impact time. What do we need to change to get the high sampling rate at 5000 Hz?

Thank you!

Looking at the datasheet (page 30) this looks only to be supported in low power mode, while the LIS3DH is initialized in normal power mode. I do not see a call to change to lower power mode. but If you know how to make changes to the source:

locate SparkFunLIS3DH.cpp and around line 452 you will find :

        case 1600:
        dataToWrite |= (0x08 << 4);
        break;
        case 5000:
        dataToWrite |= (0x09 << 4);
        break;

change that to

        case 1600:
        dataToWrite |= (0x08 << 4);
        dataToWrite |= 0x8;   // set low power mode
        break;
        case 5000:
        dataToWrite |= (0x09 << 4);
        dataToWrite |= 0x8;   // set low power mode
        break;

if you don’t know how to make changes, attached the updated library. After you download, change the extension from .txt back to .zip and install. (maybe first remove/save the current library)

SparkFun_LIS3DH_Arduino_Library-master.txt (54.2 KB)

Hello Paul and thank you for suggesting a solution.

I edited the file (changed the extension, opened it in word, made the suggested change and reverted back the extension) with your recommended changes and it did not increase the sampling rate.

Later, I was able to download the library file that you provided, I loaded it and got the following error message:

Arduino: 1.6.8 (Windows 7), Board: “Arduino Uno”

C:\Users\Paymon\Documents\Arduino\libraries\SparkFun_LIS3DH_Arduino_Library-master\src\SparkFunLIS3DH.cpp: In member function ‘status_t LIS3DH::begin()’:

C:\Users\Paymon\Documents\Arduino\libraries\SparkFun_LIS3DH_Arduino_Library-master\src\SparkFunLIS3DH.cpp:398:19: error: ‘lpen’ was not declared in this scope

applySettings(lpen);

^~~~

C:\Users\Paymon\Documents\Arduino\libraries\SparkFun_LIS3DH_Arduino_Library-master\src\SparkFunLIS3DH.cpp:398:19: note: suggested alternative: ‘fopen’

applySettings(lpen);

^~~~

fopen

exit status 1

Error compiling for board Arduino Uno.

This report would have more information with

“Show verbose output during compilation”

option enabled in File → Preferences.

I would appreciate your feedback, thank you.

My bad… I had first made a change so you can select low power mode with the begin() call, but had not removed all of the changes later on. Now attached.

Alternative : use the current library and in your sketch (after begin()) add :

  dataToWrite = 0; //Start Fresh!
  dataToWrite |= 0x9 << 4; //ODR of 5000Hz  (use 0x8  for 1600 instead of 0x9 ) 
  dataToWrite |= 0x7; //Enable all axes
  dataToWrite |= 0x8; //Enable low power

  //Now, write the patched together data
  errorsAndWarnings += myIMU.writeRegister(LIS3DH_CTRL_REG1, dataToWrite);

SparkFun_LIS3DH_Arduino_Library-master.txt (54.2 KB)

This improved on the current situation, thank you, Paul.

I am reading 1000 samples per second through the serial monitor when it is set to 5000Hz. I don’t know what is limiting it. Any new suggestions?

Cheers,

Paymon

That is progress.

  1. I discovered that we need to set (or actually NOT set) another parameter (HR in CTRL4). I have applied changes to the library to handle it now in case 1600 or 5000 HZ is selected.

  2. I assume you are connected over I2C. The default speed is 100Khz, depending on the amount of bits/bytes to transfer this might be a limiting factor. I have now set that to 400Khz. in begincore(): Wire.setClock(400000); According to the datasheet page14, it SHOULD be able to handle BUT with a remark : Data based on standard I 2 C protocol requirement, not tested in production.. if it fails to connect try set lower, e.g. 200000.

attached the update version (again with .txt to change to .zip

SparkFun_LIS3DH_Arduino_Library-master.txt (54.3 KB)

It is connected using the SPI method at this time. I was informed that it provides a higher sampling rate than the I2C method.

I downloaded the new library, however; it did not increase the sampling rate.

How should we proceed from here? Should I change it to I2C?

Thank you for your continued support with this item.

Paymon

I expect SPI is faster (clock up to 10Mhz)., but who knows ??

I looked on internet and maybe your issue is related to https://community.st.com/s/question/0D5 … t-possible.

Another aspect could be that it is still running in normal mode (Normal mode 1250 Hz and Low power mode 5000 Hz share the same speed / ODR setting ) . It can be checked with just before you do the measurement

  uint8_t dataRead;
  Serial.print("LIS3DH_CTRL_REG1: 0x");
  myIMU.readRegister(&dataRead, LIS3DH_CTRL_REG1);
  Serial.println(dataRead, HEX);

  Serial.print("LIS3DH_CTRL_REG4: 0x");
  myIMU.readRegister(&dataRead, LIS3DH_CTRL_REG4);
  Serial.println(dataRead, HEX);

[/code]

CNTR_REG 1 : 0x9F is expected ( 9 = speed, F is low power and enabled X, Y Z)

CNTR_REG 4 : 0xY0 is expected ( Y = depending on the acceleration setting, the 0 means NO HR, NO selfttest)

do you use 2g for detection ?

It is set to 16g to measure the impact forces of a crash simulation where students test their crumple zones. The current sampling rate is capped at 1250 Hz.

Paymon and Paul - I’ve been watching this thread out of curiosity. Paul - thanks for providing some excellent support here, we’re glad to have a community that can do this for one another!

Another limiting factor may be your serial monitor connection.

Can you share the format and baud rate of your setup?

Serial is slow (usually). 9600 baud is really slow. Let’s assume you’re using 115200 baud. In that case (with a typical Serial format) you are sending at most 12,800 bytes per second. If you want to print out 5,000 3-axis samples per second that gives you 12,800 / 5,000 = 2.56 bytes per sample! That’s less than one byte per axis! Not to mention that to print a number in a human readable form takes many more bytes than to simply store / transmit the number itself (because each digit uses a byte).

So let’s go the other direction. Say that you wanted to print 4 digits with a decimal point of each axis separated by spaces with a newline. That’s (3*(4+1+1))=16 bytes per sample. You want 5000 sample per second. That’s 500016=80,000 bytes per second. Since it takes 9 bits to transmit a byte in 8N1 Serial connections that’s 980,000=720,000 bits per second that you need to transmit. So… you’d need to use 921,600 baud rate (and even then that’s pushing it - you have very little wiggle room in your data format). Not to mention that you still need time for the I2C transactions… (assuming 2 bytes per axis is 6 bytes, I2C has a few bytes of overhead per transaction so call it 8 bytes per sample… 85000 = 40,000 bytes xferred over I2C just to get the data. At 400kHz 40,000 bytes is (840,000=320,000 bits) and that means simply getting the data out of the sensor will take 320,000/400,000 = 0.8 seconds!

So… from that we can conclude that it is effectively impossible to stream 5000 human-readable samples per second over Serial. What are some other options?

  • Try to stream less data: if you transmit in binary you might cut some overhead. You could transmit in 6-byte packets (2 for each axis) with (perhaps) a two-byte header (maybe a signal code and a checksum?) Then you’re down to just 8 bytes to xfer instead of 16. That means you’re taking only (720,000/921,600)/2)= ~0.4 seconds to transmit the data over serial and (still) 0.8 seconds to fetch the data from the device (best case, not counting any overhead inherent in operation of the code…). So that’s ~ 1.2 seconds for 5000 samples. Close. (Same as 4166.66 samples per second)

  • Don’t stream the data: instead consider pressing a button to start recording, then after the impact connect the Serial monitor and fetch the recorded data. You’d need (6*5000)=30,000 bytes per second for storage. This is fairly manageable on modern microcontrollers (but definitely not on an Uno - not enough RAM). What microcontroller are you using?

I did not look in detail but it seems like the LIS3DH library could use some improvements:

  • Add a call to change to low power mode

  • Remove ‘Wire.begin()’ from the ‘begin()’ call (our new standard is to have users call this themselves so that they may choose things like clock frequency and it doesn’t get overwritten by subsequent calls)

  • Allow users to specify their own I2C port (Wire, Wire1, Wire2, swWire, etc)

I added an issue to the GitHub repo for this library requesting improvements:

https://github.com/sparkfun/SparkFun_LI … y/issues/7

Yes, this is also a great consideration.

We are only looking for the x-axis data so I have disabled the y and z-axis in the code and removed the serial print commands to see if it helps. It got faster with the original code, however; Paul’s suggestions were significantly more effective to get us up to 1250 samples/second.

The controller is Arduino Uno. The baud rate is set at 115200.

The test runs for 6 seconds flat so there is an opportunity to save it and read the data later. We could consider adding BT but I did not want to add to the complexity as I do not know what is limiting us at this time.

We do appreciate your help. I attached the code in case you had other questions.

Thanks Paymon - FYI I think the attachment failed - I don’t see anything

Good point about the serial speed. Still I wonder about the normal versus low power mode. Paymon can you still try the code to read the registers. I am curious whether it is really in low power mode.

I copied the code in a text file, however; am having difficulty attaching it here. I need to follow up on this item, is it related to my user site permission?

Hello Paul, how do we verify if it is in the normal or low power modes? We are getting 1250 samples/second consistently with your recommended code, thanks.

look at my post from 11 march 6.9. Add that code to you sketch just before you do the measurement. I am interested in the values that are printed and can determine whether it is low power or normal mode