adafruit / Adafruit_nRF52_Arduino

Adafruit code for the Nordic nRF52 BLE SoC on Arduino
Other
623 stars 497 forks source link

UARTE not powered down correctly #631

Closed jpmeijers closed 3 years ago

jpmeijers commented 3 years ago

https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/527e62d5f480c3f7f529bba06d88cd165de14626/cores/nRF5/Uart.cpp#L149

There are many posts around the internet that talks about a 900uA increase in consumption after the uarte was initialised and uninitialised. One specific one has a clear workaround which can easily be added to this library: https://devzone.nordicsemi.com/f/nordic-q-a/52921/low-power-system-on-mode-in-ble_uart_app

I've tried this workaround and my sleep current now goes back to the expected value, which is 900uA lower than before.

This is however only a workaround and apparently there is a proper fix which the nrf sdk uses.

It would be great if someone with more understanding of the nrf52 than me can help us port the proper fix into this library.

My workaround:

void Uart::end()
{
  NVIC_DisableIRQ(IRQn);

  nrfUart->INTENCLR = UARTE_INTENSET_ENDRX_Msk | UARTE_INTENSET_ENDTX_Msk;

  nrfUart->TASKS_STOPRX = 0x1UL;
  nrfUart->TASKS_STOPTX = 0x1UL;

  nrfUart->ENABLE = UARTE_ENABLE_ENABLE_Disabled;

  nrfUart->PSEL.TXD = 0xFFFFFFFF;
  nrfUart->PSEL.RXD = 0xFFFFFFFF;

  nrfUart->PSEL.RTS = 0xFFFFFFFF;
  nrfUart->PSEL.CTS = 0xFFFFFFFF;

  rxBuffer.clear();

  // https://devzone.nordicsemi.com/f/nordic-q-a/52921/low-power-system-on-mode-in-ble_uart_app
  /* UARTE0 */
  *(volatile uint32_t *)0x40002FFC = 0;
  *(volatile uint32_t *)0x40002FFC;
  *(volatile uint32_t *)0x40002FFC = 1;
  /* UARTE1 */
  *(volatile uint32_t *)0x40028FFC = 0;
  *(volatile uint32_t *)0x40028FFC;
  *(volatile uint32_t *)0x40028FFC = 1;

  vSemaphoreDelete(_mutex);
  _mutex = NULL;
  _begun = false;
}
hathach commented 3 years ago

Sorry for super late response. This somehow is off my radar. Thank you for raising this issue. I will test this out as soon as I could

hathach commented 3 years ago

I spent a bit of time to investigate this issue, and I could confirm this with PPk2 and the following test

void setup()
{
  Serial1.begin(115200);
  // Serial1.end();

  suspendLoop();
}

void loop() { }

Which means the walkaround indeed work, however it is a bit strange since the walkaround is meant to fix the errata 89 which is already fixed since '840 revB (all production silicon is at least revC). Therefore I am a bit confused here. However, one thing for sure that it indeed WORK. I will spend more time to double check all the errata, manual and sdk to see if I could get anything more to update.

image

hathach commented 3 years ago

I have figured this out, the walkaround (use backport to disable UART power) is not really needed, we only need to wait for uart transceiver to stopped before disable the whole peripheral as implemented by #684 . I guess eanble =0 is implemented to freeze everything including the task that turning off transceiver therefore leaving transceiver active and consume 900uA in idle.