Lis2dw on mellow SHT36 v3 -> Invalid lis2dw id

Didn’t know that. Thought one SPI connection with different devices on it need all the same SPI speed. So I limited MAX and lis2dw. The rest like the TMC chips are limited from older problems with SKR pro and bad TMC boards / clones and I forgot the limits in the config :smiley:

1 Like

Thanks good idea!

Thats not a problem. Only one direction is needed. Dont need the SHT36 back. I need only one SHT36 and I bought also an EBB36 meanwhile as fallback. The Chance that I destroy the board by soldering the fly wires is very high :smiley: Send me a postal adress as PM and I will send it tomorrow out.

2 Likes

5 posts were split to a new topic: CANbus bandwidth usage

FWIW, I have searched my junkyard and found BIGTREETECH ADXL345/S2DW Accelerometer Board for Running Klipper – Biqu Equipment (LIS2DW variant).

It is showing the same behavior. I also agree that soldering around the BGA seems less appealing.

Maybe something like https://www.aliexpress.com/item/1005007922514548.html is better suited.

Hmmm…

void
gpio_peripheral(uint32_t gpio, int func, int pull_up)
{
    padsbank0_hw->io[gpio] = (
        PADS_BANK0_GPIO0_IE_BITS
        | (PADS_BANK0_GPIO0_DRIVE_VALUE_4MA << PADS_BANK0_GPIO0_DRIVE_MSB)
        | (pull_up > 0 ? PADS_BANK0_GPIO0_PUE_BITS : 0)
        | (pull_up < 0 ? PADS_BANK0_GPIO0_PDE_BITS : 0));
    iobank0_hw->io[gpio].ctrl = func << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
}

What if we hack a drive strength here to higher values?

#define PADS_BANK0_GPIO0_DRIVE_VALUE_8MA _u(0x2)
#define PADS_BANK0_GPIO0_DRIVE_VALUE_12MA _u(0x3)

Maybe pullups mess up with the signal?

But, still, a lower SW SPI should cover the edge/slope issues.


jfyi:

Afaik, it works on RRF, and they used 12ma as a value.
So, maybe there is a difference.

wouldnt drive strengh be an issue before the 200 MHz too? 4.7k pullups shouldnt mess with any timing, especially on those short traces.

If it is a timing issue, what about manually controlling the CS pin using [output_pin]?

something like this, instead of CS, gpio24 is the servo pin, which should be unused.

[lis2dw]
cs_pin: SHT36:gpio24
spi_software_sclk_pin: SHT36:gpio2
spi_software_mosi_pin: SHT36:gpio3
spi_software_miso_pin: SHT36:gpio4
spi_speed: 200000

[output_pin cs_pin]
pin: SHT36:gpio12

[gcode_macro test]
gcode:
  SET_PIN PIN=cs_pin VALUE=0
  G4 P1000
  ACCELEROMETER_QUERY 
  SET_PIN PIN=cs_pin VALUE=1
  G4 P1000
  ACCELEROMETER_QUERY
1 Like

From discord debugging with a logic analyzer, it seems like the SPI mode change and timing cause the issue.
So, basically, on the cold start, it errors out because the SCK line goes from default to the required state by SPI mode.

Logic analyzer screenshots


The quirk is that MAX31685 works in the SPI Mode 1.

So, every time we query it, it resets the line back to the default low state.

So, before 200 MHz, there was just more time, so it worked sometimes.
After, it just not.
The SW SPI ensures time between CS and SCK, but does nothing with the timings between prepare and CS. So, it does not help there.
But at least it explains something.

Probably on the dedicated LIS2DW board, the second query would work.

Duct tape like this one does help, probably lower values would also do the job:

diff --git a/src/rp2040/spi.c b/src/rp2040/spi.c
index d2c8df951..1bbfc3c9f 100644
--- a/src/rp2040/spi.c
+++ b/src/rp2040/spi.c
@@ -10,6 +10,7 @@
 #include "internal.h" // pclock, gpio_peripheral
 #include "hardware/structs/spi.h" // spi_hw_t
 #include "hardware/regs/resets.h" // RESETS_RESET_SPI*_BITS
+#include "board/misc.h" // timer_read_time
 
 
 DECL_ENUMERATION("spi_bus", "spi0_gpio0_gpio3_gpio2", 0);
@@ -115,10 +116,12 @@ spi_prepare(struct spi_config config)
     spi_hw_t *spi = config.spi;
     if (spi->cr0 == config.cr0 && spi->cpsr == config.cpsr)
         return;
+    uint32_t end = timer_read_time() + timer_from_us(1);
     spi->cr1 = 0;
     spi->cr0 = config.cr0;
     spi->cpsr = config.cpsr;
     spi->cr1 = SPI_SSPCR1_SSE_BITS;
+    while (timer_is_before(timer_read_time(), end));
 }
 
 void
patched image

But the hardware reason why SCK state is before CS goes down, which affects it, is still mysterious to me.

Thanks.


+2 timer ticks still fixes the issue here.

1 Like

For my BTT LIS board:

  • The first reading fails, but the second and subsequent readings succeed. This is true for both soft and hard SPI.
  • Speeds like 5M, 4M, 3M, 1M, and 500k have no effect. This is the case for both hard and soft SPI (first fail, subsequent succeed).
  • The ADXL345 on a Pico board works normally.

We had a similar issue with the ADXL345 a while back, but it only occurred with hardware SPI, not software SPI. It was fixed in this pull request.

Could you please label the traces on your images.

I think:

  • The top line is MOSI (Data from the RP2040 to the LIS2DW)
  • Next down is MISO (Data from LIS2DW to RP2040)
  • Next down is CS (from RP2040 to LIS2DW)
  • The bottom is CLK (from RP2040 to LIS2DW).

Is this correct?

If it is, then I believe that you are putting the LIS2DW into I2C mode before you start sending data:

The conditions I see above are:

  1. The CS line is high - which enables I2C mode in the LIS2DW
  2. The MOSI line is low - which is the “START” in the image above
  3. The SCK line is dropped - which is the beginning of clocking in the I2C “START”

This may result in the LIS2DW locking up - I2C implementations are fairly arbitrary, depending on how it’s implemented in the chip it could end up hanging waiting on a complete I2C command packet before returning to the basic waiting state (even if the LIS2DW CS line goes low).

This is why Analog, in the ADXL345 Datasheet recommends placing an OR gate on the MOSI line - so an I2C command packet isn’t inadvertently recognized when there is another device on the SPI bus.

I’m not sure what is the best way to eliminate the chance of the LIS2DW incorrectly recognizing the start of an I2C command packet and locking up before there is valid SPI data being sent.

I’m reluctant to say your “duct tape” solution will turn out to be a robust long term solution.

Please confirm my reading of your signals and my interpretation of their timing.

1 Like

Package to @nefelim4ag is out.

Had no time to check the output voltages of the UTOR. I was unsure if nefelim4ag has a CAN board so I added the UTOR to the package to make sure he can debug it.

I2C can be disabled in CTRL2 register. Bit 2 is I2C_DISABLE.
The problem will probably writing to that register without the lis2dw acting weird again.

1 Like

Yes,


RP2040_lis2dw_saleae.zip (99.6 KB)

Just in case, logic analyzer dumps.

About i2c, it is possible that the device is locking in it for some time.

:plus:

I somewhat expected it to have already been done. But seems like we do not touch it.

REG_LIS2DW_CTRL_REG2_ADDR = 0x21
...
            # Disable all filtering
            self.set_reg(REG_LIS2DW_CTRL_REG2_ADDR, 0)

What you’re quoting is:

And I don’t think you’re correctly interpreting what this is saying.

This is “USB to CAN bus bridge mode” - the Main Controller Board is acting as the USB to CAN interface and there is only one path for the control signals. In my opinion, it is the simpler, cheaper and more elegant method of connecting a CAN toolhead.

A “USB to CAN bus” interface is a separate piece of hardware (usually referred to as a “U2C” interface/device) that introduces a second USB bus path and adds to the volume and complexity of communications throughout the printer.

When I said “complexity”, as well as the need for supporting firmware, power and wiring on a separate device, I’m also referring to the strange way the U2C board shown above is wired - we had quite a discussion some time ago about how the U2C board above is actually wired and why (I understand how it is wired but I have no idea why). If you’re thinking of going this route, I highly recommend only using a Canable 2 board without the extra connectors.

Yes, I know that in my diagram above I have marked the lower “USB Cable” going to the USB A connectors on the card which don’t actually connect to USB signals - I did this to keep the diagram simple.


To net things out, I’ve controlled CAN devices both ways in printers and I’ve never experienced a problem. For the past few years, I’ve only run “USB to CAN bus bridge mode” because it is simpler and adding a U2C device adds its own cost and complexity to the system as discussed above.

I’m not really sure of the history behind the manual page saying there can be a problem - I suspect that some people have experienced “Timer Too Close” errors when running with a U2C device that went away when they ran their main controller board in USB to CAN bus bridge mode.

In my experience, CAN works well and is very reliable, regardless of how it is implemented.

1 Like

Nice find!

I agree with your fix - just add a 1us delay if the SPI settings change. That code path doesn’t happen frequently enough to worry about, and similarly a 1us delay in task context isn’t worth worrying about.

One note, the delay has to be relative to the time after the SCLK pin change or it doesn’t actually enforce a delay (in the event of a timer irq):

--- a/src/rp2040/spi.c
+++ b/src/rp2040/spi.c
@@ -119,6 +119,10 @@ spi_prepare(struct spi_config config)
     spi->cr0 = config.cr0;
     spi->cpsr = config.cpsr;
     spi->cr1 = SPI_SSPCR1_SSE_BITS;
+    // Give time for state to update before caller changes CS pin
+    uint32_t end = timer_read_time() + timer_from_us(1);
+    while (timer_is_before(timer_read_time(), end))
+        ;
 }
 
 void

Other chips (such as stm32h7) are also likely impacted by this.

-Kevin

1 Like

Okay, I’ve received the package.
Well, from signal integrity, it really seems fine.
So, it is probably a hardware quirk.
Yellow is SCK, blue is CS.

Oscilloscope shots


(they are crazy small :D)


(I got ground from the RGB connector, it was just handy)

I will take a look and see if it is possible to harden it from the lis2dw Python side, with registers, etc.

@ChiiSama thank you, again!


Okay, I did check the CTRL2 register.
Unfortunately, disabling I2C support does not help at all.


MAX31865 does support the SPI mode 3. So, simply switching it to this mode, also seems like a “fix”.
(it works).


PR: LIS2DW: make it work when spi bus polarity is switching by nefelim4ag · Pull Request #6944 · Klipper3d/klipper · GitHub

5 Likes