diff --git a/examples/ESP32UartMasterMidiClock/ESP32UartMasterMidiClock.ino b/examples/ESP32UartMasterMidiClock/ESP32UartMasterMidiClock.ino index f83952b..03831ee 100644 --- a/examples/ESP32UartMasterMidiClock/ESP32UartMasterMidiClock.ino +++ b/examples/ESP32UartMasterMidiClock/ESP32UartMasterMidiClock.ino @@ -18,8 +18,6 @@ // the blue led #define LED_BUILTIN 2 -volatile bool _midi_clk_income = false; - uint8_t bpm_blink_timer = 1; void handle_bpm_led(uint32_t tick) { @@ -38,8 +36,7 @@ void handle_bpm_led(uint32_t tick) // Internal clock handlers void ClockOut96PPQN(uint32_t tick) { // Send MIDI_CLOCK to external gears - //Serial.write(MIDI_CLOCK); - _midi_clk_income = true; + Serial.write(MIDI_CLOCK); handle_bpm_led(tick); } @@ -74,11 +71,5 @@ void setup() { // Do it whatever to interface with Clock.stop(), Clock.start(), Clock.setTempo() and integrate your environment... void loop() { - // watch for income signal from uClock to fire the clock over midi - if (_midi_clk_income) { - Serial.write(MIDI_CLOCK); - noInterrupts(); - _midi_clk_income = false; - interrupts(); - } -} + +} \ No newline at end of file diff --git a/library.json b/library.json index 46f5e4e..5e954bb 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "uClock", - "version": "1.4.1", + "version": "1.4.2", "description": "A Library to implement BPM clock tick calls using hardware interruption. Supported and tested on AVR boards(ATmega168/328, ATmega16u4/32u4 and ATmega2560) and ARM boards(Teensy, Seedstudio XIAO M0. ESP32 and STM32)", "keywords": "bpm, clock, timing, tick, music, generator", "repository": diff --git a/library.properties b/library.properties index 8e6d4db..9d0ad90 100755 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=uClock -version=1.4.1 +version=1.4.2 author=Romulo Silva maintainer=Romulo Silva sentence=BPM clock generator for Arduino platform. diff --git a/src/platforms/esp32.h b/src/platforms/esp32.h index 59936f1..2cbb5d6 100644 --- a/src/platforms/esp32.h +++ b/src/platforms/esp32.h @@ -1,26 +1,71 @@ #include +#include +#include #define TIMER_ID 0 - hw_timer_t * _uclockTimer = NULL; -portMUX_TYPE _uclockTimerMux = portMUX_INITIALIZER_UNLOCKED; -#define ATOMIC(X) portENTER_CRITICAL_ISR(&_uclockTimerMux); X; portEXIT_CRITICAL_ISR(&_uclockTimerMux); +// mutex control for ISR +//portMUX_TYPE _uclockTimerMux = portMUX_INITIALIZER_UNLOCKED; +//#define ATOMIC(X) portENTER_CRITICAL_ISR(&_uclockTimerMux); X; portEXIT_CRITICAL_ISR(&_uclockTimerMux); + +// FreeRTOS main clock task size in bytes +#define CLOCK_STACK_SIZE 2048 +// semaphore to signal the task from the ISR +SemaphoreHandle_t _semaphore; +// mutex to protect the shared resource +SemaphoreHandle_t _mutex; +// mutex control for task +#define ATOMIC(X) \ + do { \ + xSemaphoreTake(_mutex, portMAX_DELAY); \ + X; \ + xSemaphoreGive(_mutex); \ + } while (0); + +// forward declaration of uClockHandler +void uClockHandler(); + +// ISR handler +void ARDUINO_ISR_ATTR handlerISR(void) +{ + // notify the clockTask using the semaphore + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xSemaphoreGiveFromISR(_semaphore, &xHigherPriorityTaskWoken); + + // context switch is required? request it + if (xHigherPriorityTaskWoken == pdTRUE) + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} -// forward declaration of ISR -void ARDUINO_ISR_ATTR uclockISR(); +// task for user clock process +void clockTask(void *pvParameters) +{ + while (1) + if (xSemaphoreTake(_semaphore, portMAX_DELAY) == pdTRUE) + uClockHandler(); +} void initTimer(uint32_t init_clock) { _uclockTimer = timerBegin(TIMER_ID, 80, true); // attach to generic uclock ISR - timerAttachInterrupt(_uclockTimer, &uclockISR, false); + timerAttachInterrupt(_uclockTimer, &handlerISR, false); // init clock tick time timerAlarmWrite(_uclockTimer, init_clock, true); // activate it! timerAlarmEnable(_uclockTimer); + + // initialize the semaphore + _semaphore = xSemaphoreCreateBinary(); + + // initialize the mutex for shared resource access + _mutex = xSemaphoreCreateMutex(); + + // create the clockTask + xTaskCreate(clockTask, "clockTask", CLOCK_STACK_SIZE, NULL, 1, NULL); } void setTimer(uint32_t us_interval) diff --git a/src/platforms/samd.h b/src/platforms/samd.h index 6f5ef21..bd58a8d 100644 --- a/src/platforms/samd.h +++ b/src/platforms/samd.h @@ -11,14 +11,14 @@ IntervalTimer _uclockTimer; // forward declaration of ISR -void uclockISR(); +void uClockHandler(); void initTimer(uint32_t init_clock) { TimerTcc0.initialize(init_clock); // attach to generic uclock ISR - TimerTcc0.attachInterrupt(uclockISR); + TimerTcc0.attachInterrupt(uClockHandler); } void setTimer(uint32_t us_interval) diff --git a/src/platforms/stm32.h b/src/platforms/stm32.h index 5d4b906..fa219e8 100644 --- a/src/platforms/stm32.h +++ b/src/platforms/stm32.h @@ -16,12 +16,12 @@ HardwareTimer * _uclockTimer = new HardwareTimer(TimerInstance); #define ATOMIC(X) noInterrupts(); X; interrupts(); // forward declaration of ISR -void uclockISR(); +void uClockHandler(); void initTimer(uint32_t us_interval) { _uclockTimer->setOverflow(us_interval, MICROSEC_FORMAT); - _uclockTimer->attachInterrupt(uclockISR); + _uclockTimer->attachInterrupt(uClockHandler); _uclockTimer->resume(); } diff --git a/src/platforms/teensy.h b/src/platforms/teensy.h index 6fceb96..6e0382b 100644 --- a/src/platforms/teensy.h +++ b/src/platforms/teensy.h @@ -5,11 +5,11 @@ IntervalTimer _uclockTimer; // forward declaration of ISR -void uclockISR(); +void uClockHandler(); void initTimer(uint32_t init_clock) { - _uclockTimer.begin(uclockISR, init_clock); + _uclockTimer.begin(uClockHandler, init_clock); // Set the interrupt priority level, controlling which other interrupts // this timer is allowed to interrupt. Lower numbers are higher priority, diff --git a/src/uClock.cpp b/src/uClock.cpp index 8839914..4243484 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -2,7 +2,7 @@ * @file uClock.cpp * Project BPM clock generator for Arduino * @brief A Library to implement BPM clock tick calls using hardware interruption. Supported and tested on AVR boards(ATmega168/328, ATmega16u4/32u4 and ATmega2560) and ARM boards(Teensy, Seedstudio XIAO M0 and ESP32) - * @version 1.4.1 + * @version 1.4.2 * @author Romulo Silva * @date 10/06/2017 * @license MIT - (c) 2022 - Romulo Silva - contact@midilab.co @@ -414,10 +414,8 @@ volatile uint32_t _timer = 0; // #if defined(ARDUINO_ARCH_AVR) ISR(TIMER1_COMPA_vect) -#elif defined(ARDUINO_ARCH_ESP32) || defined(ESP32) -void ARDUINO_ISR_ATTR uclockISR() #else -void uclockISR() +void uClockHandler() #endif { // global timer counter diff --git a/src/uClock.h b/src/uClock.h index 403afad..e02c66e 100755 --- a/src/uClock.h +++ b/src/uClock.h @@ -2,7 +2,7 @@ * @file uClock.h * Project BPM clock generator for Arduino * @brief A Library to implement BPM clock tick calls using hardware interruption. Supported and tested on AVR boards(ATmega168/328, ATmega16u4/32u4 and ATmega2560) and ARM boards(Teensy, Seedstudio XIAO M0 and ESP32) - * @version 1.4.1 + * @version 1.4.2 * @author Romulo Silva * @date 10/06/2017 * @license MIT - (c) 2022 - Romulo Silva - contact@midilab.co