DW3000 HPDWARN errata: need clarification

Hello ultrawideband friends,

The DW3000 User Manual includes the following section in 9.4.1 “Delayed TX Notes”:

Due to an errata in the DW3000, there is a case when neither the HPDWARN event gets set nor does the packet get transmitted. This happens when the time at which the transmitter needs to be enabled to send occurs within the analog front-end power up time preceding the current time. To avoid this bug reliably, the delayed send time must be set far enough in advance; it should be at least equal or more than the current time + preamble length + SFD length + 20 µs, or the time should be passed which will give rise to HPDWARN.

The host can check for this issue by reading the PMSC_STATE. When this bug occurs, the PMSC_STATE will be “TX” but TX_STATE will be “IDLE”, the TXFRS event will never be set, see state descriptions in Sub-register 0x0F:30 – System state. The host should abort the transmission in this case. This check and recovery is implemented in the published DW3000 dwt-starttx() API.

I’m implementing to the registers (my target controller is not supported by your API) and alas your API is a “binary blob” so I can’t see the implementation of dwt_starrtx(). So, I’m just going by the text, but having some trouble:

First of all, PMSC_STATE apparently lives in SYS_STATE, but the SYS_STATE register is inconsistently documented. The bitfield diagram lists TX_STATE (bits 0-3), RX_STATE (bits 8-13) and TSE_STATE (bits 16-20). However, the text description lists TX_STATE (bits 0-3), RX_STATE (bits 8-11!), and PMSC_STATE (bits 16-23), with no TSE_STATE. Which is to be believed?

Following the text description (since the diagram has no PMSC_STATE at all!), I attempt to implement this with logic something like this:

    auto const state = dw3k_read<uint32_t>(DW3K_SYS_STATE);
    auto const pmsc = (state >> 16) & 0xFF;
    if ((state & 0xF) == 0 && pmsc >= 0x08 && pmsc <= 0x0F) {
      last_status = DW3KStatus::ChipError;
      error_text = "Chip: Scheduled too late*";

However, this generates many false positives on (what would otherwise be) successful transmissions, where PMSC_STATE becomes 0xA (described as indicating the TX WAIT state) and TX_STATE is 0 (idle) but that’s perfectly normal during TX WAIT. So, I added a carve-out:

    if ((state & 0xF) == 0 && pmsc >= 0x08 && pmsc <= 0x0F && pmsc != 0x0A) ...

Even that doesn’t work reliably, though – again, it produces false positives. I’d really like to know what the API dwt_starttx() actually does! If someone with access could just look that up and tell me what the logic is (or tell me where I can find the source code, if it is in fact available). Or, at least clarify the inconsistent manual text and confirm the field definitions?

Thank you kindly!
– egnor

Aha, I was able to find a version of the API that comes with source. (I think I was confused by the various downloads available.)

In decadriver.c, in dwt_starttx() line 3729 I see this:

            sys_state = dwt_read32bitreg(SYS_STATE_LO_ID);
            if (sys_state == DW_SYS_STATE_TXERR)
                retval = DWT_ERROR ; // Failed !

DW_STATE_TXERR is defined in deca_device_api.h, line 246:

#define DW_SYS_STATE_TXERR          0xD0000         // TSE is in TX but TX is in IDLE in SYS_STATE_LO register

So this actually refers to TSE, not PMSC_STATE, and only checks for the very specific TSE (PMSC_STATE?) value 0xD. I’m not sure which state this corresponds to but it must be the signature of this particular issue? Please confirm?

– egnor

Closing the loop for anyone else who finds this: I’ve covered this in the “Missing Manual” notes.