CRC errors receiving packets with Coded PHY and S=2

Code running on nRF52833 devkit version 1.0.0 that continuously sends an empty 500 kbit/s radio packet:

int main(void) {
    uint8_t packet[3] = {0, 0, 0};

    NRF_CLOCK->TASKS_HFCLKSTART = 1;
    while (!NRF_CLOCK->EVENTS_HFCLKSTARTED) {
    }

    // Radio config
    NRF_RADIO->TXPOWER = (RADIO_TXPOWER_TXPOWER_Pos4dBm << RADIO_TXPOWER_TXPOWER_Pos);
    NRF_RADIO->MODECNF0 = (RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos) | (RADIO_MODECNF0_DTX_Center << RADIO_MODECNF0_DTX_Pos);
    NRF_RADIO->TXADDRESS = 0x00UL;
    NRF_RADIO->CRCCNF = (RADIO_CRCCNF_LEN_Three << RADIO_CRCCNF_LEN_Pos) | (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos);
    NRF_RADIO->CRCPOLY = 0x0000065B;
    
    // Radio address config
    uint32_t aa = 0x53abcdef;
    NRF_RADIO->PREFIX0 = aa >> 24;
    NRF_RADIO->BASE0 = aa << 8;

    // Packet configuration
    NRF_RADIO->PCNF0 = (1                           << RADIO_PCNF0_S0LEN_Pos) |
                       (0                           << RADIO_PCNF0_S1LEN_Pos) |
                       (RADIO_PCNF0_S1INCL_Include  << RADIO_PCNF0_S1INCL_Pos) |
                       (8                           << RADIO_PCNF0_LFLEN_Pos) |
                       (2                           << RADIO_PCNF0_CILEN_Pos) |
                       (RADIO_PCNF0_PLEN_LongRange  << RADIO_PCNF0_PLEN_Pos) |
                       (3                           << RADIO_PCNF0_TERMLEN_Pos);

    // Packet configuration
    NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Enabled  << RADIO_PCNF1_WHITEEN_Pos) |
                       (RADIO_PCNF1_ENDIAN_Little    << RADIO_PCNF1_ENDIAN_Pos)  |
                       (3                            << RADIO_PCNF1_BALEN_Pos)   |
                       (0                            << RADIO_PCNF1_STATLEN_Pos) |
                       (255                          << RADIO_PCNF1_MAXLEN_Pos);
    
    NRF_RADIO->CRCINIT = 0x00555555;

    NRF_RADIO->FREQUENCY = 10;
    NRF_RADIO->DATAWHITEIV = 3;

    NRF_RADIO->PACKETPTR = (uintptr_t)packet;

    NRF_RADIO->MODE      = (RADIO_MODE_MODE_Ble_LR500Kbit << RADIO_MODE_MODE_Pos);

    NRF_TIMER0->BITMODE = TIMER_BITMODE_BITMODE_32Bit;
    NRF_TIMER0->PRESCALER = 4;

    NRF_RADIO->SHORTS = RADIO_SHORTS_TXREADY_START_Msk | RADIO_SHORTS_PHYEND_DISABLE_Msk;

    NRF_TIMER0->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk;
    NRF_TIMER0->CC[0] = 45000;

    NRF_PPI->CH[0].EEP = (uintptr_t)&NRF_TIMER0->EVENTS_COMPARE[0];
    NRF_PPI->CH[0].TEP = (uintptr_t)&NRF_RADIO->TASKS_TXEN;
    NRF_PPI->CHENSET = PPI_CHENSET_CH0_Msk;

    NRF_TIMER0->TASKS_START = 1;
    for (;;) {
        __WFI();
    }
}

Code running on nRF54L15 devkit version 0.8.1 with chip revision QFAABB 2433AA that on every packet receipt prints CRC status to the console as well as showing LED indicating CRC ok/error:

void test_rx(void) {
    uint8_t packet[3 + 255];

    NRF_RADIO->RXADDRESSES = 0x01UL;
    NRF_RADIO->CRCCNF = (RADIO_CRCCNF_LEN_Three << RADIO_CRCCNF_LEN_Pos) | (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos);
    NRF_RADIO->CRCPOLY = 0x0000065B;

    NRF_RADIO->MODE = (RADIO_MODE_MODE_Ble_LR125Kbit << RADIO_MODE_MODE_Pos);

    // Packet configuration
    NRF_RADIO->PCNF0 = (1                           << RADIO_PCNF0_S0LEN_Pos) |
                       (0                           << RADIO_PCNF0_S1LEN_Pos) |
                       (RADIO_PCNF0_S1INCL_Include  << RADIO_PCNF0_S1INCL_Pos) |
                       (8                           << RADIO_PCNF0_LFLEN_Pos) |
                       (2                           << RADIO_PCNF0_CILEN_Pos) |
                       (RADIO_PCNF0_PLEN_LongRange  << RADIO_PCNF0_PLEN_Pos) |
                       (3                           << RADIO_PCNF0_TERMLEN_Pos);

    // Packet configuration
    NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Enabled  << RADIO_PCNF1_WHITEEN_Pos) |
                       (RADIO_PCNF1_ENDIAN_Little    << RADIO_PCNF1_ENDIAN_Pos)  |
                       (3                            << RADIO_PCNF1_BALEN_Pos)   |
                       (0                            << RADIO_PCNF1_STATLEN_Pos) |
                       (255                          << RADIO_PCNF1_MAXLEN_Pos);

    NRF_RADIO->CRCINIT = 0x00555555;

    NRF_RADIO->PACKETPTR = (uintptr_t)packet;

    NRF_RADIO->FREQUENCY = 10;
    NRF_RADIO->DATAWHITE = ((0x40 | 3) << RADIO_DATAWHITE_IV_Pos) | (0x89 << RADIO_DATAWHITE_POLY_Pos);

    uint32_t aa = 0x53abcdef;
    NRF_RADIO->PREFIX0 = aa >> 24;
    NRF_RADIO->BASE0 = aa << 8;

    NRF_CLOCK->TASKS_PLLSTART = 1;
    NRF_CLOCK->TASKS_XOSTOP = 1;
    NRF_CLOCK->EVENTS_XOTUNED = 0;
    NRF_CLOCK->TASKS_XOSTART = 1;
    while (!NRF_CLOCK->EVENTS_XOTUNED) {
    }

    NRF_RADIO->EVENTS_RXREADY = 0;
    NRF_RADIO->TASKS_RXEN = 1;
    while (!NRF_RADIO->EVENTS_RXREADY) {
    }

    NRF_P1->PIN_CNF[10] = (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos);
    NRF_P1->PIN_CNF[14] = (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos);

    unsigned int cnt = 0;
    for (;;) {
        NRF_RADIO->EVENTS_END = 0;
        NRF_RADIO->TASKS_START = 1;
        while (!NRF_RADIO->EVENTS_END) {
        }
        unsigned int crc_ok = NRF_RADIO->CRCSTATUS;
        printf("%u %u\n", ++cnt, crc_ok);
        NRF_P1->OUTSET = 1U << (crc_ok ? 10 : 14);
        for (volatile int i = 0; i < 10000; i++);
        NRF_P1->OUTCLR = 1U << (crc_ok ? 10 : 14);
    }
}

nRF Connect SDK version is 2.8.0.

Result:

The first packet received has CRC status ok. The subsequent packets typically have CRC status error. If stepping through the code with a debugger line by line, the CRC ok rate increases a bit.

Running similar RX code on an nRF52 device, the code works as expected and CRC status is typically always ok.

If TX mode is changed to Coded PHY 125kbit/s instead, the problem disappears when receiving on nRF54L15 and CRC is typically always ok.

Question: why is this happening? I think I have followed the radio peripheral documentation correctly.

Parents Reply
  • Hi,

    I am sorry for the delay. We are looking into the details, but you can make this work by disabling and re-enabling the radio between receptions. You can do that by adding a pair for shorts:

    NRF_RADIO->SHORTS = RADIO_SHORTS_PHYEND_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk;

    and modifying your loop to wait on PHYEND and trigger RXEN instead of START like this:

            NRF_RADIO->EVENTS_PHYEND = 0;
            NRF_RADIO->TASKS_RXEN = 1;
            while (!NRF_RADIO->EVENTS_PHYEND) {}

    Also, while not related for this specific issue, I suggest you also add handling of erratum 20 by enabling constant latency mode while the radio is active.

Children
  • Hi again, did you got any details yet?

    1) I can see that disabling and re-enabling the radio seems to work as a workaround. However, this introduces a time window where no packets can be received, compared to when using e.g. the shortcut END_START, since it takes time to disable and ramp-up the radio. Are you basically saying that the END_START shortcut or similar approaches are broken on nRF54L15 for S=2?

    2) It also appears that if the radio has been off for a few milliseconds, the fast ramp-up time of 40 µs as specified in the data sheet is not enough for correct (non-CRC error) reception of S=2 packets. Specifically, if I start RX ramp up on the nRF54L15 ca 48 µs before the packet transmission is initiated by the sender or earliehr, then there are no CRC errors. If I instead start RX ramp up 40 µs before transmission is initiated by the sender or later, the packet will be received but often with CRC errors with a non-zero percentage. The time the radio has been off before as well as the quality of the transmitter seems to heavily affect the results. With S=8 packets, it generally works fine to receive packets as long RX ramp up starts 10 µs before transmission is initiated or earlier (taking into account that there is an RX chain delay of ca 30 µs in that case). I find this difference a bit surprising as the first part of the packet is always sent with S=8, so the required ramp-up time should be the same for both S=2 and S=8. On the nRF52 series, S=2 did not have any of these problems.

    3) Is there any reason these two issues above are not mentioned in the errata? I saw in an earlier errata for Engineering A version that S=2 had some issues regarding degraded sensitivity, but not sure if that was another issue which has now been solved.

    4) Regarding erratum 20, according to symptoms, conditions and consequences, this only seems to affect transmission (not reception). However the workaround suggests to use constlat even before triggering RXEN. What is the reason for that? Either the symptoms, conditions and consequences are wrong (missing to state that reception is also affected) or the workaround is for RXEN is unnecessary. I have indeed seen that transmission is corrupted when the conditions are true but have never seen any general problem regarding reception except for this issue (it doesn't seem to fix or affect the S=2 RX issue in any way). Since keeping the MCU domain active requires additionally ~0.3 mA at 3 V and 128 MHz if the radio is active, it seems like a bad idea to do this unless when strictly necessary.

  • Hi,

    Emil Lenngren said:
    Are you basically saying that the END_START shortcut or similar approaches are broken on nRF54L15 for S=2?

    That seems to be the case, but we have not understood the root cause yet. We are looking into this, but I do not expect we will have a full understanding of the root cause in some time (that will probably also not be public as this is internally in the radio).

    I understand that the disablign and re-enabling of the radio is not ideal as it takes a bit of time, but that is the only viable solution for now. This is also what we do internally in the SoftDevice controller.

    Emil Lenngren said:
    Is there any reason these two issues above are not mentioned in the errata

    I need to look into that. Generally though, erratas are not published before investigation of an issue has completed and also not always if there are effectve workaroudns in the SDK.

    Emil Lenngren said:
    Regarding erratum 20, according to symptoms, conditions and consequences, this only seems to affect transmission (not reception).

    This errata text is unfotunate, but you should apply this for both Tx and Rx (as describeed in the suggested workaround).

  • Thanks for the quick reply! I will use these workarounds in the meantime.

Related