Skip to content

The screen seems to break when I call Update.write() #786

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
srinn opened this issue Apr 25, 2025 · 13 comments
Open

The screen seems to break when I call Update.write() #786

srinn opened this issue Apr 25, 2025 · 13 comments

Comments

@srinn
Copy link

srinn commented Apr 25, 2025

I wanted to show OTA progress to my led matrix like this: #50 (comment)
But I cannot print anything to my led matrix while OTA updating..
I think when the Update.write() is called, the led matrix screen breaks.

IMG 1679
https://www.youtube.com/watch?v=WrNr8dVeAxI

I'm using esp32s3 n16r8 with PSRAM on.
I'm using 6 panels now, so I must enable SPIRAM_FRAMEBUFFER.

This is my sample test code:

platformio.ini

; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:esp32-s3-devkitc-1]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
board_build.arduino.memory_type = qio_opi
board_build.flash_mode = qio
board_build.prsam_type = opi
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.extra_flags = 
	-DBOARD_HAS_PSRAM
	-DSPIRAM_FRAMEBUFFER
monitor_speed = 115200
lib_deps = 
	mrfaptastic/ESP32 HUB75 LED MATRIX PANEL DMA Display@^3.0.12
	adafruit/Adafruit GFX Library@^1.12.1

ESP32HTTPUpdateServer.h (From ESP MQTT Client, avdovin/ESP MQTT Client)

#ifndef ESP32_HTTP_UPDATE_SERVER_H
#define ESP32_HTTP_UPDATE_SERVER_H

/*
  Based on the HTTP update exemple of ESP32 core
*/

#include <WebServer.h>
#include <Update.h>

#define ESP32_WEB_UPDATE_HTML "<html><body><form method='POST' action='' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form></body></html>"
#define ESP32_WEB_UPDATE_SUCCESS_RESPONSE "<META http-equiv=\"refresh\" content=\"10;URL=/\">Update Success! Rebooting...\n"

class ESP32HTTPUpdateServer
{
private:
  WebServer* _server;

  String _username;
  String _password;
  bool _serialDebugging;

public:
  ESP32HTTPUpdateServer(bool serialDebugging = false)
  {
    _server = NULL;
    _username = "";
    _password = "";
  }

  void setup(WebServer* server, const char* path = "/", const char* username = "", const char* password = "")
  {
    _server = server;
    _username = username;
    _password = password;

    // Get of the index handling
    _server->on(path, HTTP_GET, [&]() {
      Serial.println("GET requested");
      // Force authentication if a user and password are defined
      if (_username.length() > 0 && _password.length() > 0 && !_server->authenticate(_username.c_str(), _password.c_str()))
        return _server->requestAuthentication();

      _server->sendHeader("Connection", "close");
      _server->send(200, "text/html", ESP32_WEB_UPDATE_HTML);
    });

    // Post of the file handling
    _server->on(path, HTTP_POST, [&]() {
      _server->client().setNoDelay(true);
      _server->send_P(200, "text/html", (Update.hasError()) ? "FAIL" : ESP32_WEB_UPDATE_SUCCESS_RESPONSE);
      delay(100);
      _server->client().stop();
      ESP.restart();
    }, [&]() {
      HTTPUpload& upload = _server->upload();

      if (upload.status == UPLOAD_FILE_START) 
      {
        // Check if we are authenticated
        if (!(_username.length() == 0 || _password.length() == 0 || _server->authenticate(_username.c_str(), _password.c_str())))
        {
          if (_serialDebugging)
            Serial.printf("Unauthenticated Update\n");

          return;
        }

        // Debugging message for upload start
        if (_serialDebugging) 
        {
          Serial.setDebugOutput(true);
          Serial.printf("Update: %s\n", upload.filename.c_str());
        }

        // Starting update
        bool error = Update.begin(UPDATE_SIZE_UNKNOWN);
        if (_serialDebugging && error)
          Update.printError(Serial);
      }
      else if (upload.status == UPLOAD_FILE_WRITE) 
      {
        if (Update.write(upload.buf, upload.currentSize) != upload.currentSize && _serialDebugging) 
          Update.printError(Serial);
      }
      else if (upload.status == UPLOAD_FILE_END) 
      {
        if (Update.end(true) && _serialDebugging)
          Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
        else if(_serialDebugging)
          Update.printError(Serial);

        if(_serialDebugging)
          Serial.setDebugOutput(false);
      }
      else if(_serialDebugging)
        Serial.printf("Update Failed Unexpectedly (likely broken connection): status=%d\n", upload.status);
    });

    _server->begin();
  }
};

#endif

main.cpp

#include <Arduino.h>
#include <WebServer.h>
#include "ESP32HTTPUpdateServer.h"
#include <WiFi.h>
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>

#define R1_PIN 4
#define G1_PIN 5
#define B1_PIN 6
#define R2_PIN 7
#define G2_PIN 15
#define B2_PIN 16
#define A_PIN  18
#define B_PIN  8
#define C_PIN  3
#define D_PIN  42
#define E_PIN  39
#define LAT_PIN 40
#define OE_PIN  2
#define CLK_PIN 41

HUB75_I2S_CFG::i2s_pins _pins={R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN};

const int panelResX = 64;      // Number of pixels wide of each INDIVIDUAL panel module. 
const int panelResY = 64;     // Number of pixels tall of each INDIVIDUAL panel module.
// My LED Matrix's actual height is 32px however the scan rate is 1/32 so I set this value to 64 instead 32.
const int panel_chain = 1;      // Total number of panels chained one to another
MatrixPanel_I2S_DMA *dma_display = nullptr;

WebServer* _httpServer;
ESP32HTTPUpdateServer* _httpUpdater;
TaskHandle_t DisplayTask;

void displaySetup() {
  HUB75_I2S_CFG mxconfig(
    panelResX,   // module width
    panelResY,   // module height
    panel_chain,    // Chain length
    _pins
  );
  mxconfig.clkphase = false;
  mxconfig.driver = HUB75_I2S_CFG::FM6124;

  dma_display = new MatrixPanel_I2S_DMA(mxconfig);
  dma_display->begin();
}


void displayLoop(void *param) {
  Serial.print("tick");
  while (true) {
    dma_display->setBrightness8(20);
    dma_display->fillScreen(dma_display->color565(0, 0, 0));
    dma_display->setFont();
    dma_display->setCursor(0, 0);
    dma_display->print("test");
    Serial.print(".");
    vTaskDelay(1);
  }
}

void setup() {
  displaySetup();

  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  Serial.println("Wifi will begin");
  WiFi.begin(
    "SomeWifiSSID",
    "SomeWifiPassword"
  );
  _httpServer = new WebServer(80);
  _httpUpdater = new ESP32HTTPUpdateServer();
  while (!WiFi.isConnected()) {
    Serial.println("detect wifi");
    delay(1000);
  }
  _httpUpdater->setup(_httpServer, "/", "test", "test");
  _httpServer->begin();

  xTaskCreatePinnedToCore(
    displayLoop,       // 태스크 함수
    "DisplayTask",     // 테스크 이름
    10000,             // 스택 크기(워드단위)
    NULL,              // 태스크 파라미터
    1,                 // 태스크 우선순위
    &DisplayTask,      // 태스크 핸들
  0);                // 실행될 코어
}

void loop() {
  if (WiFi.isConnected()) {
    // Serial.println(WiFi.localIP());
    _httpServer->handleClient();
  }
  delay(100);
}

What is the problem and How can I solve this?

@sintrb
Copy link

sintrb commented Apr 27, 2025

You can change i2sspeed the to try. I found that this parameter will affect WiFi.

mxconfig.i2sspeed = HUB75_I2S_CFG::clk_speed::HZ_16M;

@srinn
Copy link
Author

srinn commented Apr 27, 2025

You can change i2sspeed the to try. I found that this parameter will affect WiFi.

mxconfig.i2sspeed = HUB75_I2S_CFG::clk_speed::HZ_16M;

Thank you for your reply, however it was not effective.
I think it crashes when massive psram/flash memory access.

@mrcodetastic
Copy link
Owner

Interesting. I'll try have a look and see if I can replicate.

@srinn
Copy link
Author

srinn commented May 2, 2025

Interesting. I'll try have a look and see if I can replicate.

I figured it out what is the problem.
As far as I know, Cache_WriteBack_Addr() cannot avoid DMA cache corruption.
It can avoid screen crash to use esp_cache_msync() API from ESP-IDF framework, with flags "ESP_CACHE_MSYNC_FLAG_DIR_C2M", "ESP_CACHE_MSYNC_FLAG_TYPE_DATA", "ESP_CACHE_MSYNC_FLAG_UNALIGNED".

I'm not an expert for esp32, ESP-IDF, and DMA.. so I can't explain it well. I recommend you to see this thread:
https://esp32.com/viewtopic.php?t=24459&start=130#p144126

so I modified it and now working charm!
master...srinn:ESP32-HUB75-MatrixPanel-DMA:master

However, this change ONLY works under the ESP-IDF framework because it requires the use of the esp_cache_msync() API. so I'm hesitant to pull request this change.

@mrcodetastic
Copy link
Owner

mrcodetastic commented May 2, 2025

Can you create a pull request with code that detects if the library is being compiled using the esp32-arduino framework or not? And includes this work around if no Arduino.

They would be greatly appreciated.

@Jason2866
Copy link
Contributor

However, this change ONLY works under the ESP-IDF framework because it requires the use of the esp_cache_msync() API. so I'm hesitant to pull request this change.

Why? Just call it from Arduino.

@srinn
Copy link
Author

srinn commented May 2, 2025

However, this change ONLY works under the ESP-IDF framework because it requires the use of the esp_cache_msync() API. so I'm hesitant to pull request this change.

Why? Just call it from Arduino.

Image

I don't know why it cannot import this API from arduino framework.

@srinn
Copy link
Author

srinn commented May 3, 2025

However, this change ONLY works under the ESP-IDF framework because it requires the use of the esp_cache_msync() API. so I'm hesitant to pull request this change.

Why? Just call it from Arduino.

Can you create a pull request with code that detects if the library is being compiled using the esp32-arduino framework or not? And includes this work around if no Arduino.

They would be greatly appreciated.

Sorry, Forget about it. I just forget to include esp_cache.h.

@srinn
Copy link
Author

srinn commented May 3, 2025

When I tried to use under ESP-IDF it works okay but after change to arduino framework, the screen crashes.
It is related this problem: #779

so I temporally changed 226th line of gdma_lcd_parallel16.cpp
from

#ifdef SPIRAM_DMA_BUFFER

to

#ifdef SPIRAM_FRAMEBUFFER

@srinn
Copy link
Author

srinn commented May 3, 2025

I think I misunderstood this problem has been solved. my screen still crashing in arduino framework when I tried to update.
I'll figure it out what differences between my two workspaces based on arduino framework and esp-idf framework

EDIT: I set the target_compile_option() in CMakeLists.txt on my ESP-IDF framework workspace like this:

target_compile_options(${COMPONENT_LIB} PRIVATE -DSPIRAM_FRAMEBUFFER -DMATRIX_ONE_SCAN -DBOARD_HAS_PSRAM)

but SPIRAM_FRAMEBUFFER doesn't seems to work. even MATRIX_ONE_SCAN (I added it in my forked code) is working. it's strange, anyway in ESP-IDF framework test application was always using internal sram, not the psram.

So.. my code is definitely not effective anything to this problem.

@mrcodetastic
Copy link
Owner

See if using -DSPIRAM_DMA_BUFFER solves you issue.

@srinn
Copy link
Author

srinn commented May 5, 2025

See if using -DSPIRAM_DMA_BUFFER solves you issue.

Okay, don't mind about using ESP-IDF framework, I will focusing to solve this problem now..
and now I figured it out I can recover when the screen is not working, to set:

LCD_CAM.lcd_user.lcd_start = 1;

When screen is gone.
During update, the screen is keep breaking.
and when I set this value to 1, the screen is back to normal in a very short period.
after the short period, the screen breaks again while OTA updating.

my pseudo code:

void displayLoop() {
  if (LCD_CAM.lcd_user.lcd_start != 1) {
    LCD_CAM.lcd_user.lcd_start = 1;
  }
  dma_display->setBrightness8(clockDim);
  // some display things...
}
void updateLoop() {
  // some OTA loop...
}

https://www.youtube.com/watch?v=Ko0QhLQT7tY

I don't know what makes it set to 0.
I'll figure it out about this.

@mrcodetastic
Copy link
Owner

That's bizarre, potentially worth reporting to the esp-idf repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants