This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

MCU reboots when the radio is in RX state and power management is used.

Dear support,

I am developing a TDMA protocol on a custom board with the NRF52840 and SEGGER EMbedded Studio and the SDK 15.0.0. Everything went well until I wished to reduce the power consumption using nrf_pwr_mgmt_run().

Now, on the logical analyser, I observe  that the MCU reboots about 2.6 ms after the radio is listening (READY event and START by shortcut).

Trying to solve the problem, I reduced my code and removed my protocol and I could reproduce the problem with the code below:

Radio initialisation (mode = proprietary 1 Mbps, same issue observed with BLE_1Mbps):

void radio_Init()
{
    wiseradio.hfClockAlwaysOn = FALSE;
    wiseradio.txStartCallback = NULL;
    // Proprietary mode 1 Mbps
    NRF_RADIO->MODE      = (RADIO_MODE_MODE_Nrf_1Mbit << RADIO_MODE_MODE_Pos);

    // Radio config
    WiseRadio.radio_SetTxPower(RADIO_TXPOWER_TXPOWER_Pos4dBm);
    WiseRadio.radio_SetChannel(mib.beaconChannel);

    // Radio address config
    NRF_RADIO->PREFIX0 =
        ((uint32_t)swap_bits(0xC3) << 24) // Prefix byte of address 3 converted to nRF24L series format
      | ((uint32_t)swap_bits(0xC2) << 16) // Prefix byte of address 2 converted to nRF24L series format
      | ((uint32_t)swap_bits(0xC1) << 8)  // Prefix byte of address 1 converted to nRF24L series format
      | ((uint32_t)swap_bits(0xC0) << 0); // Prefix byte of address 0 converted to nRF24L series format

    NRF_RADIO->PREFIX1 =
        ((uint32_t)swap_bits(0xC7) << 24) // Prefix byte of address 7 converted to nRF24L series format
      | ((uint32_t)swap_bits(0xC6) << 16) // Prefix byte of address 6 converted to nRF24L series format
      | ((uint32_t)swap_bits(0xC4) << 0); // Prefix byte of address 4 converted to nRF24L series format

    NRF_RADIO->BASE0 = bytewise_bitswap(0x01234567UL);  // Base address for prefix 0 converted to nRF24L series format
    NRF_RADIO->BASE1 = bytewise_bitswap(0x89ABCDEFUL);  // Base address for prefix 1-7 converted to nRF24L series format

    NRF_RADIO->TXADDRESS   = 0x00UL;  // Set device address 0 to use when transmitting
    NRF_RADIO->RXADDRESSES = 0x01UL;  // Enable device address 0 to use to select which addresses to receive

    // Packet configuration
    NRF_RADIO->PCNF0 = (PACKET_S1_FIELD_SIZE     << RADIO_PCNF0_S1LEN_Pos) |
                       (PACKET_S0_FIELD_SIZE     << RADIO_PCNF0_S0LEN_Pos) |
                       (PACKET_LENGTH_FIELD_SIZE << RADIO_PCNF0_LFLEN_Pos); //lint !e845 "The right argument to operator '|' is certain to be 0"

    // Packet configuration
    NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) |
                       (RADIO_PCNF1_ENDIAN_Big       << RADIO_PCNF1_ENDIAN_Pos)  |
                       (PACKET_BASE_ADDRESS_LENGTH   << RADIO_PCNF1_BALEN_Pos)   |
                       (PACKET_STATIC_LENGTH         << RADIO_PCNF1_STATLEN_Pos) |
                       (PACKET_PAYLOAD_MAXSIZE       << RADIO_PCNF1_MAXLEN_Pos); //lint !e845 "The right argument to operator '|' is certain to be 0"

    // CRC Config
    NRF_RADIO->CRCCNF = (RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos); // Number of checksum bits
    if ((NRF_RADIO->CRCCNF & RADIO_CRCCNF_LEN_Msk) == (RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos))
    {
        NRF_RADIO->CRCINIT = 0xFFFFUL;   // Initial value
        NRF_RADIO->CRCPOLY = 0x11021UL;  // CRC poly: x^16 + x^12^x^5 + 1
    }
    else if ((NRF_RADIO->CRCCNF & RADIO_CRCCNF_LEN_Msk) == (RADIO_CRCCNF_LEN_One << RADIO_CRCCNF_LEN_Pos))
    {
        NRF_RADIO->CRCINIT = 0xFFUL;   // Initial value
        NRF_RADIO->CRCPOLY = 0x107UL;  // CRC poly: x^8 + x^2^x^1 + 1
    }
    WiseRadio.radio_Off();
}

Turn off radio = turn off HFCLK clock as the radio is disabled by END -> DISABLE shortcut: In this case hfClockAlwaysOn is FALSE.

void radio_Off(void)
{
    DBG_DISPLAY_VAL8(0xA8);
    NRF_RADIO->EVENTS_DISABLED = 0;
    NRF_RADIO->TASKS_DISABLE = 1;
    //while (NRF_RADIO->EVENTS_DISABLED == 0){}   //Wait while radio is ramping down.   
    if (wiseradio.hfClockAlwaysOn == FALSE) {
        stop_NrfHFClock();
    }
    wiseradio.state = WISERADIO_IDLE;
}

The test program initialises the board and starts a timer which turns the radio on, set it in listening mode and when something is received, the radio is turned off and a new timer starts the same process again.

Turn on radio:

void radio_On (void)  
{
    // Because we are using the shortcuts between READY and START, here radio_On basically means
    // starting the HF clock, which takes about 350 us. The delay on waiting for this operation
    // should be set to 400 us to be on the safe side.   
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_HFCLKSTART    = 1;
}

Start listening:

void  radio_ReceiveFrame(uint8_t *buf, uint8_t maxlen, uint8_t * lenPtr, uint8_t *rssiPtr, t_timTime *timePtr,
                              void (*funStart)(void *), void (*funEnd)(void *))
{
    DBG_DISPLAY_VAL8(0xC6);
    wiseradio.rxBufLen = maxlen;
    wiseradio.rxCallback = funEnd;
    wiseradio.startCallback = funStart;
    wiseradio.rxLenPtr = lenPtr;
    *wiseradio.rxLenPtr = 0;
    wiseradio.rssiPtr = rssiPtr;
    *wiseradio.rssiPtr= 0;
    wiseradio.timePtr = timePtr;
    wiseradio.rxBufPtr = buf;
    wiseradio.rxBufferAvailable = 1;

    NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) |
                       (RADIO_PCNF1_ENDIAN_Big       << RADIO_PCNF1_ENDIAN_Pos)  |
                       (PACKET_BASE_ADDRESS_LENGTH   << RADIO_PCNF1_BALEN_Pos)   |
                       (PACKET_STATIC_LENGTH         << RADIO_PCNF1_STATLEN_Pos) |
                       (((uint32_t) maxlen)          << RADIO_PCNF1_MAXLEN_Pos);
    NRF_RADIO->PACKETPTR = (uint32_t)buf;
    NRF_RADIO->SHORTS = (RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos) |
                        (RADIO_SHORTS_END_DISABLE_Enabled << RADIO_SHORTS_END_DISABLE_Pos);

    wiseradio.state = WISERADIO_RX_WAIT_SYNC;
    NRF_RADIO->EVENTS_END = 0;
    NRF_RADIO->EVENTS_READY = 0;
    NRF_RADIO->EVENTS_ADDRESS = 0;
    NRF_RADIO->EVENTS_PAYLOAD = 0;
    NRF_RADIO->TASKS_RXEN = 1;
}

Finally, the main program:

int main(void)
{
    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    appl_Init();  // init system such as timer

    wisenode_SetUpGPIOs();  // simply configure some GPIOs
    //wisenode_SetupI2C();
   

    DBG_DISPLAY_VAL8(0x89);
    DBG_TRIGGER(6);

    // This function starts a time with startRxTest as call back. It uses app_timer_create() and app_timer_start()
    tim_TimerStartFast(TIM_TIMER_MAC1, TIM_ONE_SHOT, 100000, startRxTest, NULL, FALSE); // timeout in microseconds, thus here 100ms

    LED1_OFF();
    LED2_OFF();
    LED3_OFF();

    nrf_pwr_mgmt_init();

    while (TRUE) {
        nrf_pwr_mgmt_run();
    }
}

void startRxTest(void* arg)
{
    WiseRadio.radio_On();

    // RADIO_OFF_TO_HFCLK_ON_DELAY_US = 400 us. Increasing this value doesn't help.
    tim_TimerStartFast(TIM_TIMER_MAC1, TIM_ONE_SHOT, RADIO_OFF_TO_HFCLK_ON_DELAY_US, rxTest, NULL, FALSE);   
}

void rxTest(void* arg)
{
    DBG_TRIGGER(4);
    MyBuffer = buff_RxGetNew();

    WiseRadio.radio_ReceiveFrame((uint8_t*) dataBuf[MyBuffer].buffer, BUFF_MAX_SIZE-1, (uint8_t*) &(dataBuf[MyBuffer].len),
                                 (uint8_t*) &(dataBuf[MyBuffer].rxRssi), (t_timTime*) &(dataBuf[MyBuffer].receivedTime),
                                 rxTestStart, rxTestEnd);
}

// This routine below is called when the radio triggers the END event.

void rxTestEnd(void* arg)
{
    uint8_t i;
    uint8_t len;
    uint8_t status;

    DBG_TRIGGER(3);
    DBG_DISPLAY_VAL8(0xBF);   
    status = WiseRadio.radio_ReturnState();
    DBG_DISPLAY_VAL8(status);
    len = dataBuf[MyBuffer].len;
    /*DBG_DISPLAY_VAL8(len);
    DBG_DISPLAY_VAL8(dataBuf[MyBuffer].buffer[0]);
    if (status == WISERADIO_RX_COMPLETE) {
        for (i = 1; i <= len; i++) {
            DBG_DISPLAY_VAL8(dataBuf[MyBuffer].buffer[i]);
        }
    }*/
    WiseRadio.radio_Off();
    tim_TimerStartFast(TIM_TIMER_MAC1, TIM_ONE_SHOT, 10000, startRxTest, NULL, FALSE);
    buff_Release(MyBuffer, 0xE1);
}

When the program is executed, the MCU crashes (= reboots) about 2.6 ms after the radio event READY is thrown shortly after rxTest() is executed. If nrf_pwr_mgmt_run(); is commented out in the main loop, the same problem appears. However, if some instruction that turns on and off a GPIO is added instead of nrf_pwr_mgmt_run();, then there is no reboot.

I have spent lots of time trying to understand this issue without succes, thus any help would be greatly appreciated. Thanks and best regards,

Damien

Parents Reply Children
No Data
Related