Battery efficient LoRa revolution counter

Hello Everyone !

I am working on a project of a counter that sends me via RN2483 the number of revolution of a disk on TTN. In order to do so I used a hall sensor and a magnet on the disk, much like a tachymeter. I have the code and it works. However I am now looking to have a very good battery life.

To do so I need my installation of an Arduino nano + RN2483 + Hall sensor to be very battery efficient. I am thinking of a situation where the magnet when in front of the hall sensor triggers the Arduino nano to go out of sleep mode and do its operation leaving it in sleep mode the rest of the time.
As the hall sensor is active (draw current all the time) I don’t think its very smart so I am open to use a reed switch to do so. Is it feasible ?

Having the reed switch work somewhat like an interruptor/switch for the whole installation with the Arduino counting 1 each time it turns on and saving the data. The RN2483 (transmission module) would be powered every 100 times sending the information and going back to deep sleep the rest of the time. I don’t mind having a big battery (20000mAh for example) or multiple AAA batteries connected in parallel to achieve at least 1-2 years of life before having to change the battery.

1 Like

Cycle distance measuring computers typically use reed switches, and go quite a bit faster than it sounds like you are going to.

The stopped with magnet at the switch is one I think about at times, too. A possibility might be, when that is detected, to have software change the pulling resistor so it is no longer drawing current, go to sleep for some period of time anyway, then wake up, activate the pullup and check again (eg, change the reed switch pin from input pullup to an output driven low). There’s likely some tradeoff between power consumption in this state and the possibility of missing a revolution. Note however that you can sleep and wake an ATmega from some modes many times a second and since you are at a “click” it may take a comparatively substantial period of time to complete a full circle to another, when all you need to do is to make sure you’ve polled at some point during that, seen the magnet has moved away and reverted to normal detecting mode before it comes back.

It’s unclear if your mechanical system can ever roll backwards or even oscillate; if it can you’ll probably need a quadrature setup.

Off-the-shelf Arduino boards need modification to run at ultra low sleep power, eg removal of LEDs, removal or change of regulator, etc, this is documented in other places.

Perhaps use some logic counter with low power consumption to be the only bit that’s “awake”, MCU can then wake up, read count, reset count, sleep - and then send as and when thresholds - count or time - have been exceeded.

How many times per second/minute/hour would you expect a pulse from the sensor? This will allow us to comment on sleep/wakeup/interrupt possibilities.

Thank you for your answers !

My mechanical setup can’t roll backwards, think of it as a disk spinning such as in an old generation electrical meter. I would like to never miss a revolution. I would be putting a magnet on the disk, detected by the reed switch/hall sensor at every spin.

I know the normal Arduino boards need modification to run at ultra low sleep power, my question was more about how to make them run as such sleep power while the counter based on the reed switch/hall sensor can still count at a very low power too.

I would expect a pulse from the sensor around once every minute - once every 2 minutes
In this case we can imagine a timer sleep wakeup every 2 seconds or something, but again, I really don’t want to miss a revolution, and I want to be protected that if randomly the installation is at sleep when the magnet comes in contact with the reed switch it is aware of it and counts it.

Thank you for your answers on this thread and others, it helped me a lot along the way since I started the project !
Could you develop on the subject of logic counters ? How it works and what it could mean to my use ?
Thank you

The ATMega328P, the processor at the heart of the Nano, can sleep for up to 8 seconds at a time but then it can just be told to go back to sleep - this is what I do on the very smallest devices I make.

It can also be told to wake up if it gets an external trigger like a reed switch - at which point it can add one to the counter, do any housekeeping (check for time to send etc) and then go straight back to sleep.

As you aren’t expecting pulses that frequently, this would be the way I would proceed.

But for information, there are chips available that are much much much simpler - not even programmable - but actually the building blocks that make up the micro-controllers & CPU’s we use - that do a whole variety of basic tasks. Because they are simpler they use far less power. One set of functions include a range of counters that can count in different ways, binary, binary coded decimal, decade, hex, up, down and so on. So you could use one of these counters to do the counting and just wake up the Nano to read the count and reset. If you were getting 100 pulses a second, then this would be a useful way to let the Nano sleep as long as possible. But your pulse rate is slow enough you don’t need to look at this as a solution.

1 Like

Take a look at the Dragino Door Sensor. It detects if a door is open/closed and counts the number of times that happened (using a reed switch and magnet). It can be configured (new in firmware 1.2, thank you very much @edwin) to only transmit counts every configurable interval.
When you buy a unit you probably need to update the firmware as 1.2 is very new.

1 Like

Typically you would build this by having the reed switch connect a line to ground, which is otherwise held high by a pullup.

The simplest implementation would indeed be to use a wakeup interrupt input to the MCU to wake up on each falling edge caused by switch closure. Given how relatively infrequent these appear to be, if you do sleep mode right this is not going to cost much power.

While one could use a timer/counter chip - and in fact there’s one built into the ATmega. But it’s probably not necessary or going to save any meaningful amount of power over waking up for discerete events. And using that rather than the attention of software on the processor prevents addressing a concern you raised.

The possibility of the system stopping for potential time with the magnet activating the sensor is an interesting one. If you use a typical internal pullup, holding the switch closed against it will burn about 100 uA, which is no joke in terms of small batteries and extended life, if this is a situation which can endure for any meaningful period of time (the Dragino Door sensor hopefully has a solution!). Using really tiny switch currents can be a reliability concern; a good read switch is hopefully hermetically sealed in a glass tube to prevent contact oxidation, but those of dollar/pound store alarm buzzers are just leaves in a plastic channel exposed to air.

To me, solving the “switch stuck on” problem is the one place where polling would make sense, leveraging the fact that your wheel doesn’t spin very fast. Essentially, if the MCU sees that the switch is on, it could disable the pullup (in the simplest case go from input-pullup to output-low), then enter a a non-interruptible sleep for a time known to be safely less than the fastest revolution. After that time it wakes up by itself, re-enabled the pullup to check the sensor, and either repeats the process if things are still stuck there, or returns to normal wake-on-interrupt behavior if the magnet has moved away. Instead of polling you could also use a second sensor placed rotationally opposite, and simply toggle modes - when one fires, disable its pullup and watch the other, and so on. And divide your count by two. Incidentally, don’t just “undrive” the pullup, drive the input (and any pullup pin) low, as floating inputs can sit in the transition voltage range where the input structure draws some shoot-through current.

Granted, solving that problem is “fun” engineering - it may make sense to get an estimate of how much time the system would really spend in that position and what it would cost in battery before diving in. And in any case it would be secondary to first getting a wake-and-count-on-interrupt scheme going. It does however point to using either an internal pullup or an external one to another GPIO pin, rather than fixed wired. If making a board give yourself the option for both, you can always not install the external resistor over to the other pin.

Which reminds me, sometime I need to put a cycle computer on a microammeter and see if it draws more power with the magnet at the reed; for now I just try not to park that way.

2 Likes

Indeed, really must learn about Core Independent Peripherals - I got shanghaied in to watching the marketing launch and lost the will to live thereafter.

As an alternative to reed switches, consider some of the low-power magnetic sensors from Texas Instruments, such as the DRV5032 and DRV5012. These do not need pull-up resistors. Versions of the DRV5032 can draw typ. 0.7uA at 3V. (The lowest-power versions have a switching speed restriction, so you need to trade of frequency against power consumption).

Hello Guys! Thanks to your help I managed to write a code that triggers the Arduino nano to wake up only when it sees the magnet, do his thing and go back to sleep until the next time it gets triggered.

I will be using like @acutetech (Thank you !) mentionned AMR sensors that consume in the uA range. I will be able to test the consumption with more accuracy next week and will let you know about the results.

My main concern now is the RN2483 Sleep mode.
I am putting the Arduino Nano to sleep, but if I understand the situation right, I still need some functions like ttn.sleep() and ttn.wake() to put my RN2483 to sleep until I want to send data (In my case its every X revolution around 100 or 1000 not every X minutes). I understand that ttn.wake() does not need any argument in the brackets, but everytime I saw someone using ttn. sleep() it was with an argument in milliseconds in the brackets. In my case I am putting it to sleep until it gets triggered, can ttn.sleep() be called with no argument, meaning it sleeps forever until it sees ttn.wake in the code?
Also is there things I need to worry about in terms of rejoining the network after waking up?

Sorry for this pretty vague question, I can’t do tests until Wednesday, therefore I try to code it without direct feedback which makes my questions pretty theoretical.

The RN2483’s sys sleep (as used by TTN’s sleep command) supports 100 thru 4,294,967,296† milliseconds. That’s almost 50 days. Are you sure that’s not long enough?

(Also, as far as I know, the RN2483’s sleep preserves its settings, even if you did not call mac save. But I may be wrong there.)

† Actually, probably one less, so 4,294,967,295 or 0xFFFFFFFF. The Microchip documentation I linked to may not be the most recent version.

The problem is that they want an interruptible sleep so that they can transmit at the unknown next future time they need to.

I have no idea if that is available. If it is not, a solution might be to just keep sleeping for a reasonable amount of time until there’s a change of count that crosses a threshold, and then send. Sometimes there might be 9 one-second sleeps before you hit the criteria, sometimes 10, it probably doesn’t really matter.

Given the many potential sources of packet loss, the system should also probably have an interval after which a send is triggered even with no movement at all.

I’d suggest sending at least 16 bits of count value to avoid any ambiguity of rollover. Unless other information is being sent you might as well do 32 bits; a LoRaWAN header and trailer cost something like 13 bytes, so at the small end it doesn’t make a big difference if you send a 1, 2, or 4 byte packet. (Though there is granularity imposed by the 4/5 coding - the actual airtime doesn’t increase with each byte, but rather jumps each time a new coding group must be added, so you “pay” in airtime for the number of coding groups sent, even if the last one is only partially filled).

1 Like

You are right, it keeps all settings of the stack in memory.

That is not an issue, the RN2483 can be woken from sleep. The wake() call in the library does what the name suggests, wake the module (before the sleep time expired).

2 Likes

Thank you for this information, I was just worried that putting my Arduino nano in sleep mode, which I do using the <avr/sleep.h> library, would put the oscillator/watchdog to sleep losing complete understanding of time.
This would not be that dangerous as ttn.wake() would wake the RN2483 when needed, however I do not know how the RN2483 would react to such situation (i.e wakes up as soon as it cannot track time anymore or something like that…)

That depends on what sort of sleep or low power mode is entered.

In the schemes that have been discussed so far, the Arduino would be waking up on movement events.

If you also want it to wake up after a period of elapsed time, then you’d need to keep a counter running configured to wake the device up again seconds to minutes into the future. If you end up waking up anyway from the encoder, you can reprogram the “alarm clock” that much further into the future.

Periodically waking up for a very brief period of time doesn’t cost much power; if you have some sort of output like a quick serial message (“it is now X and I’m doing to sleep until Y or until my counts N reach threshold M”) that can be very useful for debugging as then you know it’s not dead.

My ATmega328 devices sleep for 8 seconds curtesy of the watchdog (the maximum it can do), wake, add 1 to the counter, check if enough time has passed, if it has, do something, otherwise go back to sleep. The 8 seconds is reasonably reliable. I see some very slight drift from the devices, but in the main they are on time. That said, if you need it to be absolutely on a schedule, then you do need to think of something else, like an RTC module to keep track. I’d suggest that averaging on the server side is better than messing about with transmissions scheduled to the second.

Interleaved with this you can include an interrupt on pin 2 &/or 3 that just wakes, adds one to the count and goes straight back to sleep and leave the main sleep loop to decide when to send.

Hey Guys,
I kept working in that direction achieving pretty low power, however I now have been told that waiting a bit I could get a way smaller, less consuming end node if I replace my nano and my RN2483 by the STM32WL.
How do you feel about this ?
I imagine the software of the STM32 must be very different/harder than the Arduino IDE, do you think it is worth it ?
Last but not least it seems like RN2483 + an ali express version of an Arduino nano could take me around a price of 12-13€, when the STM32WL on the following link is around 7€
(https://fr.farnell.com/stmicroelectronics/stm32wle5jci6/mcu-48mhz-arm-cortex-m4-ufbga/dp/3515810) and is supposedly doing both jobs in a 5mm over 5mm size. This seems pretty crazy to me, is there something I understood wrong about the STM32WL ?

Did you check out the link I provided to the ready made door sensor? That uses newer technology as well, the RN2483 is getting a bit long in the tooth by now…

BTW, don’t compare a single chip to a solution mounted on a pcb. The chip won’t work by itself and requires additional stuff.

I think you should go ahead with your current scheme to prove the concept.

If and when the STM32WL part is really available and people have gained experience using it with TTN, then you could consider making a transition.

There’s no reason you cannot have a hybrid “fleet” consisting of older gizmos with one hardware platform and newer ones with another.

Even if you kept the same MCU & LoRa radio solution you’d probably end up with multiple hardware generations as your understanding of the task evolved.

One thing I will say about the STM32WL (and the ACSIP) vs the Murata: monolithic packages are good, multichip modules can be problematic as they are essentially un-reworkable as they’ll internally disassemble as readily as they come off the hosting board. And the Murata module’s footprint is challenging as the lands are larger than the gaps, it really needs a very tuned SMD line, not hand prototype assembly.