From 8e9124c884e70e2402938fe7907a47eec47316af Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Sun, 15 Dec 2019 18:03:23 +0100 Subject: [PATCH] Avoid LED update glitches caused by flash access Now any access to the flash, either through update writing or SPIFFS access, is blocked while the LED stripes are written. This is accomplished using a FreeRTOS semaphore. --- include/UpdateServer.h | 6 +++++- include/WebServer.h | 6 ++++++ src/UpdateServer.cpp | 8 ++++++-- src/WebServer.cpp | 13 ++++++++++++- src/main.cpp | 20 +++++++++++++++++--- 5 files changed, 46 insertions(+), 7 deletions(-) diff --git a/include/UpdateServer.h b/include/UpdateServer.h index c94c448..1912209 100644 --- a/include/UpdateServer.h +++ b/include/UpdateServer.h @@ -2,6 +2,9 @@ #include +#include +#include + #include "ChallengeResponse.h" class UpdateServer @@ -12,7 +15,7 @@ class UpdateServer UT_SPIFFS = 1 }; - UpdateServer(const std::string &pw); + UpdateServer(const std::string &pw, SemaphoreHandle_t *ledLockoutMutex); void start(void); @@ -20,4 +23,5 @@ class UpdateServer static void updateTask(void *arg); ChallengeResponse m_cr; + SemaphoreHandle_t *m_ledLockoutMutex; }; diff --git a/include/WebServer.h b/include/WebServer.h index e41543f..6c3a08e 100644 --- a/include/WebServer.h +++ b/include/WebServer.h @@ -4,6 +4,9 @@ #include #include +#include +#include + #include "ChallengeResponse.h" class Fader; @@ -16,6 +19,7 @@ class WebServer void setFader(Fader *fader) { m_fader = fader;} void setAnimationController(AnimationController *controller) { m_animController = controller;} + void setLedLockoutMutex(SemaphoreHandle_t *ledLockoutMutex) { m_ledLockoutMutex = ledLockoutMutex; } static WebServer &instance(void) { @@ -30,6 +34,8 @@ class WebServer Fader *m_fader; AnimationController *m_animController; + SemaphoreHandle_t *m_ledLockoutMutex; + WebServer(void); static void serverTask(void *arg); diff --git a/src/UpdateServer.cpp b/src/UpdateServer.cpp index 5edf711..1390144 100644 --- a/src/UpdateServer.cpp +++ b/src/UpdateServer.cpp @@ -8,8 +8,8 @@ #include "coreids.h" -UpdateServer::UpdateServer(const std::string &pw) - : m_cr(pw) +UpdateServer::UpdateServer(const std::string &pw, SemaphoreHandle_t *ledLockoutMutex) + : m_cr(pw), m_ledLockoutMutex(ledLockoutMutex) {} void UpdateServer::start(void) @@ -177,7 +177,11 @@ void UpdateServer::updateTask(void *arg) if(client.available()) { size_t bytes_read = client.read(buf, 1024); + + // block LED updates while writing flash + xSemaphoreTake(*obj->m_ledLockoutMutex, portMAX_DELAY); Update.write(buf, bytes_read); + xSemaphoreGive(*obj->m_ledLockoutMutex); bytes_processed += bytes_read; } diff --git a/src/WebServer.cpp b/src/WebServer.cpp index a0443ca..68ffc21 100644 --- a/src/WebServer.cpp +++ b/src/WebServer.cpp @@ -22,11 +22,17 @@ bool WebServer::serveFile(String filename, httpsserver::HTTPResponse *res) { uint8_t buf[1024]; - if(!SPIFFS.exists(filename)) { + xSemaphoreTake(*instance().m_ledLockoutMutex, portMAX_DELAY); + bool exists = SPIFFS.exists(filename); + xSemaphoreGive(*instance().m_ledLockoutMutex); + + if(!exists) { return false; } + xSemaphoreTake(*instance().m_ledLockoutMutex, portMAX_DELAY); File f = SPIFFS.open(filename.c_str(), "r"); + xSemaphoreGive(*instance().m_ledLockoutMutex); if(!f) { return false; @@ -36,7 +42,10 @@ bool WebServer::serveFile(String filename, httpsserver::HTTPResponse *res) size_t nread = 1; while(nread > 0) { + xSemaphoreTake(*instance().m_ledLockoutMutex, portMAX_DELAY); nread = f.readBytes(reinterpret_cast(buf), 1024); + xSemaphoreGive(*instance().m_ledLockoutMutex); + if(nread <= 0) { break; } @@ -44,7 +53,9 @@ bool WebServer::serveFile(String filename, httpsserver::HTTPResponse *res) res->write(buf, nread); } + xSemaphoreTake(*instance().m_ledLockoutMutex, portMAX_DELAY); f.close(); + xSemaphoreGive(*instance().m_ledLockoutMutex); return true; } diff --git a/src/main.cpp b/src/main.cpp index 86bc8ee..9a8280a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,9 @@ #include #include +#include +#include + #include "WebServer.h" #include "Fader.h" #include "UDPProto.h" @@ -34,6 +37,11 @@ bool led_on = false; size_t led_idx; WiFiMulti wiFiMulti; +// this mutex is locked while LEDs are written and must be also locked +// by any task accessing the flash, as (probably) the interrupts +// from the flash cause the LED update to be unreliable. +SemaphoreHandle_t ledLockoutMutex; + Fader ledFader(NUM_STRIPS, NUM_LEDS, 1, FLIP_STRIPS_MASK); UDPProto udpProto(&ledFader); UpdateServer *updateServer; @@ -207,9 +215,11 @@ static void ledTask( void * parameter ) const Fader::Color &c = colors[i]; STRANDS[0].pixels[i] = pixelFromRGBW(c.r, c.g, c.b, c.w); } - } - digitalLeds_drawPixels(strands, 1); + xSemaphoreTake(ledLockoutMutex, portMAX_DELAY); + digitalLeds_drawPixels(strands, 1); + xSemaphoreGive(ledLockoutMutex); + } frame++; @@ -278,6 +288,9 @@ void setup() Serial.begin(115200); delay(10); + // initalize the semaphores before anything else + ledLockoutMutex = xSemaphoreCreateMutex(); + if(!initLEDs()) { Serial.println("LED setup failed!"); while(true) { @@ -326,11 +339,12 @@ void setup() // start the web server WebServer::instance().setFader(&ledFader); + WebServer::instance().setLedLockoutMutex(&ledLockoutMutex); WebServer::instance().setAnimationController(&animController); WebServer::instance().start(); // start the update server - updateServer = new UpdateServer(Config::instance().getCRPassword()); + updateServer = new UpdateServer(Config::instance().getCRPassword(), &ledLockoutMutex); updateServer->start(); }