Help with basic tx/rx example

Hello,

I am using the DWM1000 for the first time in the development of a product. I designed a pcb to house the module with, and the MCU I am using is an AVR Atmega328. Using the software API provided, I can communicate via SPI to the registers and everything seems OK.

When I use the basic tx/rx example, the tx seems to work, as I can check the registers, and they seem OK. I do not receive anything on the rx end, it stays in the inf loop waiting to recieve a frame.

Just to test to make sure my hardware is fine, I used a DWM1000 library that was written for arduino, and it works fine, I am able to tx and rx perfectly.

Any suggestions?

Thanks!

For these examples, I am still using arduino as the bootloader, just so I am comparing apples to apples.

For my debug function I get the CLKPLL_LL set in the rx code. In the tx it is not set. It’s not a hardware issue since I checked with the arduino library and it is not set. In the arduino example, i’m using basic reciever/senderhttps://github.com/thotro/arduino-dw1000/tree/e20c3b91c3d6cee0ef848aa41e72c942cb0ac7df/examples

Tx Code:

[code]#include <Arduino.h>
#include <SPI.h>
#include “decadriver/deca_device_api.h”
#include “decadriver/deca_regs.h”

/*! ----------------------------------------------------------------------------

  • @file main.c
  • @brief Simple TX example code
  • @attention
  • Copyright 2015 © Decawave Ltd, Dublin, Ireland.
  • All rights reserved.
  • @author Decawave
    */

static dwt_config_t config = {
2, /* Channel number. /
DWT_PRF_64M, /
Pulse repetition frequency. /
DWT_PLEN_1024, /
Preamble length. Used in TX only. /
DWT_PAC32, /
Preamble acquisition chunk size. Used in RX only. /
9, /
TX preamble code. Used in TX only. /
9, /
RX preamble code. Used in RX only. /
1, /
0 to use standard SFD, 1 to use non-standard SFD. /
DWT_BR_110K, /
Data rate. /
DWT_PHRMODE_STD, /
PHY header mode. /
(1025 + 64 - 32) /
SFD timeout (preamble length + 1 + SFD length - PAC size). Used in RX only. */
};

static uint8 tx_msg[] = {0xC5, 0, ‘D’, ‘E’, ‘C’, ‘A’, ‘W’, ‘A’, ‘V’, ‘E’, 0, 0};

#define BLINK_FRAME_SN_IDX 1

#define TX_DELAY_MS 1000

void reset_DW1000()
{
digitalWrite(5, LOW);
pinMode(5, OUTPUT);
delay(10);
pinMode(5, INPUT);
delay(10);
}

void spi_set_rate_low()
{
CLKPR = (1 << CLKPCE);
CLKPR = 1;
}

void spi_set_rate_high()
{
CLKPR = (1 << CLKPCE);
CLKPR = 0;
}

void debug_register(uint16_t reg, uint8_t len)
{
uint8_t ar[len];
dwt_readfromdevice (reg, 0, len, ar) ;
for (int i=0; i<len; i++)
{
Serial.print(i); Serial.print(" = "); Serial.println(ar[i]);
}
}

void setup()
{
SPI.begin();
Serial.begin(9600);

debug_register(0x0F, 5);

reset_DW1000(); /* Target specific drive of RSTn line into DW1000 low for a period. */
spi_set_rate_low();
if (dwt_initialise(DWT_LOADNONE) == DWT_ERROR)
{
Serial.println(“INIT FAILED”);
while (1)
{ };
}
spi_set_rate_high();

dwt_configure(&config);
}

void loop()
{
dwt_writetxdata(sizeof(tx_msg), tx_msg, 0); /* Zero offset in TX buffer. /
dwt_writetxfctrl(sizeof(tx_msg), 0, 0); /
Zero offset in TX buffer, no ranging. */

dwt_starttx(DWT_START_TX_IMMEDIATE);
while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS))
{ };

debug_register(0x0F, 5);

dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS);
delay(TX_DELAY_MS);

tx_msg[BLINK_FRAME_SN_IDX]++;
}
[/code]

Rx:

[code]#include <Arduino.h>
#include <SPI.h>
#include “decadriver/deca_device_api.h”
#include “decadriver/deca_regs.h”

/*! ----------------------------------------------------------------------------

  • @file main.c
  • @brief Simple RX example code
  • @attention
  • Copyright 2015 © Decawave Ltd, Dublin, Ireland.
  • All rights reserved.
  • @author Decawave
    */

static dwt_config_t config = {
2, /* Channel number. /
DWT_PRF_64M, /
Pulse repetition frequency. /
DWT_PLEN_1024, /
Preamble length. Used in TX only. /
DWT_PAC32, /
Preamble acquisition chunk size. Used in RX only. /
9, /
TX preamble code. Used in TX only. /
9, /
RX preamble code. Used in RX only. /
1, /
0 to use standard SFD, 1 to use non-standard SFD. /
DWT_BR_110K, /
Data rate. /
DWT_PHRMODE_STD, /
PHY header mode. /
(1025 + 64 - 32) /
SFD timeout (preamble length + 1 + SFD length - PAC size). Used in RX only. */
};

#define FRAME_LEN_MAX 127
static uint8 rx_buffer[FRAME_LEN_MAX];

static uint32 status_reg = 0;

static uint16 frame_len = 0;

void reset_DW1000()
{
digitalWrite(5, LOW);
pinMode(5, OUTPUT);
delay(10);
pinMode(5, INPUT);
delay(10);
}

void spi_set_rate_low()
{
CLKPR = (1 << CLKPCE);
CLKPR = 1;
}

void spi_set_rate_high()
{
CLKPR = (1 << CLKPCE);
CLKPR = 0;
}

void debug_register(uint16_t reg, uint8_t len)
{
uint8_t ar[len];
dwt_readfromdevice (reg, 0, len, ar) ;
for (int i=0; i<len; i++)
{
Serial.print(i); Serial.print(" = "); Serial.println(ar[i]);
}
}

void setup()
{
SPI.begin();
Serial.begin(9600);

reset_DW1000();
spi_set_rate_low();
if (dwt_initialise(DWT_LOADNONE) == DWT_ERROR)
{
Serial.println(“INIT FAILED”);
while (1)
{ };
}
spi_set_rate_high();

dwt_configure(&config);
}

void loop()
{
int i;

for (i = 0 ; i < FRAME_LEN_MAX; i++ )
{
rx_buffer[i] = 0;
}

dwt_rxenable(DWT_START_RX_IMMEDIATE);

while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_ERR)))
{
debug_register(0x0F, 5);
};

if (status_reg & SYS_STATUS_RXFCG)
{
frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFL_MASK_1023;
if (frame_len <= FRAME_LEN_MAX)
{
dwt_readrxdata(rx_buffer, frame_len, 0);
}
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG);
}
else
{
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR);
}
}
[/code]

spi:

[code]int openspi(/SPI_TypeDef SPIx*/)
{

return 0;

} // end openspi()

/*! ------------------------------------------------------------------------------------------------------------------

  • Function: closespi()

  • Low level abstract function to close the the SPI device.

  • returns 0 for success, or -1 for error
    */
    int closespi(void)
    {

    return 0;

} // end closespi()

/*! ------------------------------------------------------------------------------------------------------------------

  • Function: writetospi()
  • Low level abstract function to write to the SPI
  • Takes two separate byte buffers for write header and write data
  • returns 0 for success, or -1 for error
    */

uint8_t spi_recieve_byte(uint8_t b)
{
SPDR = b;
while(!(SPSR & (1<<SPIF)));
return SPDR;
}

int writetospi(uint16 headerLength, const uint8 *headerBuffer, uint32 bodylength, const uint8 *bodyBuffer)
{
decaIrqStatus_t stat ;

//stat = decamutexon() ;

digitalWrite(10, LOW);

for (uint8_t i = 0; i < headerLength; i++)
	spi_recieve_byte(headerBuffer[i]);

for (uint8_t i = 0; i < bodylength; i++)
	spi_recieve_byte(bodyBuffer[i]);

digitalWrite(10, HIGH);

//decamutexoff(stat) ;

return 0;
} // end writetospi()

/*! ------------------------------------------------------------------------------------------------------------------

  • Function: readfromspi()

  • Low level abstract function to read from the SPI

  • Takes two separate byte buffers for write header and read data

  • returns the offset into read buffer where first byte of read data may be found,

  • or returns -1 if there was an error
    */
    int readfromspi(uint16 headerLength, const uint8 *headerBuffer, uint32 readlength, uint8 *readBuffer)
    {
    decaIrqStatus_t stat ;

    //stat = decamutexon() ;

    digitalWrite(10, LOW);

    for (uint8_t i = 0; i < headerLength; i++)
    spi_recieve_byte(headerBuffer[i]);

    for (uint8_t i = 0; i < readlength; i++)
    readBuffer[i] = spi_recieve_byte(0);

    digitalWrite(10, HIGH);
    //decamutexoff(stat) ;

return 0;
} // end readfromspi()[/code]

Hi
First of all, The examples on github seem to be 2 years old.
Maybe the best approach is to take the latest examples from our website and port these to the processor of your choice

But as you also have CLKPLL_LL set this could indicate a device misconfiguration, device has not been configured or initialised correctly. For example, as part of the initialisation of the IC (dwt_initalise API function) it is required to decrease the SPI speed to less then 3MHz.

So if you do not feel like porting the example code do at least take a look at the code and/or API document (2.04) where it tells you to go down to 3Mhz SPI.

The API can be downloaded from : https://decawave.com/software-download

For trouble shooting I advice you also to have a look our application note APS022 Debugging dw1000 based products systems.
This document is an excellent aid to get to the root of problems and it can be fetched from: https://decawave.com/application-notes (under “UWB SYSTEMS”)
/Leo

Hi Leo,

I do decrease the speed to 2 Mhz. I did port the code over to my processor, that is the code I am having the issue with. The code on github works perfect, but I would like to get the decawave api working, as it is much more complete.

So I removed the line “dwt_configure(&config);” from the example code and I now can recieve a message, but I get:
RXPRD (Receiver Preamble Detected status)
RXSFDD (Receiver SFD Detected)
RXPHE (Receiver PHY Header Error)

So, using the basic tx/rx example, the supplied config isn’t working with my dwm1000. What should I try to change in the config to get it to work?

Yeah the CLKPLL_LL bit being set is odd, I’m not sure why it is, but it also has the CPLOCK bit set. So the two are controdicting each other.

So I’ve made some progress. It seems that the receiving code is working fine, it is the transmission code that is bugged. I am able to send code from my one board using the arduino library, and receive it with the basic rx example from the decawave API.

If I send from the decawave api example, and receive it from the decawave API example I receive it, but with errors.
Sometimes these bits get set:
CPLOCK, RXPRD, RXSFDD, RXPHE, SLP2INIT, CLKPLL_LL

Other times, these are set:
CPLOCK, RXPRD, RXSFDD, RXPHD, RXRFSL, SLP2INIT, CLKPLL_LL

I know the CLKPLL_LL being set isn’t good, but it isn’t an issue since it works fine when receiving a message sent from the arduino lib.

From the sending code, the proper bits are getting set (TXFRB, TXPRS, TXPHS, TXFRS)

Any help is appreciated!

Transmission code:

[code]#include <Arduino.h>
#include <SPI.h>
#include <prescaler.h>
#include <deca_device_api.h>
#include <deca_regs.h>
//#include “DW1000.h”
//#include “usart.h”

/*! ----------------------------------------------------------------------------

  • @file main.c
  • @brief Simple TX example code
  • @attention
  • Copyright 2015 © Decawave Ltd, Dublin, Ireland.
  • All rights reserved.
  • @author Decawave
    */

static dwt_config_t config = {
5, /* Channel number. /
DWT_PRF_16M, /
Pulse repetition frequency. /
DWT_PLEN_1024, /
Preamble length. Used in TX only. /
DWT_PAC32, /
Preamble acquisition chunk size. Used in RX only. /
4, /
TX preamble code. Used in TX only. /
4, /
RX preamble code. Used in RX only. /
0, /
0 to use standard SFD, 1 to use non-standard SFD. /
DWT_BR_110K, /
Data rate. /
DWT_PHRMODE_STD, /
PHY header mode. /
(1025 + 64 - 32) /
SFD timeout (preamble length + 1 + SFD length - PAC size). Used in RX only. */
};

static uint8 tx_msg[] = {0xC5, 0, ‘D’, ‘E’, ‘C’, ‘A’, ‘W’, ‘A’, ‘V’, ‘E’, 0, 0};
/* Index to access to sequence number of the blink frame in the tx_msg array. */
#define BLINK_FRAME_SN_IDX 1

/* Inter-frame delay period, in milliseconds. */
#define TX_DELAY_MS 1000

void reset_DW1000()
{
digitalWrite(5, LOW);
pinMode(5, OUTPUT);
delay(10);
pinMode(5, INPUT);
delay(10);
}

void setup()
{
SPI.begin();
Serial.begin(9600);
while (!Serial) { ; };
delay(50);

reset_DW1000();
setClockPrescaler(CLOCK_PRESCALER_8);
if (dwt_initialise(DWT_LOADNONE) == DWT_ERROR)
{
setClockPrescaler(CLOCK_PRESCALER_1);
Serial.println(“INIT FAILED”);
while (1)
{ };
}
setClockPrescaler(CLOCK_PRESCALER_1);
delay(50);

dwt_configure(&config);
}

void loop()
{
/* Write frame data to DW1000 and prepare transmission. See NOTE 4 below./
dwt_writetxdata(sizeof(tx_msg), tx_msg, 0); /
Zero offset in TX buffer. /
dwt_writetxfctrl(sizeof(tx_msg), 0, 0); /
Zero offset in TX buffer, no ranging. */

//Serial.print(“Before”); Serial.println(dwt_read32bitreg(SYS_STATUS_ID));
/* Start transmission. */
Serial.print(“Before”); Serial.println(dwt_read32bitreg(SYS_STATUS_ID));
dwt_starttx(DWT_START_TX_IMMEDIATE);

Serial.print(“After 1”); Serial.println(dwt_read32bitreg(SYS_STATUS_ID));
while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS))
{ };

Serial.print(“After 2”); Serial.println(dwt_read32bitreg(SYS_STATUS_ID));
/* Clear TX frame sent event. */
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS);

/* Execute a delay between transmissions. */
delay(TX_DELAY_MS);

/* Increment the blink frame sequence number (modulo 256). */
tx_msg[BLINK_FRAME_SN_IDX]++;
}

[/code]

So, I’m having a tough time now thinking that it is something on my end, and now thinking there could be something wrong with the driver api? At least with the dwm1000 specifically.

I now have two DWM1000s hooked up with STM32s. I am now using the board architecture that the api was designed for. I have the exact same results…

If I comment out the “dwt_configure(&config);” I am able to receive messages with the aforementioned error bits set, the rx stm32 prints “err”.

If I use any configuration, I never receive any messages at all.

These modules still work fine using the arduino library, so there is nothing wrong with them, and I have 4 modules that I have tested with each.

Please if anyone has any suggestions let me know. If not it looks like I will be moving on to a new UWB chip.

Thanks!

STM32 tx code:

[code]#include <mbed.h>
#include “decadriver/deca_device_api.h”
#include “decadriver/deca_regs.h”

static dwt_config_t config = {
2, /* Channel number. /
DWT_PRF_64M, /
Pulse repetition frequency. /
DWT_PLEN_1024, /
Preamble length. Used in TX only. /
DWT_PAC32, /
Preamble acquisition chunk size. Used in RX only. /
9, /
TX preamble code. Used in TX only. /
9, /
RX preamble code. Used in RX only. /
1, /
0 to use standard SFD, 1 to use non-standard SFD. /
DWT_BR_110K, /
Data rate. /
DWT_PHRMODE_STD, /
PHY header mode. /
(1025 + 64 - 32) /
SFD timeout (preamble length + 1 + SFD length - PAC size). Used in RX only. */
};

DigitalOut myled(PC_13);

static uint8 tx_msg[] = {0xC5, 0, ‘D’, ‘E’, ‘C’, ‘A’, ‘W’, ‘A’, ‘V’, ‘E’, 0, 0};

#define BLINK_FRAME_SN_IDX 1

#define TX_DELAY_MS 1000

DigitalInOut pin_rst(PA_10);

void reset_DW1000()
{
pin_rst.write(0);
wait(0.01);
pin_rst.write(1);
}

int main(void)
{
myled = 0;
Serial serial(PB_6, PB_7);
wait(0.5);
serial.baud(9600);

pin_rst.output();
pin_rst.mode(OpenDrain);
SPI bus(PA_7, PA_6, PA_5);//mosi, miso, clk

serial.printf("Device ID: %u\r\n", dwt_readdevid());

reset_DW1000();
bus.frequency(2000000);
if (dwt_initialise(DWT_LOADNONE) == DWT_ERROR)
{
    serial.printf("Error on init11\n\r");
    while (1) { ; };
}
bus.frequency(20000000);

//dwt_configure(&config);

while(1)
{
  dwt_writetxdata(sizeof(tx_msg), tx_msg, 0); /* Zero offset in TX buffer. */
  dwt_writetxfctrl(sizeof(tx_msg), 0, 0); /* Zero offset in TX buffer, no ranging. */

  dwt_starttx(DWT_START_TX_IMMEDIATE);

  while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS))
  { };

  dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS);

  myled = 1;
  wait(1);
  myled = 0;

  tx_msg[BLINK_FRAME_SN_IDX]++;
}

}
[/code]

STM32 rx code:

[code]#include <mbed.h>
#include “decadriver/deca_device_api.h”
#include “decadriver/deca_regs.h”

static dwt_config_t config = {
2, /* Channel number. /
DWT_PRF_64M, /
Pulse repetition frequency. /
DWT_PLEN_1024, /
Preamble length. Used in TX only. /
DWT_PAC32, /
Preamble acquisition chunk size. Used in RX only. /
9, /
TX preamble code. Used in TX only. /
9, /
RX preamble code. Used in RX only. /
1, /
0 to use standard SFD, 1 to use non-standard SFD. /
DWT_BR_110K, /
Data rate. /
DWT_PHRMODE_STD, /
PHY header mode. /
(1025 + 64 - 32) /
SFD timeout (preamble length + 1 + SFD length - PAC size). Used in RX only. */
};

#define FRAME_LEN_MAX 127
static uint8 rx_buffer[FRAME_LEN_MAX];

static uint32 status_reg = 0;

static uint16 frame_len = 0;

DigitalInOut pin_rst(PA_10);

void reset_DW1000()
{
pin_rst.write(0);
wait(0.01);
pin_rst.write(1);
}

int main(void)
{
//myled = 0;
Serial serial(PB_6, PB_7);
wait(0.5);
serial.baud(9600);

pin_rst.output();
pin_rst.mode(OpenDrain);
SPI bus(PA_7, PA_6, PA_5);//mosi, miso, clk

serial.printf("Device ID: %u\r\n", dwt_readdevid());

reset_DW1000();
bus.frequency(2000000);
if (dwt_initialise(DWT_LOADNONE) == DWT_ERROR)
{
    serial.printf("Error on init11\n\r");
    while (1) { ; };
}
bus.frequency(20000000);

//dwt_configure(&config);

while(1)
{
  int i;

  for (i = 0 ; i < FRAME_LEN_MAX; i++ )
  {
      rx_buffer[i] = 0;
  }
  dwt_rxenable(DWT_START_RX_IMMEDIATE);

  while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_ERR))) { ; }

  if (status_reg & SYS_STATUS_RXFCG)
  {
      frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFL_MASK_1023;
      if (frame_len <= FRAME_LEN_MAX)
      {
          dwt_readrxdata(rx_buffer, frame_len, 0);
          for(int s=0; s<frame_len-3; s++)
          {
            serial.printf("%c", rx_buffer[s]);
          }
          serial.printf("\r\n");
      }
      dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG);
  }
  else
  {
    dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR);
    serial.printf("Err\r\n");
  }
}

}
[/code]

OK, so I got it working now with the STM32. I can receive and send messages on all the basic examples auto ack’s!

For the twr examples, neither the single or double-sided work. They both get hung up at ret = dwt_starttx(DWT_START_TX_DELAYED | DWT_RESPONSE_EXPECTED);

The double-sided example, ret will fail 90% of the time, the other 10% I will not receive the message afterward, it will just time out

I saw other people on the forum with problems with this increasing the delay times on both the init and resp sides. That did nothing to affect my results. Is there something else to try other than increasing timeouts?

Thanks!

EDIT: So it looks like “dwt_readrxtimestamp()” within the “get_rx_timestamp_u64()” function in the resp code is returning “0” for the first poll message. This makes it so the delay value for the send is wrong, so dwt_starttx() never works.

Any thoughts?

dwt_initialise(DWT_LOADNONE) !!!

you need to load LDE if you want the RX timestamps to be valid (i.e. non zero) !!!

Please study simple examples provided by Decawave. Simple RX does not load LDE, as timestamp is not used. TWR (both SS and DS) do load LDE.

Z

Yeah, that was it. Thanks!

Hello Kylehunter,

I am running into a similar issue with the DWM1000 module and the AVR AtMega328P, where the simple tx example appears to work (the TXFRS bit becomes set) but in the simple rx example, the program gets stuck in the while loop polling for RXFCG to become set, and it never does. Did you ever solve this problem with the AtMega?

Thanks