How to adjust or cancel the LMIC libraries duty cycle check?

I wish others would sometimes think that way! Well done…

…erm, including me! :blush: …now, about that community coverage mapper/tracker I left running the other night… erm…oops!

This & other aspects and the Rolls Royce Corporate Code™️ of LoRaMac-node keeps triggering a desire to build a new implementation but keep things green and recycle & rejuvenate the implementations that exist. But starting with an actual plan rather than making it up as we go along.

A plan ? Maybe but first necessary to prove it worked.

Whilst it appears that the examples in the LMIC_low_power library had not had extensive testing, once you realise that the LMIC code does not need to know about the deep sleep periods at all it gets a lot easier. The LMIC libary changes that add in the duty cycle allowance do not seem that significant, but its only when you have a working sketch that this is clear.

The sleep mode sketches do work and the library changes do appear to mostly to work on the MCCI_LoRaWAN_LMIC_library as well.

Does the “Rolls Royce Corporate Code” not support sleep mode already ?

Yeah, but implementation of anything isn’t obvious and intricate changes are, well, a journey. And porting to a new MCU family, meh!

So having some clear modular code would be rather nice …

Well apart from a minor change to the LMIC_low_power libraries oslmic.h file all that needed sorting was to come up with a working sketch.

It not difficult to arrange it that a sketch has a build_payload() function which can deal with the differences in generating payloads from different sensors. A go_sleep() function can deal with the differences in sleep modes between platforms. Much the same would apply to wake up on event\switch type nodes.

If a nodes software handles the join, the payload transmit and the ADR stuff, does it need to be more sophisticted than that ? (excepting the ability of the node to be controlled by downlinks).

I am puzzled, does the ‘Rolls Royce Corporate Code’ really not already support deep sleep modes ?

Yes it does.

But even using it for a supported board isn’t trivial and anything more complex requires changes & additions to many files.

But what is a join? The join accept consists of many MAC commands like DutyCycleReq, RXParamSetupReq, NewChannelReq, RXTimingSetupReq and possibly TxParamSetupReq and DlChannelReq - which is 6 out of 9 commands. Except for reasons I’m still trying to figure out, the ‘official’ way to set up channels & stuff is apparently via an ADR command.

However if you are developing & deploying a device to a particular region to a particular configuration, these commands could be considered optional. But with LMIC I still seem to be chasing down the right match of LNS settings to LMIC’s 1.0.3 compliance and with LoRaMac-node I frequently end up with an Rx2 setting downlink, again, something I’ve got to set aside some serious cave time to debug. Which is why I’d rather have the pieces of the jigsaw for me to put together rather than watch two code bases (the MAC & the LNS) arguing between them about what’s what.

I have just spent quite a while taking the sketch from the LMIC_low_power library and simplifing it to remove all the #ifdefs etc to make it more or less hardware independant. The duty cycle and FUP stuff are indpendent of the hardware.

The nodes start, join, seem to do the ADR stuff OK, and also seem to follow the duty cycle and the FUP limits, which is a lot more than most nodes do.

So how much further to take it, delve into the intricate details of the LoRaWAN spec to prove that a node, that seems to work under EU868 and follows legal and FUP should not be run if its not part of the ‘one library to rule them all in all the world’ idea ?

I made some small changes to LMIC so it used the 32kHz external oscillator and a TC on the SAMD21 for its ticks. Leaving this oscillator running in standby mode means LMIC keeps time properly.

See A fork to add SAMD21 standby support to LMIC

Your power consumption will go up due to the always-running oscillator.

I tried using the ULP one that always runs anyway but it wasn’t accurate enough.

2 Likes

Thanks for that, interesting, do you know by how much the power consumption rises ?

It seems to me that the ‘always running oscillator’ is the RTC.

I modified the provided ‘ttn-otaa-feather-standby’ for the pinouts of the Seeeduino XIAO and added a BME280 temperature, hummidity and pressure sensor using Cayenne for the payload.

Initial tests, when the sleep bits for the BME280 are added, suggest the deep sleep current, with RTC timed wakeup is circa 5uA. Which is the current you would expect if the RTC was the only running timer.

And with the RTC running, and picking up the ‘real’ time at join from the gateway, you can readily see from the serial debug output what is happening.

This is amazing.

1 Like

We’re suffering from the SAMD21s not coming out of standby, so beware of that. A different piece of firmware we have has 4 mitigations for this, and still freezes so I’m not sure where to go next, other than the watchdog. This is the thread I got most of the worl-arounds from: https://www.avrfreaks.net/forum/samd21-samd21e16b-sporadically-locks-and-does-not-wake-standby-sleep-mode

As for extra power consumption, I say that because not only is the RTC running during standby but so is the logic to read the external crystal source and TCC 4/5. So two extra peripherals and an extra oscillator from what you probably had before.

Well, next step is to leave the XIAO running as a sensor, on say a one hour interval, with a openlog attached, and see how reliably it runs. The core for the XIAO is the Seeeduino specific one. I will test the LMIC_low_power version first.

OMG - that is not good, not good at all - I’d best to do some testing on the SAMR34 which I think uses the SAML core but just to be sure.

Whats a typical number of working wakeups you get before a lockup ?

A few hundred to a few thousand. I don’t think I’ve ever seen one with more than 3,500 wakeups, so it’s pretty hopeless.

I must be doing something wrong, I wish I knew what! There are countless SAMD21s out there and you’d have to think they’re not all doing this.

If you can provide, Stack Exchange style, a minimum “working” code sample, it would be possible to comment …

Thanks.

One would assume that the processor going into sleep mode does not really know, or care, exactly how long the processor has been asleep, in relation to what it does before the sleep and just after.

So it ought to be a realistic test of the SAMD21 sleep\wakeup process to blink an LED, send a packet with a LoRa library, sleep x seconds, wakeup etc and see how long it lasts.

If you operate the LoRa device @ bandwidth 500khz, sending a uint32_t counter as a packet the air time is only 7mS, so you can send a packet every 700mS.

1 Like

I am working on a cut-down version of the firmware in question, trying to pare it to the essentials.

The problem is I don’t have much time outside of work, nor a gateway reachable from my house so it might take a while.

The code I’m working with is a bit different to the example I posted above. It has a different algorithm for checking if LMIC wants to uplink again soon, say in response to a MAC command, and it also asks for the network time once a day.

But I don’t believe the lock-ups are related to any LMIC operation, they are always after it’s gone into standby.

Testing the reliability of the SAMD21 deep sleep wakeup.

When in deep sleep, the processor timers are stopped and only the low power RTC timer is running. Thus you would expect the code and processes the processor uses to go into deep sleep mode and to come out of it back to normal running, would be similar for a one hour sleep as it would be for a one second sleep.

RTCZero deep sleep

Some deep sleep code for the SAMD21 uses the RTC via the RTCZero library to set a wakeup alarm some time in the future. The code for a one hour deep sleep looks like this;

rtc.setTime(0, 0, 0);
rtc.setAlarmTime(1, 0, 0 );                  //set alarm for 1 hour
rtc.enableAlarm(rtc.MATCH_HHMMSS);

I set the sleep down to 2 seconds and using my own LoRa library I programmed the node to send a 32 bit counter as a packet, incrementing at each send, and set at bandwidth 500khz. This gave the packet an air time of 7mS so at 1% duty cycle I could send the packet every 700mS. Another node was programmed to receive the packet and copy the counter to the serial port so I could keep an eye on how many packets, and thus deep sleep wake ups, there had been.

I ran the node ran for over 25,000 deep sleeps, there were no lockups.

ArduinoLowPower deep sleep

The LowPower.sleep(sleepmS); command from the ArduinoLowPower.h library is an easy way to do deep sleeps, no need to set up the current time and alarm time through the RTC library. With the LowPower.sleep(sleepmS) function used on the XIAO SAMD21, the sleep current is around 5uA so the same as using the RTC.

Using the ArduinoLowPower.h library for deep sleep the node ran for over 50,000 deep sleeps, again with no lockups.

4 Likes