DW3000 not receiving frame but preambles

Hey folks!
I am currently working with the DWM3000EVB Kits on top of Arduino Unos. I access the DW3000 via SPI and so far it is working quite well.
For test purposes, I want to transmit simple data between two Nodes. The sending DW3000 reports that the tx procedure was successful (TXFRS bit (reg:00:44 bit:7) set to 1). It sends the same frame every 500 milliseconds.
On the other hand, there is my receiving node, which is not receiving any messages yet. I send a simple CMD_RX Fast Command via SPI, which seems to be working, because the DW3000 requests an RXPRD interrupt (Receiver Preamble Detected). After that, the DW3000 is set into RX Mode again.
The problem here is, that the receiver node doesn’t receive that event every 500 milliseconds but seemingly all the time, as it just keeps reporting an IRQ immediately after resetting the irq status bits.

The interrupt is configured as RISING Interrupt. I enabled all status bits for debugging but there is no other bit set to high.

Any advice would be greatly appreciated!

Philipp

You need to read UM… Check, did you configure both transmitter and receiver to the same phy modes: pcode, plen, etc.
Check if you ars getting OK or ERR during your RX preamble detect irq: chip is super flexoble and you can get preamble error or sfd detect timeout. Try to find the Simple API examples for dw3000, that could help you understand the transceiver

1 Like

Thanks a lot already!
There is one other thing that came to my mind that seems to not be obviously documented and probably is quite a dumb question… The register set of the DW3000 probably isn’t permanent, right? So when the chip gets reset, the register set - except the OTP Memory of course - is reset as well?

Thanks!
Philipp

Yes. All registers are lost on power down. They are in effect small blocks of RAM and so don’t maintain their value without power. This isn’t explicitly mentioned because that’s true for virtually every configuration register in every electronic device ever made.
So yes, in a way a dumb question but also an understandable one. It’s one of those things that no one mentions because it’s assumed knowledge. But if you don’t have prior experience in the area how are you supposed to know if no one mentions it.

Most registers are also lost if the device enters sleep mode, the parts of the chip that hold the settings are shut down to save power. However the Always-on registers are, as the name implies, maintained and can be used to save the registers when entering sleep mode and then restore them when waking up.

2 Likes

Hi friend, could you please send the code that you use in the Arduino IDE

I’ve packed my code into a library. Here are the methods I am using (I suppose there is something wrong in my init() method):
init():

void DW3000Class::init() {
    Serial.println("\n+++ DecaWave DW3000 Test +++\n");

    int shCmd[] = { 0 };
    writeShortCommand(shCmd, 1); 

    int data1[] = {0x80,0xEB,0x7,0x0,0x0,0x1F}; //0xF0,0x2F //0x80,0x3E,0x0,0x0,0x0,0x1F  //0x0
    DW3000Class::write(0x0, 0x3C, data1, 6); //Set IRQ for successful received data frame
  
    int data2[] = { 0x03, 0x3C };
    DW3000Class::write(0x0, 0x24, data2, 2); //Frame length setup for Transmission  

    int data3[] = {0x00,0x9, 0x0};
    DW3000Class::write(0xA, 0x0, data3, 3); //AON_DIG_CFG register setup; sets up auto-rx calibration and on-wakeup GO2IDLE  //0xA

    /*
     * Set RX and TX config
     */
    int data4[] = { 0x40,0x02,0x00,0x10 }; //DGC_CFG0  //0x3
    DW3000Class::write(0x3, 0x1C, data4, 4);

    int data5[] = { 0x89,0xa4,0x6d,0x1b }; //DGC_CFG1
    DW3000Class::write(0x3, 0x20, data5, 4);

    int data6[] = { 0xFD,0xC0,0x01,0x00 }; //DGC_LUT_0
    DW3000Class::write(0x3, 0x38, data6, 4);
   
    int data7[] = { 0x3E,0xC4,0x01,0x00 }; //DGC_LUT_1
    DW3000Class::write(0x3, 0x3C, data7, 4);
    
    int data8[] = { 0xBE,0xC6,0x01,0x00 }; //DGC_LUT_2
    DW3000Class::write(0x3, 0x40, data8, 4);
    
    int data9[] = { 0x7E,0xC7,0x01,0x00 }; //DGC_LUT_3
    DW3000Class::write(0x3, 0x44, data9, 4);
    
    int data10[] = { 0x36,0xCF,0x01,0x00 }; //DGC_LUT_4
    DW3000Class::write(0x3, 0x48, data10, 4);
    
    int data11[] = { 0xB5,0xCF,0x01,0x00 }; //DGC_LUT_5
    DW3000Class::write(0x3, 0x4C, data11, 4);
    
    int data12[] = { 0xF5,0xCF,0x01,0x00 }; //DGC_LUT_6
    DW3000Class::write(0x3, 0x50, data12, 4);

    int data13[] = { 0xF5,0xE4 };
    DW3000Class::write(0x3, 0x18, data13, 2); //THR_64 value set to 0x32

    //SET PAC TO 32 (0x00) reg:06:00 bits:1-0, bit 4 to 0 (00001100) (0xC)
    int data14[] = { 0xE };
    DW3000Class::write(0x6, 0x0, data14, 1);  //0x6

    //set SFD Detection timeout count to 1057 (0x21, 0x4); 1018 old: (0xFA, 0x3)
    int data15[] = { 0x21, 0x4 };
    DW3000Class::write(0x6, 0x2, data15, 2);

    //SET PREAMBLE CODE (RX_PCODE, TX_PCODE) TO 10 (reg:01:14) //Standard SFD Type is 11 (data: 0x56, 0x5), trying 00 (0x50, 0x5)
    int data16[] = { 0x56, 0x5 };
    DW3000Class::write(0x1, 0x14, data16, 2);  //0x1

    // write preamble length, frame length, data rate and prf in TX_FCTRL  //PSR = 1024, TXFLEN = 3 Byte (1 data, 2 CRC) TXBR = 6.81Mb/s, TR Bit enabled, FINE_PLEN = 0x0
    // reg:00:24 bits 0 - 25
    /*int data27[] = {0x03, 0x2C};
    DW3000Class::write(0x0, 0x24, data27, 2);*/





    /*
     * Things to do as documented in https://gist.github.com/egnor/455d510e11c22deafdec14b09da5bf54
     */


    int data17[] = { 0x14 };
    DW3000Class::write(0x7, 0x48, data17, 1); //LDO_RLOAD to 0x14 //0x7
    int data18[] = { 0xE };
    DW3000Class::write(0x7, 0x1A, data18, 1); //RF_TX_CTRL_1 to 0x0E
    int data19[] = { 0x34,0x11,0x07,0x1C };
    DW3000Class::write(0x7, 0x1C, data19, 4); //RF_TX_CTRL_2 to 0x1C071134 (due to channel 5, else (9) to 0x1C010034)

    int data20[] = { 0x3C,0x1F };
    DW3000Class::write(0x9, 0x0, data20, 2); //PLL_CFG to 0x1F3C (due to channel 5, else (9) to 0x0F3C)  //0x9

    int data21[] = { 0x81 };
    DW3000Class::write(0x9, 0x8, data21, 1); //PLL_CAL config to 0x81

    int data22[] = { 0x11 };
    int data23[] = { 0x0 }; //if finished with calibration go back in cal_mode //also used to reset LDO_CTRL to 0x0
 
    
    delay(200);
    for (int i = 0; i < 5; i++) {
        delay(50);
        
        uint32_t h = DW3000Class::read(0x4, 0x20); //Read antenna calibration //RX_CAL_STS => Status bit, if high antenna cal was successful
        if (h > 0) {
            Serial.println("Antenna calibration completed.");
            break;
        }
        else {
            if (i < 4) {
                Serial.println("[WARNING] Antenna auto calibration failed! Retrying...");
                DW3000Class::write(0x4, 0x0C, data22, 1);
            }
            else {
                Serial.println("[ERROR] Antenna auto calibration failed! Aborting!");
            }
        }
    }
    DW3000Class::write(0x4, 0x0C, data23, 1); //Reset antenna calibration to standard mode

    DW3000Class::resetIRQStatusBits();

    Serial.println("\nInitialization finished.\n");

}

begin():

void DW3000Class::begin() {
    delay(5);
    pinMode(CHIP_SELECT_PIN, OUTPUT);
    SPI.begin();

    attachInterrupt(digitalPinToInterrupt(2), DW3000Class::interruptDetect, RISING);
}

write():

uint32_t DW3000Class::write(int base, int sub, int *data, int data_len) {
    int* _base = DW3000Class::getBase(base);
    int* _sub = DW3000Class::getSub(sub);
    readOrWriteFullAddress(_base, 5, _sub, 7, data, data_len, 1);
    free(_base);
    free(_sub);

    return 0;
}

read():

uint32_t DW3000Class::read(int base, int sub) {
    int* _base = DW3000Class::getBase(base);
    int* _sub = DW3000Class::getSub(sub);
    
    int t[] = {0};
    uint32_t tmp;
    tmp = readOrWriteFullAddress(_base, 5, _sub, 7, t, 0, 0);
    Serial.println("");
    free(_base);
    free(_sub);

    return tmp;
}

getBase() & getSub():

int* DW3000Class::getBase(int hex_num)
{
    return hexToBin(hex_num, 5);
}

int* DW3000Class::getSub(int hex_num)
{
    return hexToBin(hex_num, 7);
}

hexToBin():

int* DW3000Class::hexToBin(int hex_num, int bit_size)
{
    int bit_count = bit_size;
    int* binary_num = (int*)malloc(bit_count * sizeof(int));
    int i;
    for (i = bit_count - 1; i >= 0; i--) {
        binary_num[i] = hex_num % 2;
        hex_num >>= 1;
    }
    return binary_num;
}

readOrWriteFullAddress():

uint32_t DW3000Class::readOrWriteFullAddress(int *base, int base_len, int *sub, int sub_len, int *data, int data_len, int readWriteBit) {
    int fill_base_len = 5;
    int num_zeros = fill_base_len - base_len;
    if (num_zeros < 0) {
        num_zeros = 0;
    }
    int fill_base[fill_base_len]; //fill leading zeros

    for (int i = 0; i < fill_base_len; i++) {
        fill_base[num_zeros + i] = base[i];
    }


    int fill_sub_len = 7;
    int fill_sub[fill_sub_len]; //fill leading zeros  
    num_zeros = fill_sub_len - sub_len;
    if (num_zeros < 0) {
        num_zeros = 0;
    }
    for (int i = 0; i < fill_sub_len; i++) {
        fill_sub[num_zeros + i] = sub[i];
    }

    int first_byte[8] = { readWriteBit, 1 };
    for (int i = 0; i < fill_base_len; i++) {
        first_byte[i + 2] = fill_base[i];
    }
    first_byte[7] = fill_sub[0];

    int second_byte[8];
    second_byte[8 - 1] = 0; //Last two bits are set to 0 (mode selector bits)
    second_byte[8 - 2] = 0;

    for (int i = 0; i < fill_sub_len - 1; i++) {
        second_byte[i] = fill_sub[i + 1];
    }

    int byteOne = 0;
    int byteTwo = 0;

    for (int i = 7; i >= 0; i--) {
        byteOne = byteOne + first_byte[i] * round(pow(2, 7 - i));
        byteTwo = byteTwo + second_byte[i] * round(pow(2, 7 - i));
    }

    uint32_t val;

    int bytes[data_len + 2] = { byteOne, byteTwo };

    for (int i = 0; i < data_len; i++) {
        bytes[i + 2] = data[i];
    }

    uint32_t res;

    if (readWriteBit == 0) {
        Serial.print("Reading from ");
        for (int i = 0; i < fill_base_len; i++) {
            Serial.print(fill_base[i]);
        }
        Serial.print(":");
        for (int i = 0; i < fill_sub_len; i++) {
            Serial.print(fill_sub[i]);
        }
        Serial.println("");
        res = (uint32_t)sendBytes(bytes, 2 + data_len, 4);
        Serial.print("Received result (HEX): ");
        Serial.print(res, HEX);
        Serial.print(" (BIN): ");
        Serial.println(res, BIN);
        return res;
    }
    else {
        Serial.print("Writing to ");
        for (int i = 0; i < fill_base_len; i++) {
            Serial.print(fill_base[i]);
        }
        Serial.print(":");
        for (int i = 0; i < fill_sub_len; i++) {
            Serial.print(fill_sub[i]);
        }
        Serial.println("");
        res = (uint32_t)sendBytes(bytes, 2 + data_len, 0);
        return res;
    }
}

sendBytes():

uint32_t DW3000Class::sendBytes(int b[], int lenB, int recLen) { //WORKING
    digitalWrite(CHIP_SELECT_PIN, LOW);
    for (int i = 0; i < lenB; i++) {
        SPI.transfer(b[i]);
    }
    int rec;
    uint32_t val, tmp;
    if (recLen > 0) {
        for (int i = 0; i < recLen; i++) {
            tmp = SPI.transfer(0x00);
            if (i == 0) {
                val = tmp; //Read first 4 octets
            }
            else {
                val |= (uint32_t)tmp << 8 * i;
            }
        }
    }
    else {
        val = 0;
    }
    digitalWrite(CHIP_SELECT_PIN, HIGH);
    return val;
}

standardTX():

void DW3000Class::standardTX() {
    if (cmd_error) {
        cmd_error = false;
        int cmd[] = { 0 };
        writeShortCommand(cmd, 1);
    }
    int data[] = { 0x36 };
    DW3000Class::write(0x14, 0x0, data, 1);
    int cmd[] = { 1 };
    DW3000Class::writeShortCommand(cmd, 1);
}

standardRX():

void DW3000Class::standardRX() {
    int cmd[] = { 1,0 };
    DW3000Class::writeShortCommand(cmd, 2);
}

I am so so sorry, that’s actually quite more than I expected it to be. If any method is missing just let me know! I am still working on making it pretty, for now it’s just a “as long as it works, it’s not dumb” approach. As I stated above, I suppose I am doing something wrong in the init() function.

In my normal program, I do the following:

#include <DW3000.h>

bool mode = 0
bool sent_rx = false

void setup() {
  Serial.begin(115200);
  DW3000.begin();
  DW3000.init();
}




void loop() {
  if(mode){ //TX
    DW3000.standardTX();
    
    delay(1000);
  }else{ //RX
    if(!sent_rx){
      DW3000.standardRX();
      sent_rx = true;
    }
  }
}

Hi Philip, I can’t find the function writeShort command, you use this but there is no description.Can you please throw off the entire project with the Arduino IDE

Thank you for your reply!
The whole library can be found on github. :slight_smile:

Best regards
Fhilb

Hello, friend! I’m trying to figure out your code, but it doesn’t quite work out.What should I change in the code so that one device works as a transmitter and the second as a receiver.How to understand that a transfer has occurred, and what type of data is being transmitted?

Sorry for my late reply. I now uploaded two Arduino scripts on the github here. The github code of the library isn’t working at the time as it is currently in work, so just stick with your older version :slight_smile:

Thanks for your help!

Best regards
Fhilb

Hello, my friend.I am using the old version, but I have a question how to adapt the code separately for the transmitter and receiver.Thank you for your answers and help