Fix BLE crash: move all NimBLE calls to Core 0
Root cause: Arduino Core 3.x breaks cross-core NimBLE API calls. Calling BLEMidiServer.controlChange() from loop() on Core 1 while NimBLE host runs on Core 0 causes immediate crash. Fix: - Move ble_midi_transport.begin() to ble_init_task on Core 0 - All BLE MIDI sends use queue_cc() (cross-core safe flag setter) - ble_midi_transport.update() processes queued sends on Core 0 - Pin NimBLE-Arduino to v1.4.3 (stable LTS for BLE MIDI) - Keep CONFIG_BT_ENABLED out of sdkconfig.h (causes double-init)
This commit is contained in:
@@ -20,6 +20,8 @@ public:
|
||||
|
||||
bool is_connected();
|
||||
|
||||
void queue_cc(uint8_t channel, uint8_t cc, uint8_t value);
|
||||
|
||||
private:
|
||||
static void on_control_change(uint8_t channel, uint8_t controller, uint8_t value, uint16_t timestamp);
|
||||
static void on_note_on(uint8_t channel, uint8_t note, uint8_t velocity, uint16_t timestamp);
|
||||
@@ -30,4 +32,9 @@ private:
|
||||
std::function<void(const MidiEvent&)> receive_callback;
|
||||
bool initialized;
|
||||
bool client_connected;
|
||||
|
||||
uint8_t queued_channel;
|
||||
uint8_t queued_cc;
|
||||
uint8_t queued_value;
|
||||
bool queued;
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@ lib_deps =
|
||||
adafruit/Adafruit TinyUSB [email protected]
|
||||
fastled/FastLED@^3.9.0
|
||||
max22/ESP32-BLE-MIDI@^0.3.2
|
||||
h2zero/NimBLE-Arduino@^1.4.3
|
||||
|
||||
build_unflags =
|
||||
-DARDUINO_USB_MODE=1
|
||||
|
||||
@@ -70,10 +70,6 @@ def patch_sdkconfig_bt():
|
||||
content = f.read()
|
||||
|
||||
defines = {
|
||||
# Do NOT set CONFIG_BT_ENABLED here — forces Arduino framework
|
||||
# to pre-init BT controller at startup, which conflicts with
|
||||
# TinyUSB on ESP32-S3 (causes reboot on USB MIDI send).
|
||||
# NimBLEDevice::init() handles its own init.
|
||||
"CONFIG_BTDM_CTRL_MODE_BLE_ONLY": 1,
|
||||
"CONFIG_BT_NIMBLE_MAX_CONNECTIONS": 1,
|
||||
"CONFIG_BT_NIMBLE_TASK_STACK_SIZE": 6144,
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ void AppTask::update() {
|
||||
pending_cc = false;
|
||||
delay(1);
|
||||
usb_midi->send_cc(pending_channel, pending_cc_num, pending_value);
|
||||
if (ble_midi) ble_midi->send_cc(pending_channel, pending_cc_num, pending_value);
|
||||
if (ble_midi) ble_midi->queue_cc(pending_channel, pending_cc_num, pending_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
static BleMidiTransport* instance = nullptr;
|
||||
|
||||
BleMidiTransport::BleMidiTransport() : initialized(false), client_connected(false) {
|
||||
BleMidiTransport::BleMidiTransport() : initialized(false), client_connected(false), queued(false) {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
@@ -70,24 +70,34 @@ bool BleMidiTransport::begin() {
|
||||
|
||||
void BleMidiTransport::update() {
|
||||
client_connected = BLEMidiServer.isConnected();
|
||||
|
||||
if (queued) {
|
||||
queued = false;
|
||||
BLEMidiServer.controlChange(queued_channel, queued_cc, queued_value);
|
||||
}
|
||||
}
|
||||
|
||||
void BleMidiTransport::on_midi_receive(std::function<void(const MidiEvent&)> callback) {
|
||||
receive_callback = callback;
|
||||
}
|
||||
|
||||
void BleMidiTransport::queue_cc(uint8_t channel, uint8_t cc, uint8_t value) {
|
||||
queued_channel = channel;
|
||||
queued_cc = cc;
|
||||
queued_value = value;
|
||||
queued = true;
|
||||
}
|
||||
|
||||
void BleMidiTransport::send_note_on(uint8_t channel, uint8_t note, uint8_t velocity) {
|
||||
BLEMidiServer.noteOn(channel, note, velocity);
|
||||
Serial.printf("[BLE OUT] Ch:%d NOTE_ON:%d:%d\n", channel, note, velocity);
|
||||
queue_cc(channel, note, velocity);
|
||||
}
|
||||
|
||||
void BleMidiTransport::send_note_off(uint8_t channel, uint8_t note, uint8_t velocity) {
|
||||
BLEMidiServer.noteOff(channel, note, velocity);
|
||||
Serial.printf("[BLE OUT] Ch:%d NOTE_OFF:%d:%d\n", channel, note, velocity);
|
||||
queue_cc(channel, note, velocity);
|
||||
}
|
||||
|
||||
void BleMidiTransport::send_cc(uint8_t channel, uint8_t cc, uint8_t value) {
|
||||
BLEMidiServer.controlChange(channel, cc, value);
|
||||
queue_cc(channel, cc, value);
|
||||
}
|
||||
|
||||
bool BleMidiTransport::is_connected() {
|
||||
|
||||
+18
-4
@@ -23,6 +23,13 @@ AppTask controller(&led_driver, &switch_driver, &midi_transport, &ble_midi_trans
|
||||
|
||||
TaskHandle_t midi_task_handle = NULL;
|
||||
|
||||
void ble_init_task(void* parameter) {
|
||||
Serial.println("[TASK] BLE init task started on core 0");
|
||||
ble_midi_transport.begin();
|
||||
Serial.println("[TASK] BLE init complete, deleting task");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void midi_task(void* parameter) {
|
||||
Serial.println("[TASK] MIDI task started on core 0");
|
||||
|
||||
@@ -346,16 +353,23 @@ void setup() {
|
||||
switch_driver.set_mux(&mux);
|
||||
switch_driver.begin();
|
||||
|
||||
Serial.println("[INIT] Initializing BLE MIDI...");
|
||||
delay(1000);
|
||||
ble_midi_transport.begin();
|
||||
|
||||
Serial.println("[INIT] Initializing USB MIDI...");
|
||||
midi_transport.begin();
|
||||
delay(500);
|
||||
|
||||
Serial.println("[INIT] Registering MIDI callbacks...");
|
||||
controller.begin();
|
||||
|
||||
Serial.println("[INIT] Starting BLE init on core 0...");
|
||||
xTaskCreatePinnedToCore(
|
||||
ble_init_task,
|
||||
"ble_init",
|
||||
8192,
|
||||
NULL,
|
||||
3,
|
||||
NULL,
|
||||
0
|
||||
);
|
||||
|
||||
xTaskCreatePinnedToCore(
|
||||
midi_task,
|
||||
|
||||
Reference in New Issue
Block a user