Odd behavior with SPI access (ID Reg sometimes read with 0xFFFFFFFF)

Hello there!

I’m having some strange issue with the SPI transactions with the DW1000. I’m trying to pair two DW1000 (resp. DWM1000) on an NXP/Freescale Kinetis MK64 platform. I’m using the Decawave demo code and I was already able to pair two devices (simple transmit and receive). So things cannot be very wrong…

However, I’m observing failed initializations often. They result in an apparently disfunctional DW1000. That is, when I read the ID register I’m receiving 0xFFFFFFFF only. I found out that this issue is triggered with the very first write operation into a register of the DW1000. I.e. I reduced the code to a simple Read ID Register and Write Register (writing a 0x01 into register 0x01) sequence and looping that one. Often I’m not reading the proper ID register value but all 1s. When I skip the write operation, reading the ID register is working always.

I know that reading all 1s can also mean that the device is
in DEEPSLEEP. But I never placed it there, and sometimes reading the ID register is working again. I’m not seeing any odds on the oscilloscope during the SPI transfers. I’m using slower SPI frequencies - 2MHz, 1MHz, 500kHz…

SPIPHA and SPIPOL are left open and WAKEUP is connected to ground.

I also do not have an explanation why the whole system is sometimes working (i.e. TX on one system, RX on another one), and is working stable over longer periods. So it seems that only the initialization phase is somehow critical.

Power-Cycling does also seem to help to bring out the DW1000 out of this strange state. I.e. after a power up the very first read of the ID register is working always.

Does anybody have an idea what could go wrong here?

Thanks,
Mario

Some update on that:

It turned out that it’s not an arbitrary write that is causing the confusions (I wrote above that writing register 0x01 is causing the problem).

It seems that the problem is triggered somewhere within dwt_softreset() (referring to deca_device.c of the DWS1000 sample code).

When I execute dwt_initialise() once, it mostly fails in subsequent attempts because the ID Reg does not read 0xDECA0130 but 0xFFFFFFFF. dwr_initialise() is called with DWT_LOADNONE - just as in case of the simple RX/TX examples of the DWS1000 sample code.

I tried to cut down the initialization sequence and did virtually end it after the very first write operation,
which is
dwt_writetodevice(PMSC_ID, PMSC_CTRL0_OFFSET, 1, &reg[0]);
in _dwt_enableclocks().
This write operation alone does trigger the problem.
Though, in contrast to register 0x01 the PMSC_ID register might be a critical one, and this write operation alone might leave the device in some critical state. However, completing the full initialization code is not making things better.

Btw., I did also try to read back the values I wrote into register 0x01 and I get back what I wrote. So this seems to be ok in general. Though, I did not ye test this specifically when the DW1000 is in this critical situation. My guess ist, that reading register 0x01 is also returninf 0xFF in that case.

Anyway, I’ll continue to hunt for the cause of this behavior and will report here accordingly…

Greeting,
Mario

Try to eat flys separatly from cotlets. Id est try to begin from discowering actual SPI signals and timings using an digital oscilloscope. After that check the actual MISO sampling moment of your uC. And then look at the spi code and dw1000 api.

Regards,
Dan

Check SPI nCS signals and MISO conflicts on the line. Some electrical levels can be changed when you pair devices on the same line, due to additional cappacitance and loadings. Try to lower SPI speed below 500kHz and check differences. Hope this can help.

Regards,
Dan

@Dan thanks for your input.
SPI timing and sampling points seem ok. SPI line conflicts can be ruled out, as the DW1000 is the only device attached to the bus.

I tested also an SPI clock rate of 100kHz and it is no game-changer…
Though, what is a bit strange with that particular uC is that in case of back-to-back byte transfers via DMA the SPI clock low period between the last falling edge of a transmitted byte and the first rising edge of the next byte is fixed to approx. 150ns regardless of the setup clock rate. This seems a bit odd to me and I don’t know yet whether this can be fixed somehow. However, the setup times required by the DW1000 are met nonetheless. Furthermore in earlier attempts I changed the SPI handling in a way so that I manually transfer single bytes causing very long low periods of the clock in between the bytes. This did not eliminate the problem.

One more thing: I should emphasize that the problem does not seem to be related with the SPI transfer or the SPI handling within the uC alone, because I already see on the oscilloscope that the DW1000 is not returning proper data when reading the ID Reg. Though, I cannot rule out yet that the DW1000 is sometimes receiving odd writes causing that behavior…

Greetings,
Mario

DW1000 has two modes of SPI timings. When you call “Init” DW1000 can some times be switched to low speed mode. It that mode 150ns byte2byte is not enought. Then second reason the particular DW IC can have an electrical damage on SPI pins, try to use another DW IC in that case.

look at the example code from DW soft package when calling init function:

spi_set_rate_low();
dwt_initialise(DWT_LOADNONE);
spi_set_rate_high();

Check datasheet on page 26 table B.
Minimum 205ns byte2byte time

@Dan Damage is always possible, of course. However, I’m having two devices here (also two uC-kits). Both show the same behavior. Furthermore in case of such hardware damage I would not expect that reading the ID Reg and writing/reading Reg 0x01 in a loop would be working flawlessly, and problems only arise after the execution of the initialization code.

I’m aware about these low and high speed SPI modes of the DW1000. The demo code is switching to 2.5MHz in spi_set_rate_low() and to 18MHz in spi_set_rate_high(). For first tests I decided to not do any switching and stay on a lower clock rate. I decided to go with 2MHz (max. is 3MHz). But as written above, even with 100kHz the issue is the same. So it seems the issue is not related with the clock speed.

These 205ns byte2byte refer to the time of the rising clock edge of the last bit to the time when the data of the first bit of the next byte is applied at MOSI (not sure whether this is correct - perhaps this is actually means the delay from the rising clock edge of the last bit to the rising clock edge of the first bit of the next byte).

Anyway, in order to rule out that matter I reverted the transmission again to that scheme where bytes are sent one by one with rather large delays resp. clock low phases in between. This does not change anything.

Regards,
Mario

Are you sure you mean Reg 0x01(8 byte RW register) insted of Reg 0x00 (4 byte RO =DECA0130)?

init code do nothing if Reg 0x00 readed as FFFFFFFF

but Reg 0x01 can be replaced by value from OTP during initialisation.
Only in IDLE state of DW1000 IC it is allow to change Reg 0x01 value.

@Dan Yes, I took Reg 0x01 as a simple scratchpad register for testing purposes in order to check whether writing registers is working. This is just the EUI code which would be mostly loaded from the OTP later on.

In a loop I did check whether 0x00 reads 0xDECA0130, then doing 256 times writing and reading back 0, 1, 2, …, 255 into Reg 0x01 with 8 bit writes and verify whether the value read back does match the written one. This is working absolutely smooth. I extended this by writing 16 bit values to Reg 0x01 and reading them back, looping all the way from 0 to 65535. This is working also perfect.

So my conclusion is that there is no issue with any SPI timings, physical damages or whatsoever.

But I’m executing this test-loop before calling any DW1000 initialization code. When Reg 0x01 can only be changed in Idle mode this is probably not an issue here, as the DW1000 should be in that mode that time.
Anyway, that is just an independent test that I’m not using for the regular firmware.

One more thing I observed: After many attempts to bring up my receiver-system so that it is properly receiving and displaying frames sent by the sender-system, I did change the call of the initialization function from dwt_initialise(DWT_LOADNONE) to dwt_initialise(DWT_DW_WAKE_UP). I did restart the system without power-cycling (I’m also not using the reset pin of the DW1000 yet), and it came up flawlessly in many successive attempts.

Greetings,
Mario

What steps do I need to do to see issue on my site?

With DWT_DW_WAKE_UP the init code do not exec SoftReset code.
SoftReset code has function like this:

// DW1000 needs a 10us sleep to let clk PLL lock after reset - the PLL will automatically lock after the reset
// Could also have polled the PLL lock flag, but then the SPI needs to be < 3MHz !! So a simple delay is easier
deca_sleep(1);

The function deca_sleep() is platform dependent. Check if it actually do waiting.

@Dan Well, I guess in order to reproduce it there is needed the same uC and tool chain. I think this needs to be solved from a more formal level. I.e. the question is merely: “What circumstances might lead to that behavior”. Perhaps I will also try something else here…

Yes, I had the to implement deca_sleep() on myself and I did it as wrapper around OSA_TimeDelay() of the Kinetis 1.3 SDK which is essentially the same. In fact, I found out that OSA_TimeDelay() is not working for delays smaller than 3ms for some reasons. I fixed that by ensuring that OSA_TimeDelay() is called to wait for at least 3ms. So a deca_sleep(1) turns into a OSA_TimeDelay(3). However, that does not seem to be the root-cause anyway. I did also step through the whole initialization routine step by step with lots of delay in between subsequent tasks and the problem is still the same.

Regards,
Mario

If you call dwt_initialise(int config) it returns immediately if REG 0x01 reads as 0xFFFFFFFF. So if problem exists it is somewhere in hardware driver/circuit.

// code
if (DWT_DEVICE_ID != dwt_readdevid()) return DWT_ERROR ;

@Dan Yes, that position is the only one in dwt_initialise() which is returning DWT_ERROR.

It should be noted again that this check is NEVER failing when executed after a power cycle. The problems start after some of the initialization code has been executed. In the mean time I also added a second check of the ID reg after the initialization in order to ensure that the DW1000 did really not crash (because the initialization is done more or less blindly without feedback from the DW1000).

In case it is a hardware issue, how do the follwing facts match that scenario?

  1. Reading the ID reg PRIOR to initialization code execution seems to be NEVER failing.
  2. Large loops executed PRIOR to initialization code execution that is reading the ID reg and writing/reading/verifying other regs (reg 0x01 in particular) seems to be NEVER failing.
  3. In those few cases where initialization has passed the actual operation seems perfect. I can transmit and reveive frames over hours with the code based on the simple TX and simple RX examples.

Regards,
Mario

If I can’t to reproduce the error, and can’t see this behaviour in my design, I suppose the cause is in difference of our hw/sw designs.
I really want to understand what triggers this behaviour to verify my design too.
I also know some IC design problem still exist (see DW1000 Errata). In some cases of RX error, for example, it is needed to reset DW1000. But your design behaviour looks like yet another problem may exist.

@Dan I appreciate your support in this. But of course, your insight is similarly limited like mine…

In the mean time I did not find the smoking gun, but at least some sort of smoke. The data sheet of the DW1000 suggests that in SPI mode 0 data on MOSI is sampled with the rising clock edge and output on MISO with the falling clock edge (table 17 on page 25). Figure 22 on page 23 suggests that with mode 0 (SPIPOL=0 & SPIPHA=0) both data sampling and output is done with the rising edge. This is conflicting with table 17. But anyway, my oscilloscope is telling me clearly that data provided on MISO is changed with the rising clock edge and not with the falling edge.

Initially I set up the SPI system of the Kinetis uC to be compatible with figure 22. As long as the PMSC register is not written in _dwt_enableclocks() everything seems fine. That is, although the DW1000 is changing MISO at the rising edge, the timing is still ok for the Kinetis uC. But writing the PMSC register is changing the situation. In particular, a 0x01 is written into PMSC[0], which means that the system clock is set to a “19.2MHz XTI clock”. Apparently this is changing SPI timings and thing are going [mostly] nuts from this moment on. My guess is that they are ok again when the system clock setting in PMSC[0] is set back to its normal value.

Right now I’m trying to get a working setup by playing around with SPIPOL and SPIPHA as well as SPI settings in the Kinetis uC. I’ll come back with a solution, hopefully…

In the mean time I did also find that thread in the forum:

Things are a bit different here, but also similar. The sporadic errors reported there might also be a result of some SPI issues during device initialization. Unfortunately, the thread does not discuss the matter to the end. @jbmillard maybe you can let us know what was your final solution here?

Thanks and regards,
Mario

As I descovered before, the master must sample just before set CLK to low.
DW will change its output after CLK transition from high to low not immediately but after fixed time.
If you sample at CLK 0->1 it will work ok only at high speed. But will not work when you switch SPI clock to lower speed. Try to sample just before switch spi clk line to low in mode 0.