beegee-tokyo / SX126x-Arduino

Arduino library to use Semtech SX126x LoRa chips and modules to communicate
MIT License
236 stars 64 forks source link

deep sleep example for nRF52832 ? Sleep current measurements? #7

Closed brolly759 closed 4 years ago

brolly759 commented 4 years ago

I see you added ESP32 sleep examples, though ESP32 is not really designed for good sleep current measurements, is there any sleep examples for the nRF52832 and any current measurements done?

Thanks!

brolly759 commented 4 years ago

Just checking in on this.

Thanks

beegee-tokyo commented 4 years ago

I don't know why all your issue were not reported to me.

I didn't find a deep sleep function in the nRF52 Arduino framework. So I am not sure how to put the nRF52 into deep sleep.

I didn't do any current measurements on the ESP32.

tusharvb19 commented 4 years ago

As you have used adafruit arduino core for nRF52XXX, to sleep the nRF just need to use delay(sleep_time); Even a suspended loop with callbacks - timer callbacks can be used to achieve low power implementation! Can you just provide the API to sleep the radio?? so we can sleep the radio before sleeping nRF52.

beegee-tokyo commented 4 years ago

Two ways to set the SX126x into sleep (independent of CPU): Receiver off:

Radio.sleep();

Receiver on in low power mode:

// To get maximum power savings we use Radio.SetRxDutyCycle instead of Radio.Rx(0)
// This function keeps the SX1261/2 chip most of the time in sleep and only wakes up short times
// to catch incoming data packages
Radio.SetRxDutyCycle(2 * 1024 * 1000 * 15.625, 10 * 1024 * 15.625);

For the second one, you need to "steal" the interrupt input from the library and attach it to your own routine which will be called after a package was received. Not sure how you can get the loop() out of delay(). It might be better to use a semaphore, when you want to sleep, take the semaphore, set the SX126x into RxDutyCycle and then try to take the semaphore again. In the interrupt routine when called you give the semaphore, which will continue your loop() and you can call Radio.IrqProcessAfterDeepSleep() to check what event happened.

Did not test this on the nRF52xxx yet.

beegee-tokyo commented 4 years ago

I added power saving example for the nRF52 family.
Tested on a Sparkfun nRF52840 mini and a RAKwireless WisBlock Core RAK4631 (I got early access)

Check out the examples
Arduino
and
PlatformIO

I couldn't measure on the Sparkfun board. But with the RAK4631 I got down to ~150uA @ 4.2V battery voltage while sleeping.

brolly759 commented 4 years ago

150uA Isnt great. Should be in the single digits. You think the current draw is coming from the power components like LDO?

beegee-tokyo commented 4 years ago

Yes, can be the LDO, can be pull-ups on I2C lines, is for sure the voltage divider to read the battery voltage. I am not sure. On a custom hardware board with an ISP4520 (SOC with nRF52832 + SX1262) I got it down to 80uA. I use a not so good LDO on that board, but the rest of the HW is optimized to low power. I think these evaluation and breakout boards are not the best on power saving. For example most of these boards have a voltage divider to measure the battery voltage. On the Adafruit Feather boards this a 2MOhm +800kOhm.that means I burn permanently 15uA for nothing. And Mosfets to switch between USB supply and battery supply eat another few uA. I made these mistakes on my custom board, as I copied the Adafruit power supply design. I guess to get into single digit uA, you need a custom HW with a PMIC and a lot more optimization, but that costs money.

brolly759 commented 4 years ago

FYI if you run the eddystone BLE example for the nrf52832, the native code, you dont need voltage divider for getting VCC, there is an internal way of getting that data.

beegee-tokyo commented 4 years ago

@brolly759 But the voltage dividers are on most boards you can buy. So even if you can read the battery voltage somehow internally, the resistors are still on the boards and wasting your battery.

piyushy6 commented 3 years ago
// To get maximum power savings we use Radio.SetRxDutyCycle instead of Radio.Rx(0)
// This function keeps the SX1261/2 chip most of the time in sleep and only wakes up short times
// to catch incoming data packages
Radio.SetRxDutyCycle(2 * 1024 * 1000 * 15.625, 10 * 1024 * 15.625);

Hi, as the Radio.SetRxDutyCycle( rxTime, sleepTime ); According to your "Radio.SetRxDutyCycle(2 1024 1000 15.625, 10 1024 * 15.625);"
Is the rxTime = 2048000 μs , sleepTime = 10240 μs ?

beegee-tokyo commented 3 years ago

@piyushy6 Never trust examples and research by yourself what is written there.

I made obviously a mistake there and missed a * 1000 in the calculation. It will be corrected in the next release.

More information about calculating the RX and Sleep times:

piyushy6 commented 3 years ago

Thanks. I think there are two issues with the "Receiving data while the ESP32 sleeps"

1.) It considers symbol time = 1024ms, but actually symbol time = 1.024ms

2.) Radio.SetRxDutyCycle( rxTime, sleepTime );

rxTime = uint32_t ((2 1024 1000) / 15.625) sleepTime = uint32_t ((10 1024 1000) / 15.625)

As, rxDuration (μs) = rxTime 15.625, so rxTime = rxDuration (μs) / 15.625 sleepDuration (μs) = sleepTime 15.625, so sleepTime = rxDuration (μs) / 15.625