From 53419fa89cb311dc13ef0e5d7717e91923cde5a4 Mon Sep 17 00:00:00 2001 From: doctea Date: Wed, 31 Jan 2024 20:59:16 +0000 Subject: [PATCH] initial working proof-of-concept of rp2040 support --- .../RP2040ClockBlink/RP2040ClockBlink.ino | 92 ++++++++++++++++++ .../RP2040UsbMasterMidiClock.ino | 96 +++++++++++++++++++ src/platforms/esp32.h | 1 + src/platforms/rp2040.h | 57 +++++++++++ src/uClock.cpp | 6 ++ 5 files changed, 252 insertions(+) create mode 100644 examples/RP2040ClockBlink/RP2040ClockBlink.ino create mode 100644 examples/RP2040UsbMasterMidiClock/RP2040UsbMasterMidiClock.ino create mode 100644 src/platforms/rp2040.h diff --git a/examples/RP2040ClockBlink/RP2040ClockBlink.ino b/examples/RP2040ClockBlink/RP2040ClockBlink.ino new file mode 100644 index 0000000..2a6dc0c --- /dev/null +++ b/examples/RP2040ClockBlink/RP2040ClockBlink.ino @@ -0,0 +1,92 @@ +/* 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 + +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) + // Serial.println("looped!"); +} diff --git a/examples/RP2040UsbMasterMidiClock/RP2040UsbMasterMidiClock.ino b/examples/RP2040UsbMasterMidiClock/RP2040UsbMasterMidiClock.ino new file mode 100644 index 0000000..cf1092a --- /dev/null +++ b/examples/RP2040UsbMasterMidiClock/RP2040UsbMasterMidiClock.ino @@ -0,0 +1,96 @@ +/* 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!) + * + * 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); + +//#define LED_BUILTIN PIN_LED_B + +//MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI); +#include + +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) { + // Send MIDI_CLOCK to external gears + MIDI_USB.sendRealTime(midi::Clock); + 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); + + Serial.begin(115200); + while (!Serial) + delay(1); + + // wait until device mounted + /*while( !TinyUSBDevice.mounted() ) { + Serial.println("waiting for usb.."); + Serial.flush(); + delay(1); + }*/ + + // 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); + // 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(126); + // 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) + Serial.println("looped!!!"); +} diff --git a/src/platforms/esp32.h b/src/platforms/esp32.h index 1344923..22e80b0 100644 --- a/src/platforms/esp32.h +++ b/src/platforms/esp32.h @@ -2,6 +2,7 @@ #include #include +// esp32-specific timer #define TIMER_ID 0 hw_timer_t * _uclockTimer = NULL; // mutex control for ISR diff --git a/src/platforms/rp2040.h b/src/platforms/rp2040.h new file mode 100644 index 0000000..1c5a37d --- /dev/null +++ b/src/platforms/rp2040.h @@ -0,0 +1,57 @@ +#include +#include "FreeRTOS.h" +#include +#include +#include "pico/sync.h" + +// 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 + add_repeating_timer_us(init_clock, &handlerISR, NULL, &timer); +} + +void setTimer(uint32_t us_interval) { + cancel_repeating_timer(&timer); + add_repeating_timer_us(us_interval, &handlerISR, NULL, &timer); +} \ No newline at end of file diff --git a/src/uClock.cpp b/src/uClock.cpp index 3ad2473..18c6883 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -57,6 +57,12 @@ #if defined(ARDUINO_ARCH_STM32) #include "platforms/stm32.h" #endif +// +// RP2040 (Raspberry Pico) family +// +#if defined(ARDUINO_ARCH_RP2040) + #include "platforms/rp2040.h" +#endif // // Platform specific timer setup/control