DWM3000 Failing After Soldering – Short Between VCC and GND After Few Minutes of Operation

Hi everyone,

I’ve run into a recurring issue while working with the DWM3000 UWB module on my custom PCB module to connect to an ESP32. I’ve successfully soldered and brought up a few DWM3000 chips, however out of 12 of them, 5 of them works well without issues. But out of the other 7, I notice 3 of them had a strange failure pattern.

After soldering a new DWM3000 chip:

  • The module works normally for the first 2–3 minutes
  • Then it suddenly stops functioning.
  • On removing power and checking with a multimeter, I find that there’s now a short circuit between VCC and GND.
  • This has happened with multiple chips, although not all. Some continue to work fine.

Attached below is the schematic used, i have soldered everything except for R3,R4, LED3 and LED4.

The code that I was using was the Makerfabs-ESP32-UWB-DW3000
ex_01a_simple_tx.ino example

(GitHub - Makerfabs/Makerfabs-ESP32-UWB-DW3000)
#include “dw3000.h”

#define APP_NAME “SIMPLE TX v1.1”

// connection pins
const uint8_t PIN_RST = 27; // reset pin
const uint8_t PIN_IRQ = 34; // irq pin
const uint8_t PIN_SS = 4; // spi select pin

/* Default communication configuration. We use default non-STS DW mode. /
static dwt_config_t config = {
5, /
Channel number. /
DWT_PLEN_128, /
Preamble length. Used in TX only. /
DWT_PAC8, /
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 8 symbol SFD, 1 to use non-standard 8 symbol, 2 for non-standard 16 symbol SFD and 3 for 4z 8 symbol SDF type /
DWT_BR_6M8, /
Data rate. /
DWT_PHRMODE_STD, /
PHY header mode. /
DWT_PHRRATE_STD, /
PHY header rate. /
(129 + 8 - 8), /
SFD timeout (preamble length + 1 + SFD length - PAC size). Used in RX only. /
DWT_STS_MODE_OFF,
DWT_STS_LEN_64, /
STS length, see allowed values in Enum dwt_sts_lengths_e /
DWT_PDOA_M0 /
PDOA mode off */
};

/* The frame sent in this example is an 802.15.4e standard blink. It is a 12-byte frame composed of the following fields:

  • - byte 0: frame type (0xC5 for a blink).
    
  • - byte 1: sequence number, incremented for each new frame.
    
  • - byte 2 -> 9: device ID, see NOTE 1 below.
    

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

#define FRAME_LENGTH (sizeof(tx_msg) + FCS_LEN) // The real length that is going to be transmitted

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

extern dwt_txconfig_t txconfig_options;

void setup()
{
UART_init();
test_run_info((unsigned char *)APP_NAME);

/* Configure SPI rate, DW3000 supports up to 38 MHz /
/
Reset DW IC */
spiBegin(PIN_IRQ, PIN_RST);
spiSelect(PIN_SS);

delay(200); // Time needed for DW3000 to start up (transition from INIT_RC to IDLE_RC, or could wait for SPIRDY event)

while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding
{
test_run_info((unsigned char *)“IDLE FAILED01\r\n”);
while (100)
;
}

dwt_softreset();
delay(200);

while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding
{
test_run_info((unsigned char *)“IDLE FAILED02\r\n”);
while (100)
;
}

// test_run_info((unsigned char *)“IDLE OK\r\n”);
if (dwt_initialise(DWT_DW_INIT) == DWT_ERROR)
{
test_run_info((unsigned char *)“INIT FAILED\r\n”);
while (100)
;
}
// test_run_info((unsigned char *)“INIT OK\r\n”);

// Enabling LEDs here for debug so that for each TX the D1 LED will flash on DW3000 red eval-shield boards.
dwt_setleds(DWT_LEDS_ENABLE | DWT_LEDS_INIT_BLINK);

// Configure DW IC. See NOTE 5 below.
if (dwt_configure(&config)) // if the dwt_configure returns DWT_ERROR either the PLL or RX calibration has failed the host should reset the device
{
test_run_info((unsigned char *)“CONFIG FAILED\r\n”);
while (100)
;
}
// test_run_info((unsigned char )“CONFIG OK\r\n”);
/
Configure the TX spectrum parameters (power PG delay and PG Count) */
dwt_configuretxrf(&txconfig_options);
}

void loop()
{
/* Write frame data to DW IC and prepare transmission. See NOTE 3 below./
dwt_writetxdata(FRAME_LENGTH - FCS_LEN, tx_msg, 0); /
Zero offset in TX buffer. */

/* In this example since the length of the transmitted frame does not change,

  • nor the other parameters of the dwt_writetxfctrl function, the
  • dwt_writetxfctrl call could be outside the main while(1) loop.
    /
    dwt_writetxfctrl(FRAME_LENGTH, 0, 0); /
    Zero offset in TX buffer, no ranging. */

/* Start transmission. */
dwt_starttx(DWT_START_TX_IMMEDIATE);
delay(10); // Sleep(TX_DELAY_MS);

/* Poll DW IC until TX frame sent event set. See NOTE 4 below.

  • STATUS register is 4 bytes long but, as the event we are looking at is in the first byte of the register, we can use this simplest API
  • function to access it.*/

while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS_BIT_MASK))
{
test_run_info((unsigned char )“WHAT!!!\r\n”);
/
Reads and validate device ID returns DWT_ERROR if it does not match expected else DWT_SUCCESS */
// if (dwt_check_dev_id() == DWT_SUCCESS)
{
// UART_puts((char *)“DEV ID OK”);
}
// else
{
// UART_puts((char *)“DEV ID FAILED”);
}
// delay(500);
// dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS_BIT_MASK);
// delay(1000);
};

/* Clear TX frame sent event. */
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS_BIT_MASK);

test_run_info((unsigned char *)“TX Frame Sent”);

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

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

/*****************************************************************************************************************************************************

  • NOTES:
    1. The device ID is a hard coded constant in the blink to keep the example simple but for a real product every device should have a unique ID.
  • For development purposes it is possible to generate a DW IC unique ID by combining the Lot ID & Part Number values programmed into the
  • DW IC during its manufacture. However there is no guarantee this will not conflict with someone else�s implementation. We recommended that
  • customers buy a block of addresses from the IEEE Registration Authority for their production items. See “EUI” in the DW IC User Manual.
    1. In a real application, for optimum performance within regulatory limits, it may be necessary to set TX pulse bandwidth and TX power, (using
  • the dwt_configuretxrf API call) to per device calibrated values saved in the target system or the DW IC OTP memory.
    1. dwt_writetxdata() takes the full size of tx_msg as a parameter but only copies (size - 2) bytes as the check-sum at the end of the frame is
  • automatically appended by the DW IC. This means that our tx_msg could be two bytes shorter without losing any data (but the sizeof would not
  • work anymore then as we would still have to indicate the full length of the frame to dwt_writetxdata()).
    1. We use polled mode of operation here to keep the example as simple as possible, but the TXFRS status event can be used to generate an interrupt.
  • Please refer to DW IC User Manual for more details on “interrupts”.
    1. Desired configuration by user may be different to the current programmed configuration. dwt_configure is called to set desired
  • configuration.
    ****************************************************************************************************************************************************/

Just some thoughts… not sure, guessing of the electrical problems.

“ * On removing power and checking with a multimeter, I find that there’s now a short circuit between VCC and GND.”

Is your multimeter powered from 9v battery?

Thinking on the sequence:

  • some code does not work (because a simple code, maybe spi issues - randomly), module goes to a strange state, visible as “module does not respond”.
  • probing the module with multimeter, and 9V shock kills it: we see the problem of gnd&vcc shortcut now.
  • Now module is killed and guarantee would not work in the future.

If I were you, l would completely disconnect the device from any sources of power, as well from debug interface.
Would wait for 5min.
Add to the code “wakeup” using SPI CS line hold it low for 200-300us would wake chip up.

Power back, connect debugger, looked if we can execute “wakeup and read_dev_id”…

Regards…

Reset isn’t supposed to be driven high, you should only use an open drain driver on that pin. That said you have 1k in series so I don’t see how that could be an issue.

Just to be sure - you did check that the 3.3V rail is connected to a 3.3V source not 5V? It’s all too easy to made a silly mistake like that at times.
You’re using an ESP so I assume all IO pins are only 3.3V not 5V?

Hi, just to clarify:

For the two chips that start up normally and work for about 3 minutes before becoming unresponsive to SPI:

  1. I removed power from the board and checked for shorts using a 9V multimeter.
  2. Once I confirmed there was no short, I powered the board again. The circuit then worked for the aforementioned 3 to 5 minutes before becoming unresponsive once more.

So, it doesn’t seem like the multimeter voltage is damaging the chip.

I have since discovered that the flux I used — Pro’sKit 8S005 — wasn’t thoroughly cleaned off. Since this flux is slightly conductive, it most likely caused the issue. For the chips that were starting up properly, I removed the remaining flux by heating it and then cleaning the chip and PCB with ethanol. After this cleaning process, the issue appears to be resolved.

As for the other chips that are permanently shorted between VCC and GND, it seems there’s nothing I can do to recover them.

The design was based on the ESP32 UWB DW3000 module by Makerfabs, and I believe the RESET pin was configured for open-drain operation. I also verified that all GPIO pins are operating at 3.3V, and that VCC is consistently 3.3V as well.

Thanks again for the feedback!