Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled

I'm working on an ESP8266/ESP32 project using the Arduino_SNMP_Manager library to retrieve SNMP data from a network device. My code works as expected, but I encounter a problem when I try to set the UDP object for the SNMP manager. Specifically, when I uncomment the line snmpRequest.setUDP(&udp); in my code, the ESP8266/ESP32 reboots continuously.

Here’s the relevant portion of my code:

#include <lvgl.h>

#include <TFT_eSPI.h>
#include "TouchScreen.h"
#include <Arduino_SNMP_Manager.h>
#include <WiFi.h>

#include <WiFiUdp.h>
// Include WiFi library for network communication
// NTP server and time zone
const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 7;      // Adjust for your time zone (e.g., -18000 for EST)
const int   daylightOffset_sec = 3600;
int pollInterval = 10000;
IPAddress router(192, 168, 88, 1);
const char *community = "public";
const int snmpVersion = 1;  // IP address of your MikroTik device
WiFiUDP udp;                                           // UDP object used to send and receive packets
SNMPManager snmp = SNMPManager(community);             // Starts an SNMPManager to listen to replies to get-requests
SNMPGet snmpRequest = SNMPGet(community, snmpVersion); 
// Variables
uint32_t ifSpeedResponse = 0;
uint32_t downloadEtherr1 = 0;
int servicesResponse = 0;
char sysName[50];
char *sysNameResponse = sysName;
long long unsigned int hcCounter = 0;
uint32_t uptime = 0;
uint32_t lastUptime = 0;
unsigned long pollStart = 0;
unsigned long intervalBetweenPolls = 0;
float bandwidthInUtilPct = 0;
uint32_t lastInOctets = 0;
// SNMP OIDs for Ether1 traffic (replace with actual OIDs for your setup)
const char *oidIfSpeedGauge1 = ".1.3.6.1.2.1.2.2.1.5.1";         // Gauge Regular ethernet interface ifSpeed.4
const char *uploadether1 = ".1.3.6.1.2.1.2.2.1.10.1";
const char *downloadether1 = ".1.3.6.1.2.1.2.2.1.6.1";
const char *oidIfSpeedGauge2 = ".1.3.6.1.2.1.2.2.1.5.2"; 
const char *downloadether2 = ".1.3.6.1.2.1.2.2.1.6.2";        // Gauge Regular ethernet interface ifSpeed.4
const char *uploadether2 = ".1.3.6.1.2.1.2.2.1.10.2"; // Counter32 ifInOctets.4
const char *oidServiceCountInt = ".1.3.6.1.2.1.1.7.0";      // Integer sysServices
const char *oidSysName = ".1.3.6.1.2.1.1.5.0";              // OctetString SysName
const char *oid64Counter = ".1.3.6.1.2.1.31.1.1.1.6.4";     // Counter64 64-bit ifInOctets.4
const char *oidUptime = ".1.3.6.1.2.1.1.3.0"; 
 

// long ether1upload = snmpRequest.addOIDPointer(".1.3.6.1.2.1.31.1.1.1.10.1"); // Replace with the correct OID for Ether1
//   long ether1Download = snmpRequest.addOIDPointer(".1.3.6.1.2.1.31.1.1.1.6.1");
ValueCallback *callbackIfSpeed;
ValueCallback *callbackInOctets;
ValueCallback *downloadEther1;
ValueCallback *callbackServices;
ValueCallback *callbackSysName;
ValueCallback *callback64Counter;
ValueCallback *callbackUptime;
  // long ether2upload = snmpRequest.addOIDPointer(".1.3.6.1.2.1.31.1.1.1.10.2"); // Replace with the correct OID for Ether1
  // long ether2Download = snmpRequest.addOIDPointer(".1.3.6.1.2.1.31.1.1.1.6.2");

const char* ssid = "BALINET";
const char* password = "";

#define YP 4  // must be an analog pin, use "An" notation!
#define XM 15  // must be an analog pin, use "An" notation!
#define YM 14   // can be a digital pin
#define XP 27   // can be a digital pin

#define MINPRESSURE 100
#define MAXPRESSURE 1000

#define TS_MINX 136

#define TS_MINY 85

#define TS_MAXX 905

#define TS_MAXY 905
// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

#define SCREEN_WIDTH 480
#define SCREEN_HEIGHT 320

// Touchscreen coordinates: (x, y) and pressure (z)
uint16_t x, y, z;

#define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 10 * (LV_COLOR_DEPTH / 8))
uint32_t draw_buf[DRAW_BUF_SIZE / 4];

// If logging is enabled, it will inform the user about what is happening in the library
void log_print(lv_log_level_t level, const char * buf) {
  LV_UNUSED(level);
  Serial.println(buf);
  Serial.flush();
}

bool getTouch(uint16_t * x, uint16_t * y) {
    TSPoint p = ts.getPoint();
    pinMode(YP, OUTPUT);
    pinMode(XM, OUTPUT);
    digitalWrite(YP, HIGH);
    digitalWrite(XM, HIGH);

    bool pressed = (p.z > 10 && p.z < 1000);
    if (pressed) {
        *x = map(p.x, TS_MINX, TS_MAXX, 0, 320);
        *y = map(p.y, TS_MINY, TS_MAXY, 0, 240);
    }

    return pressed;
}
// Get the Touchscreen data
void touchscreen_read(lv_indev_t * indev, lv_indev_data_t * data) {
  // Checks if Touchscreen was touched, and prints X, Y and Pressure (Z)
     uint16_t x, y;
    bool touched = getTouch(&x, &y);

    if (touched) {
        data->point.x = x;
        data->point.y = y;
        data->state = LV_INDEV_STATE_PR;
    } else {
    data->state = LV_INDEV_STATE_RELEASED;
  }
}




// static lv_obj_t * time_label;

// // Function to update the time label
// static void update_time(lv_timer_t * timer) {
//     time_t now;
//     struct tm timeinfo;
//     char time_str[16];

//     time(&now);  // Get the current time
//     localtime_r(&now, &timeinfo);  // Convert to local time

//     // Format the time as HH:MM:SS
//     strftime(time_str, sizeof(time_str), "%H:%M:%S", &timeinfo);

//     // Set the time label text
//     lv_label_set_text(time_label, time_str);
// }

static lv_obj_t * slider_label;
// Callback that prints the current slider value on the TFT display and Serial Monitor for debugging purposes
static void slider_event_callback(lv_event_t * e) {
  lv_obj_t * slider = (lv_obj_t*) lv_event_get_target(e);
  char buf[8];
  lv_snprintf(buf, sizeof(buf), "%d%%", (int)lv_slider_get_value(slider));
  lv_label_set_text(slider_label, buf);
  lv_obj_align_to(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
  LV_LOG_USER("Slider changed to %d%%", (int)lv_slider_get_value(slider));
}


void doSNMPCalculations()
{

   if (uptime == lastUptime) {
        Serial.println("Data not updated between polls");
         Serial.println(uptime); 
         Serial.println(lastUptime);
        return;
    } else if (uptime < lastUptime) {
        Serial.println("Uptime < lastUptime. Device restarted?");
    } else {
        if (downloadEtherr1 > 0 && lastInOctets > 0) {
            uint32_t octetsDiff;
            if (downloadEtherr1 > lastInOctets) {
                octetsDiff = downloadEtherr1 - lastInOctets;
            } else {
                // Handle counter wrap-around
                octetsDiff = (4294967295 - lastInOctets) + downloadEtherr1;
            }

            // Convert octets (bytes) to bits
            uint64_t bits = (uint64_t)octetsDiff * 8;

            // Calculate time difference in seconds
            uint32_t timeDiff = (uptime - lastUptime) / 100; // uptime is in hundredths of seconds
if (timeDiff > 0) {
    float mbps = (float)bits / (timeDiff * 1000000.0);
    Serial.printf("Bandwidth in Mbps: %.2f\n", mbps);
} else {
    Serial.println("Time difference is too small or zero.");
}
        }
    }

    // Update last samples
    lastUptime = uptime;
    lastInOctets = downloadEtherr1;
}

void lv_create_main_gui(void) {
  // Create a text label aligned center on top ("Hello, world!")
    /*Create a Tab view object*/
    lv_obj_t * tabview;
    tabview = lv_tabview_create(lv_screen_active());
    lv_tabview_set_tab_bar_position(tabview, LV_DIR_LEFT);
    lv_tabview_set_tab_bar_size(tabview, 50);
    lv_obj_set_style_bg_color(tabview, lv_palette_lighten(LV_PALETTE_RED, 2), 0);

    lv_obj_t * tab_buttons = lv_tabview_get_tab_bar(tabview);
    lv_obj_set_style_bg_color(tab_buttons, lv_palette_darken(LV_PALETTE_GREY, 3), 0);
    lv_obj_set_style_text_color(tab_buttons, lv_palette_lighten(LV_PALETTE_GREY, 5), 0);
    lv_obj_set_style_border_side(tab_buttons, LV_BORDER_SIDE_RIGHT, LV_PART_ITEMS | LV_STATE_CHECKED);

    /*Add 3 tabs (the tabs are page (lv_page) and can be scrolled*/
    lv_obj_t * tab1 = lv_tabview_add_tab(tabview, LV_SYMBOL_OK);
    lv_obj_t * tab2 = lv_tabview_add_tab(tabview, LV_SYMBOL_HOME);
    lv_obj_t * tab3 = lv_tabview_add_tab(tabview, LV_SYMBOL_WIFI);
    lv_obj_t * tab4 = lv_tabview_add_tab(tabview, LV_SYMBOL_SETTINGS);
    lv_obj_t * tab5 = lv_tabview_add_tab(tabview, LV_SYMBOL_CHARGE);

    lv_obj_set_style_bg_color(tab2, lv_palette_lighten(LV_PALETTE_AMBER, 3), 0);
    lv_obj_set_style_bg_opa(tab2, LV_OPA_COVER, 0);

    /*Add content to the tabs*/
    lv_obj_t * label = lv_label_create(tab1);
    lv_label_set_text(label, "MIKROTIK");
      /*Create a chart*/
    lv_obj_t * chart1;
    chart1 = lv_chart_create(tab1);
  lv_obj_set_size(chart1, 200, 100);
    lv_obj_align(chart1, LV_ALIGN_TOP_MID, 10, 30);
    lv_chart_set_type(chart1, LV_CHART_TYPE_LINE);  /*Show lines and points too*/

    /*Add two data series*/
    lv_chart_series_t * ser1 = lv_chart_add_series(chart1, lv_palette_main(LV_PALETTE_GREEN), LV_CHART_AXIS_PRIMARY_Y);
    lv_chart_series_t * ser2 = lv_chart_add_series(chart1, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_SECONDARY_Y);
    int32_t * ser2_y_points = lv_chart_get_y_array(chart1, ser2);

    uint32_t i;
    for(i = 0; i < 10; i++) {
        /*Set the next points on 'ser1'*/
        lv_chart_set_next_value(chart1, ser1, lv_rand(10, 50));

        /*Directly set points on 'ser2'*/
        ser2_y_points[i] = lv_rand(50, 90);
    }

    lv_chart_refresh(chart1); /*Required after direct set*/
    
    // Add "Download:" and "Upload:" labels below each chart
    lv_obj_t * download_label1 = lv_label_create(tab1);
    lv_label_set_text(download_label1, "Download:");
    lv_obj_align_to(download_label1, chart1, LV_ALIGN_BOTTOM_LEFT, 10, 30);

    lv_obj_t * upload_label1 = lv_label_create(tab1);
    lv_label_set_text(upload_label1, "Upload:");
    lv_obj_align_to(upload_label1, download_label1, LV_ALIGN_OUT_RIGHT_MID, 10, 0);

    // Create the second chart
    lv_obj_t * chart2;
    chart2 = lv_chart_create(tab1);
    lv_obj_set_size(chart2, 200, 100);
    lv_obj_align_to(chart2, chart1, LV_ALIGN_OUT_BOTTOM_MID, 0, 30);
    lv_chart_set_type(chart2, LV_CHART_TYPE_LINE);   // Show lines and points too

    // Add two data series for upload and download speeds
    lv_chart_series_t * upload_ser = lv_chart_add_series(chart2, lv_palette_main(LV_PALETTE_BLUE), LV_CHART_AXIS_PRIMARY_Y);
    lv_chart_series_t * download_ser = lv_chart_add_series(chart2, lv_palette_main(LV_PALETTE_ORANGE), LV_CHART_AXIS_PRIMARY_Y);

    for (uint32_t i = 0; i < 10; i++) {
        lv_chart_set_next_value(chart2, upload_ser, lv_rand(10, 100));   // Example upload values
        lv_chart_set_next_value(chart2, download_ser, lv_rand(10, 100)); // Example download values
    }

    lv_chart_refresh(chart2); // Required after direct set




    lv_obj_t * download_label2 = lv_label_create(tab1);
    lv_label_set_text(download_label2, "Download:");
    lv_obj_align_to(download_label2, chart2, LV_ALIGN_BOTTOM_LEFT, 10, 30);

    lv_obj_t * upload_label2 = lv_label_create(tab1);
    lv_label_set_text(upload_label2, "Upload:");
    lv_obj_align_to(upload_label2, download_label2, LV_ALIGN_OUT_RIGHT_MID, 10, 0);




    

    /*Create an Arc*/
    lv_obj_t * arc = lv_arc_create(tab1);
    lv_obj_set_size(arc, 70, 70);
    lv_arc_set_rotation(arc, 135);
    lv_arc_set_bg_angles(arc, 0, 270);
    lv_arc_set_value(arc, 10);
    lv_obj_align(arc,LV_ALIGN_TOP_LEFT,10,30);
    /*Manually update the label for the first time*/
    lv_obj_send_event(arc, LV_EVENT_VALUE_CHANGED, NULL);
        // Add CPU and Uptime labels in the top-right corner
    lv_obj_t * cpu_label = lv_label_create(tab1);
    lv_label_set_text(cpu_label, "CPU");
    lv_obj_align_to(cpu_label, arc, LV_ALIGN_OUT_BOTTOM_MID, 0, -50);

  lv_obj_t * cpu_label2 = lv_label_create(tab1);
    lv_label_set_text(cpu_label2, "%");
    lv_obj_align_to(cpu_label2, cpu_label, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);

     

    /*Create an Arc*/
    lv_obj_t * arc2 = lv_arc_create(tab1);
    lv_obj_set_size(arc2, 70, 70);
    lv_arc_set_rotation(arc2, 135);
    lv_arc_set_bg_angles(arc2, 0, 270);
    lv_arc_set_value(arc2, 10);
    lv_obj_align_to(arc2, arc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 30);


    /*Manually update the label for the first time*/
    lv_obj_send_event(arc2, LV_EVENT_VALUE_CHANGED, NULL);


    lv_obj_t * uptime_label = lv_label_create(tab1);
    lv_label_set_text(uptime_label, "Uptime: ");
    lv_obj_align(uptime_label, LV_ALIGN_TOP_RIGHT, 0, 0);


    // Create the time label and position it below the uptime label
    lv_obj_t * labeltime = lv_label_create(tab1);
    lv_label_set_text(labeltime, "TIME : ");
    lv_obj_align(labeltime,LV_ALIGN_TOP_MID, 0,0);
    // time_label = lv_label_create(tab1);
    // lv_label_set_text(time_label, "00:00:00");
    // lv_obj_align_to(time_label, labeltime, LV_ALIGN_OUT_RIGHT_MID, 0, 0);


  // TAB 2

    label = lv_label_create(tab2);
   lv_label_set_text(label, LV_SYMBOL_OK);
 // TAB 3

    label = lv_label_create(tab3);
    lv_label_set_text(label, LV_SYMBOL_WIFI);
 // TAB 4

    label = lv_label_create(tab4);
    lv_label_set_text(label, LV_SYMBOL_SETTINGS);
 // TAB 5

    label = lv_label_create(tab5);
    lv_label_set_text(label, LV_SYMBOL_SETTINGS);

    lv_obj_remove_flag(lv_tabview_get_content(tabview), LV_OBJ_FLAG_SCROLLABLE);

}

  // callbackServices = snmp.addIntegerHandler(router, oidServiceCountInt, &servicesResponse);
void printUptime(uint32_t uptime) {
    // Konversi uptime dari centi-seconds (hundredths of a second) ke detik
    uint32_t seconds = uptime / 100;

    uint32_t days = seconds / 86400; // 86400 detik dalam satu hari
    seconds %= 86400;
    uint32_t hours = seconds / 3600; // 3600 detik dalam satu jam
    seconds %= 3600;
    uint32_t minutes = seconds / 60; // 60 detik dalam satu menit
    seconds %= 60;

    Serial.printf("Uptime: %u days, %u hours, %u minutes, %u seconds\n", days, hours, minutes, seconds);
}

void setup() {
  String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
  Serial.begin(115200);
  Serial.println(LVGL_Arduino);
  
  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");
    Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
// Initialize NTP
  // configTime(25200, 0, "0.id.pool.ntp.org"); 
  // Start LVGL
  lv_init();
  // Register print function for debugging
  lv_log_register_print_cb(log_print);

  // start snmp
   snmp.setUDP(&udp); // give snmp a pointer to the UDP object
   snmp.begin();  

  // Get callbacks from creating a handler for each of the OID
  callbackIfSpeed = snmp.addGaugeHandler(router, oidIfSpeedGauge1, &ifSpeedResponse);
  downloadEther1= snmp.addCounter32Handler(router, downloadether1, &downloadEtherr1);
  // callbackServices = snmp.addIntegerHandler(router, oidServiceCountInt, &servicesResponse);
  callbackSysName = snmp.addStringHandler(router, oidSysName, &sysNameResponse);
  // callback64Counter = snmp.addCounter64Handler(router, oid64Counter, &hcCounter);
  callbackUptime = snmp.addTimestampHandler(router, oidUptime, &uptime);
  
  // Create a display object
  lv_display_t * disp;
  // Initialize the TFT display using the TFT_eSPI library
  disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
  
  // Initialize an LVGL input device object (Touchscreen)
  lv_indev_t * indev = lv_indev_create();
  lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
  // Set the callback function to read Touchscreen input
  lv_indev_set_read_cb(indev, touchscreen_read);

    // Initialize NTP
 

    // Existing LVGL setup code...

    lv_create_main_gui();

    // Add the timer to update the time label every second
    // lv_timer_create(update_time, 1000, NULL);
   
 
}


void loop() {
snmp.loop();
 intervalBetweenPolls = millis() - pollStart;
if (intervalBetweenPolls >= pollInterval)
  { getSNMP();
 doSNMPCalculations();
 }
  lv_task_handler();  // let the GUI do its work
  lv_tick_inc(5);     // tell LVGL how much time has passed
  delay(5);           // let this time pass
}
void getSNMP()
{
  // Build a SNMP get-request add each OID to the request
  snmpRequest.addOIDPointer(callbackIfSpeed);
  snmpRequest.addOIDPointer(callbackInOctets);
  snmpRequest.addOIDPointer(callbackServices);
  snmpRequest.addOIDPointer(callbackSysName);
  snmpRequest.addOIDPointer(callback64Counter);
  snmpRequest.addOIDPointer(callbackUptime);

  snmpRequest.setIP(WiFi.localIP());
 snmpRequest.setPort(161);  // Default is UDP port 161 for SNMP. But can be overriden if necessary.
 snmpRequest.setUDP(&udp);
  snmpRequest.setRequestID(rand() % 5555);
  snmpRequest.sendTo(router);
  snmpRequest.clearOIDList();
}

I've ensured that the UDP object is correctly initialized, and the rest of my code works without any issues when I comment out the setUDP() line. However, setting the UDP object seems to cause a continuous reboot loop.

  • Device: ESP32
  • Library: Arduino_SNMP_Manager, LVGL
  • Symptoms: Continuous reboot when setting the UDP object for SNMP

Has anyone else experienced this issue? What could be causing the reboots, and how can I resolve it?

Any insights or suggestions would be greatly appreciated!

I had the same issue yesterday, It seems the issue is related to TFT_eSPI and ESP board library > 2.0.14
I have reverted the ESP board to 2.0.14 and the TFT_eSPI examples are working now.

see here:

1 Like