From 99d18452016981fa8c8993ca6dca468705782325 Mon Sep 17 00:00:00 2001 From: doctea Date: Thu, 1 Feb 2024 23:13:40 +0000 Subject: [PATCH] use interrupts instead of FreeRTOS tasks -- seems to work with both cores? --- .../RP2040ClockBlink/RP2040ClockBlink.ino | 8 +- .../RP2040UsbMasterMidiClock.ino | 34 ++++- src/platforms/rp2040.h | 137 ++++++++++++------ 3 files changed, 120 insertions(+), 59 deletions(-) diff --git a/examples/RP2040ClockBlink/RP2040ClockBlink.ino b/examples/RP2040ClockBlink/RP2040ClockBlink.ino index 2a6dc0c..63c0650 100644 --- a/examples/RP2040ClockBlink/RP2040ClockBlink.ino +++ b/examples/RP2040ClockBlink/RP2040ClockBlink.ino @@ -11,6 +11,8 @@ #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) { @@ -50,14 +52,14 @@ void setup() { // A led to count bpms pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, HIGH); + /*digitalWrite(LED_BUILTIN, HIGH); delay(500); digitalWrite(LED_BUILTIN, LOW); delay(500); digitalWrite(LED_BUILTIN, HIGH); delay(500); digitalWrite(LED_BUILTIN, LOW); - delay(500); + delay(500);*/ Serial.begin(115200); @@ -88,5 +90,5 @@ void loop() { //MIDI_USB.read(); //count++; //if (millis()%1000==0) - // Serial.println("looped!"); + // ATOMIC(Serial.println("looped!")); } diff --git a/examples/RP2040UsbMasterMidiClock/RP2040UsbMasterMidiClock.ino b/examples/RP2040UsbMasterMidiClock/RP2040UsbMasterMidiClock.ino index cf1092a..f3445c0 100644 --- a/examples/RP2040UsbMasterMidiClock/RP2040UsbMasterMidiClock.ino +++ b/examples/RP2040UsbMasterMidiClock/RP2040UsbMasterMidiClock.ino @@ -9,11 +9,16 @@ 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 -//MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI); -#include +volatile uint32_t count = 0; uint8_t bpm_blink_timer = 1; void handle_bpm_led(uint32_t tick) @@ -36,6 +41,8 @@ void onSync24Callback(uint32_t tick) { // Send MIDI_CLOCK to external gears MIDI_USB.sendRealTime(midi::Clock); handle_bpm_led(tick); + + Serial.printf("ticked with %u\n", tick); } void onClockStart() { @@ -46,6 +53,16 @@ void onClockStop() { 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 @@ -58,8 +75,10 @@ void setup() { pinMode(LED_BUILTIN, OUTPUT); Serial.begin(115200); - while (!Serial) - delay(1); + #ifdef WAIT_FOR_SERIAL + while (!Serial) + delay(1); + #endif // wait until device mounted /*while( !TinyUSBDevice.mounted() ) { @@ -78,19 +97,18 @@ void setup() { uClock.setOnClockStart(onClockStart); uClock.setOnClockStop(onClockStop); // Set the clock BPM to 126 BPM - uClock.setTempo(126); + 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(); + ATOMIC(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!!!"); + ATOMIC(Serial.println("loop()!"); Serial.flush();); } diff --git a/src/platforms/rp2040.h b/src/platforms/rp2040.h index 1c5a37d..af94e12 100644 --- a/src/platforms/rp2040.h +++ b/src/platforms/rp2040.h @@ -1,57 +1,98 @@ #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); +#define MULTICORE + +#ifdef MULTICORE + // use interrupt version -- works for 2 cores ie can run loop1() and loop() simultaneously as well as the clock callback? + + // RPi-specific timer + struct repeating_timer timer; + + #define ATOMIC(X) { uint32_t __interrupt_mask = save_and_disable_interrupts(); X; restore_interrupts(__interrupt_mask); } + + // forward declaration of uClockHandler + void uClockHandler(); + + // ISR handler -- called when tick happens + bool handlerISR(repeating_timer *timer) + { uClockHandler(); + + 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 -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(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; } -} -void initTimer(uint32_t init_clock) -{ - // initialize the mutex for shared resource access - _mutex = xSemaphoreCreateMutex(); + // 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); + // 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); -} + // 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 -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(us_interval, &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 +#endif \ No newline at end of file