Arduino Nano 33 BLE crashes in loop after 1556909 loops

I've just started tinkering with arduinos and my experience level is sufficiently low when it comes to the hardware side in general.

I couldn't really identify a memory leak, but might be wrong about that. I also do not really know how to debug my code, apart from unit tests and print to serial debugging.

If I had a memory leak of say 1 bytes per led->rainbow call, that would mean I would have already reserved around 1.56 MB after the 1556909th call, which is way more than the nano 33 even has, so that shouldn't be the issue, right?

My code is as follows:

main.cpp:

#include <Arduino.h>
#include <USB/PluggableUSBSerial.h>
#include "LED/RgbLED.hpp"

std::unique_ptr<RgbLED> led1;
std::unique_ptr<RgbLED> led2;

int main(void)
{
    init();

    // we are never going to use getchar/scanf directly
    mbed::mbed_file_handle(STDIN_FILENO)->enable_input(false);

#if defined(SERIAL_CDC)
    PluggableUSBD().begin();
    _SerialUSB.begin(115200);
#endif

    setup();

    for (;;) {
        loop();
        if (arduino::serialEventRun) arduino::serialEventRun();
    }

    return 0;
}

void setup() {
    led1 = std::make_unique<RgbLED>(D9, D10, D11);
    //led2 = std::make_unique<RgbLED>(D3, D5, D6);

    led1->setColor("#FF00FF");
    //led2->setColor("#FF00FF");

    Serial.begin(8600);
    while (!Serial) delay(10);
}

unsigned long counter = 0;

void loop() {
    //delay(100);
    //led1->pulse(0.0001);
    counter++;
    Serial.println(counter);
    led1->rainbow(0.00005);
}

RgbLED.hpp:

#include <array>
#include "RainbowPhase.hpp"

class RgbLED {
public:
    RgbLED(unsigned redPin, unsigned greenPin, unsigned bluePin);

    void setColor(int redValue, int greenValue, int blueValue, double brightness);
    void setColor(int redValue, int greenValue, int blueValue);
    void setColor(std::string color, double brightness);
    void setColor(std::string color);
    void pulse(double step);
    void rainbow(double step, double brightness);
    void rainbow(double step);
    void normalizeValues();

    unsigned const COLOR_MAX_VALUE = 255;
    unsigned const BRIGHTNESS_MAX_VALUE = 1;
    unsigned const RAINBOW_MAX_VALUE = 1;
    unsigned const MIN_VALUE = 0;
private:
    void updateLED();
    void nextRainbowPhase();
    void printStatus() const;

    unsigned m_redPin;
    unsigned m_greenPin;
    unsigned m_bluePin;
    double m_redValue;
    double m_greenValue;
    double m_blueValue;
    double m_brightness;
    RAINBOW_PHASE m_rainbowPhase;
    double m_rainbowValue;
    bool m_rising;
};

RgbLED.cpp:

#include "RgbLED.hpp"
#include <Arduino.h>
#include <regex>
#include <utility>

RgbLED::RgbLED(unsigned int redPin, unsigned int greenPin, unsigned int bluePin) {
    m_redPin = redPin;
    m_greenPin = greenPin;
    m_bluePin = bluePin;
    m_redValue = MIN_VALUE;
    m_greenValue = MIN_VALUE;
    m_blueValue = MIN_VALUE;
    m_brightness = MIN_VALUE;
    m_rising = true;
    m_rainbowPhase = NONE;
    m_rainbowValue = MIN_VALUE;
}

void RgbLED::setColor(int redValue, int greenValue, int blueValue) {
    setColor(redValue, greenValue, blueValue, 1);
}

void RgbLED::setColor(int redValue, int greenValue, int blueValue, double brightness) {
    m_redValue = redValue;
    m_greenValue = greenValue;
    m_blueValue = blueValue;
    m_brightness = brightness;
    m_rainbowPhase = NONE;

    normalizeValues();
    updateLED();
}

void RgbLED::setColor(std::string color) {
    setColor(std::move(color), BRIGHTNESS_MAX_VALUE);
}

void RgbLED::setColor(std::string color, double brightness) {
    std::regex colorRegex("^#?[0-9A-F]{6}$");
    if (!std::regex_match(color, colorRegex)) {
        return;
    }

    if(color.at(0) == '#') {
        color.erase(0, 1);
    }

    setColor(std::stol(color.substr(0, 2), nullptr, 16),
             std::stol(color.substr(2, 2), nullptr, 16),
             std::stol(color.substr(4, 2), nullptr, 16),
             brightness);
}

void RgbLED::pulse(double step) {
    m_brightness += m_rising ? step : -step;

    normalizeValues();
    updateLED();
}

void RgbLED::rainbow(double step) {
    rainbow(step, BRIGHTNESS_MAX_VALUE);
}

void RgbLED::rainbow(double step, double brightness) {
    if (m_rainbowPhase == NONE) {
        m_redValue = MIN_VALUE;
        m_greenValue = MIN_VALUE;
        m_blueValue = MIN_VALUE;
        m_brightness = brightness;
        nextRainbowPhase();
    }

    double *value1, *value2;

    if (m_rainbowPhase == RED_GREEN) {
        value1 = &m_redValue;
        value2 = &m_greenValue;
    } else if (m_rainbowPhase == GREEN_BLUE) {
        value1 = &m_greenValue;
        value2 = &m_blueValue;
    } else  {
        value1 = &m_blueValue;
        value2 = &m_redValue;
    }

    double rainbowCalcBuffer = m_rainbowValue * 0.5 * M_PI;
    *value1 = COLOR_MAX_VALUE * cos(rainbowCalcBuffer);
    *value2 = COLOR_MAX_VALUE * sin(rainbowCalcBuffer);

    if (*value1 > *value2) {
        double ratio = *value1 / *value2;
        *value1 = COLOR_MAX_VALUE;
        *value2 = COLOR_MAX_VALUE / ratio;
    } else {
        double ratio = *value2 / *value1;
        *value1 = COLOR_MAX_VALUE / ratio;
        *value2 = COLOR_MAX_VALUE;
    }

    m_rainbowValue += step;

    if (m_rainbowValue > RAINBOW_MAX_VALUE) {
        nextRainbowPhase();
    }

    normalizeValues();
    updateLED();
}

void RgbLED::normalizeValues() {
    auto values = { &m_redValue, &m_greenValue, &m_blueValue };

    for (auto const& value : values) {
        if (*value < MIN_VALUE) {
            *value = MIN_VALUE;
        } else if (*value > COLOR_MAX_VALUE) {
            *value = COLOR_MAX_VALUE;
        }
    }

    if (m_brightness < MIN_VALUE) {
        m_brightness = MIN_VALUE;
        m_rising = true;
    } else if (m_brightness > BRIGHTNESS_MAX_VALUE) {
        m_brightness = BRIGHTNESS_MAX_VALUE;
        m_rising = false;
    }
}

void RgbLED::updateLED() {
    analogWrite(m_redPin, static_cast<int>(round(m_redValue * m_brightness)));
    analogWrite(m_greenPin, static_cast<int>(round(m_greenValue * m_brightness)));
    analogWrite(m_bluePin, static_cast<int>(round(m_blueValue * m_brightness)));
    //printStatus();
}

void RgbLED::nextRainbowPhase() {
    if (m_rainbowPhase == RED_GREEN) {
        m_rainbowPhase = GREEN_BLUE;
    } else if (m_rainbowPhase == GREEN_BLUE) {
        m_rainbowPhase = BLUE_RED;
    } else if (m_rainbowPhase == BLUE_RED) {
        m_rainbowPhase = RED_GREEN;
    } else {
        m_rainbowPhase = RED_GREEN;
    }

    m_rainbowValue = MIN_VALUE;
}

void RgbLED::printStatus() const {
    if (!Serial) {
        return;
    }

    auto string = "R: " + std::to_string(m_redValue) +
                  ", G: " + std::to_string(m_greenValue) +
                  ", B: " + std::to_string(m_blueValue) +
                  ", %: " + std::to_string(m_brightness);

    Serial.println(string.c_str());
}


Your post was MOVED to its current location as it is more suitable.

Could you also take a few moments to Learn How To Use The Forum.

Other general help and troubleshooting advice can be found here.
It will help you get the best out of the forum in the future.

Sorry about that. :slight_smile: Will try to do better in the future

With a delay(100) in the code, it crashed after ~50k loops. I'm guessing it might be the USB port power supply, that the PC might interrupt at some point for a short time? I just plugged it into a wall socket usb power supply and will check back with you in ~30 minutes with results :slight_smile:

Wasn't the power supply. Also got stuck at one color at a wall outlet :cry:

why did you code a main-function?
The specialty of the arduino-IDE is to not must have a main-function.

Because I'm using an IDE (CLion in this case) and it will be annoyed at having 2 methods that aren't being used/called and if they aren't named "main" ;).

Shouldn't be the issue here though, right?

You might have gone too fast.
Start small. With an Arduino Uno and the offline Arduino IDE 1.8.15.
If that works, then you can use the Arduino IDE 2.0 Beta.
Then you can move on with a faster board. I like the MKR boards with a SAMD21G processor.
Your Arduino Nano 33 BLE has the nRF52840 processor with is not used a lot. There might be problems in the libraries.

Only if you want to make us frown and pull up our noses and stick out our tongues, then you go wild and select a IDE that we don't use. You will be on your own.

I can see what you mean. I only have the 33 BLE here though. Will try the code with the Arduino IDE instead of using platformio and see if that fixes it, which would point to an issue somewhere in my toolchain.
Will update with results and if it still doesn't work, I'll post the adruino ide code here :slight_smile:

I'm a software dev and haven't touched micro controllers before. My current goal is to create my own busylight that is operable via battery and bluetooth, which is why I got myself 33 BLE :frowning:

Update: Wow can't answer anymore. Need to wait 9 hours.. so an edit it is.

Moved it.

Worked flawlessly when using the code with the Arduino IDE.

Will check with the platformio ide plugin for vscode next to see if it's an issue with the clion platformio plugin.

CLion is a full IDE like VisualStudio, Webstorm, etc. VSCode is an editor that can be made into a full IDE with a ton of plugins. /shrug

https://docs.platformio.org/en/latest//integration/ide/clion.html


Edit2:

Worked with PlatformIO extension for vscode. Also works with clion now, if I uncomment the main function. Guess I'm either not using the correct main function or it's something else.. will try to find out what the reason might be.

It's weird though that the number of upload pages is so drastically different between all the different IDEs. Arduino is using 26 pages, vscode/platformio is using 22 and clion 78. That's just weird. :frowning:

Platformio is okay, more Arduino users use that, but not me. Is the CLion just an extra shell around it ?
Start with the Arduino IDE 2.0 Beta.

That is a large page about BLE for the Nano 33 BLE: https://www.arduino.cc/en/Reference/ArduinoBLE.

There is a specific section on this forum for the Nano 33 BLE: https://forum.arduino.cc/c/hardware/nano-family/nano-33-ble/159.
If you select the :pencil2: to change the title, you can change the forum section.

Welcome to the Arduino world.

That is what the Arduino world is designed to look like. It is very limited when you are used to professional debuggers, but it allows beginners to start without being overwhelmed by settings dialogs and operating manuals.

I can see that in your code. :slight_smile: Even though you started with an Arduino with a nice 32-bit processor, you still have a very small chip with limited resources. You should try to avoid data types like double. Even float data types should be reserved for math algorithms and that if you have a hardware floating point unit available. The Arduino Nano 33 BLE has a single precision floating point unit (FPU).
Try using fixed point data types first and use floating point as last resort.

The Nano 33 BLE has SWD debug pads on the bottom, you can debug it using gdb or graphical front-ends through OpenOCD. It's easiest if you use PlatformIO. VSCode is great for this, you can view all registers, read any memory location, etc.