Everything was going great then I became more ambitious and introduced Neopixel patterns (wipe, fade, etc.) that could be controlled via BLE UART commands. That's when things started falling apart.
The code was simple enough: listen to a BLE UART, upon receiving a packet start displaying a Neopixel pattern, and keep the pattern animating until another UART command said otherwise. On the client side, I just used the UART activity of the Adafruit Bluefruit LE Connect Android app.
The UART logic and the patterns worked beautifully, but I often found that the NRF52 would lock up the instant the Android client disconnected (by closing the UART activity).
It didn't always crash when disconnecting or sometimes took multiple connect/reconnect cycles before hanging, but it was a show stopper nonetheless. I found that if the NRF52 made it through a few disconnect cycles without crashing it would likely survive until the device was turned off/on again and the disconnect testing cycle restarted.
My first thought was, since the original design called for a 24 Neopixel ring, perhaps I was drawing too much current or had a bad USB connection. I tried every combination of different USB cables, USB ports both on my computer as well as via 2A wall chargers. I even checked current consumption via a hacked up USB extension cable and a multimeter, though I found I could crash even when drawing only 20mA.
I also tried using FreeRTOS Scheduler.startLoop() and Timer as alternatives to the old style loop() + millis() timeouts in case there was some peculiarity in how loops should work on this device. There was no discernible difference in behavior either way.
I'm not sure what else to try at this point so I have put together a minimal sketch to demonstrate problem.
Code: Select all
#include <Adafruit_NeoPixel.h>
#include <bluefruit.h>
#define PIN 30
#define PIXELS 1
long timeout = 0;
long interval = 1;
bool isLit = false;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXELS, PIN, NEO_GRBW + NEO_KHZ800);
BLEUart bleuart;
void setup() {
strip.begin();
strip.show();
Bluefruit.begin();
Bluefruit.setTxPower(4);
Bluefruit.setName("Bluefruit52");
Bluefruit.autoConnLed(false);
bleuart.begin();
startAdv();
}
void startAdv(void) {
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
Bluefruit.Advertising.addService(bleuart);
Bluefruit.ScanResponse.addName();
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244);
Bluefruit.Advertising.setFastTimeout(30);
Bluefruit.Advertising.start(0);
}
void loop() {
if (millis() >= timeout) {
for (uint8_t i = 0; i < strip.numPixels(); i++) {
if (isLit) {
strip.setPixelColor(i, strip.Color(1, 0, 0));
} else {
strip.setPixelColor(i, strip.Color(0, 0, 1));
}
}
strip.show();
isLit = !isLit;
timeout = millis() + interval;
}
}
While the sketch runs, the Neopixel should appear purple. If you connect to the BLE UART and disconnect (no need to send any data via the UART activity) eventually you should notice A) the Neopixel will remain frozen as either red or blue, and B) the BLE device will no longer be discoverable or accept connections. At this point, the NRF52 must be power cycled to resume normal operation.
In my own testing of the above sketch I have noted that the tighter the Neopixel update timing, the more likely a crash will happen upon UART disconnect. One millisecond may seem needlessly aggressive, but I have encountered crashes at up to 100ms timing, albeit with much less frequency.
Is there anything obvious that I'm doing wrong either in the code or the wiring? I see that NRF52 support was added to the Adafruit Neopixel library some time last year, but I can't help but wonder if I should have just stuck with the less powerful, but more mature Adafruit Feather 32u4 Bluefruit LE.
Thanks