jgromes / RadioLib

Universal wireless communication library for embedded devices
https://jgromes.github.io/RadioLib/
MIT License
1.48k stars 375 forks source link

failure to enable low power sleep on CubeCell AB01 #705

Closed gasagna closed 1 year ago

gasagna commented 1 year ago

Describe the bug I am unable to make my cubecell go in a proper low power sleep with RadioLib. Here is a minimal working example using the default radio driver from the CubeCell-Arduino core that gives my about 30 uA. This is a bit far from the declared 3.5 uA, but it's not bad.

#include "Arduino.h"
#include "LoRaWan_APP.h"

static RadioEvents_t RadioEvents;

void setup() {
    Radio.Init(&RadioEvents);
    Radio.Sleep();
}

void loop() {
    lowPowerHandler();
}

This is a minimal working example using RadioLib's radio driver for the cube cell's SX1262

#include "Arduino.h"
#include "RadioLib.h"

SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE);

void setup() {
    Serial.begin(115200); delay(100);

    int radio_status = radio.begin();

    if (radio_status == RADIOLIB_ERR_NONE) {
        Serial.println(F("success!"));
    } else {
        while (true) {
            Serial.print(F("failed, code "));
            Serial.println(radio_status);
        }
    }
    radio.sleep();
}

void loop() {
    lowPowerHandler();
}

This sketch gives about 1.5mA, i.e. much higher than it should be.

I have done some debugging and noticed a couple of facts. Looking at the implementation of SX126X::sleep, changing the value of the waitForGpio argument to true at this line

int16_t state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false);

enables a low power sleep to be achieved, although this modified sleep function takes about 5 seconds to return. This is inconvenient, as during this time the board consumes around 10mA.

I have also tried mixing the cubecell's radio driver with RadioLib's code, i.e. this sketch

#include "Arduino.h"
#include "RadioLib.h"
#include "LoRaWan_APP.h"

// define radio
SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE);

void setup() {
    Serial.begin(115200); delay(100);

    int radio_status = radio.begin();

    if (radio_status == RADIOLIB_ERR_NONE) {
        Serial.println(F("success!"));
    } else {
        while (true) {
            Serial.print(F("failed, code "));
            Serial.println(radio_status);
        }
    }
    // this calls cubecell's implementation of sleep
    Radio.Sleep();
}

void loop() {
    lowPowerHandler();
}

uses Radio.sleep() (with Radio being defined somewhere in the radio driver implementation shipped with CubeCell-Arduino).

So, the hardware is OK, but somehow RadioLib does not seem to talk properly to the module to put it in sleep. The sleep configuration is the same in for both RadioLib and the CubeCell version, i.e. uint8_t sleepMode = RADIOLIB_SX126X_SLEEP_START_WARM | RADIOLIB_SX126X_SLEEP_RTC_OFF is 4.

Thanks for the support in advance.

Additional info (please complete):

gasagna commented 1 year ago

Some more digging shows that with waitForGpio=true, the function Module::SPItransferStream exits with RADIOLIB_ERR_SPI_CMD_TIMEOUT = -705, i presume from this point. However, the module does go indeed to sleep, as measured with a multimeter.

jgromes commented 1 year ago

I don't know which exact CubeCell you have (ASR650x vs ASR6601), but implementation of Radio.Sleep for one of them seems to be turning off some switch (https://github.com/HelTecAutomation/CubeCell-Arduino/blob/6c14f832107780af98b412481172ba1b1274619e/cores/asr6601/lora/driver/sx1262-board.c#L316). Maybe that is the difference?

gasagna commented 1 year ago

I do not think this is the cause because I have a board based on the ASR6052 (this one), and this is the implementation for the function SX126xAntSwOff that turns off that switch. As you can see for the ASR6052 i have, that function does nothing.

jgromes commented 1 year ago

One more idea - by default, RadioLib verifies SPI command state by perfornmin an additional transaction. On SX126x, this is needed to catch failed commands. However, maybe this additional transaction wakes up the SX126x somehow?

You can test this by either removing the RADIOLIB_SPI_PARANOID from BuildOpt.h, or by setting verify=false in the SPI command in SX126x::sleep implementation.

gasagna commented 1 year ago

Yes, your intuition is correct. Modifying the call to SPIwriteStream in SX1262::sleep by passing verify=false fixes the problem, and the radio goes to sleep immediately. What's the best course of action here? would it be safe to set verify=false in sleep by default? I can prepare a PR.

jgromes commented 1 year ago

I think there's no other way than to set verify to false and just trust that it works. If you could send the PR, that would be great. However, please add this for SX128x as well, since the SPI interface is pretty much identical, so this issue likely exists there too.

jgromes commented 1 year ago

Fixed by merging #708