LMIC V1.6 vs LoRaWAN 1.0.2

We have an STM32L486 Node (which we call an EP) and have gotten simple Class A communication (in North America) between our EP and MultiTech’s Conduit GateWay (GW) based on both LoRaWAN (V1.0.2) and separately on IBM’s LMIC (V1.6) libraries, and we now need to decide which library to use going forward (with the caveat of upgrading to LoRaWAN V1.0.3 if we decide on that route). They both seem to have Pros and Cons, and I am interested in the opinions of others re which library is preferred. LMIC seems to be better documented, whereas LoRaWAN appears to be somewhat simpler. The LMIC examples are based on STM32L1xx (I’m guessing an STM32L152) and use TIMER9 in Stop Mode. As far as I can tell, the examples use a 32MHz system clock, with 640 programmed into the prescaler of TIMER9, which seems to imply a 1.4s maximum low-power time, assuming I understand the examples correctly. This would imply that every 1.4s, the controller needs to come out of sleep, and check the time to see if it is necessary to send data. This seems awfully wasteful of power; am I misunderstanding something here? In our Port to the 486, we used LPTIM1 running off LSE (32768 Hz) which can give a stop time of up to 240s, but we think even this might not be adequate in applications where batteries need to last for 10 years+; again any thoughts? LoRaWAN uses the RTC clock for waking from Stop and this can be programmed for much longer times, but has a resolution (in the examples) of 1/1024 s using the sub-secs field; I think this is adequate, but also increases complexity; any thoughts?

LMIC supports Class B (although we haven’t gotten to porting it yet) whereas LoRaWAN doesn’t yet support Class B. In applications where EPs are primarily being controlled from the Server (for example, controlling lights and other household devices) then it seems Class B is necessary; do others agree? And if so, doesn’t this also really impact battery life?

Once one of the libraries has been chosen, switching to other library may be difficult; I am very interested in getting the opinions of others re which approach they think best. Thanks.

1 Like

Few thought on your post. LMIC is favored here as this stack can easily be ported to Atmega / arduino board within the 32k limit, leaving some room for the application, while the LoRaMac stack is far more bigger and not suitable for small MCU. The LMIC support class B but almost no server support it - see https://github.com/Lora-net/LoRaMac-node/issues/154.

One of the drawback of LMIC is the lack of interaction with the developers. There is no way to feedback and no visibility on its future. I guess the low power part can be rework as you wish, the separation between the ‘os’ and the stack is pretty clear, not the same with Semtech code.

A third alternative would be the ST code for LoRa - based on Semtech’s one but gone thru MCU maker http://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-expansion-software/i-cube-lrwan.html.

Regarding household control, LoRaWAN might not be the best suited solution especially for light, as there will be some latency between the order and the message reception by the end node actuator. This is due to the time taken from the sensor (button) to the GW / backen / GW / actuator (light). LoRaWAN remain fully valid for peripherals not requiring a quick response time, for example heater not necessarily needs to react within 5 minutes, but more on the quarter of an hour to adjust.

For powered devices, I would suggest the class C as they would be always listening, while class B will be listening on a periodic beat.

Check class support from your LoRaWAN server provider, as all doesn’t support all classes.

You might also want to create an abstraction layer allowing you to decouple the application from teh stack, allowing to switch from one to an other later down the road.


I can comment on that - IBM has ceased development, and myself, @telkamp and Marcus from IBM have declared the intent to take over maintanance, by moving development to github, integrating various patches from various ports into a central repository and seeing if we can focus development effort again. There has been some progress along this path, but I’m currently lacking the time to do the final bits of cleanup needed to make the new repo public and get things started. I’m hoping to get around to this in the coming weeks.


@matthijs This is an excellent news. I found LMIC clearer in its implementation than Semtech’s but refrain to invest too much time in it, as no visibility on its future and not willing to find myself alone.

I was somehow surprise to even see a 1.6 release few months back.

I’m looking forward for the restart of this and if I can bring any help, will be please to do so.

My contribution; LMIC v1.5 with some fixes and HAL ported to EFM32

I abandoned this project and focused in LoRaMac-node

1 Like

LMIC was implemented before LoRaWAN specification existed, there are some things to fix, for example:

Remove the 864.x MHz join channels deprecated in LoRaWAN 1.0.2
Remove the Re-Join FTYPE. in LoRaWAN 1.0.2 this field is RFU althoug in LoRaWAN 1.1 Re-Join will be implemented

Things to do to get started:

Fix implementation to be LoRaWAN 1.0.2 specification compatible.
Add Compliance Test code to be able to certificate under LoRaWAN 1.0.2 specification
Add Class-C support


Newbie here (sorry for asking on a old thread), the “new” LMiC repository will be a vanilla implementation of the LMiC library or it’s the arduino-lmic repo already available on your GitHub account?


The intention is to have a vanilla LMIC, which contains the Arduino-specific files in a subdirectory (so you can generate the Arduino library from this repo directly). Other targets can also be contained as subdirectories.

One more open source LoRaWAN stack for nodes: Minimouse

  __  __ _       _                                 
 |  \/  (_)     (_)                                
 | \  / |_ _ __  _ _ __ ___   ___  _   _ ___  ___  
 | |\/| | | '_ \| | '_ ` _ \ / _ \| | | / __|/ _ \
 | |  | | | | | | | | | | | | (_) | |_| \__ \  __/ 
 |_|  |_|_|_| |_|_|_| |_| |_|\___/ \__,_|___/\___|  

developed by Semtech guys, still very immature but promising.

1 Like

I am new to LMic library. I successfully port Lmic library to Arduino Uno and tested raw.ino example. I dont really completely understand this hal_ticks() function.
> u4_t hal_ticks () {

// Because micros() is scaled down in this function, micros() will
// overflow before the tick timer should, causing the tick timer to
// miss a significant part of its values if not corrected. To fix
// this, the "overflow" serves as an overflow area for the micros()
// counter. It consists of three parts:
//  - The US_PER_OSTICK upper bits are effectively an extension for
//    the micros() counter and are added to the result of this
//    function.
//  - The next bit overlaps with the most significant bit of
//    micros(). This is used to detect micros() overflows.
//  - The remaining bits are always zero.
// By comparing the overlapping bit with the corresponding bit in
// the micros() return value, overflows can be detected and the
// upper bits are incremented. This is done using some clever
// bitwise operations, to remove the need for comparisons and a
// jumps, which should result in efficient code. By avoiding shifts
// other than by multiples of 8 as much as possible, this is also
// efficient on AVR (which only has 1-bit shifts).
static uint8_t overflow = 0;

// Scaled down timestamp. The top US_PER_OSTICK_EXPONENT bits are 0,
// the others will be the lower bits of our return value.
uint32_t scaled = micros() >> US_PER_OSTICK_EXPONENT;
// Most significant byte of scaled
uint8_t msb = scaled >> 24;
// Mask pointing to the overlapping bit in msb and overflow.
const uint8_t mask = (1 << (7 - US_PER_OSTICK_EXPONENT));
// Update overflow. If the overlapping bit is different
// between overflow and msb, it is added to the stored value,
// so the overlapping bit becomes equal again and, if it changed
// from 1 to 0, the upper bits are incremented.
overflow += (msb ^ overflow) & mask;

// Return the scaled value with the upper bits of stored added. The
// overlapping bit will be equal and the lower bits will be 0, so
// bitwise or is a no-op for them.
return scaled | ((uint32_t)overflow << 24);

// 0 leads to correct, but overly complex code (it could just return
// micros() unmodified), 8 leaves no room for the overlapping bit.
static_assert(US_PER_OSTICK_EXPONENT > 0 && US_PER_OSTICK_EXPONENT < 8, "Invalid 

*For example with the typical Arduino has a 16MHz oscillator:
1 ticks of Timer0 ~ 4(us) => is that reason US_PER_OSTICK_EXPONENT = 4?
scaled= number of ticks = (micors() >> US_PER_OSTICK_EXPONENT ) = ((timer0_overflow_count << 8) + TCNT0)/4
and I dont know how to explain next parts to really get the meaning of this function.

  • About
#define OSTICKS_PER_SEC 32768 

How to get this number?