DW1000 can't receive at all due to CLKPLL_LL being set constantly

I have one DW1000 module which I program the exact same way as my other DW1000 module, however, it can only transmit but never receive because the CLKPLL_LL bit is set, even if I set TRXOFF:

def waitForSuccessfulReceive(self):
    start_time = time.time()
    self.activateReceiver()
    while True:
        SYS_STATUS = self.read(reg_addr=0x0F, sub_reg_addr=0x00, len=5)

        RXFCG = SYS_STATUS[1] & (1 << 6)
        RXDFR = SYS_STATUS[1] & (1 << 5)

        LDEERR = SYS_STATUS[2] & (1 << 2)
        RXFCE = SYS_STATUS[1] & (1 << 7)
        RXPHE = SYS_STATUS[1] & (1 << 4)
        RXRFSL = SYS_STATUS[2] & 0x01

        RXRFTO = SYS_STATUS[2] & (1 << 1)
        RXPTO = SYS_STATUS[2] & (1 << 5)
        RXSFDTO = SYS_STATUS[3] & (1 << 2)

        LDEDONE = SYS_STATUS[1] & (1 << 2)

        RFPLL_LL = SYS_STATUS[3] & 0x01
        CLKPLL_LL = SYS_STATUS[3] & (1 << 1)

        if RXFCG != 0 and RXDFR != 0 and LDEDONE != 0:
            break
        if time.time() - start_time > 1.0:
            break
        elif RFPLL_LL != 0:
            print("RF PLL Losing Lock")
        elif CLKPLL_LL != 0:
            print("Clock PLL Losing Lock")
            self.disableTransceiver()
            time.sleep(0.01)
            self.activateReceiver()
        elif LDEERR != 0:
            print("Leading edge detection processing error")
            self.activateReceiver()
        elif RXFCE != 0:
            print("Receiver CRC error")
            self.activateReceiver()
        elif RXPHE != 0:
            print("Receiver PHY Header error")
            self.activateReceiver()
        elif RXRFSL != 0:
            print("Receiver Reed Solomon Frame Sync Loss")
            self.activateReceiver()
        elif RXRFTO != 0:
            print("Receive Frame Wait timeout")
            self.activateReceiver()
        elif RXPTO != 0:
            print("Preamble detection timeout")
            self.activateReceiver()
        elif RXSFDTO != 0:
            print("Receive SFD timeout")
            self.activateReceiver()

Is my module broken - what is causing this?

Can someone help me please? I have the same problem with two other modules and I don’t know what to do

Hi @maxG
the datasheet says it clearly - the PLL is having a locking issues. This seems to be related to some HW issues. Could you post schematics and PDB Gerber files - I can take a look at it if you want.

In general I could be a bad wiring around Xtal, some noise around PLL parts or noisy power line.

Cheers
JK

1 Like

Hi,

I use this board:

and I basically just connected SPI, GND and VCC to a Raspberry Pi 4 (using loose wires) with a single 220nf capacitor between GND and VCC.

Do you know why this seems to happen predominantly in RX-mode?

Hi @maxG
the RX mode needs much more power. What I would expect here is that the RPi4 generates too noise into the 3V3 that it corrupts the DW3K chip.

How do you power the RPi4?

Cheers
JK

Replace that 220nF with something more like 10uF. The module already contains smaller high frequency capacitors. But if you are connecting power over wires from source that could be being pushed towards it’s upper output limit then a large local capacitor right on the modules power pins could make a difference.

Hi JK,

I use a 15W power supply which powers the RPi via USB-C.
Up to this point I still could not resolve the issue.

We bought 4 new modules and the error still appears on some of them.
I mean, in the end this is not a well tested module.

Hi @maxG
they sold tons of them so they are 100% OK, did you follow AndyA recommendation? The DW1000 is sensitive to noise in power which I guess is your problem. I have checked one of my old design fpr RPI and I created a carrier board for DW1000 where I have used 5V as a power source and then I used Hi speed LDO to feed the DW1000.

I would not recommend to power directly the DW1000 from 3V3 RPi power line.

Cheers
JK

We used a dozen or so of those modules for early development and I’ve never seen this issue. That was a while ago, I suppose it’s possible that with current supply chain issues there may have been a part substitution that caused this problem for new units.
But my guess is that it’s more a design implementation issue than a fundamental part issue. No RF part likes a noisy power supply. Low price consumer electronics is all about cutting all the corners you can, if that means the power supply is noisy then that’s fine. Especially if it’s sold as a bare board and so doesn’t need to go through emissions testing.

@AndyA @leapslabs
I’ve tried basically every combination of capacitors, also above 10µF.
This is so frustrating. I never had this problems with the ESP32, which also is a consumer RF-module and it operates at a similar frequency.

If you look for “DW1000 CLKPLL_LL” you will find a bunch of posts so I am definately not the only one having this problem. The weird thing is I have two modules that work fine and don’t have this error (and no, it doesn’t have a larger capacitor)

Hi @maxG
the DW1000 is very sensitive to noise in its power line much more than ESP32. Try to power it up from external low noise LDO first. If it not help then we can try to look after different solution.

Adding large capacitor does not always mean they the noise in the power path will decrease. For proper filtration you need to use proper combination of inductor and capacitors.

Cheers
JK

1 Like

I have looked at VDD with an oscilloscope and it varies up to 250mV.
The other thing I was wondering about: Is there any known configuration mistake that could produce this error? I read the chapter about initial configuration of the DW1000 User Manual probably 10 times and reproduced all the register values but maybe there is something to my configuration which produces this error?

Ok it is definately related to my configuration. Can someone please check this configuration? I basically just copied the chapter “2.5.1 Default System Configuration”:

DEV_ID = self.read(reg_addr=0x00, sub_reg_addr=0x00, len=4)
print(
	f"Device-ID: REV: {DEV_ID[0] & 0x0F}, VER: {DEV_ID[0] >> 3}, MODEL: {DEV_ID[1]}, RIDTAG: {hex(DEV_ID[3] << 8 | DEV_ID[2])}")

# DataRate = 6.8Mbps
# Preamble Symbols = 128
# PRF = 16MHz
# PAC size = 8
# Standard SFD
# TX-Channel: 5
# TX_PCODE: 3
# RX-Channel: 5
# RX_PCODE: 3

SYS_STATUS = self.read(reg_addr=0x0F, sub_reg_addr=0x00, len=5)
CPLOCK = SYS_STATUS[0] & (1 << 1)
CLKPLL_LL = SYS_STATUS[3] & (1 << 1)
print(f"CPLOCK: {CPLOCK != 0}, CLKPLL_LL: {CLKPLL_LL != 0}")
if CLKPLL_LL != 0:
	self.write(reg_addr=0x0F, sub_reg_addr=0x00, data=[0, 0, 0, 0, 0])

self.write(reg_addr=0x23, sub_reg_addr=0x04, data=0x8870.to_bytes(2, byteorder='little'))
AGC_TUNE1 = self.read(reg_addr=0x23, sub_reg_addr=0x04, len=2)
print(f"Modified AGC_TUNE1 to {hex(AGC_TUNE1[1] << 8 | AGC_TUNE1[0])}")

self.write(reg_addr=0x23, sub_reg_addr=0x0C, data=0x2502A907.to_bytes(4, byteorder='little'))
AGC_TUNE2 = self.read(reg_addr=0x23, sub_reg_addr=0x0C, len=4)
print(
	f"Modified AGC_TUNE2 to {hex(AGC_TUNE2[3] << 24 | AGC_TUNE2[2] << 16 | AGC_TUNE2[1] << 8 | AGC_TUNE2[0])}")

self.write(reg_addr=0x23, sub_reg_addr=0x12, data=0x0035.to_bytes(2, byteorder='little'))
AGC_TUNE3 = self.read(reg_addr=0x23, sub_reg_addr=0x12, len=2)
print(f"Modified AGC_TUNE3 to {hex(AGC_TUNE3[1] << 0 | AGC_TUNE3[0])}")

self.write(reg_addr=0x27, sub_reg_addr=0x02, data=0x0001.to_bytes(2, byteorder='little'))
DRX_TUNE0b = self.read(reg_addr=0x27, sub_reg_addr=0x02, len=2)
print(f"Modified DRX_TUNE0b to {hex(DRX_TUNE0b[1] << 8 | DRX_TUNE0b[0])}")

self.write(reg_addr=0x27, sub_reg_addr=0x04, data=0x0087.to_bytes(2, byteorder='little'))
DRX_TUNE1a = self.read(reg_addr=0x27, sub_reg_addr=0x04, len=2)
print(f"Modified DRX_TUNE1a to {hex(DRX_TUNE1a[1] << 8 | DRX_TUNE1a[0])}")

self.write(reg_addr=0x27, sub_reg_addr=0x06, data=0x0020.to_bytes(2, byteorder='little'))
DRX_TUNE1b = self.read(reg_addr=0x27, sub_reg_addr=0x06, len=2)
print(f"Modified DRX_TUNE1b to {hex(DRX_TUNE1b[1] << 8 | DRX_TUNE1b[0])}")

self.write(reg_addr=0x27, sub_reg_addr=0x08, data=0x311A002D.to_bytes(4, byteorder='little'))
DRX_TUNE2 = self.read(reg_addr=0x27, sub_reg_addr=0x08, len=4)
print(
	f"Modified DRX_TUNE2 to {hex(DRX_TUNE2[3] << 24 | DRX_TUNE2[2] << 16 | DRX_TUNE2[1] << 8 | DRX_TUNE2[0])}")

self.write(reg_addr=0x27, sub_reg_addr=0x26, data=0x0028.to_bytes(2, byteorder='little'))
DRX_TUNE4H = self.read(reg_addr=0x27, sub_reg_addr=0x26, len=2)
print(f"Modified DRX_TUNE4H to {hex(DRX_TUNE4H[1] << 8 | DRX_TUNE4H[0])}")

LDE_CFG1 = (3 << 5) | 13 # PMULT, NTM
self.write(reg_addr=0x2E, sub_reg_addr=0x0806, data=[LDE_CFG1])
LDE_CFG1 = self.read(reg_addr=0x2E, sub_reg_addr=0x0806, len=1)
print(f"Modified LDE_CFG1 to {hex(LDE_CFG1[0])}")

self.write(reg_addr=0x2E, sub_reg_addr=0x1806, data=0x1607.to_bytes(2, byteorder='little'))
LDE_CFG2 = self.read(reg_addr=0x2E, sub_reg_addr=0x1806, len=2)
print(f"Modified LDE_CFG2 to {hex(LDE_CFG2[1] << 8 | LDE_CFG2[0])}")

self.write(reg_addr=0x1E, sub_reg_addr=0x00, data=0x0E082848.to_bytes(4, byteorder='little'))
TX_POWER = self.read(reg_addr=0x1E, sub_reg_addr=0x00, len=4)
print(f"Modified TX_POWER to {hex(TX_POWER[3] << 24 | TX_POWER[2] << 16 | TX_POWER[1] << 8 | TX_POWER[0])}")

self.write(reg_addr=0x28, sub_reg_addr=0x0C, data=0x001E3FE0.to_bytes(4, byteorder='little'))
RF_TXCTRL = self.read(reg_addr=0x28, sub_reg_addr=0x0C, len=4)
print(
	f"Modified RF_TXCTRL to {hex(RF_TXCTRL[3] << 24 | RF_TXCTRL[2] << 16 | RF_TXCTRL[1] << 8 | RF_TXCTRL[0])}")

self.write(reg_addr=0x28, sub_reg_addr=0x0B, data=[0xD8])
RF_RXCTRLH = self.read(reg_addr=0x28, sub_reg_addr=0x0B, len=1)
print(f"Modified RF_RXCTRLH to {hex(RF_RXCTRLH[0])}")

self.write(reg_addr=0x2A, sub_reg_addr=0x0B, data=[0xC0])
TC_PGDELAY = self.read(reg_addr=0x2A, sub_reg_addr=0x0B, len=1)
print(f"Modified TC_PGDELAY to {hex(TC_PGDELAY[0])}")

self.write(reg_addr=0x2B, sub_reg_addr=0x07, data=0x0800041D.to_bytes(4, byteorder='little'))
FS_PLLCFG = self.read(reg_addr=0x2B, sub_reg_addr=0x07, len=4)
print(
	f"Modified FS_PLLCFG to {hex(FS_PLLCFG[3] << 24 | FS_PLLCFG[2] << 16 | FS_PLLCFG[1] << 8 | FS_PLLCFG[0])}")

self.write(reg_addr=0x2B, sub_reg_addr=0x0B, data=[0xBE])
FS_PLLTUNE = self.read(reg_addr=0x2B, sub_reg_addr=0x0B, len=1)
print(f"Modified FS_PLLTUNE to {hex(FS_PLLTUNE[0])}")

CHAN_CTRL = (3 << 27) | (3 << 22) | (1 << 18) | (5 << 4) | 5 # RX_PCODE, TX_PCODE, RXPRF, RX_CHAN, TX_CHAN
self.write(reg_addr=0x1F, sub_reg_addr=0x00, data=CHAN_CTRL.to_bytes(4, byteorder='little'))
CHAN_CTRL = self.read(reg_addr=0x1F, sub_reg_addr=0x00, len=4)
print(f"Modified CHAN_CTRL to {hex(CHAN_CTRL[3] << 24 | CHAN_CTRL[2] << 16 | CHAN_CTRL[1] << 8 | CHAN_CTRL[0])}")

self.write(reg_addr=0x2E, sub_reg_addr=0x2804, data=0x51EA.to_bytes(2, byteorder='little'))
LDE_REPC = self.read(reg_addr=0x2E, sub_reg_addr=0x02804, len=2)
print(f"Modified LDE_REPC to {hex(LDE_REPC[1] << 8 | LDE_REPC[0])}")

self.write(reg_addr=0x24, sub_reg_addr=0x00, data=0x00000004.to_bytes(4, byteorder='little'))
EC_CTRL = self.read(reg_addr=0x24, sub_reg_addr=0x00, len=4)
print(f"Modified EC_CTRL to {hex(EC_CTRL[3] << 24 | EC_CTRL[2] << 16 | EC_CTRL[1] << 8 | EC_CTRL[0])}")

SYS_STATUS = self.read(reg_addr=0x0F, sub_reg_addr=0x00, len=5)
CPLOCK = SYS_STATUS[0] & (1 << 1)
CLKPLL_LL = SYS_STATUS[3] & (1 << 1)
print(f"CLKPLL_LL: {CLKPLL_LL != 0}, CPLOCK: {CPLOCK != 0}")
if CLKPLL_LL != 0:
	self.write(reg_addr=0x0F, sub_reg_addr=0x00, data=[0, 0, 0, 0, 0])

This gives me the output

Device-ID: REV: 0, VER: 6, MODEL: 1, RIDTAG: 0xdeca
CPLOCK: True, CLKPLL_LL: False
Modified AGC_TUNE1 to 0x8870
Modified AGC_TUNE2 to 0x2502a907
Modified AGC_TUNE3 to 0x35
Modified DRX_TUNE0b to 0x1
Modified DRX_TUNE1a to 0x87
Modified DRX_TUNE1b to 0x20
Modified DRX_TUNE2 to 0x311a002d
Modified DRX_TUNE4H to 0x28
Modified LDE_CFG1 to 0x6d
Modified LDE_CFG2 to 0x1607
Modified TX_POWER to 0xe082848
Modified RF_TXCTRL to 0xde1e3fe0
Modified RF_RXCTRLH to 0xd8
Modified TC_PGDELAY to 0xc0
Modified FS_PLLCFG to 0x800041d
Modified FS_PLLTUNE to 0xbe
Modified CHAN_CTRL to 0x18c40055
Modified LDE_REPC to 0x51ea
Modified EC_CTRL to 0xdead0004
CLKPLL_LL: False, CPLOCK: True

The strange thing is, that CPLOCK and CLKPLL_LL are both set to true on one of my devices. This basically means that the PLL is locked and not-locked at the same time?

I read this sentence in the User Manual:

Although the DW1000 will power up in a usable mode for the default configuration outlined, some of the
register defaults are sub optimal and should be overwritten before proceeding to use the device in the
default mode

Basically, this means if I just hard reset the DW1000 it should work without errors - right? But still, if I just hard-reset the chip I still see the CLKPLL_LL bit set.

Hi @maxG
if your VDD varies with 250mV then your issue is right here. But proper noise measurement is a very hard and tricky. It is very easy to measure inducted noise to the leads. For VDD measurement you need to shorten the GND pat as much as possible so be sure that you dont get any noise into the GND wire which hangs form the oscilloscope probe.

FYI: Im designing the power lines to not producing any noise above 25mV.

Regarding the PLLLOCK) it is possible that it is toggling between locked and unlocked state.

Cheers
JK