Arduino Pro Mini, RFM95 - data transmission aborted

Hi together,

I try to built a LoraNode with an Arduino Pro mini 3,3V and a RFM95 Lora-Module. I checked different topic here but couldn’t find one solving my problem. The problem is:
I had one transmission to the TTN, so that I saw the Uplink data in the Live Data of the End Device. But after this no other transmission was made.
When I check the serial monitor/debugger of Arduino IDE an unkown event occurs and seems to abort the transmission but I can’t find out, what creates this event.

Here is the Code:

/*****************************************************************************************

  • INCLUDE FILES

*/
#include “lmic.h”
#include <hal/hal.h>
#include <SPI.h>
#include <LowPower.h>
#include <Wire.h>
#include “adcvcc.h”

/*****************************************************************************************

  • DEFINES

*/
#define debugSerial Serial
#define SHOW_DEBUGINFO
#define debugPrintLn(…) { if (debugSerial) debugSerial.println(VA_ARGS); }
#define debugPrint(…) { if (debugSerial) debugSerial.print(VA_ARGS); }

#define FASTINTERVAL 60 // 60 seconds (for testing)
#define NORMALINTERVAL 900 // (5)15 minutes (normal)

/************************************************************************************
*Verbindung zum LoraChip RFM95w und TTN-Verbinungsdaten
************************************************************************************/
// Pin mapping CH2I (check out : Full Arduino Mini LoraWAN below 1uA Sleep Mode )
//Definieren der Anschlüsse zum RFM95-LoRaModul:
/*Nss – Arduino Pin 6
*RxTx – Unused
*RST – Arduino Pin 5
*DIO0 – Arduino Pin 2
*DIO1 – Arduino Pin 3
*DIO0 – Arduino Pin 4
*/
const lmic_pinmap lmic_pins = {
.nss = 6,
.rxtx = LMIC_UNUSED_PIN,
.rst = 5,
.dio = {2, 3, 4},
};

// UPDATE WITH YOURE TTN KEYS AND ADDR
static const PROGMEM u1_t NWKSKEY[16] = {0xFB, 0xEA, 0xE5, 0x62, 0xD2, 0x20, 0xCA, 0x05, 0xAC, 0x41, 0x48, 0x2E, 0xB7, 0x47, 0xEF, 0xFB}; // LoRaWAN NwkSKey, network session key (msb)
static const u1_t PROGMEM APPSKEY[16] = {0x3D, 0xCA, 0x49, 0xB8, 0xC2, 0xFB, 0x23, 0xFC, 0x53, 0x42, 0x17, 0x4E, 0xA2, 0x38, 0xBF, 0xD8} ; // LoRaWAN AppSKey, application session key (msb)
static const u4_t DEVADDR = 0x260BB22F ; // LoRaWAN end-device address (DevAddr)

// 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) { }

/*********************

  • weitere Parameter
    ********************/
    static osjob_t sendjob;

// global enviromental parameters - Testdaten
static float temp = 10.0;
static float pressure = 0.0;
static float humidity = 25.0;

int interval = FASTINTERVAL;

//Übertragungs-Überwachungsparameter
byte LMIC_transmitted = 0;
byte LMIC_event_Timeout = 0;

/*******************************************************************************

  • Funktions-Defnitionen
    *****************************************************************************/
    /
    ======================================================================
    Function: ADC_vect
    Purpose : IRQ Handler for ADC
    Input : -
    Output : -
    Comments: used for measuring 8 samples low power mode, ADC is then in
    free running mode for 8 samples
    ====================================================================== */
    ISR(ADC_vect)
    {
    // Increment ADC counter
    _adc_irq_cnt++;
    }

void onEvent (ev_t ev) //Fehlerüberwachung mit Debug-Code für Seriellen Monitor
{
debugPrint(os_getTime());
debugPrint(": ");
debugPrintLn(ev);
switch(ev)
{
case EV_SCAN_TIMEOUT:
debugPrintLn(F(“EV_SCAN_TIMEOUT”));
break;
case EV_BEACON_FOUND:
debugPrintLn(F(“EV_BEACON_FOUND”));
break;
case EV_BEACON_MISSED:
debugPrintLn(F(“EV_BEACON_MISSED”));
break;
case EV_BEACON_TRACKED:
debugPrintLn(F(“EV_BEACON_TRACKED”));
break;
case EV_JOINING:
debugPrintLn(F(“EV_JOINING”));
break;
case EV_JOINED:
debugPrintLn(F(“EV_JOINED”));
break;
case EV_RFU1:
debugPrintLn(F(“EV_RFU1”));
break;
case EV_JOIN_FAILED:
debugPrintLn(F(“EV_JOIN_FAILED”));
break;
case EV_REJOIN_FAILED:
debugPrintLn(F(“EV_REJOIN_FAILED”));
break;
case EV_TXCOMPLETE:
debugPrintLn(F(“EV_TXCOMPLETE”));
if (LMIC.txrxFlags & TXRX_ACK)
debugPrintLn(F(“R ACK”)); // Received ack
if (LMIC.dataLen)
{
debugPrintLn(F(“R “));
debugPrintLn(LMIC.dataLen);
debugPrintLn(F(” bytes”)); // of payload
}
// Schedule next transmission
// os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
LMIC_transmitted = 1;
break;
case EV_LOST_TSYNC:
debugPrintLn(F(“EV_LOST_TSYNC”));
break;
case EV_RESET:
debugPrintLn(F(“EV_RESET”));
break;
case EV_RXCOMPLETE:
// data received in ping slot
debugPrintLn(F(“EV_RXCOMPLETE”));
break;
case EV_LINK_DEAD:
debugPrintLn(F(“EV_LINK_DEAD”));
break;
case EV_LINK_ALIVE:
debugPrintLn(F(“EV_LINK_ALIVE”));
break;
default:
debugPrintLn(F(“Unknown event”));
break;
}
}

/*

  • Sendefunktion: Überprüft, ob gerade eine Übertragung stattfindet.

  • Wenn nicht werden die Parameter berechnet und im

  • seriellen Monitor ausgegeben. Anschließend werden die Parameter als Paket

  • in mydata angelegt und so das zu sendende Paket erstellt (Ausgabe "Packet ready).

  • Mit LMIC_setTxData2() wird das Paket als Sende Daten an den Chip übergeben und anschließend

  • “Packet Queued” ausgegeben.
    /
    void do_send(osjob_t
    j)
    {
    // Check if there is not a current TX/RX job running
    if (LMIC.opmode & OP_TXRXPEND)
    {
    debugPrintLn(F(“OP_TXRXPEND”)); //P_TXRXPEND, not sending
    }
    else
    {

     int batt = (int)(readVcc() / 100);  // readVCC returns  mVolt need just 100mVolt steps
     byte batvalue = (byte)batt; // no problem putting it into a int. 
    

    #ifdef SHOW_DEBUGINFO
    debugPrint(F(“T=”));
    debugPrintLn(temp);

     debugPrint(F("P="));
     debugPrintLn(pressure); 
     
     debugPrint(F("H="));
      debugPrintLn(humidity); 
    
     debugPrint(F("B="));
     debugPrintLn(batt);
     debugPrint(F("BV="));
     debugPrintLn(batvalue);  
    

    #endif
    int t = (int)((temp + 40.0) * 10.0);
    // t = t + 40; => t [-40…+85] => [0…125] => t = t * 10; => t [0…125] => [0…1250]
    int p = (int)(pressure); // p [300…1100]
    int h = (int)(humidity);

     unsigned char mydata[6];
     mydata[0] = batvalue;      
     mydata[1] = h & 0xFF; 
     mydata[2] = t >> 8;
     mydata[3] = t & 0xFF;
     mydata[4] = p >> 8;
     mydata[5] = p & 0xFF; 
    
     debugPrintLn(F("Packet ready\n"));
     LMIC_setTxData2(1, mydata, sizeof(mydata), 0);
     debugPrintLn(F("Packet queued\n")); //Packet queued
    

    }
    debugPrintLn(F(“do_send - Letzte Zeile\n”)); //Testmeldung für Abschluss von do_send
    // Next TX is scheduled after TX_COMPLETE event.
    }

/********************************************************************

  • Setup
    *******************************************************************/
    void setup() {
    Serial.begin(115200); //Baud-Rate, bei seriellem Monitor muss dasselbe eingestellt sein
    debugPrintLn(F("\n—Starting—"));

    // LMIC init
    os_init();

    // Reset the MAC state. Session and pending data transfers will be discarded.
    LMIC_reset();

    // 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 size_appskey[sizeof(APPSKEY)];
    uint8_t size_nwkskey[sizeof(NWKSKEY)];
    memcpy_P(size_appskey, APPSKEY, sizeof(APPSKEY));
    memcpy_P(size_nwkskey, NWKSKEY, sizeof(NWKSKEY));
    LMIC_setSession (0x1, DEVADDR, size_nwkskey, size_appskey);
    #else
    // If not running an AVR with PROGMEM, just use the arrays directly
    LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY);
    #endif

    /********************

    • Frequenz festlegen
      ********************/
      #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

    // For single channel gateways: Restrict to channel 0 when defined above
    #ifdef CHANNEL0
    LMIC_disableChannel(1);
    LMIC_disableChannel(2);
    LMIC_disableChannel(3);
    LMIC_disableChannel(4);
    LMIC_disableChannel(5);
    LMIC_disableChannel(6);
    LMIC_disableChannel(7);
    LMIC_disableChannel(8);
    #endif

    // 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.
    // gateway-conf/US-global_conf.json at master · TheThingsNetwork/gateway-conf · GitHub
    LMIC_selectSubBand(1);
    #endif

    // Disable link check validation
    LMIC_setLinkCheckMode(0);

    // 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)
    LMIC_setDrTxpow(DR_SF7,14);
    debugPrintLn(F(“Setup complete”)); // Setup complete!"
    delay(1000); // allow serial to send.
    }

void loop() {
// put your main code here, to run repeatedly:
// Start job
do_send(&sendjob);
debugPrintLn(F(“do_send() finished\n”));
// Wait for response of the queued message (check if message is send correctly)
os_runloop_once();
debugPrintLn(F(“os_runloop_once() finished\n”));

// Continue until message is transmitted correctly
debugPrintLn("\tWaiting for transmittion\n");
while(LMIC_transmitted != 1) //Solange keine Übertragung abgeschlossen wurde (EC_TXCOMPLETE im Monitor), wird gewartet. Nach 60s Abbruch
{
os_runloop_once();
// Add timeout counter when nothing happens:
LMIC_event_Timeout++;
delay(1000);
if (LMIC_event_Timeout >= 60)
{
// Timeout when there’s no “EV_TXCOMPLETE” event after 60 seconds
debugPrintLn(F("\tETimeout, msg not tx\n"));
break;
}
}

//Übetragung wurde abgeschlossen, da while() verlassen, Parameter zurücksetzen
LMIC_transmitted = 0;
LMIC_event_Timeout = 0;

//debugPrintLn(F("Going to sleep."));
delay(1000);  // allow serial to send.

for (int i = 0; i < interval; i++)
{  
      i +=7 ; // no normal 1 second run but 8 second loops m.      
      // Enter power down state for 8 s with ADC and BOD module disabled
      LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);   
}  
debugPrintLn("--- LOOP END ---");

}

The Serial Monitor:
10:27:48.896 → —Starting—
10:27:48.896 → Setup complete
10:27:49.922 → T=10.00
10:27:49.922 → P=0.00
10:27:49.922 → H=25.00
10:27:49.922 → B=31
10:27:49.922 → BV=31
10:27:49.922 → Packet ready
10:27:49.922 →
10:27:49.969 → 67046: 17
10:27:49.969 → Unknown event
10:27:49.969 → Pac⸮
10:27:51.472 → —Starting—

Has anybody here an Idea how to solve this?

Thanks for the support! :slight_smile:

Please specify exactly which LMiC repo you used, and at what head / version.

Generally it’s going to be challenging to get this to work on a pro mini, as up to date version like MCCI LMiC probably won’t fit.

I use the MCCI LoRaWAN LMIC library. In the README is written that at least Arduino IDE 1.6.6 is required. So is it even possible to get this running on Arduino Pro mini?

For information

Board Arduino Pro Mini with ‘out of the box’ bootloader
Transceiver : SX1276, RFM95…
Library : MCCI Catena LMIC V4.0.0 https://github.com/mcci-catena/arduino-lmic
IDE Arduino 1.8.15

Code : ttn-otaa.ino, unmodified (except FILLME datas and LMIC_CLOCK_ERROR ).
No sleep mode used

Runs OK on TheThing Stack and gives :

Le croquis utilise 24744 octets (80%) de l'espace de stockage de programmes. Le maximum est de 30720 octets.

Les variables globales utilisent 1517 octets (74%) de mémoire dynamique, ce qui laisse 531 octets pour les variables locales

So , not much space left for own additionnal code but ‘it works’ with recent LMIC library w Pro Mini :slightly_smiling_face:

With sleep mode ?
OK again (Pro Mini and same V4.0.0.LMIC libray) with Jack Gruber’s Code on PlatformIO :
https://github.com/JackGruber/Arduino-Pro-Mini-LoRa-Sensor-Node

Hi together,

I solved the problem. Thanks for the hint with the library. I’m using the IBM LMIC framework and now I’m only using 89% of the storage space, so that’ better.
But the actual problem was that the wiring had a sometimes loose contact because of the connectors we used. We changed everything to a breadboard and now the code is running fine.

Thanks for the support! :slight_smile: