diff --git a/README.md b/README.md index 839bbdd..2782dd5 100755 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ The **uClock BPM Generator library** is designed to implement precise and reliable BPM clock tick calls using the microcontroller's timer hardware interruption. It is designed to be multi-architecture, portable, and easy to use within the open source community universe. -We have chosen PlatformIO and Arduino as our official deployment platforms. The library has been supported and tested on general **AVR boards (ATmega168/328, ATmega16u4/32u4, and ATmega2560)** as well as **ARM boards (Teensy, STM32XX, and Seedstudio XIAO M0)**. +We have chosen PlatformIO and Arduino as our official deployment platforms. The library has been supported and tested on general **AVR boards (ATmega168/328, ATmega16u4/32u4, and ATmega2560)** as well as **ARM boards (Teensy, STM32XX, and Seedstudio XIAO M0, Raspberry Pico, Seeed XIAO RP2040)**. The absence of real-time features necessary for creating professional-level embedded devices for music and video on open source community-based platforms like Arduino led to the development of uClock. By leveraging the use of timer hardware interruptions, the library can schedule and manage real-time-like processing with safe shared resource access through its API. @@ -370,4 +370,4 @@ void loop() //processYourLeds(); //processYourPots(); } -``` +``` \ No newline at end of file diff --git a/examples/RP2040UsbUartMasterClock/RP2040UsbUartMasterClock.ino b/examples/RP2040UsbUartMasterClock/RP2040UsbUartMasterClock.ino new file mode 100644 index 0000000..e571da9 --- /dev/null +++ b/examples/RP2040UsbUartMasterClock/RP2040UsbUartMasterClock.ino @@ -0,0 +1,89 @@ +/* + * USB/Uart MIDI Sync Box + * + * This example code is in the public domain. + * + */ + +#include +#include + +#include + +// 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); + +// 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 of 4 quarter pulse will flash longer + bpm_blink_timer = 8; + ledOn(); + } else if ( !(tick % (24)) ) { // each quarter led on + bpm_blink_timer = 1; + ledOn(); + } else if ( !(tick % bpm_blink_timer) ) { // get led off + 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); +} + +void onClockStart() { + MIDI.sendRealTime(midi::Start); + MIDI_USB.sendRealTime(midi::Start); +} + +void onClockStop() { + MIDI.sendRealTime(midi::Stop); + 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 + + // Initialize USB midi stack + MIDI_USB.begin(MIDI_CHANNEL_OMNI); + // Initialize UART midi stack + MIDI.begin(MIDI_CHANNEL_OMNI); + + // Initialize builtin led for clock timer blinking + initBlinkLed(); + + // 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(126); + // Starts the clock, tick-tac-tick-tac.. + uClock.start(); +} + +// 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(); +} 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/library.json b/library.json index e64bcf2..1952300 100644 --- a/library.json +++ b/library.json @@ -1,7 +1,7 @@ { "name": "uClock", - "version": "2.0.0", - "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)", + "version": "2.1.0", + "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(RPI2040, Teensy, Seedstudio XIAO M0 and ESP32)", "keywords": "bpm, clock, timing, tick, music, generator", "repository": { @@ -22,5 +22,5 @@ "headers": "uClock.h", "dependencies": {}, "frameworks": "Arduino", - "platforms": "atmelavr,atmelmegaavr,espressif32,ststm32,teensy,atmelsam" + "platforms": "atmelavr,atmelmegaavr,espressif32,ststm32,teensy,atmelsam,raspberrypi" } diff --git a/library.properties b/library.properties index fa4b2e8..c03f701 100755 --- a/library.properties +++ b/library.properties @@ -1,10 +1,10 @@ name=uClock -version=2.0.0 +version=2.1.0 author=Romulo Silva maintainer=Romulo Silva sentence=BPM clock generator for Arduino platform. -paragraph=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) +paragraph=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(RPI2040, Teensy, Seedstudio XIAO M0 and ESP32) category=Timing url=https://github.com/midilab/uClock -architectures=avr,arm,samd,stm32,esp32 +architectures=avr,arm,samd,stm32,esp32,rp2040 includes=uClock.h 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..eb918c2 --- /dev/null +++ b/src/platforms/rp2040.h @@ -0,0 +1,30 @@ +#include +#include "pico/sync.h" + +// 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 -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 diff --git a/src/uClock.cpp b/src/uClock.cpp index 3ad2473..8196f49 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -1,8 +1,8 @@ /*! * @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 2.0.0 + * @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(RPI2040, Teensy, Seedstudio XIAO M0 and ESP32) + * @version 2.1.0 * @author Romulo Silva * @date 10/06/2017 * @license MIT - (c) 2024 - Romulo Silva - contact@midilab.co @@ -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 diff --git a/src/uClock.h b/src/uClock.h index 722b385..9b438c2 100755 --- a/src/uClock.h +++ b/src/uClock.h @@ -1,8 +1,8 @@ /*! * @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 2.0.0 + * @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(RPI2040, Teensy, Seedstudio XIAO M0 and ESP32) + * @version 2.1.0 * @author Romulo Silva * @date 10/06/2017 * @license MIT - (c) 2024 - Romulo Silva - contact@midilab.co