Use 32kHz clock source for hal_ticks()


I have implemented LoRaWAN using LMIC library for MSP430 as I’m memory constrained and have got it working somewhat, but I have problems with getting correct RX timings even with LMIC_setClockError to 10-50%.

The problem is that I do not have the function micros() and as I’m sleeping and waking up every 1 second, I need to use 32768Hz ACLK clock. Right now I have a divider of 2, which makes the counter go up to 16384 every second. Therefor I have set OSTICKS_PER_SEC to 16384 and I need to modify the hal_ticks() function.

u4_t hal_ticks()
    volatile u4_t seconds = sec2osticks(APP.hal_uptime); // Whole seconds since start
    volatile u4_t timer_A_count = (u4_t)Timer_A_getCounterValue(TIMER_A3_BASE); // Timer A counts (0-16384)

    return (seconds<<24)|timer_A_count;

Timer A using 32kHz ACLK source, with divider=2, counter resets at 16384.

#pragma vector=TIMER3_A0_VECTOR
void TIMER1_A3_ISR (void)
    APP.hal_uptime += 1; // every 1 second
    __bic_SR_register_on_exit(LPM0_bits); // wake up

in mail loop:

            // We do not want to sleep between TX and RX1/2 
        while ((LMIC.opmode & OP_TXRXPEND));

But the timing is still not very accurate and misses 1 second RX windows, however 5 second windows can work.

Arduino uses a 16MHz clock for micros(), therefor it is not possible to match the ticks settings to match OSTICKS_PER_SEC exactly. However I don’t think I need to do that.

Anyone that has experience with this?


The critical timing to get the RX windows is done in schedRx12 , you may manually check the result of this calculation with your OSTICKS_PER_SEC value.
You can also adjust RX_RAMPUP, it is also important because it is the time needed for the processor to prepare the frame and setup radio.
To check the timing I toggle in radio.c an extra pin after the end of transmission (in radio_irq_handler after if( flags & IRQ_LORA_TXDONE_MASK )) and just before reception (before opmode(OPMODE_RX_SINGLE);) and I check it with an external system.

The LMIC version you reference seems quite old, take a look at the modification done in MCCI one or mine if you accept C++.
Good luck with the timing it is an hard subject.

How much flash & RAM does the MCU have?

Presumably you are staying awake whilst LMIC preps & sends the payload - the internal scheduler isn’t deterministic - so you can see variations in time between telling it to send, it starting the process & then it actually transmitting.

But if you are sleeping between the end of Tx and the beginning of Rx1, then you will have your work cut out for you - probably easier to stay awake.

Also consider you need to get the radio listening for the preamble just before the Rx1 window opens, just in case the gateway has a drifty clock as well.

But mostly, anything based on Matt’s LMIC 1.5 is going to challenge & be challenged by the Network Server as it does ADR as a MAC command & that’s about it. I’ve already conversed with another TTNer today about how to configure anything less than LoRaWAN v1.0.3 to cope and the simple answer is neither of us knew.

Can you consider moving to a larger ATmega like the 4808 so you aren’t porting code over on each MCCI LMIC release?


I have 16kB for LMIC library, which I was able to fit using this library by disabling class B, pings etc. in config.h. I cannot change hardware.

Note that I’m not sleeping between TX and RX, see my while loop code above. (LMIC.opmode & OP_TXRXPEND).

Please note that if I have this code in hal_ticks, TX/RX works perfectly on all SFs, however overflowing time is not handled then:

u4_t hal_ticks()

    volatile u4_t sec = sec2osticks(APP.hal_uptime); // seconds to ticks
    volatile u4_t ms = (u4_t)Timer_A_getCounterValue(TIMER_A3_BASE); // ticks (0-16384)

    return (u4_t)(sec + ms);

So I basically need help scaling this down and handling overflowing of “sec”, which should happened after 262144 seconds.

This is a coding issue fundamental to LMIC, I’ve not read the source for a while but I thought there was some overflow calculations in there originally as on the Arduino the overflow is 1 << 32 ms aka 49 days so there should be something in there that does it already.

Most of the Hal ticks centres around the scheduler which you could remove and use a simpler delay for the Tx1 window and use @grazy’s suggestion for tracking the timing with some pin waggling. The raw.ino will give some hints on driving the LMIC bits directly and it will give you more space if you can eliminate the oslmic code.

If you’re going to do heart surgery on the library, are you able to patch in any of the MAC commands that v3 will be expecting a response to?

Out of curiosity, what made you start out with the MSP430?

Yeah I tried using that code, but could not get it to work properly, hence this post.

The library is compliant to LoRaWAN 1.0.2 so I don’t see a problem there, what commands are you referring to exactly? This is the available MAC commands:

// MAC downlink commands
enum {
    // Class A
    MCMD_LCHK_ANS = 0x02, // link check answer  : u1:margin 0-254,255=unknown margin / u1:gwcnt
    MCMD_LADR_REQ = 0x03, // link ADR request   : u1:DR/TXPow, u2:chmask, u1:chpage/repeat
    MCMD_DCAP_REQ = 0x04, // duty cycle cap     : u1:255 dead [7-4]:RFU, [3-0]:cap 2^-k
    MCMD_DN2P_SET = 0x05, // 2nd DN window param: u1:7-4:RFU/3-0:datarate, u3:freq
    MCMD_DEVS_REQ = 0x06, // device status req  : -
    MCMD_SNCH_REQ = 0x07, // set new channel    : u1:chidx, u3:freq, u1:DRrange
    // Class B
    MCMD_PING_SET = 0x11, // set ping freq      : u3: freq
    MCMD_BCNI_ANS = 0x12, // next beacon start  : u2: delay(in TUNIT millis), u1:channel

MSP430 because of built-in hardware modules in some chips, that is specific to our application. LoRaWAN is just an add-on for communication, therefor it comes in second hand.

You could try running the base version of the library from Matt’s repro on an Arduino so you can see what happens. I’ll retest to be sure, but I’ve seen & others have commented on this forum that they have been getting a huge number of downlinks when using 1.0.2 on LMIC. There are things that can be set on the server to tell it the config but it’s still work in progress.

It’s also been noted that TTS appears to like 1.0.3 far more.

The MCCI LMIC 3.1.0 is declared as being “Highly compliant Class A operation” and supports both 1.0.2 and 1.0.3 - if you are going to hack up a version, that may be worth investigating.