DWM1000 Simple Examples - No Rx

[color=#222222][size=small][font=Calibri, sans-serif]Hello,[/font][/size][/color]
[color=#222222][size=small][font=Calibri, sans-serif]I am an engineer currently working on a project involving the DWM1000, we want to use the ranging feature of the module in a product currently in development.[/font][/size][/color]

[color=#222222][size=small][font=Calibri, sans-serif]I am using the decawave API on a stm32 f3. The SPI is currently running at a clock frequency of 250KHz, it is using simple but very reliable bit banging functions to ensure that the problem was not in a misbehaving peripheral. [/font][/size][/color]

[color=#222222][size=small][font=Calibri, sans-serif]Currently I am trying to get the simple_rx and simple_tx examples running. The problem seems to be the RX is not receiving as it should be. I have searched the forum and tried any potential solutions to similar problems but I am still stuck.[/font][/size][/color]

[color=#222222][size=small][font=Calibri, sans-serif]The SPI works as shown by the dwt_initialise function returning successfully. The Tx seems to work as it runs around in the loop provided in the example code and reads the TXFRS bit. Therefore I believe the problem lies in the RX but I am open to any other potential issues causing this.[/font][/size][/color]

[color=#222222][size=small][font=Calibri, sans-serif]The RX runs in the example code loop waiting for the RXFCG bit to be set but it never is. The status_reg returned is always 0x800002. I have tried using the default config and the config specified in the examples on both modules. [/font][/size][/color]

[color=#222222][size=small][font=Calibri, sans-serif]Another issue I have run into that may or may not be related is if I try to read the system status register twice in a row it returns 0xFFFFFFFF or 0xDEADDEAD and the system does not recover. The work around is a write to the register 0x0 between reads (a dummy write). I have checked with two different logical analysers and they show the correct serial is being sent to the DWM1000.[/font][/size][/color]

[color=#222222][font=Calibri, sans-serif][size=small]Hopefully someone on this forum could point out something that might help in getting this running as I have spent several days trying everything I can to get these modules working, it will be very much appreciated[/size][size=small].[/size] [size=small]:)[/size] [/font][/color]

[color=#222222][size=small][font=Calibri, sans-serif]Thank you in advance,[/font][/size][/color]
[color=#222222][size=small][font=Calibri, sans-serif]Tom[/font][/size][/color]

I have same problem but i use msp430g2955. I dont think the source of this problem is rx. Because if i transmit data from msp432f4, i can receive.

guys your problem is in the SPI… once you have reliable SPI comms the examples will work fine.

please check the SPI. Why are you using bit bashing? The simple examples provided by Decawave are already set up to run on STM32. There is a CubeMX/ System Workbench project - this should be very straightforward to port to any STM… this is the whole point of having this package.


i look my spi data from logic analyzer and i see datas that i want to send. Also, i writed same code on MSP432 and that’s worked. And and, i writed a code on STM and that’s worked too. But MSP430 code is not working.

You can look this post. https://www.decawave.com/decaforum/showthread.php?tid=755&pid=2255#pid2255


I am sure there was nothing wrong with the SPI, I did originally use the SPI peripheral setup with Cubemx. I ended up using the bit banging SPI I had previously written because it is 100 percent reliable, just to eliminate any doubt. I checked everything throughly with a logic analyser and an osciliscope.

I have implemented all kinds of serial protocols in multiple projects. I am sure it wasn’t the problem.

I also designed and got manufactured a pcb to ensure signal integrity between the dwm and uc.

I ended up buying dwm1001 dev modules to evaluate the product.

If anyone else has this problem and can figure out a solution, it would be appreciated to understand what was going on.


Hi Tom, you can check if the SPI is working properly with the DWM1000. I use this code:

[code]volatile uint8 dataA[20] = {19, 18, 17, 16, 15, 14, 13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 11};
volatile uint8 dataB[20];

dwt_writetodevice(0x21, 0, 20, &dataA[0]);
dwt_readfromdevice(0x21, 0, 20, &dataB[0]);[/code]

You have to check if the value readed (dataB) has the same values than the written (dataA).
If you don’t, then you have a problem with SPI.


I am experiencing issues similar to what Tom is experiencing. While the simple tx example appears to work and the TXFRS bit is set and the program repeats, the simple rx example gets stuck waiting for the RXFCG bit to be set, and it never does. I tested my SPI as per dpeinado’s suggestion, and my SPI works. I have also checked this by reading the partid, lotid, and deviceid from the module. I am using an atmega328p and avr-gcc. Was Tom’s issue resolved? And if so, how so? Otherwise, does anyone have any suggestions of what I may have done wrong? Shall I post my code as well?

Thank you.

My issue was never resolved. I ended up giving up on the dwm1000. I bought some dwm1001 dev boards and used them for testing.

It hasn’t been a very good experience on the support side of things.


I don’t like seeing that folks had trouble with SPI on DWM1000 and switched to DWM1001. I just moved the other direction, giving up on DWM1001 because it was revealed in the forums that the the DWM1001 and DWM1001-DEV firmware v1 doesn’t support data transmission, so I’m trying direct SPI access via the DWM1000. Consequently, this thread gives me some concern.

Does SPI on the DWM1000 work?

I never had any issues with it.
I’ve used an NXP running the mbed libraries to a DWM1000 and then both the mbed and native SPI libraries directly to a DW1000 chip. In both cases no issues at all with SPI or sending/receiving. The first implementation was a a simple PCB connecting the module to an mbed module and a few other odds and ends, the most recent is a full custom board with the parts placed directly.

I manually control the chip select line rather than letting the hardware control it in order to keep it selected for the whole transmission but that’s nothing too unusual.
SPI is rock solid on everything up to around 15 MHz, on the latest version (no dev boards/modules) it’s good up to 20 MHz.

On the boards I’ve taken care to ensure plenty of decoupling capacitors on the power and clean, short SPI traces but that’s all standard PCB best practices that anyone making a board that they want to work should know to do.

Does SPI on the DWM1000 work?

:slight_smile: … does it, a strange question? … as DW IC can only be controlled via the SPI interface, it is a must that SPI on DWM1000 works. There is no question of that.

As SPI is the only interface to DW1000 IC, it must work on DWM1000. There should be no problem with DWM1000.


Hello there,

I have a similar issue as you guys, let me show you.

I have my own simple TX, RX. When I send a message just after booting (assuming that transmission has never been called before) I can receive every incoming message. But, after I call TX, then the reception of the next message is not done properly. IRQ is called, but no “RX COMPLETE” bits are set (SYS_STAT 0x0000800002), so dwt_isr() routine decides not to call RX callback. Next messages are then processed properly since the receiver do TX. Then again, first incoming message did not set RX OK bits.

So it happens every time it ends transmission and switches to reception. Do you have any idea what could cause this?

I hope you understand me.

Best regards.

If the IRQ is called, then an event bit has to be set? Do you have auto RX re-enable on? If you do then an error event may generate interrupts, but then the event is automatically cleared as RX is re-enabled. The auto re-enable should not be used.

Yes, for now, I have auto re-enable. But even if with auto re-enable off, it behaves same.

I am not sure if you understand what I would like to say.

When I at least one time do in “device 1” a transmission, then go to RX enable and waiting for message, the first message from other “device X” is received, but no event status bit arises in SYS_STATUS… only interrupt is called, but dwt_isr() did not call any respective callback, because it does not find any bit set like RXPRD, RXSFD, RXPRD set…

The very next message (second) is then received and processed properly, all mentioned bits are set, so rx callback is called.

It looks like the reception after TX is something like bad configured, but I can’t figure out what I’ve missed. I only do force to idle and RX enable after a transmission is done. I hope, nothing more is required.

NOTE: also no error flag arises, as I wrote, the SYS_STATUS value, read immediately when dwt_isr started is 0x0000800002, saying only that CPLL is locked and SLP2INIT (don’t know why SLP2INIT because I don’t use SLEEP, but I don’t care about this for now).

Thank you for helping,

few comments:

  1. How do you enable RX after TX? Do you use TX with wait-4-response?

  2. If you use auto rx re-enable, then you can get a glitch (few nano seconds long) on the interrupt line (e.g. RX error event which triggers interrupt, but then gets cleared because RX is re-enabled). This may be enough to trigger interrupt in the micro.

  3. If you enter the ISR, but there are no events, what do you do? What does the register 0x19 report (see APS022 if you need to understand this register)? Is the device in IDLE at this time or doing something else?

  4. You could be getting RX error after TX if the receiver is not enabled in time for the incoming frame, if the receiver is enabled too late. Do you have PTO set? If you don’t have auto RX re-enable then you will have to get an event once the interrupt is triggered.

  5. There are no issues with RX after TX that I now of, lots of examples from Decawave use this feature (especially TX wait 4 response).

  6. Auto RX re-enable should not be used as it will give rise to incorrect timestamps.

  7. Don’t worry about SLP2INIT.

Thank you. I try to answer to your comms:

I enable RX after TX in TX callback (assuming that TX is already complete). Here is code snippet:

dwt_forcetrxoff(); // ensure that DWM1000 is in idle (i see it somewhere) dwt_rxreset(); // reset the RX (this is not neccessary i think, but i try everything i know about) rxEnFlag = dwt_rxenable(0); // 0 = imidiate RX (according to coments in API)

Here is core snippet how I do a transmission:

dwti_forceidle(); // ensure that DWM1000 is in idle (i see it somewhere) stats = dwt_writetxdata(txDataLen,(uint8_t *)txData,0); // fill TX buffer stats = dwt_writetxfctrl(txDataLen, 0); // upload TX cfg (not sure if neccesarry) stats = dwt_starttx(0); // start TX (0=immidiate TX according to coments in API)

So the answer is, I do not use delayed TX or wait-4-resp.

OK auto re-enable will not be used anymore.

It does nothing. (dont know how it is possible that second message is then received at this point).

Register states after successful reception:
0x19 register (SYS_STATE): 0x0000010000 (idle, am I right?)
0x0F register (SYS_STATUS): 0x0000806F03 (IQS, CPLLOCK, RXPRD, RXSFDD, LDEDONE, RXPHD, RXDFR, RXFCG, SLP2INIT - all good i think[exept SLP2INIT -dont care as zou said])

Register states after successful transmission:
0x19 register (SYS_STATE): 0x0000010000 (again idle)
0x0F register (SYS_STATUS): 0x00008000F3 (IQS, CPLLOCK, TXFRB, TXPRS, TXPHS, TXFRS, SLP2INIT - all good)

Register states after broken reception of very first message just after transmission:
0x19 register (SYS_STATE): 0x0B40050500 (0050500 => in RX mode and waiting for preamble according to APS022 ? hopefully, yes, but what is 0B4 ???)
0x0F register (SYS_STATUS): 0x0000800002 (only CPLLOCK and SLP2INIT - can’t imagine how it is possible that interrupt happens if IQS bit is not set, but it really happens, I check it using the oscilloscope, but it is very very very short <100 ns !! compared to 5ms of successful receive interrupt)

I know that 5ms is also too long, it is caused by slow SPI and debug prints etc. But also <100ns is too too fast, signalizing that there is something wrong in the DWM1000.
(Interrupts oscilloscope records are in attachments)

I know what you mean, but this is not my case. The current implementation of transmission is using a debug button on my control board. So when I press the button, transmission is performed. What is PTO ? You mean Preamble detection time out - RXPTO ? Yes, it is set, did not arise anytime. (SYS_MASK 0x2423F080)
What do you mean by this?: If you don’t have auto RX re-enable then you will have to get an event once the interrupt is triggered.

Do you know about some examples, where is RX implemented together with TX? I have only those:

… I try to investigate the ex_03a_tx_wait_resp since we found the solution. Must say that I haven’t do it before, I am using my last project which is based on Arduino Throtro from GitHub.

OK, you convinced me to auto RX [color=#ff3333]disable[/color]. So the most correct flow (with respect to timestamps) is re-enabling RX manually eg. in TX or RX callback?


NOTE: Maybe I already write this… It cant be come HW issue, because when I run my device from blank (turn of the power supply) and did not perform TX before, then every (even the first) message is received. So there should be some problem with the transition from TX to RX or something like that.

NOTE2: Sometimes occasionally this “blank” interrupt is generated randomly without any proven transmission. I think this is caused by some electromagnetic noise around me.

Thank you very much for your time Zoran.
Best regards,


Now i try to mask as much interrupts as possible and relates to reception (before I use mask reused from TREK source code dwt_setinterrupt(DWTI_INT_RXDFR | DWT_INT_TFRS | DWT_INT_RFCG | (DWT_INT_ARFE | DWT_INT_RFSL | DWT_INT_SFDT | DWT_INT_RPHE | DWT_INT_RFCE | DWT_INT_RFTO | DWT_INT_RXPTO), 1):wink:

Current mask is:
dwt_setinterrupt(0b00111100001101111111111110000000, 1); (sory for the binary)

And behavior is the following:

A) Successful reception

[code][18/09/18 - 15:05:11:635] NEW ISR CALLED //ISR start

[18/09/18 - 15:05:11:636] SYS_STAT 0000800103 // all
[18/09/18 - 15:05:11:639] SYS_MASK 3C37FF80 // this
[18/09/18 - 15:05:11:639] states 0B00050C00 // is
[18/09/18 - 15:05:11:642] SYS_STAT 0000806F03 // done
[18/09/18 - 15:05:11:642] SYS_MASK 3C37FF80 // in one
[18/09/18 - 15:05:11:644] states 0000010000 // do {dwt_isr()} while (IRQ == 1)
[18/09/18 - 15:05:11:647]
[18/09/18 - 15:05:11:647] RX callback routine - receiver reenable; // callback called
[18/09/18 - 15:05:11:650]
[18/09/18 - 15:05:11:650] RECEIVED DATA: AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA: // print out received data in RX callback
[18/09/18 - 15:05:11:656] AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:
[18/09/18 - 15:05:11:662] AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:C1:
[18/09/18 - 15:05:11:664] D5:

A) Broken reception

[18/09/18 - 15:11:06:139] NEW ISR CALLED // TX before investigated reception [18/09/18 - 15:11:06:140] SYS_STAT 02008000F3 // ... [18/09/18 - 15:11:06:142] SYS_MASK 3C37FF80 // continuing ... [18/09/18 - 15:11:06:144] states 0000010000 // ... [18/09/18 - 15:11:06:145] TX callback routine - reenable RX // ... [18/09/18 - 15:11:06:151] RX ENABLE: OK // ... [18/09/18 - 15:11:11:261] [18/09/18 - 15:11:11:262] [18/09/18 - 15:11:11:262] NEW ISR CALLED // ISR start of tracked reception [18/09/18 - 15:11:11:262] SYS_STAT 0000800103 // ... [18/09/18 - 15:11:11:264] SYS_MASK 3C37FF80 // ... [18/09/18 - 15:11:11:265] states 0B00050C00 // ...

So now it seems that preamble is detected. SYS_STAT 0000800[color=#ff3333]1[/color]03 but nothing more…
Thinking about incorrect PAC size or something, but why only during the first message? I use nsSFD with 2048 and PAC size 64 as recommended. SFD timeout is not defined… is it a problem?

NOTE: There is no change in code, only I have modified the SYS_MASK as proposed in the post beginning.


  1. If you are in TX callback, the device should be in IDLE already. TX is done and you don’t have W4R, so you should not need to do TRXOFF or RX reset.

  2. dwti_forceidle(); - this function is not part of DW1000 API, what does it do? Why do you use it? The device should be in IDLE automatically unless you actually put it/force it into INIT state?

0x19 register (SYS_STATE): 0x0B40050500 (0050500 => in RX mode and waiting for preamble according to APS022 ? hopefully, yes, but what is 0B4 ???)
0x0F register (SYS_STATUS): 0x0000800002 (only CPLLOCK and SLP2INIT - can’t imagine how it is possible that interrupt happens if IQS bit is not set, but it really

if the 0x19 is in RX state (0505) then the RX has not finished … so not sure why interrupt would trigger…

    • I can only vouch for Decawave projects/examples from www.decawave.com … not sure how good the Arduino ones are…
  1. yes. manual is the best.

…What data rate are you using? 110k? … if you don’t have SFD timeout (you should at least set it to max value, but it should really be set to preamble length + 1 - PAC) … in 110k mode preamble can be detected from noise (false positive) and if there is no SFD timeout the device will wait forever for SFD.

you could poll the status/states registers in the ISR to see do they change.

dwti_forcetodile(); // is my function, it does following

void dwti_forceidle(void)
dwt_write32bitoffsetreg(SYS_CTRL_ID, 0, SYS_CTRL_TRXOFF);

… it is basically the same as dwt_trxoff(); I think… I did it because I didn’t found the dwt_trxoff(); before… But if I know now about SYS_STATES, it is not necessary as you recommended.

Please take a look to my very last reply (before this)… There is some change in SYS_STATES (050C).

I added SFD timeout (2049 + 64 - 64), remove auto-rx-enable but still the same problem :frowning:

Yes, I use 110kbps for now.

Yes, the registers are polled, the result is in the post before.