Adafruit M0 LoRa & RPI Gateway

(William Porras) #1

Hi all!.
I´m trying to make my first LoRa network. I have already a RPI Gateway configurated in the US band Frequency and running on TTN.

This is my Global_conf.json:

Now I’m trying to connect a node with a Feather M0 900 LoRa Board, I’m following this tutorial:

In summary, the changes I made were:

  1. Change the SPI Clock Frequency in the HAL.cpp file:
    static const SPISettings settings(8E6, MSBFIRST, SPI_MODE0);
  2. Edit the Transceiver config.h (Uncomment the CFG_us915):
    //#define CFG_eu868 1
    #define CFG_us915 1
  3. In the ttn-abp example:
    3.1 insert LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100); after the LMIC_reset(); in the setup function
    3.2 change the pin settings as follow at the start of the application:
    3.3 Copy the TTN network session key and the TTN app session key as “c-style” and with “msb”.
    3.4 Copy the TTN device address as hexadecimal string.
  4. Finally, I uploaded the program.

But I don’t get any messages on my TTN console, I dont know why.
If someone could help me, I would be very grateful.

(William Porras) #2

By the way here’s my arduino sketch:
#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>

// LoRaWAN NwkSKey, network session key
// This is the default Semtech key, which is used by the early prototype TTN
// network.
static const PROGMEM u1_t NWKSKEY[16] = { MYNWSKEY };

// LoRaWAN AppSKey, application session key
// This is the default Semtech key, which is used by the early prototype TTN
// network.
static const u1_t PROGMEM APPSKEY[16] = { MYAPPSKEY };

// LoRaWAN end-device address (DevAddr)
static const u4_t DEVADDR = MYDEVADDR ; // <-- Change this address for every node!

// These callbacks are only used in over-the-air activation, so they are
// left empty here (we cannot leave them out completely unless
// DISABLE_JOIN is set in config.h, otherwise the linker will complain).
void os_getArtEui (u1_t* buf) { }
void os_getDevEui (u1_t* buf) { }
void os_getDevKey (u1_t* buf) { }

static uint8_t mydata[] = "Hello, world!";
static osjob_t sendjob;

// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = 60;

// Pin mapping
const lmic_pinmap lmic_pins = {
    .nss = 8,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 4,
    .dio = {3, 6, 11},

void onEvent (ev_t ev) {
    Serial.print(": ");
    switch(ev) {
        case EV_SCAN_TIMEOUT:
        case EV_BEACON_FOUND:
        case EV_BEACON_MISSED:
        case EV_BEACON_TRACKED:
        case EV_JOINING:
        case EV_JOINED:
        case EV_RFU1:
        case EV_JOIN_FAILED:
        case EV_REJOIN_FAILED:
        case EV_TXCOMPLETE:
            Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
            if (LMIC.txrxFlags & TXRX_ACK)
              Serial.println(F("Received ack"));
            if (LMIC.dataLen) {
              Serial.println(F("Received "));
              Serial.println(F(" bytes of payload"));
            // Schedule next transmission
            os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
        case EV_LOST_TSYNC:
        case EV_RESET:
        case EV_RXCOMPLETE:
            // data received in ping slot
        case EV_LINK_DEAD:
        case EV_LINK_ALIVE:
            Serial.println(F("Unknown event"));

void do_send(osjob_t* j){
    // Check if there is not a current TX/RX job running
    if (LMIC.opmode & OP_TXRXPEND) {
        Serial.println(F("OP_TXRXPEND, not sending"));
    } else {
        // Prepare upstream data transmission at the next possible time.
        LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
        Serial.println(F("Packet queued"));
    // Next TX is scheduled after TX_COMPLETE event.

void setup() {

    #ifdef VCC_ENABLE
    // For Pinoccio Scout boards
    pinMode(VCC_ENABLE, OUTPUT);
    digitalWrite(VCC_ENABLE, HIGH);

    // LMIC init
    // Reset the MAC state. Session and pending data transfers will be discarded.
    LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);
    // Set static session parameters. Instead of dynamically establishing a session
    // by joining the network, precomputed session parameters are be provided.
    #ifdef PROGMEM
    // On AVR, these values are stored in flash and only copied to RAM
    // once. Copy them to a temporary buffer here, LMIC_setSession will
    // copy them into a buffer of its own again.
    uint8_t appskey[sizeof(APPSKEY)];
    uint8_t nwkskey[sizeof(NWKSKEY)];
    memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
    memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
    LMIC_setSession (0x1, DEVADDR, nwkskey, appskey);
    // If not running an AVR with PROGMEM, just use the arrays directly
    LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY);

    #if defined(CFG_eu868)
    // Set up the channels used by the Things Network, which corresponds
    // to the defaults of most gateways. Without this, only three base
    // channels from the LoRaWAN specification are used, which certainly
    // works, so it is good for debugging, but can overload those
    // frequencies, so be sure to configure the full frequency range of
    // your network here (unless your network autoconfigures them).
    // Setting up channels should happen after LMIC_setSession, as that
    // configures the minimal channel set.
    // NA-US channels 0-71 are configured automatically
    LMIC_setupChannel(0, 868100000, 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
    // TTN defines an additional channel at 869.525Mhz using SF9 for class B
    // devices' ping slots. LMIC does not have an easy way to define set this
    // frequency and support for class B is spotty and untested, so this
    // frequency is not configured here.
    #elif defined(CFG_us915)
    // NA-US channels 0-71 are configured automatically
    // but only one group of 8 should (a subband) should be active
    // TTN recommends the second sub band, 1 in a zero based count.

    // Disable link check validation

    // TTN uses SF9 for its RX2 window.
    LMIC.dn2Dr = DR_SF9;

    // Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library)

    // Start job

void loop() {


that’s because the frequencys set in your 2 channel gateway don’t match your node’s lmic code which
is apparently set to EU frequencies.

LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band

(William Porras) #4

That’s why I commented out the line #define CFG_eu868 1 in the config.h

so I think the code pass through the #elif defined(CFG_us915) and not on the #if defined(CFG_eu868)


ah ok sorry missed that … as long as your node channels are the same as your gateway

(William Porras) #6

Yes, I forgot to say that I also modify the lorabase.h:

// Default frequency plan for US 915MHz
enum { US915_125kHz_UPFBASE = 903900000,
       US915_125kHz_UPFSTEP =    200000,
       US915_500kHz_UPFBASE = 904100000,
       US915_500kHz_UPFSTEP =   1600000,
       US915_500kHz_DNFBASE = 923300000,
       US915_500kHz_DNFSTEP =    600000

With the same frequency of my gateway.

(William Porras) #7

Suddenly began to transmit.
this is the package in my TTN console:
But now I don’t know why it transmit when it wants. :sweat:


did you register your node in an application
are the keys correct in your sketch
do you see your node trying to join the network

(William Porras) #9

Yes, now this happens:


you are probably using 8 channels on your node while your gateway is receiving 2… so it could look like ‘suddenly’ its transmiiting because you missed a lot of packets… and then suddenly they are on the same channel

(William Porras) #11

Yes, that was the problem, I followed the instructions of the following post: Can LMIC 1.6 be set up to use a single channel and SF?
it’s almost working well, now I get messages from the node at the correct time, but now is changing the payload, the correct dev addr is 260219F8 and it’s sending different dev addrs, sometimes it sends the correct payload but most of the messages are wrong.

(Jac Kersing) #12
  1. Make sure to only forward packets with a correct CRC to TTN, not packets with CRC errors or without CRC.
  2. What is the distance between node and gateway? At least 7 foot?

(William Porras) #13

Hi kersing.

  1. Can you tell me please, how do I check CRC errors?
  2. Like 0.6 foot

(Jac Kersing) #17
  1. Check your gateway configuration and code to see what gets forwarded.
  2. The hint was in the second part of the sentence. Node too close to the gateway will result in error packets. Move it further away.

(William Porras) #18

I moved the device away from the gateway and kept sending random packets, but when I moved it, I accidentally touched the antenna and stopped sending noise, so I guess there must be a bad contact on the antenna.
Now it’s working perfectly :grin:
Thank you very much for your help. @BoRRoZ @kersing
Greetings from Colombia.

UPDATE: It was not the antenna that caused the problem, when I execute the command “./dual_chan_pkt_fwd” to see the messages in real time in the RPI, in the ttn console arrive messages with different devadrr, it could be some kind of bug or something similar , to solve it, simply run the service automatically and in the background.