I'm trying to use my ESP32 (WROOM-DA) to control WS2812 and SK6812 led strips with the Neopixel library. I want to be able to control the animations etc via a web server, similar to projects like WLED. I program the ESP with the Arduino IDE.
Right now I essentially create two tasks, one for the webserver, and one for the color calculation and led programming loop. I pin the webserver task to core 0, since if I understand correctly, wifi tasks only run on core 0, or at least need core 0? The led loop I pin to core 1, which, unless the GPIO stuff is also managed by core 0, should work.
The whole thing works fine with both tasks running concurrently, but it fails if I press buttons on the website, therefore sending data to the web server. The led tasks completely halts for a good second before resuming. I thought if i ran both tasks on two different cores, I could avoid that and both tasks run concurrently? Why would it even halt for that long, it's not like there is a lot of data being sent?
Here is my cleaned up code. Note that the web server doesn't actually influence the led loop yet, this is just for testing, but that also means that IMO no multithreading issues like race conditions or whatever should be the problem.
Setup and the two task loops are at the bottom of the code, those are the most relevant, you can ignore all the led helper functions before that.
- #include <math.h>
- #include <stdlib.h>
- #include <WiFi.h>
- #include <string.h>
- #include <Adafruit_NeoPixel.h>
- #include "driver/gpio.h"
- #ifdef __AVR__
- #include <avr/power.h>
- #endif
- #define NUMPIXELS_RIGHT 72
- #define NUMPIXELS_LEFT 73
- #define NUMPIXELS_TOP 95
- #define NUMPIXELS 240
- #define RIGHT_PIN 4
- #define TOP_PIN 26
- #define LEFT_PIN 33
- Adafruit_NeoPixel rightStrip = Adafruit_NeoPixel(NUMPIXELS_RIGHT, RIGHT_PIN, NEO_RGBW + NEO_KHZ800);
- Adafruit_NeoPixel topStrip = Adafruit_NeoPixel(NUMPIXELS_TOP, TOP_PIN, NEO_RGB + NEO_KHZ800);
- Adafruit_NeoPixel leftStrip = Adafruit_NeoPixel(NUMPIXELS_LEFT, LEFT_PIN, NEO_RGBW + NEO_KHZ800);
- int running;
- int test;
- const char* ssid = "ObfuscatedRouterName";
- const char* password = "ObfuscatedPassword";
- WiFiServer server(80);
- String header;
- unsigned long currentTime = millis();
- unsigned long previousTime = 0;
- const long timeoutTime = 2000;
- TaskHandle_t webserver ;
- TaskHandle_t ledcontroller ;
- std::uint32_t randomColor(){
- return leftStrip.Color(rand() % 255, rand() % 255, rand() % 255, 0);
- }
- std::uint32_t col1 = randomColor();
- std::uint32_t col2 = randomColor();
- std::uint32_t col3 = randomColor();
- int getRed(int x){
- int y = constrain((abs((x % 150) - 75) -25 ) / 50.0f * 255, 0, 255);
- return y;
- }
- int getGreen(int x){
- return constrain((50 - abs((x % 150) - 50)) / 50.0f * 255, 0, 255);
- }
- int getBlue(int x){
- return constrain((50 - abs((x % 150) - 100)) / 50.0f * 255, 0, 255);
- }
- void sendToRespectiveStripesW(int n, int r, int g, int b, int w){
- if(n < NUMPIXELS_RIGHT){
- rightStrip.setPixelColor(n, rightStrip.Color(g, r, b, w));
- } else if (n < NUMPIXELS_RIGHT + NUMPIXELS_TOP){
- topStrip.setPixelColor(n - NUMPIXELS_RIGHT, topStrip.Color(g, r, b,0));
- } else if (n < NUMPIXELS_RIGHT + NUMPIXELS_TOP + NUMPIXELS_LEFT){
- leftStrip.setPixelColor(n - NUMPIXELS_RIGHT - NUMPIXELS_TOP, leftStrip.Color(g, r, b, w));
- }
- }
- void setRangeSingleColor(int first, int second, int r, int g, int b, int w){
- for(int counter = first; counter <= second; counter++){
- sendToRespectiveStripesW(counter, r, g, b, w);
- }
- }
- void setSingleColor(int r, int g, int b, int w){
- for(int n = 0; n < NUMPIXELS; n++){
- sendToRespectiveStripesW(n, r, g, b, w);
- }
- }
- void setAllBlack(){
- for(int n = 0; n < NUMPIXELS; n++){
- sendToRespectiveStripesW(n, 0, 0, 0, 0);
- }
- }
- void gaussDistribution(int center, int variance, int r, int g, int b, int w){
- int cutoff = sqrt(log(255) * 2 * variance);
- for(int n = center - cutoff; n <= center + cutoff; n++){
- double coeff = exp(-1 * pow(n - center, 2) / (2 * variance));
- sendToRespectiveStripesW(n, (int) ( r * coeff), (int) (g * coeff), (int) (b * coeff), (int)(w * coeff));
- }
- }
- void startupAnimation(int time){
- if(time < 100){
- setAllBlack();
- setRangeSingleColor(time, time + 20, 255, 255, 255, 255);
- setRangeSingleColor(240 - 20 - time, 240 - time, 255, 255, 255, 255);
- } else if(time <= 240){
- setRangeSingleColor(100, 140, 255, 255, 255, 255);
- setRangeSingleColor(200 - time, 100, 255, 255, 255, 255);
- setRangeSingleColor(140, time + 40, 255, 255, 255, 255);
- }
- }
- void setup() {
- Serial.begin(115200);
- Serial.println("Starting");
- srand(234231);
- running = 0;
- test = 0;
- pinMode(RIGHT_PIN, OUTPUT);
- pinMode(TOP_PIN, OUTPUT);
- pinMode(LEFT_PIN, OUTPUT);
- pinMode(21, OUTPUT);
- rightStrip.begin();
- topStrip.begin();
- leftStrip.begin();
- setAllBlack();
- Serial.print("Connecting to ");
- Serial.println(ssid);
- WiFi.begin(ssid, password);
- while (WiFi.status() != WL_CONNECTED) {
- delay(500);
- Serial.print(".");
- }
- Serial.println("");
- Serial.println("WiFi connected.");
- Serial.println("IP address: ");
- Serial.println(WiFi.localIP());
- server.begin();
- Serial.println("Task 1 starting");
- xTaskCreatePinnedToCore (
- loop1, // Function to implement the task
- "loop1", // Name of the task
- 30000, // Stack size in bytes
- NULL, // Task input parameter
- 4, // Priority of the task
- &ledcontroller, // Task handle.
- 1 // Core where the task should run
- );
- Serial.println("Task 1 started");
- xTaskCreatePinnedToCore (
- loop2, // Function to implement the task
- "loop2", // Name of the task
- 10000, // Stack size in bytes
- NULL, // Task input parameter
- 2, // Priority of the task
- &webserver, // Task handle.
- 0 // Core where the task should run
- );
- Serial.println("Task 2 started");
- }
- void loop1(void* pvParameters) {
- for(;;){
- long time1 = millis();
- if(running % 240 == 0){
- col1 = randomColor();
- }
- if((running - 80) % 240 == 0){
- col2 = randomColor();
- }
- if((running - 160) % 240 == 0){
- col3 = randomColor();
- }
- setAllBlack();
- gaussDistribution(running % 240, 30, (col1 >> 0) & 0xff, (col1 >> 8) & 0xff, (col1 >> 16) & 0xff, 0);
- gaussDistribution((running + 80) % 240 , 30, (col2 >> 0) & 0xff, (col2 >> 8) & 0xff, (col2 >> 16) & 0xff, 0);
- gaussDistribution((running + 160) % 240, 30, (col3 >> 0) & 0xff, (col3 >> 8) & 0xff, (col3 >> 16) & 0xff, 0);
- running += 1;
- test += 1;
- if(running == NUMPIXELS){
- running = 0;
- }
- rightStrip.show();
- topStrip.show();
- leftStrip.show();
- delay(3);
- }
- }
- void loop2(void* pvParameters){
- for(;;){
- WiFiClient client = server.available();
- if (client) {
- currentTime = millis();
- previousTime = currentTime;
- Serial.println("New Client.");
- String currentLine = "";
- while (client.connected() && currentTime - previousTime <= timeoutTime) {
- currentTime = millis();
- if (client.available()) {
- char c = client.read();
- Serial.write(c);
- header += c;
- if (c == '\n') {
- if (currentLine.length() == 0) {
- client.println("HTTP/1.1 200 OK");
- client.println("Content-type:text/html");
- client.println("Connection: close");
- client.println();
- if (header.indexOf("GET /26/on") >= 0) {
- Serial.println("GPIO 26 on");
- } else if (header.indexOf("GET /26/off") >= 0) {
- Serial.println("GPIO 26 off");
- } else if (header.indexOf("GET /27/on") >= 0) {
- Serial.println("GPIO 27 on");
- } else if (header.indexOf("GET /27/off") >= 0) {
- Serial.println("GPIO 27 off");
- }
- client.println("<!DOCTYPE html><html>");
- client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
- client.println("<link rel=\"icon\" href=\"data:,\">");
- client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
- client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
- client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
- client.println(".button2 {background-color: #555555;}</style></head>");
- client.println("<body><h1>ESP32 Web Server</h1>");
- if (output26State=="off") {
- client.println("<p><a href=\"/26/on\"><button class=\"button\">ON</button></a></p>");
- } else {
- client.println("<p><a href=\"/26/off\"><button class=\"button button2\">OFF</button></a></p>");
- }
- if (output27State=="off") {
- client.println("<p><a href=\"/27/on\"><button class=\"button\">ON</button></a></p>");
- } else {
- client.println("<p><a href=\"/27/off\"><button class=\"button button2\">OFF</button></a></p>");
- }
- client.println("</body></html>");
- client.println();
- break;
- } else {
- currentLine = "";
- }
- } else if (c != '\r') { // if you got anything else but a carriage return character,
- currentLine += c; // add it to the end of the currentLine
- }
- }
- header = "";
- client.stop();
- Serial.println("Client disconnected.");
- Serial.println("");
- }
- delay(30);
- }
- }
- void loop(){ }