ADXL345: Different between RPi Pico and RPi 3B

I noticed some (for me) inexplicable differences between running an ADXL345 on a RPi 3B compared to a RPi Pico

Setup:

  • Both RPi’s are running Klipper current git
  • Same ADXL board is used for the tests
  • Same cable is used to connect the ADXL to either RPi
  • ADXL is mounted on my printer

RPi Pico Startup issue:
After connecting the RPi Pico to the Klipper RPi, the first measurement will fail with:

Invalid adxl345 id (got f2 vs e5).
This is generally indicative of connection problems
(e.g. faulty wiring) or a faulty adxl345 chip.

Subsequent measurements do work fine. Also reproduced by @w00sh

MEASURE_AXES_NOISE

RPi 3B:

Axes noise for xy-axis accelerometer: 74.778312 (x), 82.936874 (y), 92.104252 (z)

RPi Pico:

Axes noise for xy-axis accelerometer: 444.563409 (x), 393.935782 (y), 532.200080 (z)

Order of magnitude is reproducible. Tested multiple times also spi0a or spi0b behaves the same.
Order of magnitude for the RPi 3B is in line with countless tests, I did on my printer.

TEST_RESONANCES AXIS

Practically testing the resonance measurements with both devices seem to yield comparable results within the expected error margin

X-Axis
(Pico left / Rpi 3B right)

Y-Axis
(Pico left / Rpi 3B right)

Raw Data: Google-Drive

Pinging @dmbutyugin, hoping to shed some light into a possible cause.

I get noise in the thousands with fans on and under 100 with fans off.

The only fan that is running during the measurements is the cooling fan for the TMC drivers. It is running in both cases.

Trying to test @w00sh experience:

Without Fan:

Axes noise for xy-axis accelerometer: 412.634090 (x), 438.330375 (y), 547.795035 (z)

Without Fan and using a different power-supply for RPI3B to which the Pico is connected:

Axes noise for xy-axis accelerometer: 416.011163 (x), 402.645052 (y), 537.584865 (z)

Edit:
Forgot to mention: Even steppers have been off in the above test

I’ve previously made only basic tests with adxl345 (and 343) connected to RPi Pico. It did work for me, but I’ve never made any comparison like that, nor did I run the actual resonance tests in such configuration.

@Sineos

Same cable is used to connect the ADXL to either RPi

But the connectors are different, not sure if that could affect anything though. I guess depends on the cable length.

What you could do is just run instead of MEASURE_AXES_NOISE command the following sequence of commands

ACCELEROMETER_MEASURE CHIP=...
;  wait a few seconds, maybe around ~10 seconds
ACCELEROMETER_MEASURE CHIP=... NAME=adxl345-rpi3

when connected to RPi3 and similarly when connected to RPi Pico (e.g. with NAME=adxl345-pico). Then post the generated raw csv files for analysis.

After connecting the RPi Pico to the Klipper RPi, the first measurement will fail with:

FWIW, I have similar experience with SKR 1.4 (Turbo). I traced it down with a help from an oscilloscope to an initialization of the SPI bus on that board: it seems that some part of the initialization performed by Klipper happens too late on that board, and so CS signal (and probably the whole SPI controller) does not keep up with the first transmission. I wonder if it is similar with RPi Pico? Though after some changes in adxl345 C code and added retries in late 2021, this error is less likely to occur (or more like the retries usually fix it).

Thanks for chiming in @dmbutyugin

In both cases it is exactly the same cable. Using a Cat 5E cable with crimped DuPont connector on the pin headers of the RPi’s

See attached:
20220120_measure.zip (2.3 MB)

Here it is reproducible that the first measurement fails when freshly connecting the Pico or when restarting Klipper with connected Pico

Interesting. It seems that when adxl345 is connected to pico, it is just more noisy:

So, it does not appear to be a problem of communication per se (so there are no large outliers in the data). This could have something to do with the pico powerchain. It’s not very good, btw. You could try a few things:

Set GPIO23 pin on Pico high. E.g.

[mcu pico]
....

[output_pin pico_pwm]
pin: pico:gpio23

and then SET_PIN PIN=pico_pwm VALUE=1.
This may improve the stability of the 3.3V on Pico and reduce ripples in 3.3V line.

Alternatively, depending on which adxl345 board you have, you may try to connect pico 3.3v power to VIN/VCC instead of 3V3 pin. Or, if you have one of the Chinese boards that does not have logic level shifter, connect its VCC to 5V pin (VBUS pico pin, more specifically, pin 40, which comes from USB). Note that if adxl345 has that shifter (e.g. from Adafruit or SparkFun), this will fry Pico, so exercise caution.

Here it is reproducible that the first measurement fails when freshly connecting the Pico or when restarting Klipper with connected Pico

Yeah, I’m not sure why that happens. It won’t be easy to debug without an oscilloscope.

1 Like

@dmbutyugin As usual, your analysis has been spot on. Many thanks.

As far as I have looked at my Adafruit board and also my cheap Chinese boards, they are 5V tolerant but do not do any level shifting. They are just featuring voltage regulators on the ADXL345 VCC side (Ref: Schematic). At least my Pico survived the experiments with both input voltages

Results:

Test 1:

  • ADXL345 (with voltage regulator) connected to its 3V3 pin (bypassing the voltage regulator)
  • Pico Out: 3V3_Out (Pin 36)
  • pico:gpio23 = 0
Axes noise for xy-axis accelerometer: 422.847659 (x), 440.765710 (y), 573.882944 (z)

Test 2:

  • ADXL345 (with voltage regulator) connected to its 3V3 pin (bypassing the voltage regulator)
  • Pico Out: 3V3_Out (Pin 36)
  • pico:gpio23 = 1
Axes noise for xy-axis accelerometer: 2082.481562 (x), 1811.512203 (y), 1468.473208 (z)

Test 3:

  • ADXL345 (with voltage regulator) connected to its Vin pin (using the voltage regulator)
  • Pico Out: 3V3_Out (Pin 36)
  • pico:gpio23 = 0
 Axes noise for xy-axis accelerometer: 61.505179 (x), 65.680486 (y), 125.514755 (z)

Test 4:

  • ADXL345 (with voltage regulator) connected to its Vin pin (using the voltage regulator)
  • Pico Out: 3V3_Out (Pin 36)
  • pico:gpio23 = 1
 Axes noise for xy-axis accelerometer: 34.149376 (x), 38.443227 (y), 68.200905 (z)

Test 5:

  • ADXL345 (with voltage regulator) connected to its Vin pin (using the voltage regulator)
  • Pico Out: VBus (Pin 40)
  • pico:gpio23 = 0
 Axes noise for xy-axis accelerometer: 44.865702 (x), 46.473726 (y), 108.655407 (z)

Test 6:

  • ADXL345 (with voltage regulator) connected to its Vin pin (using the voltage regulator)
  • Pico Out: VBus (Pin 40)
  • pico:gpio23 = 1
Axes noise for xy-axis accelerometer: 47.233344 (x), 41.827197 (y), 106.881142 (z)

Assessment:

  • Using the 3V3 input of the ADXL345 is generally worse than going via its voltage regulator
  • When using the 3V3 input and Pico 3V3 out, setting the GPIO23 to high makes it even worse
  • Connecting the Vin of the ADXL345 AND using Pico 3V3_Out AND setting GPIO23 to high, consistently gives the best results (Test 4)
  • Using VBus (Pin 40) on the Pico improves the situation but is still worse than Test 4
  • When using VBus, the GPIO23 makes no difference

I have verified the measurements at least two times with various Klipper restarts in between. The results are reproducible with my equipment. Both the Adafruit ADXL345 and the Chinese clone (both have a voltage regulator) behave the same with respect to the order of magnitude.

That upper part of the schematics is a logic level shifter on the Adafruit board AFAICT (it brings the ‘1’ level on SDA/SCL pins from 3.3V to VIN level). FWIW, this page also claims that at least some of the boards in the popular form-factor have logic level shifter, but I’m unsure about that. It is good that pico survived, but its docs say strict 3.3V voltage on all pins. So, I would not recommend this setup.

Also, tests 5 and 6 should have produced the same results (the differences are probably just the noise). This is because you power the accelerometer from external 5V, so gpio23 should have no effect.

As for conclusion, it seems that using VIN/VCC pin is generally preferable to use, connected to 3v3 output (FWIW, many Chinese boards do not expose 3v3 pin in the first place). I wonder if it is the case also with RPi v3? If yes, then maybe this should be the preferred option. On Pico, additionally, one could configure gpio23 either as a static_digital_output, or by specifying this pin to set high when compiling the firmware.

Doh, yes, you are right, these are FETs that bring a high to VIN. Brave little Pico, it survived.

Image taken from this site:

I have such a board. What they claim to be a level shifter is a tantalum capacitor with the SMD code 163N1 106C

grafik

Above image is the Adafruit board. I have marked the level shifting FETs in green

So apparently we have 4 different board types:

  • Voltage regulator + Level shifter (Example)
    • 5V tolerant
    • Only suitable with 3V3 as input together with RPi’s as they will output 5V on SDA and SCL if connected to 5V input
  • Only voltage regulator (many Chinese ADXL345 boards) (Example)
    • 5V tolerant
  • ADXL345 without voltage regulator (Example)
    • Only 3V3 input voltage
    • Potentially highest noise impact, at least on the Pico
  • I2C versions
    • I2C interface is too slow for measuring resonances
    • Not suitable

RPi3B with Adafruit ADXL

Vin

Axes noise for xy-axis accelerometer: 66.135597 (x), 74.319175 (y), 115.586080 (z)
Axes noise for xy-axis accelerometer: 64.729976 (x), 68.685450 (y), 112.779932 (z)

3V3

Axes noise for xy-axis accelerometer: 75.956035 (x), 84.278292 (y), 93.680134 (z)
Axes noise for xy-axis accelerometer: 73.335349 (x), 87.497612 (y), 94.576402 (z)

As these results seem inclusive, here a longer measurement:

  • For my RPi3B, indeed the 3V3 input of the Adafruit ADXL seems preferable
  • MEASURE_AXES_NOISE does partially not match longer term measurement, i.e. x and y axis

Verifying Test 4 vs Test 5 with Chinese Clone

  • Chinese Clone with only Vin
  • Pico 3V3 with GPIO23 high vs. Pico Vbus

MEASURE_AXES_NOISE Pico Vin

Axes noise for xy-axis accelerometer: 19.115907 (x), 21.747045 (y), 60.706260 (z)

MEASURE_AXES_NOISE Pico 3V3 GPIO23 high

Axes noise for xy-axis accelerometer: 38.335651 (x), 41.643309 (y), 77.499608 (z)

  • MEASURE_AXES_NOISE does not match longer term measurements
  • Longer term measurement does not show any real difference between Vbus and 3V3 with GPIO23 high
  • Compared to my measurements above, this Chinese clone yields yet other results
  • Raw Data of the GPIO23=1 looks a bit strange. Lots of 0 measurements for the x axis
    pico_w_chinese.zip (3.1 MB)

Verifying Test 2 vs Test 4 with Adafruit

  • Adafruit ADXL345
  • Pico 3V3 with GPIO23 high
  • Adafruit Vin vs. 3V3

MEASURE_AXES_NOISE Adafruit Vin

Axes noise for xy-axis accelerometer: 33.081588 (x), 40.508943 (y), 72.386914 (z)
Axes noise for xy-axis accelerometer: 36.807020 (x), 39.708927 (y), 67.968386 (z)

MEASURE_AXES_NOISE Adafruit 3V3

Axes noise for xy-axis accelerometer: 1962.414723 (x), 1736.280859 (y), 1429.332079 (z)
Axes noise for xy-axis accelerometer: 1971.595544 (x), 1712.454929 (y), 1414.578886 (z)

Seems to make no sense: Mostly 0 values for the x-Axis in the Adafruit 3V3 test. See raw data
adafruit_pico_3v3.zip (1.5 MB)

Overall

grafik

Fan off, China made ADXL345 with regulator, connected to 3.3V on Pico:
Axes noise for xy-axis accelerometer: 18.037788 (x), 25.423976 (y), 68.314371 (z)

Fan on:
Axes noise for xy-axis accelerometer: 7441.054760 (x), 3397.476784 (y), 7453.363937 (z)

Even with such huge noise result, I had great improvement with automatic input shaping.

I tried a different approach now. Would appreciate if @dmbutyugin could comment if it makes sense.

Following boards were used:

  • 2 different Adafruit ADXL345 → adafruit / adafruit2 in the following list
  • A “standard” Chinese board with voltage regulator only → chinese
  • An Adafruit ADXL343 with voltage regulator and level shifter → adxl343

Input to the boards:

  • adxl _vin → ADXL345 with Vin input
  • adxl _3v3 → ADXL345 with 3V3 input
  • Likewise for the other boards when applicable

Following connection schemas have been tested:

  • Pico 3v3 out with GPIO23=0 → pico3V3_gpio_low
  • Pico 3v3 out with GPIO23=1 → pico3V3_gpio_high
  • Pico 5V out via Pin40 → picoVbus
  • RPi 3B on 3V3 pin 17 → rpi3b

Process:

  1. Restart Klipper service
  2. FIRMWARE_RESTART
  3. SET_PIN PIN=pico_pwm VALUE=1 → When applicable by the given test
  4. MEASURE_AXES_NOISE → Only to overcome SPI initialization and check for response
  5. ACCELEROMETER_MEASURE CHIP=adxl345
  6. Wait 20 sec → manually timed with a stopwatch
  7. ACCELEROMETER_MEASURE CHIP=adxl345 NAME=... → NAME according to above schema
  8. Wait 10 sec → manually timed with a stopwatch
  9. FIRMWARE_RESTART
  10. Start over with next test

Results:

  • Goal was to base the evaluation on around 64k samples
  • “Null Samples” → How often a flat 0 showed up in the measurement of the given axis
  • “StaDev” → Standard Deviation of the given axis measurement
  • “Min / Max” → Minimum value and maximum value
  • “Min / Max Sample Time” → Minimum value and maximum value of (Timestamp_n+1 - Timestamp_n)

  • Only a few measurements show a low standard deviation. These values has to be interpreted together with the Null Samples: Lots of Null Samples will have a (unwanted) positive impact on standard deviation
  • Partially over 50% Null Samples: Looking at the other numbers, my feeling is that a Null Sample is quite unlikely to happen, especially not to such an extend
  • Something I realized too late: Different tests show a different sampling time. Not all my tests actually reached >64k values although I tried to time it precisely
  • When taking into account the number of Null Samples and standard deviation, the best result shows the Chinese board (No 7, 15, 16, 21)
  • All Adafruit boards deliver somewhat crappy results: Although possible but 3 defect boards would be hard

Raw Data and Excel:
Google-Drive zip file

Edit:
Forgot to mention one strange thing I cannot explain:

  • The sample times point to 3000 Hz to 3200 Hz
  • With 10 sec measurement time I would have expected around 30,000 to 32,000 values
  • Actually measured are around 64k values
  • Adding up the Sample Times would point to a measurement period of 20 sec

Have you tried reducing the spi_speed setting? The default is 5000000 (5 Mhz) and a minimum of 2000000 (2 Mhz) is needed for the desired 3200 samples/s data rate.

As a guess, it’s possible that the “level shifters” on the adafruit boards are not handling high data speeds well. Going to a slower speed may improve results.

Separately, I only have the “standard chinese” adxl345 boards. I haven’t had any issues with them.

-Kevin

EDIT: after looking at generic LDO output behavior I no longer think that voltage would drop to 2.5v, however, power output could be affected.

@koconnor thanks for your input, Kevin.

I did some spot checks:

  • Same procedure as in my post above
  • Naming convention spi_red1mhz / spi_red2mhzspi_speed under [adxl345] set to 1000000 / 2000000
  • Naming convention rate16rate under [adxl345] set to 1600
  • Results No 17, 18, 19, 20 copied from table above as reference
  • adxl345spi_git_a05f03a_... comparison to nagimov/adxl345spi called with ./adxl345spi -f 3200 -t 10 -s adxl345spi.csv

Observations

  • Reducing spi_speed had no visible effect, even down to 1 MHz still produced the same number of samples with about the same number of Null Samples as with 5 MHz
  • Reducing rate to 1600 halved the number of samples and also the Null Samples. Still ~20% to 75% Null Samples
  • Significant differences between the axes WRT Null Samples: strong concentration on X, nothing on Z
  • adxl345spi tool looks much better, but I not dare to judge this

Raw Data
Google Drive zip file

Thanks for doing this analysis.

Were the boards securely mounted during each test, and was each test run with the boards in the same physical orientation?

FYI, I’m not sure the zero count means that much. I have seen that the adxl345 frequently reports a zero sample when going from positive to negative acceleration. I’ve taken this to be a quirk of the adxl345 sensing mechanism (or perhaps its reporting mechanism). Your spreadsheet doesn’t show the average for each axis, but I wonder if the zero counts are just an artefact of an average closer to zero (and thus more cases where the sensor reacts to positive vs negative acceleration).

Another possible influence is temperature. I wouldn’t be surprised if the sensors changed results slightly with changes in temperature. This could also lead to subtle skewing of the results if heat from the board’s regulator impacts the adxl345…

What’s your goal accuracy for the sensors? Looking at the various stddev results, it seems to me that the sensors are roughly all reporting similar results. The exception seems to be the adafruit boards when powered via 3v3 via pico. Maybe there’s just a bad voltage interaction there…

Cheers,
-Kevin

For every test the boards have been mounted on my printhead. Printer is heavily damped and decoupled from the bench

Printer is in my office / man cave with quite stable 21°C - 22°C

I can do this but due to the lots of Null Samples, I thought it doesn’t make too much sense (since I regarded the Null Samples as faulty). I mean with around 60k to 64k samples having 30k to 50k exactly Zero does not generate too much trust in the measurement, does it?

I’m surely not a statistical expert, but when I have a lot of Null Samples, I do not longer trust the stddev. When looking at the Min / Max values they range anywhere from -3000 to +2500 (for X) (disregarding the 3V3 which are even worse)

I had no specific goal. When playing with the Pico, I noticed it behaved differently on the Pico than on the RPi 3B, so I started digging and noticed numbers that I could not explain. Also the figures did not match up with MEASURE_AXES_NOISE.
Basically when testing resonance or trying new ideas also from @dmbutyugin, it would make sense to measure halfway accurate values and not some crap. Having all the same ADXL345 chip, the results are deviating too much for my taste.

Even if the result of this analysis is to stay clear of Adafruit or to stay clear of boards with level shifter, this would also be worthwhile for other users.
Another result could also be that the test is crap, because in standstill the sensors do not work properly or that it has no influence when actually measuring movement.
This is why I brought it up to the experts :slightly_smiling_face:

FWIW, I’m not sure this is good approach for the adxl345. I think the sensor tends to report 0 around the zero point, but I don’t think that necessarily means it is less accurate in general. Many of the chips (or perhaps boards) will have a bias on each axis - that bias can move the average away from zero and thus result in less zero reports - but that doesn’t necessarily mean the sensor is more accurate.

One way to test for this would be to compare just the Z axis - as it shouldn’t have the “report zero when near zero” issue. I suppose one could also mount the sensor on its side to verify X axis inaccuracy - if you still get lots of zero reports when it is side mounted then it does indicate a problem - if you don’t and the stddev stays roughly the same then it indicates its just a quirk around zero.

Separately, FWIW, the board mounting can introduce a small bias to the axis measurements. The sensors are very sensitive - pressure from hanging wires, pressure from screw tightness, and pressure from gravity can all twist the board enough to cause a bias. (There’s a section on this in the adxl345 datasheet.) I don’t think this bias would have any notable impact on an input shaper resonance test, but it might be enough to skew a measurement of noise.

Cheers,
-Kevin

@Sineos, my few cents:

  • I agree with Kevin in that 0 values do not necessarily mean something is wrong. Ultimately, you had no ambient noise, therefore the values are expected to be near 0. The fact that you have lots of 0 values on X, few on Y and none on Z could indicate that you sensor is nearly perfectly leveled on X axis, tiny bit tilted around X axis so Y is a bit misaligned and picks up some of the freefal gravity, and Z takes most of freefall gravity. Note that the acceleration data is read from adxl345/343 in a single SPI transmission (modulo possible splitting of that transmission into bytes / double-bytes by some HW, probably not by RPiv3). Any broken transmissions are more likely to have some random bits flipped, which would manifest itself as outliers from the mean value, but we don’t see that in your data. In fact, Z axis consistently shows freefall acceleration. It is not very likely that the beginning of an SPI transmission is broken and gives 0 values and the end of the transmission is correct. Therefore, I have little reason to believe that the data is wrong in some way.
  • Similarly, I do not think that level shifter(s) could have any effect on the reading of the data from ADXL345. If they affected the signal quality, I’d expect some transmissions to retrieve incorrect data, with the bits flipped, but that is apparently not the case.
  • You apparently saw sometimes 64k instead of expected 32k samples. However, if you check the measurement range, you see that the measurements were apparently performed over 20 seconds in such cases (e.g. rpi3b_spi_red2mhz_adafruit343_3v3.csv starts at 274.3 sec and ends on 294.9 sec).
  • With pico boards, we can apparently recommend to connect the accelerometer board to 3v3 pin via VIN/VCC pin, and recommend to set gpio23 pin high. It would be great to confirm this finding on other boards and/or by other users. When I have time, I can also repeat this experiment on my pico board. On RPi3 and such, it seems it does not matter too much how to connect the board to it. We may want to recommend also to connect them via VIN/VCC pins for consistency.

Thanks a lot @koconnor and @dmbutyugin. This sound like a valid explanation.

I took another look at the data and in fact, the Null Samples might really be valid data. See these two histogram representations:

Although I have to admit, that I like the first normal distribution much more than the second one.

I will test with a tilt sensor around X and Y to see how the data changes

Please be so kind to revisit this point. I painstakingly followed this process:

  1. Restart Klipper service
  2. FIRMWARE_RESTART
  3. SET_PIN PIN=pico_pwm VALUE=1 → When applicable by the given test
  4. MEASURE_AXES_NOISE → Only to overcome SPI initialization and check for response
  5. ACCELEROMETER_MEASURE CHIP=adxl345
  6. Wait 20 sec → manually timed with a stopwatch
  7. ACCELEROMETER_MEASURE CHIP=adxl345 NAME=... → NAME according to above schema
  8. Wait 10 sec → manually timed with a stopwatch
  9. FIRMWARE_RESTART
  10. Start over with next test

My timing should have been accurate within 0,5 seconds.
All measurements from the first campaign (the first bigger one) returned between 59800 and 67000 samples
Even the measurement with rate: 1600 from the second spot check (following the very same process) returned ~32k samples although only 16k should have returned.
Is it possible that it has internally a 10 seconds buffer that is not reset between step 5 and step 9?