Attempt to sleep RN2483 causes system to hang

I’ve made a small test based on:

Once I try to include the RN2483 in the equation, the program just hangs until reset by the WDT.
However, the device runs the SodaqOne-UniversalTracker code just fine, so it’s not a hardware defect. The start of the program is shown below. Functions such as setLedColour¹ and initLora have been copied from the SodaqOne-UniversalTracker and placed in the aptly named header files.

This code hangs at initLora until reset by the WDT and repeats until depowered.

#define DEFAULT_IS_OTAA_ENABLED 1
#define DEFAULT_APPSKEY_OR_APPEUI "ITSASECRET"
#define DEFAULT_NWSKEY_OR_APPKEY "ANDTHISONEISSECRETTOO"
#include "LoraStuff.h"
#include "LedStuff.h"
#define BUTTON 11
#define DEBUG_STREAM SerialUSB
volatile bool buttonPressed;

void setup()
{
  delay(3000);
  DEBUG_STREAM.println("Starting...");
  sodaq_wdt_enable(WDT_PERIOD_8X);
  sodaq_wdt_reset();
  // Button pin in internal pullup mode
  pinMode(BUTTON, INPUT_PULLUP);
  // Attach interrupt to BUTTON
  attachInterrupt(BUTTON, buttonCallback, RISING);
  DEBUG_STREAM.println("Attached Interrupt...");
  // Set the XOSC32K to run in standby
  SYSCTRL->XOSC32K.bit.RUNSTDBY = 1;
  // Configure EIC to use GCLK1 which uses XOSC32K 
  // This has to be done after the first call to attachInterrupt()
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(GCM_EIC) |
                      GCLK_CLKCTRL_GEN_GCLK1 |
                      GCLK_CLKCTRL_CLKEN;
  //Set sleep mode
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
  setLedColour(GREEN);
  sodaq_wdt_safe_delay(5000);
  DEBUG_STREAM.println("Initialising LoRa...");
  initLora();
  setLedColour(RED);
  sodaq_wdt_safe_delay(50);
  DEBUG_STREAM.println("Finished setup...");
  DEBUG_STREAM.flush();
  DEBUG_STREAM.end();
  USB->DEVICE.CTRLA.reg &= ~USB_CTRLA_ENABLE; // Disable USB
}

Does anyone have a clue what I’m doing wrong?


  1. Yes, I changed it to the British spelling, since I kept getting compile errors because I misspelled it.

Can you post the code for initLora().

Initial thoughts, the initiLora() method is taking more than 8s (WDT_PERIOD_8X) resulting in a WDT reset. Two possible solutions include: initialise the WDT after you initialise LoRa; modify initLora() to use sodaq_wdt_safe_delay() and possibly add additional calls to sodaq_wdt_reset().

Thanks for the quick reply, I should’ve clarified a bit more. Without the watchdog, the program just seems to hang indefinitely on the same line.
I don’t have access to the code right now, so I’ll post the details of the initLora() function later. However, I do know that I commented the actual call to initOTAA() for testing purposes, so it doesn’t even get to the part where it actually tries to initiate a Lora connection.
Could it be hanging on getHWEUI()? On the other hand, It also hangs when I just do a call to LoRaBee.sleep();, without a preliminary initLora() call. (Hence the title of the thread) I only switched to the initLora() call when the LoRaBee.sleep() function didn’t work and I thought that it might be because the initLora() wasn’t called first. Since it is called first in the UniversalTracker code.

Here’s a non-hanging version of the initLoRa() function.

bool initLora()
{
    LORA_STREAM.begin(LoRaBee.getDefaultBaudRate());
    uint8_t devEui[8];
    uint8_t appEui[8];
    uint8_t appKey[16];
    convertAndCheckHexArray((uint8_t*)devEui, DEFAULT_DEVADDR_OR_DEVEUI, sizeof(devEui));
    convertAndCheckHexArray((uint8_t*)appEui, DEFAULT_APPSKEY_OR_APPEUI, sizeof(appEui));
    convertAndCheckHexArray((uint8_t*)appKey, DEFAULT_NWSKEY_OR_APPKEY, sizeof(appKey));
    // try to initialize the lorabee regardless the validity of the parameters,
    // in order to allow the sleeping mechanism to work
    return true; //LoRaBee.initOTA(LORA_STREAM, loraHWEui, appEui, appKey, 1);
}

However, it simply does not really do anything.
Any call to the RN2483 will cause the system to hang, and I can’t find why…
sleep(), wakeup(), getHWEui(), they will all hang…
The weird thing is that with the SodaqOneTracker code it all works fine.
I’ve compared the code and I don’t know why my code doesn’t work.

EDIT: Oh Dang! It’s right there in the comment. Apparently the initOTA() call does something that enables the sleep mechanism.
However I tried to call getHWEUI() (which calls sleep()) before initOTA(). Which apparently does not work.
I’m going to find out what initOTA() does exactly, and do it manually, so I can call getHWEUI() before initOTA(), so I can OTA with the HWEUI by default.

UPDATE:
Ok, I rewrote the Sodaq_RN2483 library a bit to make several methods non-private. In initLora() I now call init(), then getHWEUI() and then initOTA() (I removed the init() call there). Now it’s working.

Hi @Ghostbird and @GabrielNotman,

I am facing a similar issue when detecting a movement and reporting it through LoRa module. I have created a function, which is triggered when a movement is detected by the accelerometer, the function looks like below(the interruption is enabled before and it does work).

What I see is that after the first send of the movement, the device hangs and I don’t understand why. Looking into the code of Sodaq_RN2483.cpp to search where it gets stuck I reached till the method uint8_t Sodaq_RN2483::macTransmit(const char* type, uint8_t port, const uint8_t* payload, uint8_t size)
when it calls bool Sodaq_RN2483::expectString(const char* str, uint16_t timeout), there it hangs in readLn()

ACC activated
-0.53
1.73
0.16
DEBUG:BEFORE PACKET FALSE ACK SENT
[send]
[macTransmit]
[expectString] expecting ok.

I have tried with two GW and the node is quite close to the GW. I see in the the log of my GW that there is an OTAA association but just that, not a package sending after the first time(when OTAA association plus package happens). Further, I see how the device hangs and after 10s the device is rebooted (since I see the OTAA association again) by the WDT.

Any idea of why is this happening?

Thanks in advance

unsigned int loraTransmit(bool pktAck) {
      unsigned int status = 0;
      if (pktAck)
        status = LoRaBee.sendReqAck(port, (uint8_t*)packet, MAX_PAYLOAD_SIZE, msRetrails);
      else
        status = LoRaBee.send(port, (uint8_t*) packet, MAX_PAYLOAD_SIZE);
      return(status)
}

void movementDetectedHandler()
{
  noInterrupts();//avoid a new interruption

  x = accelerometer.getX();
  y = accelerometer.getY();
  z = accelerometer.getZ();

  if (digitalRead(ACCEL_INT1)) {

    #ifdef DEBUG
        debugSerial.println("ACC activated");
        SerialUSB.println(x);
        SerialUSB.println(y);
        SerialUSB.println(z);
    #endif

    //mask the movement error
    fault_flag &= MASK_MOVEMENT;
    SerialUSB.println("DEBUG:BEFORE PACKET FALSE ACK SENT");
    if (loraTransmit(false) != 0){
      fault_still_pending = true;
      SerialUSB.println("DEBUG:ERROR IoT_Transmit");
    }
    itWasMoved = true;
  }
  setLoraActive(false);//LoRa to sleep
  interrupts();//enabling interrupts again
}

Is movementDetectedHandler() the ISR (directly called by the interrupt)?

If so you should generally avoid doing any real work in an ISR. It is better to simply set a flag and then handle that in your main routine. Also be very careful disabling interrupts. Many different components rely on interrupts in some for or another.

Yes it is. So, do you think that this may be a cause of my issue?

Yes that is likely the issue.

1 Like

Thanks @GabrielNotman that seems to be the issue, I’ve moved the processing to the main routine; however I am wondering, is the accelerometer capable of waking up the device when an acceleration is detected?

Yes, this should be possible. I implemented a system for this on the v1 board, and I am certain that the accelerometer on the v2 supports the same. However, I haven’t tried it.

There were a lot of registers to configure on the accelerometer to achieve this.

I understand, so isnt’ enough to have the interruption enabled in order to make the device wake up?

There are two parts.

The first is to configure the accelerometer to output the interrupt signal. There are a lot of configuration parameters for this, which axes are enabled, G-range, threshold etc.

The second part is configuring the MCU to respond to that interrupt. This requires enabling the interrupt and making sure that it is configured correctly (e.g. PULLUP for a HIGH -> LOW transition etc). Also there are some complications with sleep mode.

This one I have already made it, setting it as

  accelerometer.enable(true, LIS3DE::NormalLowPower10Hz, LIS3DE::XYZ, LIS3DE::Scale8g, true);
  sodaq_wdt_safe_delay(100);


  accelerometer.enableInterrupt1(
    LIS3DE::XHigh | LIS3DE::XLow | LIS3DE::YHigh | LIS3DE::YLow | LIS3DE::ZHigh | LIS3DE::ZLow,
    gPercentage * 8.0 / 100.0, accDuration, LIS3DE::MovementRecognition);

That second is the one that I am struggling with, especially with the sleep mode, I use the instruction below to set the sleep mode, but how can I set those values you refer to ?

void initSleep()
{
  // Set the sleep mode
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
}

You will need to check the datasheet (or possibly examples) of what type of signal the accelerometer generates when it fires the interrupt. Is the signal ordinarily LOW and then the interrupt generates a HIGH reading on the pin, is it the opposite (PULLUP, LOW signal at interrupt)?

Here is an example of an interrupt with sleep mode. It adds the additional code for the CHANGE type interrupts. https://github.com/GabrielNotman/AutonomoTesting/tree/master/Interrupts/SleepChangeInterrupt