Custom Teensy-LC + RFM95W no join accept


I’m new to TTN and have an issue that I see many have experienced before. Using the “standard” ttn-otaa.ino sketch from the MCCI LMIC examples on github, I can contact TTN with a join request, and sometimes the TTIG gateway registers the accept, but I haven’t seen the join accept actually being received by the end device.

The end device (on serial port) inevitably says “EV_JOIN_TXCOMPLETE: no JoinAccept”.

I have tried the solutions I could find on the forum (although for sure I’ve not read everything yet), but I’m at the point where I need some experienced hands to help me out.

LoraWAN node: custom PCB with Teensy-LC and RFM95W
Gateway: TTIG

Lora 0.8.0 by Sandeep Mistry (only for testing locally)
MCCI_LoRaWAN_LMIC_library version 4.0.0 (for TTN)

ttn-otaa.ino from MCCI LMIC library only changed for keys and pinning (all pins are wired explicitly, including RESET, DIO0, DIO1, DIO2 on RFM95W)

TTN settings:
MAC v1.02
PHY v1.02 rev B
Frequency plan Europe 863-870 (SF9 for RX2 - recommended)
Activation mode OTAA

Join settings:
I have not set any of the IDs and Labels here, only the APPKEY which was prefilled

Tests done:

  • Changed bit order of keys: any other permutation of keys leads to a MIC mismatch error in the TTN console
  • bidirectional communication using Lora 0.8.0 library between two local nodes → all works like a charm

I tried the following solution variants from other forum posts and github:

//    LMIC.dn2Dr = SF9; 

//    LMIC_setClockError(MAX_CLOCK_ERROR * 10 / 100);
//    LMIC_setClockError(MAX_CLOCK_ERROR * 2 / 100);

    LMIC_setupChannel(0, 868000000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band 
    LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI);      // g-band 
    LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band 
    LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band 
    LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band 
    LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band 
    LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band 
    LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band 
    LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK,  DR_FSK),  BAND_MILLI);      // g2-band


and also tried the solutions found in these posts:
Readme from LMIC:

Forum entries tried:

Typical TTN console output of live data from end device:

Typical gateway (TTIG) output on console:

The keys are all OK, everything seems fine for as far as I can tell.

TTIG serial logging of the same time period:
2021-08-05 19:22:02.195 [SYS:DEBU] Free Heap: 18944 (min=15464) wifi=5 mh=7 cups=8 tc=4
2021-08-05 19:22:07.199 [SYS:DEBU] Free Heap: 18944 (min=15464) wifi=5 mh=7 cups=8 tc=4
2021-08-05 19:22:10.577 [S2E:VERB] RX 868.1MHz DR4 SF8/BW125 snr=9.8 rssi=-95 xtime=0x6900022CEE1804 - jreq MHdr=00 JoinEui=4e69:59a3:96e4:2210 DevEui=86e4
2021-08-05 19:22:12.203 [SYS:DEBU] Free Heap: 18944 (min=15464) wifi=5 mh=7 cups=8 tc=4
2021-08-05 19:22:12.435 [S2E:DEBU] ::1 diid=64312 [ant#0] - next TX start ahead by 3s123ms
2021-08-05 19:22:15.538 [S2E:VERB] ::1 diid=64312 [ant#0] - starting TX in 19ms881us
INFO: tx_start_delay=1493 () - (0, bw_delay=, notch_delay=)
2021-08-05 19:22:15.566 [S2E:INFO] TX ::1 diid=64312 [ant#0] - dntxed: 868.1MHz 16.0dBm ant#0(0) DR4 SF8/BW125 frame=20949B454A3A2F38C891AAB4…4F7E5BD6
2021-08-05 19:22:15.692 [S2E:DEBU] Tx done diid=64312
2021-08-05 19:22:16.715 [SYN:VERB] Time sync rejected: quality=2074 threshold=1067
2021-08-05 19:22:17.206 [SYS:DEBU] Free Heap: 18944 (min=15464) wifi=5 mh=7 cups=8 tc=4
2021-08-05 19:22:18.819 [SYN:INFO] Time sync qualities: min=1044 q90=1066 max=2074 (previous q90=1067)
2021-08-05 19:22:22.210 [SYS:DEBU] Free Heap: 18944 (min=15464) wifi=5 mh=7 cups=8 tc=4
2021-08-05 19:22:27.214 [SYS:DEBU] Free Heap: 18944 (min=15464) wifi=5 mh=7 cups=8 tc=4
2021-08-05 19:22:31.431 [SYN:VERB] Time sync rejected: quality=1504 threshold=1066

Note that the TTIG reports time two hours earlier, these screenshots and logs are from the same join requests. Could that be a problem?

In my noob eyes all appears good until this point (except maybe the time sync failure). I don’t know what to do next to try and debug it.

Any suggestions? These are my best hypotheses:

  1. Maybe the end device RFM95W somehow isn’t switching from TX to RX. With Sandeep Mistry’s Lora library this hardware could send and receive. But the RFM95W doesn’t expose an explicit RXTX pin to force the switch, should LMIC do that under the hood?
  2. Somehow there is a timing problem and my understanding of the LoraWAN protocol isn’t good enough to pinpoint it.

In either case I don’t feel these hypotheses are too likely and I don’t know what else to try to figure this problem out.

Any help is greatly appreciated.


Good detail, nice selection of links showing good research, good testing of Rx/Tx with the other library.

There can’t be much wrong with most of it as the console is getting, processing & accepting the join-request.

The first question that comes to mind is how close is the device to the TTIG - they need a good few metres & possibly a brick wall - too close and the signal can overwhelm the input stages of the chip scrambling the signal.

Thanks for the quick reply!

Indeed at first it was maybe a bit too close (5 meters, only a window in between), but now there is about 10 meters and a small brick building in between. That’s easy to increase though, so I’ll do that right away.

Intuitively it feels a bit weird that the end device reaches the TTIG every time while the return signal always fails. Using Sandeep’s lib I never had any issues even in short range with plenty of reflections, other than sometimes bits falling over. But maybe the TTIG is far more powerful than the end device (a bit hard to believe with an internal antenna).

Which reminds me: I’m using a 0.9dB 1/2 wave antenna for 868-915 range (not ideal I know but should do the trick in these experiments).

The TTIG responded in 2 seconds (from sending uplink to sending downlink), is that in the normal range? Not too fast?

Will get back with range tests.

That’s what we call “console time” - like “bullet time” in The Matrix - it’s not real. The TTIG relays the join request, the network server processes and responds and the TTIG transmits at the appropriate point in time as instructed by the NS.

There is the LMIC-node example that wraps up the LMIC library and is known to work with the Teensy-LC:

Yes this one example to rule them all :P.

I believe I’ve tried the tricks here (except those I’m too daft to spot), I have the feeling it’s one stupid bit somewhere and everything else is OK already. But what bit?

One thing that has me stumped: there is something called the RX1 window, which is 5 seconds long, and then the RX2 window, which is 5 more seconds. To me that sounds like “after the Lora device sends out a join request it will listen for a response on frequency 1 for 5 seconds and then another one for 5 more seconds”. After that all is lost. Is that reasonable view or should i be reading the docs some more?

Did you actually try LMIC-node?

On V3 RX1 is set to 5 seconds but RX2 is only one second (‘comes 1 second after RX1’).

The other day I couldn’t get a B-L072Z to co-operate using the official STM32duino setup & LMIC. But LMIC-node made it all work first time …

I’ll get on it! I’ve read that example extensively and tried the parts I could but haven’t installed platform IO yet. Also I thought it still uses the MCCI LMIC lib underneath. But will definitely give it a try. Thanks for the suggestions!

See this:

Got it Nick!

Update on the distance experiments: still the dreaded “EV_JOIN_TXCOMPLETE: no JoinAccept”.

Next stop: LMIC-Node.

Thanks for clarifying bluejedi!

Custom Teensy-LC

Not sure where the custom part is but do (after reading have a look at the board support file (BSF) for the Teensy included with LMIC-node, for pin mappings and GPIO assignments. You may need to adapt some mappings/settings for your custom board.

The most common cause for failing OTAA (joins) and downlinks with LMIC is when DIO1 is incorrectly mapped/connected. So you may have to double (or triple) check your connections and mappings (again).


First time ever, don’t even know what made the difference this time! Only change I made today is crank up the clock error to 50%, but I had tried that before.


Not sure where the custom part is

Yeah I should have been clearer: the Teensy-LC is totally standard. It’s put on a custom PCB with the RFM95W with some analog signal processing.

I’ll try and reproduce this with another device and see if I can isolate the culprit and what made it work this time.

Another big win for LMIC-node :100: :heart: :dancing_women: :partying_face: :beers: :champagne:

1 Like

Yes sorry Nick I was just about to add: that result is still using the modified ttn-otaa.ino from the MCCI LMIC library, not LMIC-node!

Even so, I’ll have a long hard look at that too, because I’ve been trying to get this to work for weeks and all of a sudden it just stops not working and I don’t understand why yet. So great progress, but I’m not very confident of a stable solution yet.

In any case thanks a lot for helping me get this far!

The slower 8 MHz 8-bit ATmega328 and ATmega32u4 MCUs (which require Clock Error to be set) will work with a Clock Error of 3%.

Setting Clock Error is not required for Teensy LC and is therefore bad practice to do so.

Setting Clock Error to 50% (500000 ppm) is just crazy!

As precaution (to prevent ‘unaware’ abuse) MCCI LMIC limits Clock Error to max 0.4% (to enable higher values an additional parameter needs to be defined).

Just try LMIC-node…

Thanks bluejedi,

Yes during normal workdays I can’t just do a lot of TTN debugging, but I’ll try LMIC-node as well, but still I’m very happy that I got it to work after weeks of trying. Not confident that I understand what’s going on though.

Extra checks done using original tnn-otaa.ino:

  • setting timing error to non-crazy level does result in joins failing, setting it to 50 means joins succeed again
  • DIO 1 is indeed connected correctly, checked with multimeter

Outcome from testing with LMIC-node:
Device-id: teensylc
LMIC library: MCCI
Activation: OTAA
Interval: 60 seconds

000000082777:  Event: EV_JOINING

000000082784:  doWork job started
000000572168:  Event: EV_TXSTART
000000893209:  Event: EV_JOINED
               Network Id: 19
               Device Address: 260B3666
               Application Session Key: 08-F7-C9-17-1B-6A-6E-01-FE-32-CD-D5-F8-F8-12-12
               Network Session Key:     01-94-39-A7-D0-A0-FB-6B-71-FD-5F-81-9F-19-8D-07

Right out of the box (after pin updates in BSF)! So now it’s working without crazy timing error settings.

Woo Hoo!


This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.