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:
parent
9ddb2063bb
commit
8e9124c884
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
18
src/main.cpp
18
src/main.cpp
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
xSemaphoreTake(ledLockoutMutex, portMAX_DELAY);
|
||||||
digitalLeds_drawPixels(strands, 1);
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue