From 9d8865b024ac83abe7652292d7a4205caa0f449c Mon Sep 17 00:00:00 2001 From: midilab Date: Thu, 11 Apr 2024 11:10:47 -0300 Subject: [PATCH] remove freertos support(unstable so far) and make interrupted version the default only. update main example --- .../RP2040ClockBlink/RP2040ClockBlink.ino | 94 --------------- .../RP2040UsbUartMasterClock.ino} | 76 +++++------- .../RP2040UsbUartMasterClock/builtin_led.ino | 37 ++++++ src/platforms/rp2040.h | 110 ++++-------------- 4 files changed, 84 insertions(+), 233 deletions(-) delete mode 100644 examples/RP2040ClockBlink/RP2040ClockBlink.ino rename examples/{RP2040UsbMasterMidiClock/RP2040UsbMasterMidiClock.ino => RP2040UsbUartMasterClock/RP2040UsbUartMasterClock.ino} (52%) create mode 100644 examples/RP2040UsbUartMasterClock/builtin_led.ino diff --git a/examples/RP2040ClockBlink/RP2040ClockBlink.ino b/examples/RP2040ClockBlink/RP2040ClockBlink.ino deleted file mode 100644 index 63c0650..0000000 --- a/examples/RP2040ClockBlink/RP2040ClockBlink.ino +++ /dev/null @@ -1,94 +0,0 @@ -/* USB MIDI Sync Box - RP2040 example that just blinks LED - * - * - * This example code is in the public domain. - * - */ - -//#define LED_BUILTIN PIN_LED_B - -#include "Adafruit_TinyUSB.h" - -#include - -#define ATOMIC(X) { uint32_t __interrupt_mask = save_and_disable_interrupts(); X; restore_interrupts(__interrupt_mask); } - -uint8_t bpm_blink_timer = 1; -void handle_bpm_led(uint32_t tick) -{ - // BPM led indicator - if ( !(tick % (96)) || (tick == 1) ) { // first compass step will flash longer - bpm_blink_timer = 8; - digitalWrite(LED_BUILTIN, LOW); - } else if ( !(tick % (24)) ) { // each quarter led on - bpm_blink_timer = 1; - digitalWrite(LED_BUILTIN, LOW); - } else if ( !(tick % bpm_blink_timer) ) { // get led off - digitalWrite(LED_BUILTIN, HIGH); - } -} - - -// Internal clock handlers -void onSync24Callback(uint32_t tick) { - handle_bpm_led(tick); -} - -void onClockStart() { - //MIDI_USB.sendRealTime(midi::Start); -} - -void onClockStop() { - //MIDI_USB.sendRealTime(midi::Stop); -} - -void setup() { -/*#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040) - // Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040 - TinyUSB_Device_Init(0); -#endif*/ - - //MIDI_USB.begin(MIDI_CHANNEL_OMNI); - - // A led to count bpms - pinMode(LED_BUILTIN, OUTPUT); - /*digitalWrite(LED_BUILTIN, HIGH); - delay(500); - digitalWrite(LED_BUILTIN, LOW); - delay(500); - digitalWrite(LED_BUILTIN, HIGH); - delay(500); - digitalWrite(LED_BUILTIN, LOW); - delay(500);*/ - - - Serial.begin(115200); - /*while (!Serial) - delay(1);*/ - - // Setup our clock system - - // Inits the clock - uClock.init(); - // Set the callback function for the clock output to send MIDI Sync message. - uClock.setOnSync24(onSync24Callback); - // Set the callback function for MIDI Start and Stop messages. - uClock.setOnClockStart(onClockStart); - uClock.setOnClockStop(onClockStop); - // Set the clock BPM to 126 BPM - uClock.setTempo(60); - // Starts the clock, tick-tac-tick-tac.. - //Serial.println("about to uClock.start()..."); Serial.flush(); - uClock.start(); - //Serial.println("uClock.start()ed!"); Serial.flush(); -} - -uint32_t count = 0; - -// Do it whatever to interface with Clock.stop(), Clock.start(), Clock.setTempo() and integrate your environment... -void loop() { - //MIDI_USB.read(); - //count++; - //if (millis()%1000==0) - // ATOMIC(Serial.println("looped!")); -} diff --git a/examples/RP2040UsbMasterMidiClock/RP2040UsbMasterMidiClock.ino b/examples/RP2040UsbUartMasterClock/RP2040UsbUartMasterClock.ino similarity index 52% rename from examples/RP2040UsbMasterMidiClock/RP2040UsbMasterMidiClock.ino rename to examples/RP2040UsbUartMasterClock/RP2040UsbUartMasterClock.ino index 666bd38..e571da9 100644 --- a/examples/RP2040UsbMasterMidiClock/RP2040UsbMasterMidiClock.ino +++ b/examples/RP2040UsbUartMasterClock/RP2040UsbUartMasterClock.ino @@ -1,95 +1,74 @@ -/* USB MIDI Sync Box - example that also prints to serial and sends USB midi as well as blinking LED - * (usb part still needs testing to make sure it works!) +/* + * USB/Uart MIDI Sync Box * * This example code is in the public domain. * */ + #include #include -Adafruit_USBD_MIDI usb_midi; -MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MIDI_USB); -//MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI); - #include -#define ATOMIC(X) { uint32_t __interrupt_mask = save_and_disable_interrupts(); X; restore_interrupts(__interrupt_mask); } -//#define LED_BUILTIN PIN_LED_B -//#define WAIT_FOR_SERIAL -#define ENABLE_MULTICORE +// Instantiate the MIDI interfaces +Adafruit_USBD_MIDI usb_midi; +MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MIDI_USB); +MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI); -volatile uint32_t count = 0; +// Do your rpi 2040 has a ws2812 RGB LED? set the pin! +// otherwise keep it commented for normal LED_BUILTIN led blinking +#define WS2812_BUILTIN_LED 16 uint8_t bpm_blink_timer = 1; void handle_bpm_led(uint32_t tick) { // BPM led indicator - if ( !(tick % (96)) || (tick == 1) ) { // first compass step will flash longer + if ( !(tick % (96)) || (tick == 1) ) { // first of 4 quarter pulse will flash longer bpm_blink_timer = 8; - digitalWrite(LED_BUILTIN, LOW); + ledOn(); } else if ( !(tick % (24)) ) { // each quarter led on bpm_blink_timer = 1; - digitalWrite(LED_BUILTIN, LOW); + ledOn(); } else if ( !(tick % bpm_blink_timer) ) { // get led off - digitalWrite(LED_BUILTIN, HIGH); + ledOff(); } } - // Internal clock handlers void onSync24Callback(uint32_t tick) { // Send MIDI_CLOCK to external gears + MIDI.sendRealTime(midi::Clock); MIDI_USB.sendRealTime(midi::Clock); + // blink tempo handle_bpm_led(tick); - - Serial.printf("ticked with %u\n", tick); } void onClockStart() { + MIDI.sendRealTime(midi::Start); MIDI_USB.sendRealTime(midi::Start); } void onClockStop() { + MIDI.sendRealTime(midi::Stop); MIDI_USB.sendRealTime(midi::Stop); } -#ifdef ENABLE_MULTICORE - void setup1() { - } - - void loop1() { - if (count%1000==0) - ATOMIC(Serial.println("loop1()!"); Serial.flush()); - } -#endif - void setup() { #if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040) // Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040 TinyUSB_Device_Init(0); #endif + // Initialize USB midi stack MIDI_USB.begin(MIDI_CHANNEL_OMNI); + // Initialize UART midi stack + MIDI.begin(MIDI_CHANNEL_OMNI); - // A led to count bpms - pinMode(LED_BUILTIN, OUTPUT); - - Serial.begin(115200); - #ifdef WAIT_FOR_SERIAL - while (!Serial) - delay(1); - #endif - - // wait until device mounted - while( !TinyUSBDevice.mounted() ) { - Serial.println("waiting for usb.."); - Serial.flush(); - delay(1); - } + // Initialize builtin led for clock timer blinking + initBlinkLed(); // Setup our clock system // Inits the clock - Serial.println("about to uClock.init()..."); Serial.flush(); uClock.init(); // Set the callback function for the clock output to send MIDI Sync message. uClock.setOnSync24(onSync24Callback); @@ -97,17 +76,14 @@ void setup() { uClock.setOnClockStart(onClockStart); uClock.setOnClockStop(onClockStop); // Set the clock BPM to 126 BPM - uClock.setTempo(60); + uClock.setTempo(126); // Starts the clock, tick-tac-tick-tac.. - Serial.println("about to uClock.start()..."); Serial.flush(); uClock.start(); - ATOMIC(Serial.println("uClock.start()ed!"); Serial.flush();) } // Do it whatever to interface with Clock.stop(), Clock.start(), Clock.setTempo() and integrate your environment... void loop() { + // handle midi input? + MIDI.read(); MIDI_USB.read(); - count++; - if (millis()%1000==0) - ATOMIC(Serial.println("loop()!"); Serial.flush();); } diff --git a/examples/RP2040UsbUartMasterClock/builtin_led.ino b/examples/RP2040UsbUartMasterClock/builtin_led.ino new file mode 100644 index 0000000..7a1eedf --- /dev/null +++ b/examples/RP2040UsbUartMasterClock/builtin_led.ino @@ -0,0 +1,37 @@ +#if defined(WS2812_BUILTIN_LED) +#include +#define NUMPIXELS 1 +Adafruit_NeoPixel pixels(NUMPIXELS, WS2812_BUILTIN_LED, NEO_GRB + NEO_KHZ800); +#endif + +// check the pinage for BUILTIN LED of your model in case LED_BUILTIN wont ligth up +// this is valid only if you're not using rgb version ws2812 (WS2812_BUILTIN_LED) +//#define LED_BUILTIN PIN_LED_B + +void initBlinkLed() { +#if defined(WS2812_BUILTIN_LED) + // use adafruit neo pixel + pixels.begin(); +#else + // normal led pin + pinMode(LED_BUILTIN, OUTPUT); +#endif +} + +void ledOn() { +#if defined(WS2812_BUILTIN_LED) + pixels.setPixelColor(0, pixels.Color(0, 0, 20)); + pixels.show(); // turn the LED on (HIGH is the voltage level) +#else + digitalWrite(LED_BUILTIN, LOW); +#endif +} + +void ledOff() { +#if defined(WS2812_BUILTIN_LED) + pixels.setPixelColor(0, pixels.Color(0, 0, 0)); + pixels.show(); +#else + digitalWrite(LED_BUILTIN, HIGH); +#endif +} \ No newline at end of file diff --git a/src/platforms/rp2040.h b/src/platforms/rp2040.h index 7cf1069..eb918c2 100644 --- a/src/platforms/rp2040.h +++ b/src/platforms/rp2040.h @@ -1,98 +1,30 @@ #include #include "pico/sync.h" -// todo: make this a build flag, so user can choose which method to use? -#define MULTICORE +// RPi-specific timer +struct repeating_timer timer; -#ifdef MULTICORE - // use interrupt version -- works for 2 cores ie can run loop1() and loop() simultaneously as well as the clock callback? +#define ATOMIC(X) { uint32_t __interrupt_mask = save_and_disable_interrupts(); X; restore_interrupts(__interrupt_mask); } - // RPi-specific timer - struct repeating_timer timer; +// forward declaration of uClockHandler +void uClockHandler(); - #define ATOMIC(X) { uint32_t __interrupt_mask = save_and_disable_interrupts(); X; restore_interrupts(__interrupt_mask); } +// ISR handler -- called when tick happens +bool handlerISR(repeating_timer *timer) +{ + uClockHandler(); - // forward declaration of uClockHandler - void uClockHandler(); + return true; +} - // ISR handler -- called when tick happens - bool handlerISR(repeating_timer *timer) - { - uClockHandler(); +void initTimer(uint32_t init_clock) { + // set up RPi interrupt timer + // todo: actually should be -init_clock so that timer is set to start init_clock us after last tick, instead of init_clock us after finished processing last tick! + add_repeating_timer_us(init_clock, &handlerISR, NULL, &timer); +} - return true; - } - - void initTimer(uint32_t init_clock) { - // set up RPi interrupt timer - // todo: actually should be -init_clock so that timer is set to start init_clock us after last tick, instead of init_clock us after finished processing last tick! - add_repeating_timer_us(init_clock, &handlerISR, NULL, &timer); - } - - void setTimer(uint32_t us_interval) { - cancel_repeating_timer(&timer); - // todo: actually should be -us_interval so that timer is set to start init_clock us after last tick, instead of init_clock us after finished processing last tick! - add_repeating_timer_us(us_interval, &handlerISR, NULL, &timer); - } -#else - // use FreeRTOS scheduling/mutex version -- doesn't work (task starts but does not run) if using loop1() ie core 2 - - #include "FreeRTOS.h" - #include - #include - - // RPi-specific timer - struct repeating_timer timer; - - // FreeRTOS main clock task size in bytes - #define CLOCK_STACK_SIZE 5*1024 // adjust for your needs, a sequencer with heavy serial handling should be large in size - TaskHandle_t taskHandle; - // mutex to protect the shared resource - SemaphoreHandle_t _mutex; - // mutex control for task - #define ATOMIC(X) xSemaphoreTake(_mutex, portMAX_DELAY); X; xSemaphoreGive(_mutex); - - // forward declaration of uClockHandler - void uClockHandler(); - - // ISR handler -- called when tick happens - bool handlerISR(repeating_timer *timer) - { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - // Send a notification to task1 - vTaskNotifyGiveFromISR(taskHandle, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); - - return true; - } - - // task for user clock process - void clockTask(void *pvParameters) - { - while (1) { - // wait for a notification from ISR - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - uClockHandler(); - } - } - - void initTimer(uint32_t init_clock) - { - // initialize the mutex for shared resource access - _mutex = xSemaphoreCreateMutex(); - - // create the clockTask - xTaskCreate(clockTask, "clockTask", CLOCK_STACK_SIZE, NULL, 1, &taskHandle); - - // set up RPi interrupt timer - // todo: actually should be -init_clock so that timer is set to start init_clock us after last tick, instead of init_clock us after finished processing last tick! - add_repeating_timer_us(init_clock, &handlerISR, NULL, &timer); - } - - void setTimer(uint32_t us_interval) { - cancel_repeating_timer(&timer); - // todo: actually should be -us_interval so that timer is set to start init_clock us after last tick, instead of init_clock us after finished processing last tick! - add_repeating_timer_us(us_interval, &handlerISR, NULL, &timer); - } - -#endif \ No newline at end of file +void setTimer(uint32_t us_interval) { + cancel_repeating_timer(&timer); + // todo: actually should be -us_interval so that timer is set to start init_clock us after last tick, instead of init_clock us after finished processing last tick! + add_repeating_timer_us(us_interval, &handlerISR, NULL, &timer); +} \ No newline at end of file