1
\$\begingroup\$

I am creating a device to use a bluetooth app to control the effects in the ws2812fx library on a esp32 thing from Sparkfun. It works great using the arduino serial monitor to update. But whenever I add the BLE code the led signal becomes unstable and starts to make the leds flicker and change colors.

I get the same result with multithreading or not.

I have tried running this with the leds being powered from the chip and on their own power supply.

I have tried the following wiring configurations with a 16led ws2812 ring (I have also tried these with different led fixtures including a ws2811 string): 1. esp32.usb > led.5v, esp32.gnd > led.gnd, esp32.gpio16(I have tried on other gpio's) > led.din a. esp32.gpio > 470ohm resistor > led.din 2. I also tried this configuration with a 3.3v-5v logic level converter in between. Placing the resistor before and after the logic level converter.

I have tried this with 2 different Sparkfun esp32 thing's. I also tried this on an Adafruit esp32 Feather. All with the same results.

Here is the code: main.cpp

#include <Arduino.h>
#include <Streaming.h>
#include <comm.h>
#include <led.h>

TaskHandle_t taskComm, taskLED;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  delay(500);

  xTaskCreatePinnedToCore(
   TaskComm,                  /* pvTaskCode */
   "Communication",            /* pcName */
   2048,                   /* usStackDepth */
   NULL,                   /* pvParameters */
   1,                      /* uxPriority */
   &taskComm,                 /* pxCreatedTask */
   0);                     /* xCoreID */

  Serial.println("Start Comm process on Core 0");

  xTaskCreatePinnedToCore(
   TaskLED,                  /* pvTaskCode */
   "LED",            /* pcName */
   1024,                   /* usStackDepth */
   NULL,                   /* pvParameters */
   1,                      /* uxPriority */
   &taskLED,                 /* pxCreatedTask */
   1);                     /* xCoreID */

  Serial.println("Start LED process on Core 1");
}

void loop() {
  // put your main code here, to run repeatedly:
  if(cmd_complete) { //from comm.h
    ProcessCommand(); //from led.h
  }
}

comm.h

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

#define SERVICE_UUID        "71ae1439-4160-4532-b952-74fa9ccbd337"
#define CHARACTERISTIC_UUID "0fffbd21-d7ca-4869-88d3-53005b6192a7"

#define MAX_NUM_CHARS 16 // maximum number of characters read from the Serial Monitor

char cmd[MAX_NUM_CHARS];       // char[] to store incoming serial commands
boolean cmd_complete = false;  // whether the command string is complete

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string value = pCharacteristic->getValue();

      int index;
      if (value.length() > 0) {
        for (int i = 0; i < value.length(); i++) {
          cmd[i] = value[i];
          index = i + 1;
        }
        cmd[index] = '\0'; // terminate the string
        Serial << "BLE received '" << cmd << "'" << endl;
        cmd_complete = true;
      }
    }
};

void recvChar(void) {
    static byte index = 0;
    while (Serial.available() > 0 && cmd_complete == false) {
        char rc = Serial.read();
        if (rc != '\n') {
            if(index < MAX_NUM_CHARS) cmd[index++] = rc;
        } else {
            cmd[index] = '\0'; // terminate the string
            index = 0;
            Serial << "received '" << cmd << "'" << endl;
            cmd_complete = true;
        }
    }
}

void TaskComm( void * parameter ) {
    //Setup
    //Bluetooth Setup
    char chipName[20];
    uint64_t chipid=ESP.getEfuseMac();
    snprintf(chipName, 20, "board-%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
    Serial << "Chip Name: " << chipName << endl;
    BLEDevice::init(chipName);

    BLEServer *pServer = BLEDevice::createServer();

    BLEService *pService = pServer->createService(SERVICE_UUID);

    BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                          CHARACTERISTIC_UUID,
                                          BLECharacteristic::PROPERTY_READ |
                                          BLECharacteristic::PROPERTY_WRITE
                                        );

    pCharacteristic->setCallbacks(new MyCallbacks());

    pCharacteristic->setValue("Isomia LED Controller");
    pService->start();

    BLEAdvertising *pAdvertising = pServer->getAdvertising();
    pAdvertising->start();

    for (;;) {
        //Loop
        recvChar(); // read serial comm

        delay(10);
    }
}

led.h

#include <WS2812FX.h>

#define LED_COUNT 16
#define LED_PIN 16

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
WS2812FX ws2812fx = WS2812FX(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

void ProcessCommand() {
    if (strncmp(cmd,"b ",2) == 0) {
      uint8_t b = (uint8_t)atoi(cmd + 2);
      ws2812fx.setBrightness(b);
      Serial << "Set brightness to: " << ws2812fx.getBrightness() << endl;
    }
    if (strncmp(cmd,"s ",2) == 0) {
      uint16_t s = (uint16_t)atoi(cmd + 2);
      ws2812fx.setSpeed(s); 
      Serial << "Set speed to: " << ws2812fx.getSpeed() << endl;
    }
    if (strncmp(cmd,"m ",2) == 0) {
      uint8_t m = (uint8_t)atoi(cmd + 2);
      ws2812fx.setMode(m);
      Serial << "Set mode to: " << ws2812fx.getMode() << " - " << ws2812fx.getModeName(ws2812fx.getMode()) << endl;
    }
    if (strncmp(cmd,"c ",2) == 0) {
      uint32_t c = (uint32_t)strtoul(cmd + 2, NULL, 16);
      ws2812fx.setColor(c);
      Serial << "Set color to: 0x" << String(ws2812fx.getColor(), HEX) << endl;
    }

    cmd[0] = '\0';         // reset the commandstring
    cmd_complete = false;  // reset command complete
}

void TaskLED( void * parameter ) {
    //Setup
    ws2812fx.init();
    ws2812fx.setBrightness(1);
    ws2812fx.setSpeed(1000);
    ws2812fx.setColor(0x007BFF);
    ws2812fx.setMode(1);
    ws2812fx.start();

    for (;;) {
        //Loop
        ws2812fx.service();
    }
}
```
\$\endgroup\$
1
  • \$\begingroup\$ I figure it out by using RMT on the esp32. I took out the multithreading and it worked great. I used the example form the ws2812fx library called ws2812fx_esp32 which uses RMT \$\endgroup\$ Apr 5, 2020 at 23:19

1 Answer 1

1
\$\begingroup\$

Using RMT on the esp32 chip solved my problem. I even tested on a board without a 470ohm resistor or logic level converter. I took out the multithreading as well. Here is the source code. You need to add the ESP32_RMT_Driver.h from the ws2812fx_esp32 example

#include <Arduino.h>
#include <WS2812FX.h>
#include <Streaming.h>
#include "ESP32_RMT_Driver.h"
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

#define SERVICE_UUID        "71ae1439-4160-4532-b952-74fa9ccbd337"
#define CHARACTERISTIC_UUID "0fffbd21-d7ca-4869-88d3-53005b6192a7"

#define LED_COUNT 16
#define LED_PIN 16

#define MAX_NUM_CHARS 16 // maximum number of characters read from the Serial Monitor

char cmd[MAX_NUM_CHARS];       // char[] to store incoming serial commands
boolean cmd_complete = false;  // whether the command string is complete

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
WS2812FX ws2812fx = WS2812FX(LED_COUNT, LED_PIN, NEO_GRB  + NEO_KHZ800);

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string value = pCharacteristic->getValue();

      int index;
      if (value.length() > 0) {
        for (int i = 0; i < value.length(); i++) {
          cmd[i] = value[i];
          index = i + 1;
        }
        cmd[index] = '\0'; // terminate the string
        Serial << "BLE received '" << cmd << "'" << endl;
        cmd_complete = true;
      }
    }
};

// Custom show functions which will use the RMT hardware to drive the LEDs.
void myCustomShow1(void) {
  uint8_t *pixels = ws2812fx.getPixels();
  // numBytes is one more then the size of the ws2812fx's *pixels array.
  // the extra byte is used by the driver to insert the LED reset pulse at the end.
  uint16_t numBytes = ws2812fx.getNumBytes() + 1;
  rmt_write_sample(RMT_CHANNEL_0, pixels, numBytes, false); // channel 0
}

void recvChar(void) {
    static byte index = 0;
    while (Serial.available() > 0 && cmd_complete == false) {
        char rc = Serial.read();
        if (rc != '\n') {
            if(index < MAX_NUM_CHARS) cmd[index++] = rc;
        } else {
            cmd[index] = '\0'; // terminate the string
            index = 0;
            Serial << "received '" << cmd << "'" << endl;
            cmd_complete = true;
        }
    }
}

void ProcessCommand() {
    if (strncmp(cmd,"b ",2) == 0) {
      uint8_t b = (uint8_t)atoi(cmd + 2);
      ws2812fx.setBrightness(b);
      Serial << "Set brightness to: " << ws2812fx.getBrightness() << endl;
    }
    if (strncmp(cmd,"s ",2) == 0) {
      uint16_t s = (uint16_t)atoi(cmd + 2);
      ws2812fx.setSpeed(s); 
      Serial << "Set speed to: " << ws2812fx.getSpeed() << endl;
    }
    if (strncmp(cmd,"m ",2) == 0) {
      uint8_t m = (uint8_t)atoi(cmd + 2);
      ws2812fx.setMode(m);
      Serial << "Set mode to: " << ws2812fx.getMode() << " - " << ws2812fx.getModeName(ws2812fx.getMode()) << endl;
    }
    if (strncmp(cmd,"c ",2) == 0) {
      uint32_t c = (uint32_t)strtoul(cmd + 2, NULL, 16);
      ws2812fx.setColor(c);
      Serial << "Set color to: 0x" << String(ws2812fx.getColor(), HEX) << endl;
    }

    cmd[0] = '\0';         // reset the commandstring
    cmd_complete = false;  // reset command complete
}

void setup() {
  Serial.begin(115200);
  delay(500);

  //Bluetooth Setup
  char chipName[20];
  uint64_t chipid=ESP.getEfuseMac();
  snprintf(chipName, 20, "chip-%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
  Serial << "Chip Name: " << chipName << endl;
  BLEDevice::init(chipName);
  BLEServer *pServer = BLEDevice::createServer();
  BLEService *pService = pServer->createService(SERVICE_UUID);
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                        CHARACTERISTIC_UUID,
                                        BLECharacteristic::PROPERTY_READ |
                                        BLECharacteristic::PROPERTY_WRITE
                                      );
  pCharacteristic->setCallbacks(new MyCallbacks());
  pCharacteristic->setValue("Isomia LED Controller");
  pService->start();
  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();

  //LED Setup
  ws2812fx.init();
  ws2812fx.setBrightness(10);
  rmt_tx_int(RMT_CHANNEL_0, ws2812fx.getPin()); // assign ws2812fx1 to RMT channel 0
  ws2812fx.setCustomShow(myCustomShow1); // set the custom show function to forgo the NeoPixel
  // parameters: seg_index, start, stop, mode, color, speed, options
  ws2812fx.setSegment(0, 0, LED_COUNT-1, FX_MODE_COMET, GREEN, 1000, NO_OPTIONS);
  ws2812fx.start(); // start'em up
}

void loop() {
  ws2812fx.service(); // service each ws2812fx instance

  recvChar(); // read serial comm
  if (cmd_complete) {
    ProcessCommand();
  }
}
```
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.