RAKWireless / WisBlock

Quickstart, tutorials and examples for the RAKwireless WisBlock product line.
https://www.rakwireless.com
MIT License
158 stars 117 forks source link

RS485 in DeepSleep #12

Closed jpmeijers closed 3 years ago

jpmeijers commented 3 years ago

In the low power documentation it is stated that SerialUSB can not be used, as that will cause a FreeRTOS task to always run and prevent the microcontroller from sleeping. See docs: https://github.com/RAKWireless/WisBlock/blob/master/examples/communications/LoRa/LoRaWAN/Low_Power_Example.md#code-explanation

I would like to read out a sensor over RS485, for which one of the HardwareSerial ports are initialised. What I do is:

It seems like the RS485/HardwareSerial is doing the same as the documentation says for the SerialUSB - a always running task. Power usage with the RS485 code included makes the Wisblock use just below 1mA when I'm expecting it to sleep. Without the RS485 code the current usage is around 27uA during the expected sleep times.

Can we somehow change the way serial ports are handled, so that the Wisblock can go into deep sleep, even when RS485 or SerialUSB is used?

I would preferable also want to use hardware Serial1 (TX1, RX1 on J10) for debugging, as when I power my board from the Otii current sensor, I want to capture logs of what the Wisblock is doing, without powering the board over USB.

beegee-tokyo commented 3 years ago

@jpmeijers I think that will be difficult, because the low level UART functions are from the nRF SDK. But you can try Serial1.end() and check if the power consumption goes down. This should work on the HW Serials (Serial1 and Serial2), it will not work on the USB Serial.

jpmeijers commented 3 years ago

I've changed the deepsleep example to have this code in the case 1 in the main loop, with timer events firing every 30s even if lora hasn't joined.

case 1: // Wakeup reason is timer
      Serial2.begin(57600);
      Serial2.println("Awake");
      Serial2.flush();
      Serial2.end();
      break;

Green graph the case 1 is empty except for the break. Yellow graph is with the Serial2 code like above. Screenshot from 2021-04-14 13-01-09

When the timer event fires the first time (highlighted area), the usage will be around 976uA when the Serial2 code is added, while it will be 24uA when the Serial code is not present. Therefore I can see that the Serial2.end() function does not disable everything that Serial2.begin() enabled.

beegee-tokyo commented 3 years ago

As said before, the low level UART is controlled from the nRF SDK and there is nothing we can change. Serial1.end() or Serial2.end() was my hope, but as you say, it is not giving the expected result.

jpmeijers commented 3 years ago

I've found a lot of references to this issue in the nrf forums. One specific one has a workaround that solves the high current draw. See https://devzone.nordicsemi.com/f/nordic-q-a/52921/low-power-system-on-mode-in-ble_uart_app

In raknrf/hardware/nrf52/0.21.1/cores/nRF5/Uart.cpp, around line 166 inside Uart::end() I added:

  // 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;

My power consumption now looks like it goes back down to 24uA after I called Serial2.end().

I also filed an issue with the upstream nrf52 library: https://github.com/adafruit/Adafruit_nRF52_Arduino/issues/631

beegee-tokyo commented 3 years ago

@jpmeijers Thank you for sharing. We will somehow ping this/add it to the documentation.

jpmeijers commented 3 years ago

Also adding another note here, as this exact fix also helped me get the power usage down after using the RAK1910 GPS.