🤖Have you ever tried Chat.M5Stack.com before asking??😎
    M5Stack Community
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Register
    • Login

    M5Atom S3 Exception LoadProhibited if dead code is present

    Arduino
    2
    5
    440
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • N
      nelll
      last edited by

      I am experiencing a odd behavior with my code, which I am not able to solve by myself. I'm using platformio to implement and upload code to my Atom S3.

      I have following code which first waits for a BLE connection and then sends/receives information.

      #include <M5AtomS3.h>
      #include <Preferences.h>
      #include <M5Unified.h>
      #include <NimBLEDevice.h>
      #include "Buttons.cpp"
      
      #define SERVICE_UUID *HIDDEN*
      #define CHARACTERISTIC_UUID *HIDDEN*
      
      #define DEBUG
      // Debugging helper for Serial connection
      #ifdef DEBUG
      #define PRINTF(text, ...) Serial.printf(text, __VA_ARGS__)
      #define PRINTLN(text) Serial.println(text)
      #define PRINT(text) Serial.print(text)
      #else
      #define PRINTF(text, ...)
      #define PRINTLN(text)
      #define PRINT(text)
      #endif
      
      using namespace std;
      
      NimBLEServer *pServer;
      NimBLECharacteristic *pCharacteristic;
      M5Canvas canvas(&AtomS3.Display);
      LGFX_Button button;
      Preferences preferences;
      
      // Parameters
      auto *font = &fonts::DejaVu18;
      unsigned int counter;
      int offset_from_top = 5;
      const char *games_counter_key = "games";
      
      // BLE Commands
      const string recording_prefix = "recording:";
      const string ready_prefix = "ready:";
      
      const string cmd_rec = "REC";
      const string cmd_stop = "STOP";
      
      // Placeholder for recording timestamp
      string time_label = "";
      
      // State machine
      enum pi_state
      {
          disconnected = 1,
          connected = 2,
          recording = 3,
      };
      pi_state p_s = disconnected;
      
      volatile bool update = false;
      
      // Button Bitmaps
      extern const unsigned short rec_inactive[];
      extern const unsigned short rec_unpressed[];
      extern const unsigned short rec_pressed[];
      extern const unsigned short stop_unpressed[];
      extern const unsigned short stop_pressed[];
      
      // BLE Callbacks
      class MyServerCallbacks : public NimBLEServerCallbacks
      {
          void onConnect(NimBLEServer *pServer)
          {
              // p_s = connected;
              PRINT("Client connected!\n");
          }
      
          void onDisconnect(NimBLEServer *pServer)
          {
              p_s = disconnected;
              PRINT("Client disconnected.\n");
          }
      };
      
      class MyCharacteristicCallbacks : public NimBLECharacteristicCallbacks
      {
          void onWrite(NimBLECharacteristic *pCharacteristic)
          {
              update = true;
          }
      };
      
      void put_asleep()
      {
          M5.Display.sleep();
          M5.Display.waitDisplay();
          gpio_get_level(GPIO_NUM_41);
          gpio_wakeup_enable((GPIO_NUM_41),GPIO_INTR_LOW_LEVEL);
          esp_sleep_enable_gpio_wakeup();
          NimBLEDevice::stopAdvertising();
          Serial.print("Sleepy\n");
          esp_light_sleep_start();
          // Start from the beginning... will return excp in Serial
          esp_restart();
      }
      
      void setup()
      {
          auto cfg = M5.config();
      #if defined(DEBUG)
          cfg.serial_baudrate = 115200;
      #endif
          AtomS3.begin(cfg);
          preferences.begin(
              "my-app",
              false);
      
          counter = preferences.getUInt(
              games_counter_key,
              0);
          PRINTF("Counter: %d\n", counter);
          if (AtomS3.Display.isEPD())
          {
              AtomS3.Display.setEpdMode(epd_mode_t::epd_fastest);
          }
          canvas.setColorDepth(16);
          canvas.createSprite(AtomS3.Display.width(),
                              AtomS3.Display.height());
          canvas.setTextColor(WHITE);
          canvas.setTextDatum(middle_centre);
          canvas.setFont(font);
          canvas.setTextSize(0.9f);
          offset_from_top = (canvas.fontHeight(font) / 2) + 2;
      
          int edge_length = canvas.height() - (canvas.fontHeight(font) * 2) - 15;
          button.initButton(&canvas, canvas.width() / 2, canvas.height() / 2 + (canvas.fontHeight(font)) + 4, edge_length, edge_length, TFT_LIGHTGREY, TFT_DARKGREY, TFT_BLACK, "");
      
          NimBLEDevice::init("Kicker_GATT_Server");
      
          pServer = NimBLEDevice::createServer();
          pServer->setCallbacks(new MyServerCallbacks());
      
          NimBLEService *pService = pServer->createService(SERVICE_UUID);
      
          pCharacteristic = pService->createCharacteristic(
              CHARACTERISTIC_UUID,
              NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::NOTIFY);
      
          pCharacteristic->setCallbacks(new MyCharacteristicCallbacks());
          pCharacteristic->setValue("Hello GATT!");
      
          pService->start();
          NimBLEDevice::startAdvertising();
      
          canvas.drawString("Stats", canvas.width() / 2, offset_from_top);
          canvas.drawString("Games played:", canvas.width() / 2, canvas.height() / 2 - (canvas.fontHeight(font) / 2) - 2);
          canvas.drawNumber(counter, canvas.width() / 2, canvas.height() / 2 + (canvas.fontHeight(font) / 2) + 2, &fonts::DejaVu24);
          canvas.pushSprite(0, 0);
          delay(3000);
      
          PRINTLN("Setup done");
      }
      
      void loop()
      {
          if(update){
              std::string value = pCharacteristic->getValue().c_str();
      
              PRINTF("Received data: \"%s\"\n", value.c_str());
      
              if (value.compare(0, recording_prefix.length(), recording_prefix) == 0)
              {
                  if (p_s == connected)
                  {
                      counter++;
                      preferences.putUInt(
                          games_counter_key,
                          counter);
                  }
                  canvas.fillRect(0, offset_from_top + canvas.fontHeight(font) * 2 + 2, canvas.width(), canvas.height(), TFT_BLACK);
                  canvas.pushImage(canvas.width() / 2 - 40, canvas.height() / 2 + (canvas.fontHeight(font)) + 4 - 40, 80, 80, (uint16_t *)stop_unpressed);
                  p_s = recording;
                  if (value.length() > 10)
                      time_label = value.substr(recording_prefix.length());
              }
              else if (value.compare(0, ready_prefix.length(), ready_prefix) == 0)
              {
                  canvas.fillRect(0, offset_from_top + canvas.fontHeight(font) * 2 + 2, canvas.width(), canvas.height(), TFT_BLACK);
                  canvas.pushImage(canvas.width() / 2 - 40, canvas.height() / 2 + (canvas.fontHeight(font)) + 4 - 40, 80, 80, (uint16_t *)rec_unpressed);
                  p_s = connected;
                  time_label = "";
              }
              update = false;
          }
          AtomS3.update();
          switch (p_s)
          {
          case connected:
              canvas.fillRect(0, 0, canvas.width(), offset_from_top + canvas.fontHeight(font) * 2 + 2, TFT_BLACK);
              canvas.drawString("Press to", canvas.width() / 2, offset_from_top);
              canvas.drawString("record", canvas.width() / 2, offset_from_top + canvas.fontHeight(font) + 2);
              if (AtomS3.BtnA.isHolding() || AtomS3.BtnA.wasPressed())
              {
                  canvas.fillRect(0, offset_from_top + canvas.fontHeight(font) * 2 + 2, canvas.width(), canvas.height(), TFT_BLACK);
                  canvas.pushImage(canvas.width() / 2 - 40, canvas.height() / 2 + (canvas.fontHeight(font)) + 4 - 40, 80, 80, (uint16_t *)rec_pressed);
                  PRINTLN("Pressed");
              }
              if (AtomS3.BtnA.wasReleased())
              {
                  canvas.fillRect(0, offset_from_top + canvas.fontHeight(font) * 2 + 2, canvas.width(), canvas.height(), TFT_BLACK);
                  canvas.pushImage(canvas.width() / 2 - 40, canvas.height() / 2 + (canvas.fontHeight(font)) + 4 - 40, 80, 80, (uint16_t *)rec_unpressed);
      
                  pCharacteristic->setValue(cmd_rec);
                  pCharacteristic->notify();
      
                  PRINTLN("Released");
              }
              break;
      
          case recording:
              canvas.fillRect(0, 0, canvas.width(), offset_from_top + canvas.fontHeight(font) * 2 + 2, TFT_BLACK);
              canvas.drawString("Recording", canvas.width() / 2, offset_from_top);
              canvas.drawString(time_label.c_str(), canvas.width() / 2, offset_from_top + canvas.fontHeight(font) + 2);
              if (AtomS3.BtnA.isHolding() || AtomS3.BtnA.wasPressed())
              {
                  canvas.fillRect(0, offset_from_top + canvas.fontHeight(font) * 2 + 2, canvas.width(), canvas.height(), TFT_BLACK);
                  canvas.pushImage(canvas.width() / 2 - 40, canvas.height() / 2 + (canvas.fontHeight(font)) + 4 - 40, 80, 80, (uint16_t *)stop_pressed);
      
                  PRINTLN("Pressed");
              }
              if (AtomS3.BtnA.wasReleased())
              {
                  canvas.fillRect(0, offset_from_top + canvas.fontHeight(font) * 2 + 2, canvas.width(), canvas.height(), TFT_BLACK);
                  canvas.pushImage(canvas.width() / 2 - 40, canvas.height() / 2 + (canvas.fontHeight(font)) + 4 - 40, 80, 80, (uint16_t *)stop_unpressed);
                  pCharacteristic->setValue(cmd_stop);
                  pCharacteristic->notify();
      
                  PRINTLN("Released");
              }
              break;
      
          default:
              canvas.fillRect(0, 0, canvas.width(), offset_from_top + canvas.fontHeight(font) * 2 + 2, TFT_BLACK);
              canvas.drawString("Disconnected", canvas.width() / 2, offset_from_top);
              canvas.drawString("Waiting for Pi", canvas.width() / 2, offset_from_top + canvas.fontHeight(font) + 2);
              canvas.fillRect(0, offset_from_top + canvas.fontHeight(font) * 2 + 2, canvas.width(), canvas.height(), TFT_BLACK);
              canvas.pushImage(canvas.width() / 2 - 40, canvas.height() / 2 + (canvas.fontHeight(font)) + 4 - 40, 80, 80, (uint16_t *)rec_inactive);
              break;
          }
          canvas.pushSprite(0, 0);
      }
      

      Buttons.cpp only contains images in binary format. put_asleep() is dead code but will become relevant in a few seconds. It's just some random code I've used to test other things and features, which led me to the issue in the first place.

      If I run this code, I will get the following exception once a BLE connection is established and first informations should be displayed (line 196 is the line starting with canvas.drawString("record"... in the first switch case block.

      Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
      
      Core  1 register dump:
      PC      : 0x42003e62  PS      : 0x00060630  A0      : 0x8201d918  A1      : 0x3fcebe40  
      A2      : 0x3fc9d4b4  A3      : 0x3fc98730  A4      : 0x3fc9872c  A5      : 0x00000040  
      A6      : 0x00000000  A7      : 0x00000080  A8      : 0x82003e60  A9      : 0x3fcebe20  
      A10     : 0x00000036  A11     : 0x3c07029e  A12     : 0x00000040  A13     : 0x0000001c  
      A14     : 0x0000002c  A15     : 0x00000000  SAR     : 0x00000010  EXCCAUSE: 0x0000001c  
      EXCVADDR: 0x00000018  LBEG    : 0x400570a4  LEND    : 0x400570a9  LCOUNT  : 0x00000000  
      
      
      Backtrace: 0x42003e5f:0x3fcebe40 0x4201d915:0x3fcebeb0
        #0  0x42003e5f in loop() at src/main.cpp:196
        #1  0x4201d915 in loopTask(void*) at /Users/xyz/.platformio/packages/framework-arduinoespressif32/cores/esp32/main.cpp:50
      
      
      
      
      
      ELF file SHA256: c74994da80137adc
      
      Rebooting...
      ESP-ROM:esp32s3-20210327
      Build:Mar 27 2021
      rst:0xc (RTC_SW_CPU_RST),boot:0x28 (SPI_FAST_FLASH_BOOT)
      Saved PC:0x420663d6
        #0  0x420663d6 in esp_pm_impl_waiti at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp_pm/pm_impl.c:855
      

      I am already aware that this indicates some sort of null pointer problem. However, the corresponding line does not have a null pointer (at least from my understanding). canvas is used in the line before, without any issue. The problem still persists if I remove the font height getter. Also, the stack trace will simply point to the next line, if I comment out line 196.
      The weirdest part here is, that if put_asleep() is removed or commented out, the exception does not occur. The issue persists regardless of its content. Especially this aspect makes me wonder what the underlying issue is. I've changed the overall code a lot, while trying to solve it, but I'm out of ideas now.

      Does somehow have any clue what the problem/error here is?

      felmueF 1 Reply Last reply Reply Quote 0
      • felmueF
        felmue @nelll
        last edited by

        Hello @nelll

        it looks like the crash is happening when AtomS3.BtnA.isHolding() is called.

        Now the strange part. When I modify below two lines in put_asleep() the crash goes away.

        //    M5.Display.sleep();
        //    M5.Display.waitDisplay();
            AtomS3.Display.sleep();
            AtomS3.Display.waitDisplay();
        

        I can only guess that while put_asleep() isn't called anywhere it still confuses somehow the namespaces - but that is really just a wild guess.

        Thanks
        Felix

        GPIO translation table M5Stack / M5Core2
        Information about various M5Stack products.
        Code examples

        N 1 Reply Last reply Reply Quote 0
        • N
          nelll @felmue
          last edited by

          Hi @felmue

          thank you for your help!

          This solves the issue in the mentioned example.
          However, I took a look at an earlier version of my code and this issue persists if I add AtomS3.Power.deepSleep(0,false); or M5.Power.deepSleep(0,false); somewhere. This was the reason for the messy implementation of put_asleep as a workaround in the first place. I've checked it with the code above and if you replace the content of put_asleep with just the deepSleep call, it still runs into the exception. Same applies to lightSleep.

          I assume the reason behind this, is the fact, that the AtomS3 library contains calls to the Unified library (M5.(...))?!

          Nonetheless, from my understanding, it has to be some mistake I must have made, because otherwise this problem would have happened to other devs as well, as this is pretty significant. However, I'm out of ideas with my limited knowledge about C++ and ESP overall.

          P.S.: I've removed the redundant #include <M5Unified.h>. Still the same issues...

          felmueF 1 Reply Last reply Reply Quote 0
          • felmueF
            felmue @nelll
            last edited by

            Hello @nelll

            have you tried to not use M5AtomS3 library and only use M5Unified library and replace all AtomS3. with M5.? Note: not tested myself - just an idea.

            Thanks
            Felix

            GPIO translation table M5Stack / M5Core2
            Information about various M5Stack products.
            Code examples

            N 1 Reply Last reply Reply Quote 0
            • N
              nelll @felmue
              last edited by

              Hey @felmue,

              thanks, this did solve all the issues! Didn't know that I can solely rely on the Unified library without any further changes.
              Do you know if this is intended, and if so, why does the Board-specific library exist?

              Thank you so much for your help!

              1 Reply Last reply Reply Quote 0
              • First post
                Last post