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.
This commit is contained in:
Thomas Kolb 2019-12-15 18:03:23 +01:00
parent 9ddb2063bb
commit 8e9124c884
5 changed files with 46 additions and 7 deletions

View file

@ -2,6 +2,9 @@
#include <string> #include <string>
#include <FreeRTOS.h>
#include <freertos/semphr.h>
#include "ChallengeResponse.h" #include "ChallengeResponse.h"
class UpdateServer class UpdateServer
@ -12,7 +15,7 @@ class UpdateServer
UT_SPIFFS = 1 UT_SPIFFS = 1
}; };
UpdateServer(const std::string &pw); UpdateServer(const std::string &pw, SemaphoreHandle_t *ledLockoutMutex);
void start(void); void start(void);
@ -20,4 +23,5 @@ class UpdateServer
static void updateTask(void *arg); static void updateTask(void *arg);
ChallengeResponse m_cr; ChallengeResponse m_cr;
SemaphoreHandle_t *m_ledLockoutMutex;
}; };

View file

@ -4,6 +4,9 @@
#include <HTTPResponse.hpp> #include <HTTPResponse.hpp>
#include <HTTPServer.hpp> #include <HTTPServer.hpp>
#include <FreeRTOS.h>
#include <freertos/semphr.h>
#include "ChallengeResponse.h" #include "ChallengeResponse.h"
class Fader; class Fader;
@ -16,6 +19,7 @@ class WebServer
void setFader(Fader *fader) { m_fader = fader;} void setFader(Fader *fader) { m_fader = fader;}
void setAnimationController(AnimationController *controller) { m_animController = controller;} void setAnimationController(AnimationController *controller) { m_animController = controller;}
void setLedLockoutMutex(SemaphoreHandle_t *ledLockoutMutex) { m_ledLockoutMutex = ledLockoutMutex; }
static WebServer &instance(void) static WebServer &instance(void)
{ {
@ -30,6 +34,8 @@ class WebServer
Fader *m_fader; Fader *m_fader;
AnimationController *m_animController; AnimationController *m_animController;
SemaphoreHandle_t *m_ledLockoutMutex;
WebServer(void); WebServer(void);
static void serverTask(void *arg); static void serverTask(void *arg);

View file

@ -8,8 +8,8 @@
#include "coreids.h" #include "coreids.h"
UpdateServer::UpdateServer(const std::string &pw) UpdateServer::UpdateServer(const std::string &pw, SemaphoreHandle_t *ledLockoutMutex)
: m_cr(pw) : m_cr(pw), m_ledLockoutMutex(ledLockoutMutex)
{} {}
void UpdateServer::start(void) void UpdateServer::start(void)
@ -177,7 +177,11 @@ void UpdateServer::updateTask(void *arg)
if(client.available()) { if(client.available()) {
size_t bytes_read = client.read(buf, 1024); 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); Update.write(buf, bytes_read);
xSemaphoreGive(*obj->m_ledLockoutMutex);
bytes_processed += bytes_read; bytes_processed += bytes_read;
} }

View file

@ -22,11 +22,17 @@ bool WebServer::serveFile(String filename, httpsserver::HTTPResponse *res)
{ {
uint8_t buf[1024]; 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; return false;
} }
xSemaphoreTake(*instance().m_ledLockoutMutex, portMAX_DELAY);
File f = SPIFFS.open(filename.c_str(), "r"); File f = SPIFFS.open(filename.c_str(), "r");
xSemaphoreGive(*instance().m_ledLockoutMutex);
if(!f) { if(!f) {
return false; return false;
@ -36,7 +42,10 @@ bool WebServer::serveFile(String filename, httpsserver::HTTPResponse *res)
size_t nread = 1; size_t nread = 1;
while(nread > 0) { while(nread > 0) {
xSemaphoreTake(*instance().m_ledLockoutMutex, portMAX_DELAY);
nread = f.readBytes(reinterpret_cast<char*>(buf), 1024); nread = f.readBytes(reinterpret_cast<char*>(buf), 1024);
xSemaphoreGive(*instance().m_ledLockoutMutex);
if(nread <= 0) { if(nread <= 0) {
break; break;
} }
@ -44,7 +53,9 @@ bool WebServer::serveFile(String filename, httpsserver::HTTPResponse *res)
res->write(buf, nread); res->write(buf, nread);
} }
xSemaphoreTake(*instance().m_ledLockoutMutex, portMAX_DELAY);
f.close(); f.close();
xSemaphoreGive(*instance().m_ledLockoutMutex);
return true; return true;
} }

View file

@ -6,6 +6,9 @@
#include <WiFiMulti.h> #include <WiFiMulti.h>
#include <SPIFFS.h> #include <SPIFFS.h>
#include <FreeRTOS.h>
#include <freertos/semphr.h>
#include "WebServer.h" #include "WebServer.h"
#include "Fader.h" #include "Fader.h"
#include "UDPProto.h" #include "UDPProto.h"
@ -34,6 +37,11 @@ bool led_on = false;
size_t led_idx; size_t led_idx;
WiFiMulti wiFiMulti; 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); Fader ledFader(NUM_STRIPS, NUM_LEDS, 1, FLIP_STRIPS_MASK);
UDPProto udpProto(&ledFader); UDPProto udpProto(&ledFader);
UpdateServer *updateServer; UpdateServer *updateServer;
@ -207,9 +215,11 @@ static void ledTask( void * parameter )
const Fader::Color &c = colors[i]; const Fader::Color &c = colors[i];
STRANDS[0].pixels[i] = pixelFromRGBW(c.r, c.g, c.b, c.w); 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++; frame++;
@ -278,6 +288,9 @@ void setup()
Serial.begin(115200); Serial.begin(115200);
delay(10); delay(10);
// initalize the semaphores before anything else
ledLockoutMutex = xSemaphoreCreateMutex();
if(!initLEDs()) { if(!initLEDs()) {
Serial.println("LED setup failed!"); Serial.println("LED setup failed!");
while(true) { while(true) {
@ -326,11 +339,12 @@ void setup()
// start the web server // start the web server
WebServer::instance().setFader(&ledFader); WebServer::instance().setFader(&ledFader);
WebServer::instance().setLedLockoutMutex(&ledLockoutMutex);
WebServer::instance().setAnimationController(&animController); WebServer::instance().setAnimationController(&animController);
WebServer::instance().start(); WebServer::instance().start();
// start the update server // start the update server
updateServer = new UpdateServer(Config::instance().getCRPassword()); updateServer = new UpdateServer(Config::instance().getCRPassword(), &ledLockoutMutex);
updateServer->start(); updateServer->start();
} }