cancel
Showing results for 
Search instead for 
Did you mean: 

LIS3DSH SPI interface issue (bug??)

Rick Schue
Associate II
Posted on June 20, 2018 at 17:39

I've been beating my head against the wall for the last couple of days trying to figure out why I cannot read registers at odd addresses through the LIS3DSH SPI interface with the nRF52832.  Byte accesses to even addresses work fine, but byte accesses to odd addresses always return the value of the register at the even address one location lower.  16-bit accesses only work when the address is even.  It seems like the LSB of the register address is always read by the LIS3DSH as a zero.

Communicating via the I2C bus works fine - bytes, words, even and odd alignment are all OK.

So, it looks to me like the LIS3DSH has a bug in the SPI interface.  My best guess is that the last bit of the address is not correctly latched internally by the rising edge of SCL, and must be held static until the next falling edge of SCL (at which time the LIS3DSH starts to drive the data bus).

Here's my proof:

Shown below is a logic analyzer capture with showing a single byte read of the WHO_AM_I register (address 0x0F).   The bottom 4 traces are a delayed (expanded) version of the top four. Here, I drive MOSI (SDI) to zero after the rising edge of the 8th clock in the ''address'' phase of the transfer.  The hold time is shown to be about 460nsec.  You can see that the data (MISO) returned during the next 8 clocks is 0x00 (corresponding to register 0x0E, INFO2).

0690X00000604csQAA.jpg

In the second capture, I hold the last bit of the address until the falling edge of that same clock.  Here, the data returned is correct for WHO_AM_I (0x3F).

0690X00000604RCQAY.jpg

The data sheet says the hold time is only 15 nsec, relative to the rising edge of SCL.  It looks like you have to hold the 8th bit of the address (and only the 8th bit) until the falling edge of SCL.

So, is this a bug in the chip?  I didn't see any mention of this in the errata sheet.

This is not a problem if the last bit of the address is held static through the data transfer.  In my case, I'm now bit-banging the I/O ports, so I merely leave the MOSI (SDI) pin in its last state. 

Unfortunately the built-in SPI interface of some micro's (like the nRF52832) drive the MOSI line low immediately after the last bit of the address is clocked out during read operations. This means you can't do individual byte reads of registers at odd addresses.  The work-around would be to do a word-aligned 16-bit read and select the proper byte. Fortunately the 16-bit X, Y, and Z data values in the LIS3DSH are word aligned and 16-bit SPI reads with chips like the nRF52832 work fine.

11 REPLIES 11
Posted on June 20, 2018 at 17:52

Are you sure the CS pin stays high long enough? Looks awfully short

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on June 20, 2018 at 18:40

I'm bit-banging the SPI lines, so it's hard to violate any set-up or hold times.  In this case, the CS hold time relative to SCL going high is about 440 nsec.  Data sheet spec is 8 nsec.

I'm not familiar with any minimum CS high spec.  There's none in the data sheet.  It would be dictated by the minimum SCL period and the set-up and hold times relative to SCK.

In the example shown, CS is high for about 700 nsec.

GioP
Associate II
AK.08
Associate III

I am facing similar issue with I2C. can anyone guide me on how to proceed?

Rick Schue
Associate II

When I switched the interface to I2C, everything worked fine (see my original post). The problem I noticed was only with the SPI interface.

What issues are you seeing with the I2C interface?

Rick

I am implementing the wake up state machine. All the registers I am configuring according to whats mentioned in the application note. I am unable to write into register 1. after writing 0x01 to it, when I read it, its 0x00. all other registers work fine. Is there any sequence to write into the registers or something that I might be missing?

Rick Schue
Associate II

I've not used with any of the state machine features of the LIS3DSH and I've not looked at the Ap Note in detail.

The application note (AP3393) "Wake Up" example makes reference to CTRL_REG1 (address 0x21)? Is this what you mean by "register 1"?

If so, you should be able to write and read it.

Some more questions:

  1. With regard to CTRL_REG1, if you write another bit pattern into to it and read it back, do the other bits function? Is it just a problem bit bit 0 in the register, or does any value written always read back as 0x00?
  2. When you say "all the other registers work fine", does that include the other registers in this vicinity - like CTRL_REG4 (address 0x20) and CTRL_REG3 (address 0x23)? Can you write and read back random bit patterns in those registers?
  3. Have you tried any of the other simple examples in the Ap Note - like "Toggle"?

Rick

Yes I meant CTRL_REG1(0x21).

  1. I have tried writing other bits too, it is read back always as 0x00.
  2. Yes, it includes CTRL_REG3 and REG4.
  3. I have tried the freefall state machine, but since I am unable to write into CTL_REG1, the state machines are not enabled.
Rick Schue
Associate II

Sorry you're having problems. I hooked up an LIS3DSH to my Bluefruit Feather board this morning and typed in the Wake-up example in AP3393 and it appears to work fine. I can load all the registers with the values shown and read them back and get the same results, including CTRL_REG1. I can shake the board and the INT1 line goes high (although it does not return low after the motion stops).

My code uses direct pin I/O to implement the I2C interface - I don't use the Arduino "Wire" library, as I've never trusted it to implement the repeated start condition.

At this point, it's either a problem in your code, or you've got a bad device. Is there anything different you're doing when you write CTRL_REG1 that you are doing differently with the other registers? For example, are you programming the I2C transfers in "straight line code" or are you calling a function and passing the register number and data value as parameters?

Rick