Hello everyone,
I wanted to shortly present a port of mcci-catena/arduino-lmic for a STM32L071KBT. The application is an electric fence monitor which in regular intervals wakes up and samples the fence voltage through a resistor divider. Should the voltage fall below a certain level or be not present it sends out a message using an RFM95 module. It also sends out a heartbeat with the current voltage measurement regularly.
You can find the source files for hardware and software at github.com/Luddi1/LoRaWAN-fence-monitor. Beware that the current hardware needs a second revision with a few fixes.
The software is based on generated code from STM32CubeMX using the LL drivers. It features:
Regular wakeup with RTC.
Save of all lmic variables in EEPROM with wear leveling.
Comparator + ADC for voltage measurement.
Simple battery empty detection with PVD.
Current arduino-lmic v3.1.0 with HAL in pure C
The sleep current is ~4uA. So two AA batteries should last a few years.
I hope this helps a few people that want to use this library without Arduino, like I did.
Thanks to terrillmoore and all other contributers to this library.
It is the name of Github account STM32duino · GitHub.
(Where the Arduino_Core_STM32 repository is hosted.)
Some use it for Roger Clark’s ‘Arduino STM32’ Arduino core.
Others use it for the ‘Arduino Core STM32’ Arduino core, while both cores are different.
It is better and more clear to use the full names of above Arduino cores.
The name stm32duino should be used for the website only and not for an Arduino core.
That is the ‘Arduino Core STM32’. (In the Arduino IDE it has been given a different name to confuse people even more. I really don’t understand the lack of naming consistency and why they make things so confusing.)
You normally should be able to use MCCI LoRaWAN LMIC library.
There appear to be some timing issues with STM32 in combination with LMIC (both classic and MCCI) but I am not aware of the exact cause and if this has been fixed in MCCI LMIC already. It is fixed in MCCI LMIC for the ST L072Z-LRWAN1 Discovery kit board but only specific for that board (in a board definition file included with MCCI LMIC library). I am not sure how it will behave with other STM32 boards (e.g. bluepill).
As a workaround, for testing purposes I currently use the classic LMIC Arduino library. This library is no longer maintained and does not include the enhancements added to MCCI’s version but at least appears to work properly with both uplink and downlink messages (and hence also works with OTAA). But requires the following:
I use the following workaround to fix the timing issue experienced with downlinks (I determined this workaround empirically):
If using the newer MCCI version, be aware that the maximum clock error is limited to 0.4% if the LMIC_ENABLE_arbitrary_clock_error is not defined. See also arduino-lmic/README.md at master · mcci-catena/arduino-lmic · GitHub.
With the STM32L071 running from the 16MHz HSI a clock error setting of 0.4% works for me. Though I have not tested at highest or lowest expected temperatures yet, which will have an effect on clock drift.
The time critical part in Class A is between end of uplink and beginning of downlink Receive Delay 1/2.
To my understanding of the lmic library the following parts play a role here:
The end of transmission is time stamped in lmic using the radio_irq_handler() in hal.c. This can be done via interrupts on DIO0 or in software by polling the pin. The software version requires the os_runloop_once() to be called often enough to precisely register an event. So the interrupt version should be preferred if possible.
Waiting the exact delay of Receive Delay 1/2 is based on the micros() timer and requires the system clock to be precise. Using a quartz over an internal oscillator is an example of how this could be improved. This is where LMIC_setClockError() can be used to allow more drift over this timespan.
A setup time in which latency, also due to SPI clock rate is accounted for is defined in oslmic:128. To my understanding this is where such a constant delay should be corrected.
#ifndef RX_RAMPUP_DEFAULT
//! \brief RX_RAMPUP_DEFAULT specifies the extra time we must allow to set up an RX event due
//! to platform issues. It's specified in units of ostime_t. It must reflect
//! platform jitter and latency, as well as the speed of the LMIC when running
//! on this plaform. It's not used directly; clients call os_getRadioRxRampup(),
//! which might adaptively vary this based on observed timeouts.
#define RX_RAMPUP_DEFAULT (us2osticks(10000))
#endif
You are right, it should not be changed at that point. But it is checked if RX_RAMPUP_DEFAULT is already defined and only defines it if not done already.
To change this and other values like spi frequency or debug level which are set in config.h the lmic_project_config.h states:
// We need to be able to compile with different options without editing source.
// When building with a more advanced environment, set the following variable:
// ARDUINO_LMIC_PROJECT_CONFIG_H=my_project_config.h
//
// otherwise the lmic_project_config.h from the ../../project_config directory will be used.
#ifndef ARDUINO_LMIC_PROJECT_CONFIG_H
# define ARDUINO_LMIC_PROJECT_CONFIG_H ../../project_config/lmic_project_config.h
#endif
So that is to my understanding where these settings could be applied without messing with the library itself.
Correct.
I’m using PlatformIO and define configuration settings in PlatformIO’s platformio.ini project configuration file (which is possible with PltformIO but not Arduino IDE).