LMIC oslmic.c.53 Error in ESP8266 NodeMCU-12F and SX1276 Context

Dear Professionals,

Current status:
I have had a device running in the TTN EU868 network for 2 years without any problems. It sends various sensor data. The device hardware is built with an ESP8266 NodeMCU-12E and an SX1276.

Should be:
I wanted to expand the circuit to include the analog A0 pin for measuring the photovoltaic battery voltage.
In order not to disrupt “production”, I rebuilt the circuit (see circuit diagram 2023). This time with an ESP8266 NodeMCU-12F and again the SX1276.
See sketch from 2023 (version 4.1.1 lmic.h) which leads to following

Problem:
The following error message occurs after calling “os_init()”:

16:54:57.336 ->  ets Jan  8 2013,rst cause:4, boot mode:(3,6)
16:54:57.336 -> 
16:54:57.336 -> wdt reset
16:54:57.336 -> load 0x4010f000, len 3424, room 16 
16:54:57.336 -> tail 0
16:54:57.336 -> chksum 0x2e
16:54:57.336 -> load 0x3fff20b8, len 40, room 8 
16:54:57.409 -> tail 0
16:54:57.409 -> chksum 0x2b
16:54:57.409 -> csum 0x2b
16:54:57.409 -> v00048c20
16:54:57.409 -> ~ld
16:54:57.430 ->    �n� r��n|�l�l`  b   b r  l�nb�n l` � r l�l ��bis daher hats noch funktioniert?
16:54:57.552 -> FAILURE 
16:54:57.552 -> oslmic.c:53

Pin mapping:

const lmic_pinmap lmic_pins = {
  .nss = 16,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = LMIC_UNUSED_PIN,  //5
  .dio = {5, 4, LMIC_UNUSED_PIN},
};

I carried out the following tests to isolate the error:
• Old device (ESP8266 NodeMCU-12E) on new board: error-free, sends data to TTN, so the new board is ok.
• Sketch from 2021 compiled on a new device (ESP8266 NodeMCU-12F) leads to the same error again, so there should be no error in the new Sketch 2023.
• ESP8266 NodeMCU-12F tested with other sketches without LMIC works perfectly, so NodeMCU-12F has no HW error.
• Pin mapping ESP8266 / SX1276 / LMIC checked several times.
• LMIC Library Version 3.3.0 ex 2021 installed and recompiled, same error again.
• Some hours in the relevant forums.
• Test sketch compiled on ESP8266 NodeMCU-12F results in this error:

���Starting
FAILURE 
oslmic.c:53

The hardware seems fine. Have been anything changed significantly in the Libraries between 2021 and 2023? Now I don’t know what to do and I’m hoping for help from the professionals!

Thank you, Peter

Sketch 2021:

/***************************************************/
/* NODEMCU 1.0 Gartenhaus                          */
/* Version 02 / 06.03.2021: DHT22 Structure        */
/* Version 03 / 07.03.2021: LoRa Sender            */
/*                          MQ2 Structure          */
/* Version 04 / 09.03.2021: BME680 Structure       */
/* Version 05 / 11.03.2021: Fenster/Tür            */
/* Version 06 / 29.03.2021: DHT22 Sensor eingebaut */
/* Version 07 / 10.05.2021: LoRaWAN payload        */
/***************************************************/

// Includes für WiFi und ESP-NOW
#include <ESP8266WiFi.h>
#include <espnow.h>

// Includes und Definitionen für DHT22
#include <Adafruit_Sensor.h>
#include <DHT.h>
// Digital pin GPIO0 = D3
#define DHTPIN D3     
// Verwendeter Sensortyp DHT22 (AM2302):
#define DHTTYPE DHT22 
DHT dht(DHTPIN, DHTTYPE);
// current temperature & humidity, updated in loop()
float t = 0.0;
float h = 0.0;

// Includes für Wire und LoRa
#include <Wire.h>
#include <lmic.h>
#include <hal/hal.h>

// Definition der ESP-NOW Eingabestruktur
uint8_t  mydata[20];
uint16_t LoRaByte2;

#define RUNDEN0(x)    ((unsigned) ((x) + .5))

typedef struct struct_message {
  float    DHT_Temp;
  float    DHT_Feucht;
  float    MQ2_Gaswert;
  char     MQ2_Gasalarm;
  float    BME_Temp;
  float    BME_Feucht;
  float    BME_Iaq;
  float    BME_Druck;
  float    BME_CO2;
  char     Fenster_Status;
  char     Tuer_Status;
} struct_message;
// Create a struct_message Sensoren_Daten
struct_message Sensoren_Daten;

// Callback function that will be executed when data is received
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
  memcpy(&Sensoren_Daten, incomingData, sizeof(Sensoren_Daten));
  Serial.print("Bytes received:   ");
  Serial.println(len);
  Serial.print("Temperatur DHT:   ");
  Serial.println(Sensoren_Daten.DHT_Temp);
  Serial.print("Luftfeuchte DHT:  ");
  Serial.println(Sensoren_Daten.DHT_Feucht);
  Serial.print("Gaskonzentration: ");
  Serial.println(Sensoren_Daten.MQ2_Gaswert);
  Serial.print("Gasalarm Status:  ");
  Serial.println(Sensoren_Daten.MQ2_Gasalarm);
  Serial.print("Temperatur BME:   ");
  Serial.println(Sensoren_Daten.BME_Temp);
  Serial.print("Luftfeuchte BME:  ");
  Serial.println(Sensoren_Daten.BME_Feucht);
  Serial.print("IAQ BME:          ");
  Serial.println(Sensoren_Daten.BME_Iaq);
  Serial.print("Luftdruck BME:    ");
  Serial.println(Sensoren_Daten.BME_Druck);
  Serial.print("CO2 BME:          ");
  Serial.println(Sensoren_Daten.BME_CO2);
  Serial.print("Fenster offen:    ");
  Serial.println(Sensoren_Daten.Fenster_Status);
  Serial.print("Tür offen:        ");
  Serial.println(Sensoren_Daten.Tuer_Status);
  Serial.print("Temper. Aussen:   ");
  Serial.println(t);
  Serial.print("Feuchte Aussen:   ");
  Serial.println(h);
  Serial.println();
}

/*********************************************/
/* LoRaWAN                                   */
/*********************************************/
// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3, 0x70.
static const u1_t PROGMEM APPEUI[8]={ x };
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]={ x };
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 ttnctl can be copied as-is.
static const u1_t PROGMEM APPKEY[16] = { x };
void os_getDevKey (u1_t* buf) {  memcpy_P(buf, APPKEY, 16);}

// Pin mapping
const lmic_pinmap lmic_pins = {
  .nss = 16,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = LMIC_UNUSED_PIN,  //5
  .dio = {5, 4, LMIC_UNUSED_PIN},
};

unsigned long lastTime = 0;  
unsigned long timerDelay = 300000;  // LoRa send alle 5 Min.
String output;

unsigned long lastDHT = 0;  
unsigned long DHTDelay = 10000;     // Sensor alle 10 Sec. auslesen

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"));
      break;
    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;
    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"));
      }
      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;
    case EV_TXSTART:
      Serial.println(F("EV_TXSTART"));
      break;
    case EV_JOIN_TXCOMPLETE:
      Serial.println(F("EV_JOIN_TXCOMPLETE"));
      break;
    default:
      output = "Unknown event: " + String(ev);
      Serial.println(output);
      break;
  }
}

void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);
  
  // Initialize DHT22 Sensor
  dht.begin();
  
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
  esp_now_register_recv_cb(OnDataRecv);
  
  // LMIC init
  os_init();
  // Reset the MAC state. Session and pending data transfers will be discarded.
  LMIC_reset();
  LMIC_setAdrMode(1);
  LMIC_setLinkCheckMode(1);
  LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);
}

void loop() {
  os_runloop_once();
   
  if ((millis() - lastDHT) > DHTDelay) {
    // Read temperature as Celsius (the default)
    float newT = dht.readTemperature();
    // Read temperature as Fahrenheit (isFahrenheit = true)
    //float newT = dht.readTemperature(true);
    // if temperature read failed, don't change t value
    if (isnan(newT)) {
      Serial.println("Failed to read Temperatur from DHT sensor!");
    }
    else {
      t = newT;
      Serial.println(t);
    }
    // Read Humidity
    float newH = dht.readHumidity();
    // if humidity read failed, don't change h value 
    if (isnan(newH)) {
      Serial.println("Failed to read Humidity from DHT sensor!");
    }
    else {
      h = newH;
      Serial.println(h);
    }
	lastDHT = millis();
  }
  
  if ((millis() - lastTime) > timerDelay) {
	  
  // LoRaWAN payload aufbereiten
  //* 1 Temperatur Gewächshaus ex DHT22
  Sensoren_Daten.DHT_Temp = (Sensoren_Daten.DHT_Temp + 50) * 10; // ev. Minus-Grade wegaddieren, ohne Komma
  LoRaByte2  = Sensoren_Daten.DHT_Temp;
  mydata[0]  = LoRaByte2;
  mydata[1]  = LoRaByte2 >> 8;
  //* 2 Feuchtigkeit Gewächshaus ex DHT22
  mydata[2]  = RUNDEN0(Sensoren_Daten.DHT_Feucht); // Feuchigkeit wird nur ganzzahlig benötigt
  //* 3 Gaswert Gewächshaus ex MQ2
  LoRaByte2  = Sensoren_Daten.MQ2_Gaswert;
  mydata[3]  = LoRaByte2;
  mydata[4]  = LoRaByte2 >> 8;
  //* 4 Gasalarm Gewächshaus ex MQ2
  mydata[5]  = Sensoren_Daten.MQ2_Gasalarm;
  //* 5 Temperatur Gewächshaus ex BME680
  Sensoren_Daten.BME_Temp = (Sensoren_Daten.BME_Temp + 50) * 100; // ev. Minus-Grade wegaddieren, ohne Komma
  LoRaByte2  = Sensoren_Daten.BME_Temp;
  mydata[6]  = LoRaByte2;
  mydata[7]  = LoRaByte2 >> 8;
  //* 6 Feuchigkeit Gewächshaus ex BME680
  mydata[8]  = RUNDEN0(Sensoren_Daten.BME_Feucht);
  //* 7 IAQ Gewächshaus ex BME680
  Sensoren_Daten.BME_Iaq = Sensoren_Daten.BME_Iaq * 100; // ohne Komma
  LoRaByte2  = Sensoren_Daten.BME_Iaq;
  mydata[9]  = LoRaByte2;
  mydata[10] = LoRaByte2 >> 8;
  //* 8 Luftdruck Gewächshaus ex BME680
  Sensoren_Daten.BME_Druck = RUNDEN0(Sensoren_Daten.BME_Druck / 100); // 300 bis 1100
  LoRaByte2  = Sensoren_Daten.BME_Druck;
  mydata[11]  = LoRaByte2;
  mydata[12] = LoRaByte2 >> 8;
  //* 9 CO2 Equivalten Gewächshaus ex BME680
  Sensoren_Daten.BME_CO2 = RUNDEN0(Sensoren_Daten.BME_CO2);          
  LoRaByte2  = Sensoren_Daten.BME_CO2;
  mydata[13]  = LoRaByte2;
  mydata[14] = LoRaByte2 >> 8;
  //* 10 Dachfenster Gewächshaus
  mydata[15]  = Sensoren_Daten.Fenster_Status;
  //* 11 Schiebetür Gewächshaus
  mydata[16]  = Sensoren_Daten.Tuer_Status;
  //* 12 Temperatur Gartenhaus-Außen ex DHT22
  t = (t + 50) * 10; // ev. Minus-Grade wegaddieren, ohne Komma
  LoRaByte2  = t;
  mydata[17]  = LoRaByte2;
  mydata[18]  = LoRaByte2 >> 8;
  //* 13 Feuchtigkeit Gartenhaus-Außen  ex DHT22
  mydata[19]  = RUNDEN0(h); // Feuchigkeit wird nur ganzzahlig benötigt

  // 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), 0);
        Serial.println(F("Packet queued"));
      }
  	// save the last time you updated the DHT values
	lastTime = millis();
  }
}

Sketch 2023:

/****************************************************/
/* NODEMCU 1.0 Gartenhaus                           */
/* Version 02 / 06.03.2021: DHT22 Structure         */
/* Version 03 / 07.03.2021: LoRa Sender             */
/*                          MQ2 Structure           */
/* Version 04 / 09.03.2021: BME680 Structure        */
/* Version 05 / 11.03.2021: Fenster/Tür             */
/* Version 06 / 29.03.2021: DHT22 Sensor eingebaut  */
/* Version 07 / 10.05.2021: LoRaWAN payload         */
/* Version 08 / 10.12.2023: Spannungsmessung mit A0 */
/****************************************************/

// Includes für WiFi und ESP-NOW
#include <ESP8266WiFi.h>
#include <espnow.h>

// Includes und Definitionen für DHT22
#include <Adafruit_Sensor.h>
#include <DHT.h>
// Digital pin GPIO0 = D3
#define DHTPIN D3     
// Verwendeter Sensortyp DHT22 (AM2302):
#define DHTTYPE DHT22 
DHT dht(DHTPIN, DHTTYPE);
// current temperature & humidity, updated in loop()
float t = 0.0;
float h = 0.0;

// Includes für Wire und LoRa
#include <Wire.h>
#include <lmic.h>
#include <hal/hal.h>

// Definition der LoRa Ausgabestruktur, ab V08 [22] Bytes statt [20]
uint8_t  mydata[22];
uint16_t LoRaByte2;

#define RUNDEN0(x)    ((unsigned) ((x) + .5))

// Definition der ESP-NOW Eingabestruktur
typedef struct struct_message {
  float    DHT_Temp;
  float    DHT_Feucht;
  float    MQ2_Gaswert;
  char     MQ2_Gasalarm;
  float    BME_Temp;
  float    BME_Feucht;
  float    BME_Iaq;
  float    BME_Druck;
  float    BME_CO2;
  char     Fenster_Status;
  char     Tuer_Status;
} struct_message;
// Create a struct_message Sensoren_Daten
struct_message Sensoren_Daten;

// Callback function that will be executed when data is received
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
  memcpy(&Sensoren_Daten, incomingData, sizeof(Sensoren_Daten));
  Serial.print("Bytes received:   ");
  Serial.println(len);
  Serial.print("Temperatur DHT:   ");
  Serial.println(Sensoren_Daten.DHT_Temp);
  Serial.print("Luftfeuchte DHT:  ");
  Serial.println(Sensoren_Daten.DHT_Feucht);
  Serial.print("Gaskonzentration: ");
  Serial.println(Sensoren_Daten.MQ2_Gaswert);
  Serial.print("Gasalarm Status:  ");
  Serial.println(Sensoren_Daten.MQ2_Gasalarm);
  Serial.print("Temperatur BME:   ");
  Serial.println(Sensoren_Daten.BME_Temp);
  Serial.print("Luftfeuchte BME:  ");
  Serial.println(Sensoren_Daten.BME_Feucht);
  Serial.print("IAQ BME:          ");
  Serial.println(Sensoren_Daten.BME_Iaq);
  Serial.print("Luftdruck BME:    ");
  Serial.println(Sensoren_Daten.BME_Druck);
  Serial.print("CO2 BME:          ");
  Serial.println(Sensoren_Daten.BME_CO2);
  Serial.print("Fenster offen:    ");
  Serial.println(Sensoren_Daten.Fenster_Status);
  Serial.print("Tür offen:        ");
  Serial.println(Sensoren_Daten.Tuer_Status);
  Serial.print("Temper. Aussen:   ");
  Serial.println(t);
  Serial.print("Feuchte Aussen:   ");
  Serial.println(h);
  Serial.println();
}

/*********************************************/
/* LoRaWAN                                   */
/*********************************************/
// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3, 0x70.
static const u1_t PROGMEM APPEUI[8]={ x };
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]={ x };
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 ttnctl can be copied as-is.
static const u1_t PROGMEM APPKEY[16] = { x };
void os_getDevKey (u1_t* buf) {  memcpy_P(buf, APPKEY, 16);}

// Pin mapping
const lmic_pinmap lmic_pins = {
  .nss = 16,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = LMIC_UNUSED_PIN,  //5
  .dio = {5, 4, LMIC_UNUSED_PIN},
};

unsigned long lastTime = 0;  
unsigned long timerDelay = 300000;  // LoRa send alle 5 Min.
String output;

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"));
      break;
    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;
    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"));
      }
      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;
    case EV_TXSTART:
      Serial.println(F("EV_TXSTART"));
      break;
    case EV_JOIN_TXCOMPLETE:
      Serial.println(F("EV_JOIN_TXCOMPLETE"));
      break;
    default:
      output = "Unknown event: " + String(ev);
      Serial.println(output);
      break;
  }
}

// Messung der Batteriespannung
int BAT= A0;              //Analog channel A0 as used to measure battery voltage
float RatioFactor=3.147;  //Resistors Ration Factor, siehe Excel


void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);
  
  // Initialize DHT22 Sensor
  dht.begin();
  
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
  esp_now_register_recv_cb(OnDataRecv);
  
  Serial.println("bis daher hats noch funktioniert?");
  
  // LMIC init
  os_init();
  
  Serial.println("nach os_init nicht mehr");
  // Reset the MAC state. Session and pending data transfers will be discarded.
  LMIC_reset();
  LMIC_setAdrMode(1);
  LMIC_setLinkCheckMode(1);
  LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);
}

void loop() {
  os_runloop_once();
    
  // wieder 5 Minuten um, daher senden
  if ((millis() - lastTime) > timerDelay) {
	  
  // Spannungsmessung und für LoRa aufbereiten
  float Tvoltage=0.0;
  float Vvalue=0.0,Rvalue=0.0;
  
  for(unsigned int i=0;i<10;i++){
  Vvalue=Vvalue+analogRead(BAT);         //Read analog Voltage
  delay(5);                              //ADC stable
  }
  Vvalue=(float)Vvalue/10.0;            //Find average of 10 values
  Rvalue=(float)(Vvalue/1024.0)*5;      //Convert Voltage in 5v factor
  Tvoltage=Rvalue*RatioFactor;          //Find original voltage by multiplying with factor
  Serial.print("Durchschnitt =\t");
  Serial.println(Vvalue);
  Serial.print("Korrigiert =\t");
  Serial.println(Rvalue);
  Serial.print("Battery Voltage =\t");
  Serial.println(Tvoltage);
  
  // Read temperature as Celsius (the default)
  float newT = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  //float newT = dht.readTemperature(true);
  // if temperature read failed, don't change t value
  if (isnan(newT)) {
    Serial.println("Failed to read Temperatur from DHT sensor!");
  }
  else {
    t = newT;
    Serial.println(t);
  }
  // Read Humidity
  float newH = dht.readHumidity();
  // if humidity read failed, don't change h value 
  if (isnan(newH)) {
    Serial.println("Failed to read Humidity from DHT sensor!");
  }
  else {
    h = newH;
    Serial.println(h);
  }
    
  // LoRaWAN payload aufbereiten
  //* 1 Temperatur Gewächshaus ex DHT22
  Sensoren_Daten.DHT_Temp = (Sensoren_Daten.DHT_Temp + 50) * 10; // ev. Minus-Grade wegaddieren, ohne Komma
  LoRaByte2  = Sensoren_Daten.DHT_Temp;
  mydata[0]  = LoRaByte2;
  mydata[1]  = LoRaByte2 >> 8;
  //* 2 Feuchtigkeit Gewächshaus ex DHT22
  mydata[2]  = RUNDEN0(Sensoren_Daten.DHT_Feucht); // Feuchigkeit wird nur ganzzahlig benötigt
  //* 3 Gaswert Gewächshaus ex MQ2
  LoRaByte2  = Sensoren_Daten.MQ2_Gaswert;
  mydata[3]  = LoRaByte2;
  mydata[4]  = LoRaByte2 >> 8;
  //* 4 Gasalarm Gewächshaus ex MQ2
  mydata[5]  = Sensoren_Daten.MQ2_Gasalarm;
  //* 5 Temperatur Gewächshaus ex BME680
  Sensoren_Daten.BME_Temp = (Sensoren_Daten.BME_Temp + 50) * 100; // ev. Minus-Grade wegaddieren, ohne Komma
  LoRaByte2  = Sensoren_Daten.BME_Temp;
  mydata[6]  = LoRaByte2;
  mydata[7]  = LoRaByte2 >> 8;
  //* 6 Feuchigkeit Gewächshaus ex BME680
  mydata[8]  = RUNDEN0(Sensoren_Daten.BME_Feucht);
  //* 7 IAQ Gewächshaus ex BME680
  Sensoren_Daten.BME_Iaq = Sensoren_Daten.BME_Iaq * 100; // ohne Komma
  LoRaByte2  = Sensoren_Daten.BME_Iaq;
  mydata[9]  = LoRaByte2;
  mydata[10] = LoRaByte2 >> 8;
  //* 8 Luftdruck Gewächshaus ex BME680
  Sensoren_Daten.BME_Druck = RUNDEN0(Sensoren_Daten.BME_Druck / 100); // 300 bis 1100
  LoRaByte2  = Sensoren_Daten.BME_Druck;
  mydata[11]  = LoRaByte2;
  mydata[12] = LoRaByte2 >> 8;
  //* 9 CO2 Equivalten Gewächshaus ex BME680
  Sensoren_Daten.BME_CO2 = RUNDEN0(Sensoren_Daten.BME_CO2);          
  LoRaByte2  = Sensoren_Daten.BME_CO2;
  mydata[13]  = LoRaByte2;
  mydata[14] = LoRaByte2 >> 8;
  //* 10 Dachfenster Gewächshaus
  mydata[15]  = Sensoren_Daten.Fenster_Status;
  //* 11 Schiebetür Gewächshaus
  mydata[16]  = Sensoren_Daten.Tuer_Status;
  //* 12 Temperatur Gartenhaus-Außen ex DHT22
  t = (t + 50) * 10; // ev. Minus-Grade wegaddieren, ohne Komma
  LoRaByte2  = t;
  mydata[17]  = LoRaByte2;
  mydata[18]  = LoRaByte2 >> 8;
  //* 13 Feuchtigkeit Gartenhaus-Außen  ex DHT22
  mydata[19]  = RUNDEN0(h); // Feuchigkeit wird nur ganzzahlig benötigt
  //* neu in Version V08:
  //* 14 Batteriespannung ex A0 Analogeingang
  Tvoltage = Tvoltage * 100; // ohne Komma
  LoRaByte2  = Tvoltage;
  mydata[20] = LoRaByte2;
  mydata[21] = LoRaByte2 >> 8;

  // 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), 0);
        Serial.println(F("Packet queued"));
      }
  	// zu diesem Timestamp wurde zuletzt gesendet
	lastTime = millis();
  }
}

Test Sketch:

/*******************************************************************************
 * Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
 * Copyright (c) 2018 Terry Moore, MCCI
 *
 *******************************************************************************/

#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>

//
// For normal use, we require that you edit the sketch to replace FILLMEIN
// with values assigned by the TTN console. However, for regression tests,
// we want to be able to compile these scripts. The regression tests define
// COMPILE_REGRESSION_TEST, and in that case we define FILLMEIN to a non-
// working but innocuous value.
//
#ifdef COMPILE_REGRESSION_TEST
# define FILLMEIN 0
#else
# warning "You must replace the values marked FILLMEIN with real values from the TTN control panel!"
# define FILLMEIN (#dont edit this, edit the lines that use FILLMEIN)
#endif

// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
// 0x70.
static const u1_t PROGMEM APPEUI[8]={ x };
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]={ x };
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 ttnctl can be copied as-is.
static const u1_t PROGMEM APPKEY[16] = { x };
void os_getDevKey (u1_t* buf) {  memcpy_P(buf, APPKEY, 16);}

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 = 16,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = LMIC_UNUSED_PIN, //5
    .dio = {5, 4, LMIC_UNUSED_PIN},
};

void printHex2(unsigned v) {
    v &= 0xff;
    if (v < 16)
        Serial.print('0');
    Serial.print(v, HEX);
}

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("AppSKey: ");
              for (size_t i=0; i<sizeof(artKey); ++i) {
                if (i != 0)
                  Serial.print("-");
                printHex2(artKey[i]);
              }
              Serial.println("");
              Serial.print("NwkSKey: ");
              for (size_t i=0; i<sizeof(nwkKey); ++i) {
                      if (i != 0)
                              Serial.print("-");
                      printHex2(nwkKey[i]);
              }
              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;
        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.print(F("Received "));
              Serial.print(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;
        case EV_TXCANCELED:
            Serial.println(F("EV_TXCANCELED"));
            break;
        case EV_RXSTART:
            /* do not print anything -- it wrecks timing */
            break;
        case EV_JOIN_TXCOMPLETE:
            Serial.println(F("EV_JOIN_TXCOMPLETE: no JoinAccept"));
            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() {
    Serial.begin(9600);
    Serial.println(F("Starting"));

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

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

    // Start job (sending automatically starts OTAA too)
    do_send(&sendjob);
}

void loop() {
    os_runloop_once();
}

Circuit Diagram 2023:

Gartenhaus_V2.pdf (38.9 KB)

What is the code on line 53 of oslmic.c - that is where the actual action is, the rest is all staging & backdrop?

Not a valid assumption unless you’ve exercised the SPI interface with another sketch so don’t discard that idea too soon.

Does the 12E in the new board with the new code work?

And does the 12E work with the test sketch?

But overall, it’s all about that line 53 - which comes up on the forum search as well …

First the solution: You were absolutely right. I still had an original packaged module and surprise, it works with the old an new sketch code :grinning:. It’s not always your own code’s fault…

Just to answer your questions:

Sure, a missing test case, but in the event of an error without a backup solution it wasn’t an option.

I found some posts about it, e.g. https://www.thethingsnetwork.org/forum/t/error-mcci-lorawan-lmic-library-3-0-99-src-lmic-oslmic-c-53/33401 which reference to the code line in oslmic. But I had no idea what to do with it.

void os_init() {
    if (os_init_ex((const void *)&lmic_pins))
        return;
    ASSERT(0);
}

However, thank you very much for the essential hint.

Peter

That’s thinking too hard. The line has the hint - lmic_pins.

For most it’s just that they’ve used the wrong pins. For some the pins lack a substance alien to their software experience - solder. I think you’re the first who suffered at the hands of a faulty module. But either way, the assert message narrowed down the area to look at.

It may be worth touching up the header pins on the 12F - very occasionally there is a dry joint that just needs some love.

2 Likes

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