[solved] LoRa Feather M0 Node Fails to Join

I’ve recently purchased the RAK831 + Raspberry Pi kit and setup it up as a gateway using this git: [https://github.com/RAKWireless/RAK2245-RAK831-LoRaGateway-RPi-Raspbian-OS](http://RAK831 Setup). The gateway appears to be operating correctly b/c I can see it connected to thethingsnetwork. The gateway is running in the US so it’s freq is set to 915Mhz. So far so good.

I also purchased the Adafruit Lora Feather M0 and configured it using their tutorial: [https://learn.adafruit.com/the-things-network-for-feather](http://Adafruit Feather M0). As part of the process I setup an application/device on the thethignsnetwork and copied all of the keys. The issue I am having is that the gateway both on the pi and thethingsnetwork indicate that the feather/node is broadcasting and trying to make a join. But the application/device side of thethingsnetwork never see any data. In addition the feather’s serial port data shows continuous TXSTART and then JOIN_FAILED. Has anyone had this issue and know how to fix it?

Here is my Arduino code:
’’’
static const u1_t PROGMEM APPEUI[8] = { 0x77, 0xCB, 0x01, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };
void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}

// This should also be in little endian format, see above.
static const u1_t PROGMEM DEVEUI[8] = { 0xA6, 0x89, 0x5F, 0xA2, 0x42, 0x57, 0x3E, 0x00 };
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}

// This key should be in big endian format (or, since it is not really a
// number but a block of memory, endianness does not really apply). In
// practice, a key taken from the TTN console can be copied as-is.
static const u1_t PROGMEM APPKEY[16] = { 0xA6, 0x86, 0xB1, 0xD0, 0x55, 0x0C, 0x34, 0x6E, 0x56, 0x09, 0x67, 0xCE, 0x6E, 0x31, 0xE7, 0xC2 };
void os_getDevKey (u1_t* buf) {  memcpy_P(buf, APPKEY, 16);}

static uint8_t mydata[] = "H";
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 for Adafruit Feather M0 LoRa
const lmic_pinmap lmic_pins = {
    .nss = 8,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 4,
    .dio = {3, 6, LMIC_UNUSED_PIN},
    .rxtx_rx_active = 0,
    .rssi_cal = 8,              // LBT cal for the Adafruit Feather M0 LoRa, in dB
    .spi_freq = 8000000,
};

void onEvent (ev_t ev) {
    Serial.print(os_getTime());
    Serial.print(": ");
    switch(ev) {
        case EV_SCAN_TIMEOUT:
            Serial.println(F("EV_SCAN_TIMEOUT"));
            break;
        case EV_BEACON_FOUND:
            Serial.println(F("EV_BEACON_FOUND"));
            break;
        case EV_BEACON_MISSED:
            Serial.println(F("EV_BEACON_MISSED"));
            break;
        case EV_BEACON_TRACKED:
            Serial.println(F("EV_BEACON_TRACKED"));
            break;
        case EV_JOINING:
            Serial.println(F("EV_JOINING"));
            break;
        case EV_JOINED:
            Serial.println(F("EV_JOINED"));
            {
              u4_t netid = 0;
              devaddr_t devaddr = 0;
              u1_t nwkKey[16];
              u1_t artKey[16];
              LMIC_getSessionKeys(&netid, &devaddr, nwkKey, artKey);
              Serial.print("netid: ");
              Serial.println(netid, DEC);
              Serial.print("devaddr: ");
              Serial.println(devaddr, HEX);
              Serial.print("artKey: ");
              for (int i=0; i<sizeof(artKey); ++i) {
                if (i != 0)
                  Serial.print("-");
                Serial.print(artKey[i], HEX);
              }
              Serial.println("");
              Serial.print("nwkKey: ");
              for (int i=0; i<sizeof(nwkKey); ++i) {
                      if (i != 0)
                              Serial.print("-");
                      Serial.print(nwkKey[i], HEX);
              }
              Serial.println("");
            }
            // Disable link check validation (automatically enabled
            // during join, but because slow data rates change max TX
	    // size, we don't use it in this example.
            LMIC_setLinkCheckMode(0);
            break;
        /*
        || This event is defined but not used in the code. No
        || point in wasting codespace on it.
        ||
        || case EV_RFU1:
        ||     Serial.println(F("EV_RFU1"));
        ||     break;
        */
        case EV_JOIN_FAILED:
            Serial.println(F("EV_JOIN_FAILED"));
            break;
        case EV_REJOIN_FAILED:
            Serial.println(F("EV_REJOIN_FAILED"));
            break;
            break;
        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(LMIC.dataLen);
              Serial.println(F(" bytes of payload"));
            }
            // Schedule next transmission
            os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
            break;
        case EV_LOST_TSYNC:
            Serial.println(F("EV_LOST_TSYNC"));
            break;
        case EV_RESET:
            Serial.println(F("EV_RESET"));
            break;
        case EV_RXCOMPLETE:
            // data received in ping slot
            Serial.println(F("EV_RXCOMPLETE"));
            break;
        case EV_LINK_DEAD:
            Serial.println(F("EV_LINK_DEAD"));
            break;
        case EV_LINK_ALIVE:
            Serial.println(F("EV_LINK_ALIVE"));
            break;
        /*
        || This event is defined but not used in the code. No
        || point in wasting codespace on it.
        ||
        || case EV_SCAN_FOUND:
        ||    Serial.println(F("EV_SCAN_FOUND"));
        ||    break;
        */
        case EV_TXSTART:
            Serial.println(F("EV_TXSTART"));
            break;
        default:
            Serial.print(F("Unknown event: "));
            Serial.println((unsigned) ev);
            break;
    }
}

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() {
    delay(5000);
    while (! Serial)
        ;
    Serial.begin(9600);
    Serial.println(F("Starting"));

    // LMIC init
    os_init();
    // Reset the MAC state. Session and pending data transfers will be discarded.
    LMIC_reset();
    
    LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);
    //LMIC_setLinkCheckMode(1);
    LMIC_setAdrMode(1);
    Serial.println(DR_NONE);
    LMIC_setDrTxpow(DR_SF7,14);
    LMIC_selectSubBand(1);
    // Start job (sending automatically starts OTAA too)
    do_send(&sendjob);
}

void loop() {
    os_runloop_once();
}

’’’
This is what the gateway is sending to thethingsnetwork:

image

Here is what the Raspberry Pi log shows:

image

Thanks for any insight!

Did your check the App EUI and Dev EUI in the join request actually match the ones for your device in the App? And is the secret correct (check the byte order!)

Oh, and take a minute to learn how to format you posts. Huge amounts of program code dumped into a message does not make a good question…

Hi Jac,

Thanks for the reply. I appreciate the feedback to make sure I format my question properly. I’ve tried to make the code more readable.

When I setup the Arduino code I made sure (per the directions) to use lsb format. I also checked and made sure the ids are correct. The ones from the gateway data page match what was setup in the application/node page of thethingsnetwork - see below:

image

I don’t know what the secret is? was that just that they are entered in the correct byte order? Sorry I am new to all of this.

Thanks,

Steve

For the App key as well? Because that needs to be big endian…

Thank you for the help! That did the trick - it’s working now!!

1 Like