I’m currently comparing various lora boards for use in my project. I recently found RAK3172 and liked a lot about what I read about the unit. But there is one thing I need to find out more about before ordring. That is how I can use RAK3172 in a mode where it is listening for incoming lora messages and at the same time is using as little power as possible. Earlier I came across the RYLR998 module from REYAX. If you look at page 9 on the datasheet for the RYLR998: https://reyax.com//upload/products_download/download_file/RYLR998_EN.pdf
it show a way to put the unit in smart receiving power saving mode. If using:
AT+MODE=2,1000,1000 it will use 2.65mA in average.
If: AT+MODE=2,100,1000 it will use 0.525mA in average.
MODE=2,100,1000 means it will actively listen for lora messages in 100ms and sleep for 1000ms, then start over and do 100ms listening and 1000ms sleep.
So my question is this: Is it possible to do something similar with the RAK3172 so my receiving battery powered unit can listen for incoming messages at a predefined interval e.g. listen for 30ms and then sleep for 100ms, and continue doing this until either an incoming message or that my ESP32 actively put the RAK3172 in another modus. I have looked at a lot of documents for the RAK3172 but could not see any documentation for how to do something similar. In the datasheet for RAK3172:
RAK3172 WisDuo LoRaWAN Module Datasheet | Specs & Features
I found this:
RX Mode 5.22mA (minimum)
but what criteria for this minimum current usage in RX mode? is this when RAK3172 is powered with 3.3V or perhaps much less (2.2V?)
and this:
Sleep current: 1.69μA
So if someone could tell me if it is possible to get a similar smart receiving power mode current usage for the RAK3172 (or perhaps even better in comparison to the RYLR998 module) it would be great, and how this is achieved?
Welcome to RAK forum @rakbubba ,
I am not familiar with REYAX but it seems it is plain LoRa-to-LoRa and not LoRaWAN.
In that case, having a 100ms RX mode (listening) and 1000ms sleep is possible but you have to write the firmware for that. For example, write a code for setting up RX mode - RUI3 LoRaWAN API | Key Management, Data Transmission, & Configuration
Here’s a pseudocode. I didn’t test it. But in principle, this is how you can possible do it.
/*
* RUI3 LoRa P2P Duty-Cycle: 100ms RX / 1000ms Sleep
*/
// Global variable to store the last received uplink
uint8_t last_received_data[256];
uint16_t last_received_len = 0;
// Forward declarations for timer callbacks
void start_rx();
void start_sleep();
void recv_cb(rui_lora_p2p_recv_t data) {
last_received_len = data.BufferSize;
memcpy(last_received_data, data.Buffer, data.BufferSize);
Serial.printf("P2P Revcv - RSSI: %d, SNR: %d, Length: %d\r\n", data.Rssi, data.Snr, data.BufferSize);
}
void start_rx() {
// Open RX window for 100ms
api.lora.precv(100);
// Schedule the next sleep cycle to start in 100ms
api.system.timer.start(RAK_TIMER_0, 100, NULL);
}
void start_sleep() {
// Put the device to sleep for 1000ms
// This will trigger the start_rx callback after the duration
api.system.sleep.all(1000);
api.system.timer.start(RAK_TIMER_1, 1000, NULL);
}
void setup() {
Serial.begin(115200);
delay(2000);
Serial.println("RUI3 P2P Duty Cycle Initializing...");
// 1. Set mode to P2P
if(api.lora.nwm.get() != 0)
{
Serial.printf("Set Node device work mode %s\r\n",
api.lora.nwm.set() ? "Success" : "Fail");
api.system.reboot();
}
// 2. Configure P2P Parameters (Frequency, SF, BW, etc.)
// Ensure these match your transmitter!
api.lora.pfreq.set(868000000);
api.lora.psf.set(7);
api.lora.pbw.set(125);
// 3. Register the receive callback
api.lora.registerPRecvCallback(recv_cb);
// 4. Initialize Timers
// Timer 0 triggers the start of sleep after RX ends
api.system.timer.create(RAK_TIMER_0, (RAK_TIMER_HANDLER)start_sleep, RAK_TIMER_ONESHOT);
// Timer 1 triggers the start of RX after sleep ends
api.system.timer.create(RAK_TIMER_1, (RAK_TIMER_HANDLER)start_rx, RAK_TIMER_ONESHOT);
}
void loop() {
// loop() is kept empty to allow the RUI3 scheduler to handle sleep and timers
}
Thank you so much for your quick and detailed reply. In my project I will handle the incoming P2P lora message via the UART on an external microcontroller.
But if I add my own custom AT command to RAK3172 and use that to run e.g. the start_sleep() function in your example code, then I should be able to put the RAK3172 module in the custom low power listening mode I described in my original question, whenever I want.
When an incoming P2P lora message is detected by the RAK3172 I need to make sure that the custom low power listening mode is turned off. Could I e.g. use this function :
void recv_cb(rui_lora_p2p_recv_t data)
and add some code in that function to stop the timer related to start_sleep and start_rx functions from your example, like this:
api.system.timer.stop(RAK_TIMER_1);
api.system.timer.start(RAK_TIMER_0);
if I do that, will the RAK3172 module automatically go into sleep mode without a timeout?
… and then it’s just for me to call my custom AT command to again set the RAK3172 in the wanted custom low power listening mode?
Is this a good way to do this?
I also wonder if you could say anything about the time used (in microseconds) for the RAK3172 module, to go from
sleep.all mode to api.lora.precv(100) mode?
and time used to go from
api.lora.precv(100) mode to sleep.all mode?
I am not aware of any implementation of this kind of modified sleep mode. Maybe @beegee has more idea.
But implementing a custom ATC command to have 100ms listening and 1000ms sleep should be possible.
You can enable and disable it. This will depend on how you wrote the custom AT command.
I am not sure though how you will sync your tx device to the rx device.
But on the rx device main loop you can stop and start the TIMER that handles the 100ms RX - 1000ms sleep mode via ATC+CUSTOM_SLEEP that you will create. Maybe there is flag that will be enable/disabled by this custom sleep mode. Then it will be captured/service in the main loop to start (or stop) the 100ms and 1000ms TIMERs.
What do you mean by this?
If you mean how do I make sure the rx device actually get the sent lora packet from the tx device - then I was thinking of making sure the sleep period is a bit shorter than the preamble air time - at least a couple of preamble symbols shorter in time. This way the rx device should be able to get the lora packet from the tx device without much problem. I have been testing this modus on the RYLR998 at it is working fine in this mode: MODE=2,30,80 making sure the preamble time is at least two preamble symbols longer in time than the sleep period (here 80ms). Since I like the form factor of your RAK3172 and the fact that it has castellated soldering points on the board - will make the RAK3172 better for my project… as well as more flexible antenna configuration.
Seeing how practical the MODE=2,RX-time,SLEEP-time on the RYLR998 works, maybe you could make it so that a similar functionality is added to the RAK3172 via AT built in AT command? I’m sure more users would appreciate this feature.
A little more information on this smart power saving mode and how it will affect battery life without having to syncronize the rx and tx unit - and still receiving all sent lora messages:
Looking at the datasheet for the RAK3172 it gives this information (at least the one I’m considering testing):
- minimum current consumption in RX mode (listening but not receiving I guess): 5.22mA
- current consumption in sleep mode: 1.69uA
So, if using a similar smart power mode as described here, (and in my first post) one can save a lot of battery power if implementing this the right way.
Now, lets assume a battery can deliver 2000mAh
If rx unit is in constant listening mode then it consumes those 2000mAh in about 383 hours (assuming 5.22 mA current consumption in RX mode not receiving anything).
Then… if implementing a smart power saving mode like:
rx listen for 500ms and rx unit sleep for 500ms (for simplicity I say 1.69uA equals to zero ampere: then the rx unit can, if preamble air time is longer than sleep period, still catch every incoming lora message - but now rx unit can last for double time: 766 hours on the same battery. If you do not want preamble time to last as long than e.g. 510ms to 515ms (to work for 500ms sleep time), but let say only 65ms, then we could use rx time of 50ms and sleep time of 50ms, and still get every incoming lora message, and operating for the same time (766 hours).
But by adjusting rx time and sleep time to let say 30ms (rx time), 120ms (sleep time), and and ajusting preamble airtime to be a little over 120ms (let say 130ms, probably at least 2 preamble symbols longer), we can achieve dramatically better up time for the rx unit, while still being able to catch every incoming lora packet (assuming P2P communication) - and without any syncronization between rx and tx unit. Pretty cool in my opinion. So for those running on battery and not wanting to syncronize rx and tx unit - implementing this "smart power saving mode) is one simple way to save a lot of power while maintaining the ability to receive any incoming lora message.
A few questions in relation to your suggested code:
- How is the UART2 affected by this code. Will UART2 be active after waking up after: api.system.sleep.all? If not, how to activate the UART2 again - and how long in microseconds will the eventual reactivation of UART2 be?
- When using api.system.sleep.all(1000), when it goes from active RX mode (just listening), and to this sleep all mode: how long does the unit use (in microseconds) to go from RX mode to sleep all mode?
- When unit goes from sleep all mode to active listening in RX mode, how long (in microseconds) does the unit use to go from sleep all mode to RX mode?
I need to know how many microseconds it takes for RAK3172 to wake up and be ready for an incoming P2P message after putting unit to sleep using: api.system.sleep.all(200), and waking unit up using api.lora.precv(40).
Surely some engineer at RAK must have done these tests, and documented the result somewhere?
Could you please link to a document here which show the wake-up time in this particular scenario?
Hi @rakbubba ,
I can check with our team if there was extensive testing done on this timing. I can tag as well @beegee if he has idea.
Since most our use case is LoRaWAN, we do not have this strict timing on waking up since RX1 and RX2 wakeup times for LoRaWAN is specific to 5 and 6 seconds normally, not in milliseconds.
Btw, please take note that I haven’t tested the code I’ve shared. Please do not take it as a functional code. But it shows the idea how your requirements can possibly done with RUI3.
Thanks… looking forward to get some data from the team. I’m about to start testing on RAK3172 modules in a few days, but in order to test the intended functionality properly, I need the described (accurate) wake-up time.
Another thing that has to be solved is this.
Let say I want RX mode for 30ms and sleep mode for 100ms.
Let say module is put into RX for 30ms mode using your modified code above.
To make it work so I can send P2P message only once, preamble time in that case has to be 100ms plus some preamble time equal minimum preamble symbols that is needed to synchronize signal. So let say total pramble time of about: 115ms.
RX unit enter the 30ms RX active listening moe, and start to detect preamble.
But then there is a TIMER_0 activated which will put it to sleep at the end of 30ms RX mode. For the unit to be able to get the whole P2P message, it has to stay in RX mode much longer than the planned 30ms active RX mode.
So, when unit start to detect incoming preamble… is there anything in the low level code handling the incoming P2P message that will stop the TIMER_0, so unit does not goes into (next scheduled) sleep mode automatically because of the incoming P2P message?
Or does it work like this:
a) custom start_rx function put module into active RX listening mode and start timer to put module into sleep after active RX listening mode time (here 30ms).
b) while in RX mode the unit detect incoming P2P message, in some way prevent the scheduled TIMER_0 to fire (which would have put module into sleep mode again), then takes care of incoming P2P message, and then and call:
the function: recv_cb(rui_lora_p2p_recv_t data)
and then I can use code like this in this function to stop TIMER_0:
api.system.timer.start(RAK_TIMER_0);
A RAK3172 goes automatically into sleep mode when there is no TX or RX window active. I never use the api.system.sleep.xxx function in my codes.
RX and TX functions are asynchronous, they return immediately while the TX or RX is done in the background.
There are callbacks to check whether TX is finished or the RX window has received any data.
Maybe try to rethink how you use the features of RAK3172.
Simplified flow
Enable sleep mode, I do this once with AT command AT+LPM=1, but you can use as well an API call.
Use a timer for the interval you want to send data.
If you want to wait for a response packet after you sent your data, enable RX in the TX finished callback
Once RX time is finished, the RAK3172 goes into sleep by itself.
If an packet is received during RX time, there is a callback to handle the received packet. Once the callback is finished, the RAK3172 goes into sleep by itself
// send packet
api.lora.psend(.....);
// wait for TX finished callback is triggered
// in callback enable RX for nnn seconds
api.lora.precv(nnn);
// use RX callback to see if a response was received, after callback is finished, device goes into sleep again
// if no data was received, the device goes into sleep after the timeout by itself
To Beegee:
Please read my original post at top. Also please read the proposed solution from carlrowan. From what you write above - it does not look like you have read what I would like to accomplish. Anyway, your “answer” does not answer any of my questions above.
In short - my original question is related to if it is possible to implement a custom low power mode for receiving messages in P2P mode - that will make it possible to save battery power. Similar to how it is implemented in Reyax RYL998 tranceiver (more about this in my first post). But basically putting the RAK3172 module in a special mode where it is set in RX mode for 30ms and then set in sleep mode for e.g. 100ms. Repeating this (awake,sleep,awake,sleep…) continously until a P2P message is received. Doing it right with the correct preamble time for the incoming message, there is no need for synchronizing the TX module with the RX module (as long as preamble time is a little bit longer than the sleep time (at least 2 preamble symbols longer). This would a very practical feature when in P2P mode. From what carlrowan proposed, it looks like it might be possible to implement a similar smart low power solution for the RAK3172 module that is implemented in the Reyax RYL998 tranceiver - either by some custom code written in RUI3 (hopefully), or if not possible via RUI3 code, then perhaps it could be implemented as a new feature by RAK Wireless engineers using some kind of low level code (updated RAK Wireless firmware). Anyway, from carlrowan’s proposed solution - it looks like it should be possible to implement using e.g. RUI3 code. That is what I’m to test on the RAK3172 modules I just received. But as I mentioned in the two last comments of mine above this comment, there is at least 1 more thing I need to know (perhaps 2). The first is how long time in microseconds the RAK3172 module need to wake up and be ready for an incoming P2P message - if first put to sleep using e.g. api.system.sleep.all(100), and waking unit up using api.lora.precv(30). In this scenario it is important to know exactly how many microseconds the RAK3172 use to wake up and be ready for an incoming P2P message - in order to know if this is even possible, and to be able to test this in a good way. I do not want to guess how many microseconds the RAK3172 use to wake up in the scenario described above. carlrowan has allready said he would “…check with our team if there was extensive testing done on this timing…”.
The RAK3172 operating characteristics are almost entirely determined by the STM32WLE5 MCU (which combines the MCU and LoRaWAN radio).
You may be able to find more detailed information from the ST Micro page
Ref. your code proposal above, and further up in this thread:
Let say preamble is detected some time within the last 40ms of the RX window above.
Also let us assume preamble pluss data takes 100ms to transfer (air-time).
Here a TIMER_0 is planned to start 100ms after the RAK3172 module was set in RX mode, which according to plan should set module in sleep mode after the RX window of 100ms (in this case before the whole message is received).
BUT, when RAK3172 detect that preamble, will TIMER_0 be stopped by some low level code (or other code), or put on hold, because of the incoming P2P message?
If TIMER_0 is not stopped or put on hold, do you know how to handle this kind of scenario?
I’m on thin ice here, but I suspect that if I had access to a flag which is set when P2P RX preamble was detected, then I could test against this flag before eventually setting module in sleep mode, and if that flag was set - then just keep module in RX mode untill message recieved… do whatever need to be done based on incoming message, and then go into continous alternating rx mode, sleep mode cycles again. For this to work I have to modify your proposed code, but I have an idea on how to do this. Just need access to some kind of preambleDetected flag via RUI3 that can be used in Arduino IDE (and some way to unset this flag again).
Looking on the RUI3 code might help - GitHub - RAKWireless/RAK-STM32-RUI: RUI3 BSP for RAK3172 modules
We already open source it for this kind of custom use cases. It is still worth to try on default RUI3 functions/apis.
Is there a callback available in RUI3 (and accessible from Arduino IDE) that is triggered when RAK3172 is in RX listening mode (either set using precv(rx-time) or set using precv(65533) - as soon as preamble symbol is detected?
Maybe something similar to this:
RadioEvents.RxDone = OnRxDone;
if there was something similar which trigger a callback when correct number of preamble symbols are detected while in RX mode:
RadioEvents.RxPreamble = OnRxPreamble;
Is this available via RUI3 and accessible via Arduino IDE?
If not, can RAK add this kind of callback?
I need this callback function to be able put module in a custom smart low power RX mode while still beeing able to active listening for incoming p2p messages. In this custom low power RX mode unit is alternating between sleep mode and rx mode, continously until a preamble is detected. The preamble callback here is to be able TO NOT set module in sleep (according to planned rx-time, sleep-time) if a preamble is detected. I cannot use
api.lora.registerPRecvCallback(recv_cb)
to handle this custom smart rx mode, since I want the rx period to last only about 30-40ms, and sleep period of e.g. 100ms and in that time there would be no time to receive the incoming message.
NB! This preamble callback is not for when sending a P2P message!!!
This is not for sending, this is for detecting incoming P2P message in custom low power RX mode (for more on this please read thread start).
If I had access to such a preamble callback function, then I think I could make the proposed code above from @carlrowan work, with some small changes.
I have looked at CAD (Channel Activity Detection) in relation to RAK3172. But it looks to me this is not implemented for use while in RX mode (only for checking if radio is available for use when sending). Here is one interesting discussion:
The best thing would be if RAK engineers implemented a similar functionality as I mentioned in thread start, where we just could call something like:
api.lora.rxDutyCycle(rx-time,sleep-time)
to put unit in alternating RX mode and sleep mode (preferably a sleep mode where setup does not have to have to be run more than when module first start up).
and if an incomming P2P message is detected, it just put module in precv(65533) mode, and we then could handle message and further logic using something like:
api.lora.registerPRecvCallback(recv_cb);