I was looking for a board compatible with Raspberry to implement ranging with UWB and I’ve come across the DWM1000 and DWM1001.
I’ve understood the DWM1000 is just the “UWB compliant wireless transceiver module based on Decawave’s DW1000 IC” and the DWM1001 development board includes the DW1000, a Nordic Semiconductor nRF52832 MCU, and a 3-axis accelerometer soldered into a Raspberry compatible board.
Hi ,
The examples in the API have been designed to run on an EVB1000 board with an stm32f105rc Processor.
To have these examples run on a DWM1001 these examples need to be ported to the MCU on the DWM1001 (nRF52832).
Some examples have been ported. You can go to https://github.com/Decawave/dwm1001-examples to access a couple of very basic software routines for implementing a single-sided TWR exchange between two nodes using the DWM1001.
Regards
Leo
So basically, if I want to read registers such as, for instance, the accumulator after a correct reception, I need to rewrite the functions written for the stm32f105rc in the deca_device.c for the nRF52832
In theory yes. The underlying interface is standard SPI so you’ll need to configure the SPI interface either by direct access to the hardware or more likely through some supplied SPI device drivers.
That same driver should have a simple read/write function (on SPI you do both at the same time). The only slightly odd bit is how the address setup is done.
e.g. the code below is taken from my DW1000 driver.
void DW1000::readRegister(uint8_t reg, uint16_t subaddress, uint8_t *buffer, int length)
{
setupTransaction(reg, subaddress, false);
for(int i=0; i<length; i++) // get data
buffer[i] = spi.write(0x00);
deselect();
}
void DW1000::writeRegister(uint8_t reg, uint16_t subaddress, uint8_t *buffer, int length)
{
setupTransaction(reg, subaddress, true);
for(int i=0; i<length; i++) // put data
spi.write(buffer[i]);
deselect();
}
void DW1000::setupTransaction(uint8_t reg, uint16_t subaddress, bool write)
{
reg |= (write * DW1000_WRITE_FLAG); // set read/write flag
select();
if (subaddress > 0) { // there's a subadress, we need to set flag and send second header byte
spi.write(reg | DW1000_SUBADDRESS_FLAG);
if (subaddress > 0x7F) { // sub address too long, we need to set flag and send third header byte
spi.write((uint8_t)(subaddress & 0x7F) | DW1000_2_SUBADDRESS_FLAG); // and
spi.write((uint8_t)(subaddress >> 7));
} else {
spi.write((uint8_t)subaddress);
}
} else {
spi.write(reg); // say which register address we want to access
}
}
void DW1000::select() { // always called to start an SPI transmission
irq.disable_irq(); // disable interrupts from DW1000 during SPI
cs = 0; // set Select pin low to start transmission
}
void DW1000::deselect() } // always called to end an SPI transmission
cs = 1; // set Select pin high to stop transmission
irq.enable_irq(); // reenable the interrupt handler
}
I then define a load of constants for the various register addresses and have functions like:
void DW1000::startRX() {
writeRegister(DW1000_SYS_CTRL, 0x01, 0x01, 1); // start listening by setting the RXENAB bit
}
uint64_t DW1000::getTXTimestamp() {
return readRegister(DW1000_TX_TIME, 0, 5); // 40 bit read
}