sandeepmistry / arduino-LoRa

An Arduino library for sending and receiving data using LoRa radios.
MIT License
1.69k stars 637 forks source link

Low power example #365

Open maxholgasson opened 4 years ago

maxholgasson commented 4 years ago

Hi, do you have a sample code for the sender and receiver you show on youtube with rfm95 in sleep mode and CAD mode? Thanks a lot for this awesome example. 0.9mA receiving consumption is great!!

IoTThinks commented 4 years ago

I believe only need to run LoRa.end() before setting the MCU to deep sleep.

maxholgasson commented 4 years ago

I guess probably not or how do you make sure to wake up the whole setting when there's a packet sent?

IoTThinks commented 4 years ago

You want wake up event? May be you can play around with CAD in DIO1. I never try yet, btw.

Now, I prefer doing like Class A of LoRaWAN. Node to wake up periodically, send a packet to gateway and wait a while for downloading packet. Then back to sleep.

maxholgasson commented 4 years ago

I want what Sandeep showed in the video. A low power receiver that wakes up with CAD eg

sandeepmistry commented 4 years ago

I never made a video :)

Do you have a link?

maxholgasson commented 4 years ago

Hi, ah I thought that's your video because this github is linked there https://www.youtube.com/watch?v=_Lw62DjQsZ8

chocotov1 commented 4 years ago

I made that video, including (pt. 1: https://www.youtube.com/watch?v=fP5RO6sIQGk).

In the video you can see an implementation of CAD mode that's described in the Semtech SX1276 datasheet on page 42. I never published the code as it's pretty experimental and in this setup with the watch crystal nobody would probably want to try to implement it.

I'll tidy up the code that's used in the video and make an example that uses the watchdog instead of the watch crystal for the sleep intervals. Should be ready in a few days in my fork.

Would love to see CAD mode in the original arduino-LoRa library!

IoTThinks commented 4 years ago

@chocotov1 : So eager to wait for your code :-)

chocotov1 commented 4 years ago

I created the branch cadmode in my fork. It's a working showcase of CAD mode, nothing more! I don't really encourage anyone to use it because there's probably a better way to implement it in the library. I commented out a couple of attachInterrupt() lines, so I definitely broke something in the process.

I included the example LoRaReceiverCadDemo328p. Here the watchdog timer of the 328p (UNO) is configured with a 16 ms sleep time. Power consumption: 1.17 mA.

Setting the watchdog to 30 ms had a consumption of 680 uA. You can change the sleep time by changing these lines:

WDTCSR = WDTO_30MS;
//WDTCSR = WDTO_15MS;

Be sure to also check that the preamble is set appropriately in the sender. It must be at least as long as the sleep time:

LoRa.setPreambleLength(35);
maxholgasson commented 4 years ago

Thanks for your work. I'm getting my RFM95 modules ready and am curious about testing your code. Which sketch would you recommend for the sender unit?

chocotov1 commented 4 years ago

LoRaSender should work. It's probably best to define the longer preamble there too, for instance like this:

LoRa.setPreambleLength(30);
chocotov1 commented 4 years ago

I uploaded a new demonstration video that uses the code of my cadmode branch: https://www.youtube.com/watch?v=b3Wj6lMpMNk

If nobody else is interested i'd be happy to help to add CAD mode to the upstream repository. Im hesitant because i'm not familiar with how the other interrupt based code works.

morganrallen commented 4 years ago

If you check the PRs there are multiple attempts to include CAD detection, that part of the code is fairly straight forward. I'd suggest looking over #334

Would be awesome to finally land a PR for CAD detection.

chocotov1 commented 4 years ago

Thanks for pointing that out. I'll take a look over there!

maxholgasson commented 4 years ago

Great! btw you wrote "I'll tidy up the code that's used in the video and make an example that uses the watchdog instead of the watch crystal for the sleep intervals. " I read that the internal watchdog of the 328P is quite power hungry. Someone suggested to use a watchdog IC instead like this https://github.com/TomWS1/tplWDT Would that be also an option to use such a hardware watchdog?

2) how do you parse the received information of LoRa.read()? in your latest video? can this simply stored in a string or other variable? I would like to blink a led on pin7 when the first node is received and blink pin8 when second node..as an example

morganrallen commented 4 years ago

Having this particular software library require an external piece of hardware would be completely prohibitive for multi-device compatibility. Instead establishing a MACRO or extern function to use the best available method for the MCU is use is probably a better approach.

IoTThinks commented 4 years ago

@morganrallen The CAD is still pending for a release, right?

In LoRaWAN, a CAD is useful to detect a packet from any SF of a frequency.

maxholgasson commented 4 years ago

@morganrallen it was just a question as this timer IC is obiously more power efficeint than the internal watchdog. There are even breakoutboard available for those who don't use selfmade pcbs. To have this at least as an option for low power devices would be great. but chocotov1's example is still in this state awesome and works nice

chocotov1 commented 4 years ago

@maxholgasson

The 8 uA power consumption of the watchdog of the 328p (or any other Atmel chip) is so low that trying to optimize it isn't worth it.

About parsing the data my latest video: The data of the nodes is packed into a compact format, roughly using the principles that are explained here: https://www.thethingsnetwork.org/docs/devices/bytes.html

I would like to blink a led on pin7 when the first node is received and blink pin8 when second node..as an example

Easy solution:

neo7530 commented 4 years ago

Cad mode is working excellent on a receiving only node. But sadly it can't mixed with transmitting code. Have modified the gateway code to act as repeater. So if I were able to have cad mode in addition, (for sleep mode) this would give a nice solar powered repeater...

chocotov1 commented 4 years ago

I uploaded a new demonstration video that uses the code of my cadmode branch: https://www.youtube.com/watch?v=b3Wj6lMpMNk

I discovered that in my example sketch and the sketch of my video that the ADC was turned on. With it turned off the power consumption dropped to 590 uA (display turned off).

ADCSRA = 0;
maxholgasson commented 4 years ago

Wow ok, where did you put the ADCSRA = 0; int the go_to_sleep() function?

neo7530 commented 4 years ago

It is in setup()

neo7530 commented 4 years ago

@chocotov1 Can you transmit with your CAD-Code? Didn't got it to work yet.

chocotov1 commented 4 years ago

@neo7530

I didn't try before, but now i've tested it and it worked for me. I modified my example. The new code is commented out, so you need to uncomment it first to send a message like I did.

maxholgasson commented 4 years ago

Nice! btw Do both Dio0 and DIO1 need interrupt capable pins? I would need at least one interrupt pin on the 328P for something else

neo7530 commented 4 years ago

Yea, you need both interrupt pins. Dio1 is for cad detect, so the avr will wake up if a cad occurs.

IoTThinks commented 4 years ago

@neo7530 I only have dio0 connected to MCU.

Can I short circuit DIO0 and DIO1 to use CAD too? So basically, dio0 and dio1 connect to the same GPIO.

neo7530 commented 4 years ago

@IoTThinks you can separate the Dios with a diode, but this wouldn't work with this code, because it have 2 separate int handlers and flags.maybe you can modify the code. Don't have a clue if this works as expected then.

neo7530 commented 4 years ago

@chocotov1 This works, bud sadly enableInvertIQ and disableInvertIQ are not working :(

UPDATE, IT IS WORKING... The Node has to be on the same Preamble-length, otherwise it won't receive the Reply...

morganrallen commented 4 years ago

You do not need both DIO0 & DIO1 for CAD detection. It is possible with just DIO0. image As you can see DIO0 has CADDone, and DIO1 has CADDetected. The way this runs is...

Even without DIO1 the CADDetectedMask can be check after DIO0 is triggered.

neo7530 commented 4 years ago

Have tested CAD Mode again. I am not going to get it below 4mA power consumption while sleeping. Have ripped off LDO from Arduino, Power-LED, Crystal and flashed 8MHz internal Bootloader. Then i tested again, and got 4mA while CAD, 11mA while receiving and 120mA while Transmitting. (RFM98W Module). Do i overlook something? How do you get 0.6mA?

Found it. I have sf 11, so cad lasts longer... Changed to defaults and get 560uA. Am happy now. All is working well. Now I will start a long range test in Berlin urban environment 😀

chocotov1 commented 4 years ago

You do not need both DIO0 & DIO1 for CAD detection. It is possible with just DIO0.

I implemented the idea of @morganrallen with the interrupt flag / mask in my cadmode branch. The accompanying example sketch is LoRaReceiverCadDemo328pDIO0. For receiving with the interrupt pins you'd need one for RxDone and RxTimeout so I modified that to receiving without the DIO pins.

@maxholgasson: If you run out of interrupt pins again check out the pin change interrupt that's available on all pins.

@neo7530: great!

maxholgasson commented 4 years ago

That's awesome!

neo7530 commented 4 years ago

I have added some features in my repo. (Full working Gateway with invertIQ and a periodical beacon)

neo7530 commented 4 years ago

Have done some power measurements:

//WDTCSR = WDTO_1S; //SF11 (receiving not every packet) 50uA / SF12 100uA (receiving not every packet) //WDTCSR = WDTO_500MS; //SF11 430uA / SF12 1.5mA recommended for SF12 //WDTCSR = WDTO_250MS; //SF10 600uA / SF11 1.2mA / SF12 2.1mA recommended for SF11 //WDTCSR = WDTO_120MS; //SF9 460uA / SF10 900uA / SF11 1,8mA recommended for SF10 WDTCSR = WDTO_60MS; //SF8 480uA / SF9 870uA / SF10 1.57mA recommended for SF9 //WDTCSR = WDTO_30MS; //SF7 540uA / SF8 920uA / SF9 1.59mA recommended for SF7 & SF8

maxholgasson commented 4 years ago

@neo7530 and @chocotov1 will your code also work with a SAMD21 used in an Arduino Zero? A Im running out of space, ram, pins and I'm looking for an alternative to an 328P

chocotov1 commented 4 years ago

@maxholgasson I don't have a Arduino Zero so i'm not 100% certain. My code specifically sets up the watchdog registers of the 328p and also uses the sleep functions of avr/wdt.h.

A similar approach is probably also possible on the SAMD21. You just need to be able to put the chip in a low power state for say 15 or more ms. The SAMD21 might offer alternative ways other than the watchdog to achieve that.

chocotov1 commented 4 years ago

@maxholgasson SAMD21 sleeping info: https://www.youtube.com/watch?v=wmWqkJ97Zsc https://www.arduino.cc/en/Reference/ArduinoLowPower

maxholgasson commented 4 years ago

OK, yes as far as I remind avr/wdt.h won't work an a SAMD21 but as you shown there are other libraries or commands for this purpose. So I would have to change just the sleeping part to use it on a SAMD21? e.g change the content of go_to_sleep() with the according sleepfunction for 15ms sleep of the SAMD21?

chocotov1 commented 4 years ago

Yeah, that should work. You also need make sure the interrupt for DIO0 is setup correctly.

I saw the in the video I linked that the power consumption of the mkr1000 in sleep was 580 uA. That's a lot more than the 8 uA I see using the wdt on the 328p. The 328p cadmode demo I presented here uses 590 uA while actively receiving messages.

maxholgasson commented 4 years ago

Yeah 590µA is amazing. However I need a bigger MCU for menu, display etc. I'm gonna try it with the SAMD21 to get your code running as sone as I got my prototyping board done. Other option is to connect a 328P to a SAMD21 and exchange data over I2C or SPI or so

IoTThinks commented 4 years ago

@chocotov1 @maxholgasson : The following code is for Arduino only, right? I'm using ESP32, What should I do for ESP32? Thanks a lot.

 // wdt sleep settings:
  // 10.8 Watchdog Timer
  WDTCSR |= 1<<WDCE | 1<<WDE;

  // Table 10-3. Watchdog Timer Prescale Select
  //WDTCSR = WDTO_8S; // 1<<WDP3 | 1<<WDP0;           // 8 seconds
  //WDTCSR = WDTO_4S; // 1<<WDP3;                     // 4 seconds
  //WDTCSR = WDTO_2S; // 1<<WDP2 | 1<<WDP1 | 1<<WDP0; // 2 seconds
  //WDTCSR = WDTO_1S; // 1<<WDP2 | 1<<WDP1;           // 1 seconds
chocotov1 commented 4 years ago

@IoTThinks These settings are only for the 328p. I don't have experience with the ESP32.

chocotov1 commented 4 years ago

Yeah 590µA is amazing. However I need a bigger MCU for menu, display etc. I'm gonna try it with the SAMD21 to get your code running as sone as I got my prototyping board done. Other option is to connect a 328P to a SAMD21 and exchange data over I2C or SPI or so

I've tried a SPI relay setup with 2 MCUs (Pro Minis running 8 MHz). I had to look up this technique, but with a little effort I can confirm it can be done. I made a little demo video:

https://www.youtube.com/watch?v=vsuVu33MASg

As for the alternative with SAMD21, i've bought a couple of SAMD21 boards and looked into that too.

The challenge there is not only the Lora part (with cad mode) but more so getting down with the details of the SAMD21. The SAMD21 has some advanced features like the builtin RTC with 32 kHz crystal. Another huge benefit is that it's possible to debug your program with a debugger.

The problem is that SAMD21 is more complex, the datasheet is bigger and sadly only a few people (compared to the AVR Arduinos) are using the more advanced features.

In the meantime I've tackled the challenge of getting the SAMD21 to sleep for a short time (32 ms for instance). One problem that arises is that you then shouldn't try to use the USB cable anymore. It becomes unusable. Uploading code is then only possible via the SWD pads (all boards seem to have these exposed). You need a programmer for this. I have the Atmel ICE.

Some general SAMD21 boards with Lora tips i've gathered so far (note that I still haven't made a CAD MODE solution for SAMD21 yet):

With some tweaks in the SAMD21 Arduino core, I made some board variants with lower clock speeds. This way the SAMD21 boards also work at lower voltages (like with 2x NiMH battery setup). At low voltage the power consumption during sleep is around 250 uA. I suspect it can be lowered a bit with some hardware mods. Since these boards are so expensive I won't mess with them for now.

IoTThinks commented 4 years ago

My esp32 now can reach 60uA deepsleep with LoRa. When I switch off power for LoRa, I can reach 30uA.

You can check how much your LDO consumes to go under 60uA.

Btw, I check CAD mode. It costs like a RX around 18mA so I guess we can not use it during deep sleep. Unless someone has greater idea.

chocotov1 commented 4 years ago

CAD mode with SAMD21 / MKRZERO:

https://youtu.be/tunuQ5vRMbY

I'll make a similar SAMD21 sketch with serial output instead and put add it to my fork this week.

maxholgasson commented 4 years ago

@chocotov1 Thanks for this awesome demonstration.

builtin RTC with 32 kHz crystal. Another huge benefit is that it's possible to debug your program with a debugger. That's true, however I could get to run either one of these^^ Tried using a debugger last year with eclipse I think but it was too complicated.

during sleep is around 250 uA. Mh yes the SAMD21 is quite power hungry in comparison toa 328P. I think if the SPI communication between 328P and SAMD21 works -like you proofed- I would add a mosfet to the circuit and cut off the SAMD21 power.

maxholgasson commented 4 years ago

@chocotov1 In your sketch LoRaReceiverCadDemo328pDIO0 you using while (LoRa.available()) { Serial.print((char)LoRa.read()); } to print out the packets. i would like to transmit at least two different vales: first packet should contain the sensor's ID and the second packet the battery voltage.

Does anyone have a clue how to transmit and process the data so I can use those two values?

chocotov1 commented 4 years ago

@maxholgasson The while loop printing LoRa.read() in the example prints all bytes in the message. Notice that this works well with arbitrary / unknown message lengths.

For your sensor data you can define a custom message format. For instance the first byte could be the sensor id from 0 till 255. The second byte could be the temperature from 0 till 255.

byte sensor_id   = LoRa.read();
byte temperature = LoRa.read();

These values are not so practical, so you are free to organize it in your own format. It's good practice to not waste bytes because then the radio transmissions takes longer. For instance if you have 8 sensors, you'd ony need 3 bits for the sensor id field.

See also my reply of 24 May and look here: https://www.thethingsnetwork.org/docs/devices/bytes.html

To efficiently organize your sensor data into different bytes you'll have to understand the bit operations: https://playground.arduino.cc/Code/BitMath/