From 7faa14d8d4ff25566a8e96de2c5cdc5b3c9a6753 Mon Sep 17 00:00:00 2001 From: midilab Date: Tue, 3 May 2022 06:12:10 -0300 Subject: [PATCH 01/11] seedstudio xiao m0 support --- .../AcidStepSequencer/AcidStepSequencer.ino | 6 +- .../LeonardoUsbSlaveMidiClockMonitor.ino | 10 +-- examples/MidiClock/MidiClock.ino | 2 +- .../TeensyUsbMasterMidiClock.ino | 10 +-- .../TeensyUsbSlaveMidiClock.ino | 8 +- .../TeensyUsbSlaveMidiClockMonitor.ino | 8 +- src/uClock.cpp | 83 ++++++++++++------- src/uClock.h | 22 ++--- 8 files changed, 87 insertions(+), 62 deletions(-) diff --git a/examples/AcidStepSequencer/AcidStepSequencer.ino b/examples/AcidStepSequencer/AcidStepSequencer.ino index 19a3c27..bed0953 100644 --- a/examples/AcidStepSequencer/AcidStepSequencer.ino +++ b/examples/AcidStepSequencer/AcidStepSequencer.ino @@ -64,13 +64,13 @@ void sendMidiMessage(uint8_t command, uint8_t byte1, uint8_t byte2) } // The callback function wich will be called by uClock each Pulse of 16PPQN clock resolution. Each call represents exactly one step. -void ClockOut16PPQN(uint32_t * tick) +void ClockOut16PPQN(uint32_t tick) { uint16_t step; uint16_t length = NOTE_LENGTH; // get actual step. - _step = *tick % _step_length; + _step = tick % _step_length; // send note on only if this step are not in rest mode if ( _sequencer[_step].rest == false ) { @@ -102,7 +102,7 @@ void ClockOut16PPQN(uint32_t * tick) } // The callback function wich will be called by uClock each Pulse of 96PPQN clock resolution. -void ClockOut96PPQN(uint32_t * tick) +void ClockOut96PPQN(uint32_t tick) { // Send MIDI_CLOCK to external hardware Serial.write(MIDI_CLOCK); diff --git a/examples/LeonardoUsbSlaveMidiClockMonitor/LeonardoUsbSlaveMidiClockMonitor.ino b/examples/LeonardoUsbSlaveMidiClockMonitor/LeonardoUsbSlaveMidiClockMonitor.ino index 1c0d0b4..738ddcb 100644 --- a/examples/LeonardoUsbSlaveMidiClockMonitor/LeonardoUsbSlaveMidiClockMonitor.ino +++ b/examples/LeonardoUsbSlaveMidiClockMonitor/LeonardoUsbSlaveMidiClockMonitor.ino @@ -34,22 +34,22 @@ uint8_t bpm_blink_timer = 1; uint8_t clock_state = 1; uint8_t clock_mode = 0; -void handle_bpm_led(uint32_t * tick) +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 compass step will flash longer bpm_blink_timer = 8; TXLED1; - } else if ( !(*tick % (24)) ) { // each quarter led on + } else if ( !(tick % (24)) ) { // each quarter led on TXLED1; - } else if ( !(*tick % bpm_blink_timer) ) { // get led off + } else if ( !(tick % bpm_blink_timer) ) { // get led off TXLED0; bpm_blink_timer = 1; } } // Internal clock handlers -void ClockOut96PPQN(uint32_t * tick) { +void ClockOut96PPQN(uint32_t tick) { // Send MIDI_CLOCK to external gears MIDI.sendRealTime(MIDI_CLOCK); handle_bpm_led(tick); diff --git a/examples/MidiClock/MidiClock.ino b/examples/MidiClock/MidiClock.ino index eb05552..6ca4bb5 100755 --- a/examples/MidiClock/MidiClock.ino +++ b/examples/MidiClock/MidiClock.ino @@ -7,7 +7,7 @@ #define MIDI_STOP 0xFC // The callback function wich will be called by Clock each Pulse of 96PPQN clock resolution. -void ClockOut96PPQN(uint32_t * tick) +void ClockOut96PPQN(uint32_t tick) { // Send MIDI_CLOCK to external gears Serial.write(MIDI_CLOCK); diff --git a/examples/TeensyUsbMasterMidiClock/TeensyUsbMasterMidiClock.ino b/examples/TeensyUsbMasterMidiClock/TeensyUsbMasterMidiClock.ino index 3c27364..542b7b5 100644 --- a/examples/TeensyUsbMasterMidiClock/TeensyUsbMasterMidiClock.ino +++ b/examples/TeensyUsbMasterMidiClock/TeensyUsbMasterMidiClock.ino @@ -21,22 +21,22 @@ #include uint8_t bpm_blink_timer = 1; -void handle_bpm_led(uint32_t * tick) +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 compass step will flash longer bpm_blink_timer = 8; digitalWrite(LED_BUILTIN, HIGH); - } else if ( !(*tick % (24)) ) { // each quarter led on + } else if ( !(tick % (24)) ) { // each quarter led on digitalWrite(LED_BUILTIN, HIGH); - } else if ( !(*tick % bpm_blink_timer) ) { // get led off + } else if ( !(tick % bpm_blink_timer) ) { // get led off digitalWrite(LED_BUILTIN, LOW); bpm_blink_timer = 1; } } // Internal clock handlers -void ClockOut96PPQN(uint32_t * tick) { +void ClockOut96PPQN(uint32_t tick) { // Send MIDI_CLOCK to external gears usbMIDI.sendRealTime(usbMIDI.Clock); handle_bpm_led(tick); diff --git a/examples/TeensyUsbSlaveMidiClock/TeensyUsbSlaveMidiClock.ino b/examples/TeensyUsbSlaveMidiClock/TeensyUsbSlaveMidiClock.ino index a8aa6f0..aae743a 100644 --- a/examples/TeensyUsbSlaveMidiClock/TeensyUsbSlaveMidiClock.ino +++ b/examples/TeensyUsbSlaveMidiClock/TeensyUsbSlaveMidiClock.ino @@ -24,19 +24,19 @@ 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 compass step will flash longer bpm_blink_timer = 8; digitalWrite(LED_BUILTIN, HIGH); - } else if ( !(*tick % (24)) ) { // each quarter led on + } else if ( !(tick % (24)) ) { // each quarter led on digitalWrite(LED_BUILTIN, HIGH); - } else if ( !(*tick % bpm_blink_timer) ) { // get led off + } else if ( !(tick % bpm_blink_timer) ) { // get led off digitalWrite(LED_BUILTIN, LOW); bpm_blink_timer = 1; } } // Internal clock handlers -void ClockOut96PPQN(uint32_t * tick) { +void ClockOut96PPQN(uint32_t tick) { // Send MIDI_CLOCK to external gears on other port? //usbMIDI.sendRealTime(usbMIDI.Clock); handle_bpm_led(tick); diff --git a/examples/TeensyUsbSlaveMidiClockMonitor/TeensyUsbSlaveMidiClockMonitor.ino b/examples/TeensyUsbSlaveMidiClockMonitor/TeensyUsbSlaveMidiClockMonitor.ino index 835b028..d912b90 100644 --- a/examples/TeensyUsbSlaveMidiClockMonitor/TeensyUsbSlaveMidiClockMonitor.ino +++ b/examples/TeensyUsbSlaveMidiClockMonitor/TeensyUsbSlaveMidiClockMonitor.ino @@ -37,19 +37,19 @@ uint8_t clock_state = 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 compass step will flash longer bpm_blink_timer = 8; digitalWrite(LED_BUILTIN, HIGH); - } else if ( !(*tick % (24)) ) { // each quarter led on + } else if ( !(tick % (24)) ) { // each quarter led on digitalWrite(LED_BUILTIN, HIGH); - } else if ( !(*tick % bpm_blink_timer) ) { // get led off + } else if ( !(tick % bpm_blink_timer) ) { // get led off digitalWrite(LED_BUILTIN, LOW); bpm_blink_timer = 1; } } // Internal clock handlers -void ClockOut96PPQN(uint32_t * tick) { +void ClockOut96PPQN(uint32_t tick) { // Send MIDI_CLOCK to external gears usbMIDI.sendRealTime(MIDI_CLOCK); handle_bpm_led(tick); diff --git a/src/uClock.cpp b/src/uClock.cpp index 43cde97..37f311f 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -30,25 +30,18 @@ // // Timer setup for work clock // -#if defined(TEENSYDUINO) && !defined(__AVR_ATmega32U4__) +// all non-avr timmers setup +// Teensyduino port +#if defined(TEENSYDUINO) IntervalTimer _uclockTimer; -void uclockISR(); -void uclockInitTimer() -{ - ATOMIC( +#endif +// Seedstudio XIAO M0 port +#if defined(SEEED_XIAO_M0) +#include +TimerTCC0 _uclockTimer; +#endif - // begin at 120bpm (20833us) - _uclockTimer.begin(uclockISR, 20833); - - // Set the interrupt priority level, controlling which other interrupts - // this timer is allowed to interrupt. Lower numbers are higher priority, - // with 0 the highest and 255 the lowest. Most other interrupts default to 128. - // As a general guideline, interrupt routines that run longer should be given - // lower priority (higher numerical values). - _uclockTimer.priority(0); - ) -} -#else +#if defined(ARDUINO_ARCH_AVR) void uclockInitTimer() { ATOMIC( @@ -67,6 +60,32 @@ void uclockInitTimer() TIMSK1 |= (1 << OCIE1A); ) } +#else +void uclockISR(); +void uclockInitTimer() +{ + // begin at 120bpm (20833us) + const uint16_t init_clock = 20833; + ATOMIC( + #if defined(TEENSYDUINO) + _uclockTimer.begin(uclockISR, init_clock); + + // Set the interrupt priority level, controlling which other interrupts + // this timer is allowed to interrupt. Lower numbers are higher priority, + // with 0 the highest and 255 the lowest. Most other interrupts default to 128. + // As a general guideline, interrupt routines that run longer should be given + // lower priority (higher numerical values). + _uclockTimer.priority(0); + #endif + + #if defined(SEEED_XIAO_M0) + _uclockTimer.initialize(init_clock); + + // attach to generic uclock ISR + _uclockTimer.attachInterrupt(uclockISR); + #endif + ) +} #endif namespace umodular { namespace clock { @@ -153,11 +172,7 @@ void uClockClass::setTimerTempo(float bpm) tick_us_interval = (60000000 / 24 / bpm); tick_hertz_interval = 1/((float)tick_us_interval/1000000); -#if defined(TEENSYDUINO) && !defined(__AVR_ATmega32U4__) - ATOMIC( - _uclockTimer.update(tick_us_interval); - ) -#else +#if defined(ARDUINO_ARCH_AVR) uint32_t ocr; uint8_t tccr = 0; @@ -188,6 +203,16 @@ void uClockClass::setTimerTempo(float bpm) TCCR1B |= (1 << WGM12); TCCR1B |= tccr; ) +#else + ATOMIC( + #if defined(TEENSYDUINO) + _uclockTimer.update(tick_us_interval); + #endif + + #if defined(SEEED_XIAO_M0) + _uclockTimer.setPeriod(tick_us_interval); + #endif + ) #endif } @@ -355,15 +380,15 @@ void uClockClass::handleTimerInt() } if (onClock96PPQNCallback) { - onClock96PPQNCallback(&internal_tick); + onClock96PPQNCallback(internal_tick); } if (mod6_counter == 0) { if (onClock32PPQNCallback) { - onClock32PPQNCallback(&div32th_counter); + onClock32PPQNCallback(div32th_counter); } if (onClock16PPQNCallback) { - onClock16PPQNCallback(&div16th_counter); + onClock16PPQNCallback(div16th_counter); } div16th_counter++; div32th_counter++; @@ -371,7 +396,7 @@ void uClockClass::handleTimerInt() if (mod6_counter == 3) { if (onClock32PPQNCallback) { - onClock32PPQNCallback(&div32th_counter); + onClock32PPQNCallback(div32th_counter); } div32th_counter++; } @@ -439,10 +464,10 @@ volatile uint32_t _timer = 0; // TIMER INTERRUPT HANDLER // // -#if defined(TEENSYDUINO) && !defined(__AVR_ATmega32U4__) -void uclockISR() +#if defined(ARDUINO_ARCH_AVR) +ISR(TIMER1_COMPA_vect) #else -ISR(TIMER1_COMPA_vect) +void uclockISR() #endif { // global timer counter diff --git a/src/uClock.h b/src/uClock.h index 6a3c18f..083f1f8 100755 --- a/src/uClock.h +++ b/src/uClock.h @@ -62,17 +62,17 @@ class uClockClass { void setTimerTempo(float bpm); float inline freqToBpm(uint32_t freq); - void (*onClock96PPQNCallback)(uint32_t * tick); - void (*onClock32PPQNCallback)(uint32_t * tick); - void (*onClock16PPQNCallback)(uint32_t * tick); + void (*onClock96PPQNCallback)(uint32_t tick); + void (*onClock32PPQNCallback)(uint32_t tick); + void (*onClock16PPQNCallback)(uint32_t tick); void (*onClockStartCallback)(); void (*onClockStopCallback)(); // internal clock control - volatile uint32_t internal_tick; - volatile uint32_t div32th_counter; - volatile uint32_t div16th_counter; - volatile uint8_t mod6_counter; + uint32_t internal_tick; + uint32_t div32th_counter; + uint32_t div16th_counter; + uint8_t mod6_counter; // external clock control volatile uint32_t external_clock; @@ -81,7 +81,7 @@ class uClockClass { volatile uint32_t indiv16th_counter; volatile uint8_t inmod6_counter; volatile uint32_t interval; - volatile uint32_t last_interval; + uint32_t last_interval; uint32_t sync_interval; uint32_t tick_us_interval; @@ -111,15 +111,15 @@ class uClockClass { uClockClass(); - void setClock96PPQNOutput(void (*callback)(uint32_t * tick)) { + void setClock96PPQNOutput(void (*callback)(uint32_t tick)) { onClock96PPQNCallback = callback; } - void setClock32PPQNOutput(void (*callback)(uint32_t * tick)) { + void setClock32PPQNOutput(void (*callback)(uint32_t tick)) { onClock32PPQNCallback = callback; } - void setClock16PPQNOutput(void (*callback)(uint32_t * tick)) { + void setClock16PPQNOutput(void (*callback)(uint32_t tick)) { onClock16PPQNCallback = callback; } From d39de549cc7b1619442f37d7f22773a61a51ae16 Mon Sep 17 00:00:00 2001 From: midilab Date: Tue, 3 May 2022 15:44:01 -0300 Subject: [PATCH 02/11] timer setup changes for non avr --- src/uClock.cpp | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 37f311f..a5ee8e6 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -66,25 +66,23 @@ void uclockInitTimer() { // begin at 120bpm (20833us) const uint16_t init_clock = 20833; - ATOMIC( - #if defined(TEENSYDUINO) - _uclockTimer.begin(uclockISR, init_clock); - - // Set the interrupt priority level, controlling which other interrupts - // this timer is allowed to interrupt. Lower numbers are higher priority, - // with 0 the highest and 255 the lowest. Most other interrupts default to 128. - // As a general guideline, interrupt routines that run longer should be given - // lower priority (higher numerical values). - _uclockTimer.priority(0); - #endif +#if defined(TEENSYDUINO) + _uclockTimer.begin(uclockISR, init_clock); + + // Set the interrupt priority level, controlling which other interrupts + // this timer is allowed to interrupt. Lower numbers are higher priority, + // with 0 the highest and 255 the lowest. Most other interrupts default to 128. + // As a general guideline, interrupt routines that run longer should be given + // lower priority (higher numerical values). + _uclockTimer.priority(0); +#endif - #if defined(SEEED_XIAO_M0) - _uclockTimer.initialize(init_clock); +#if defined(SEEED_XIAO_M0) + _uclockTimer.initialize(init_clock); - // attach to generic uclock ISR - _uclockTimer.attachInterrupt(uclockISR); - #endif - ) + // attach to generic uclock ISR + _uclockTimer.attachInterrupt(uclockISR); +#endif } #endif From 197edd788850ee0ae54c1347062b802d7ce4244a Mon Sep 17 00:00:00 2001 From: midilab Date: Tue, 3 May 2022 15:53:58 -0300 Subject: [PATCH 03/11] added samd as arch on libraries.properties for xiao m0 support --- library.properties | 4 ++-- src/uClock.cpp | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/library.properties b/library.properties index be293af..d213f22 100755 --- a/library.properties +++ b/library.properties @@ -3,8 +3,8 @@ version=1.0.0 author=Romulo Silva maintainer=Romulo Silva sentence=BPM clock generator for Arduino and Teensy boards -paragraph=A Library to implement BPM clock tick calls using hardware interruption. Tested on ATmega168/328, ATmega16u4/32u4, ATmega2560 and Teensy ARM boards. +paragraph=A Library to implement BPM clock tick calls using hardware interruption. Tested on ATmega168/328, ATmega16u4/32u4, ATmega2560, Teensy ARM boards and Seedstudio XIAO M0 SAMD.. category=Timing url=https://github.com/midilab/uClock -architectures=avr,arm +architectures=avr,arm,samd includes=uClock.h diff --git a/src/uClock.cpp b/src/uClock.cpp index a5ee8e6..0c72666 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -202,7 +202,6 @@ void uClockClass::setTimerTempo(float bpm) TCCR1B |= tccr; ) #else - ATOMIC( #if defined(TEENSYDUINO) _uclockTimer.update(tick_us_interval); #endif @@ -210,7 +209,6 @@ void uClockClass::setTimerTempo(float bpm) #if defined(SEEED_XIAO_M0) _uclockTimer.setPeriod(tick_us_interval); #endif - ) #endif } From 731bb41f49786122a69ef94aeec1031de6f687f2 Mon Sep 17 00:00:00 2001 From: midilab Date: Tue, 3 May 2022 16:11:59 -0300 Subject: [PATCH 04/11] change notes --- README.md | 12 ++++++------ library.properties | 4 ++-- src/uClock.cpp | 38 +++++++++++++++++++------------------- src/uClock.h | 24 ++++++++++++------------ 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index c663d48..08d1864 100755 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # uClock -**BPM clock generator for Arduino and Teensy** is a library to implement BPM clock tick calls using **hardware interruption** for tight and solid timing clock ticks. Tested on ATmega168/328, ATmega16u4/32u4, ATmega2560 and Teensy LC. +**BPM clock generator for Arduino and Teensy** is a library to implement BPM clock tick calls using **hardware interruption** for tight and solid timing clock ticks. Tested on ATmega168/328, ATmega16u4/32u4, ATmega2560, Teensy ARM boards and Seedstudio XIAO M0. Generate your self tight BPM clock for music, audio/video productions, performances or installations. You can clock your MIDI setup or sync different protocols as you wish. @@ -34,7 +34,7 @@ Here is an example on how to create a simple MIDI Sync Box on Arduino boards #define MIDI_STOP 0xFC // The callback function wich will be called by Clock each Pulse of 96PPQN clock resolution. -void ClockOut96PPQN(uint32_t * tick) { +void ClockOut96PPQN(uint32_t tick) { // Send MIDI_CLOCK to external gears Serial.write(MIDI_CLOCK); } @@ -81,7 +81,7 @@ An example on how to create a simple MIDI Sync Box on Teensy boards and USB Midi #include // The callback function wich will be called by Clock each Pulse of 96PPQN clock resolution. -void ClockOut96PPQN(uint32_t * tick) { +void ClockOut96PPQN(uint32_t tick) { // Send MIDI_CLOCK to external gears usbMIDI.sendRealTime(usbMIDI.Clock); } @@ -185,13 +185,13 @@ void sendMidiMessage(uint8_t command, uint8_t byte1, uint8_t byte2) } // The callback function wich will be called by uClock each Pulse of 16PPQN clock resolution. Each call represents exactly one step. -void ClockOut16PPQN(uint32_t * tick) +void ClockOut16PPQN(uint32_t tick) { uint16_t step; uint16_t length = NOTE_LENGTH; // get actual step. - _step = *tick % _step_length; + _step = tick % _step_length; // send note on only if this step are not in rest mode if ( _sequencer[_step].rest == false ) { @@ -223,7 +223,7 @@ void ClockOut16PPQN(uint32_t * tick) } // The callback function wich will be called by uClock each Pulse of 96PPQN clock resolution. -void ClockOut96PPQN(uint32_t * tick) +void ClockOut96PPQN(uint32_t tick) { // Send MIDI_CLOCK to external hardware Serial.write(MIDI_CLOCK); diff --git a/library.properties b/library.properties index d213f22..310f3c8 100755 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=uClock -version=1.0.0 +version=1.1.0 author=Romulo Silva maintainer=Romulo Silva sentence=BPM clock generator for Arduino and Teensy boards -paragraph=A Library to implement BPM clock tick calls using hardware interruption. Tested on ATmega168/328, ATmega16u4/32u4, ATmega2560, Teensy ARM boards and Seedstudio XIAO M0 SAMD.. +paragraph=A Library to implement BPM clock tick calls using hardware interruption. Tested on ATmega168/328, ATmega16u4/32u4, ATmega2560, Teensy ARM boards and Seedstudio XIAO M0 category=Timing url=https://github.com/midilab/uClock architectures=avr,arm,samd diff --git a/src/uClock.cpp b/src/uClock.cpp index 0c72666..1f9572b 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -1,10 +1,10 @@ /*! * @file uClock.cpp * Project BPM clock generator for Arduino - * @brief A Library to implement BPM clock tick calls using hardware timer interruption. Tested on ATmega168/328, ATmega16u4/32u4 and ATmega2560 and Teensy LC. - * @version 1.0.0 + * @brief A Library to implement BPM clock tick calls using hardware timer interruption. Tested on ATmega168/328, ATmega16u4/32u4, ATmega2560, Teensy ARM boards and Seedstudio XIAO M0 + * @version 1.1.0 * @author Romulo Silva - * @date 01/04/2022 + * @date 04/03/2022 * @license MIT - (c) 2022 - Romulo Silva - contact@midilab.co * * Permission is hereby granted, free of charge, to any person obtaining a @@ -45,7 +45,7 @@ TimerTCC0 _uclockTimer; void uclockInitTimer() { ATOMIC( - // Timer1 init + // 16bits Timer1 init // begin at 120bpm (48.0007680122882 Hz) TCCR1A = 0; // set entire TCCR1A register to 0 TCCR1B = 0; // same for TCCR1B @@ -66,23 +66,23 @@ void uclockInitTimer() { // begin at 120bpm (20833us) const uint16_t init_clock = 20833; -#if defined(TEENSYDUINO) - _uclockTimer.begin(uclockISR, init_clock); - - // Set the interrupt priority level, controlling which other interrupts - // this timer is allowed to interrupt. Lower numbers are higher priority, - // with 0 the highest and 255 the lowest. Most other interrupts default to 128. - // As a general guideline, interrupt routines that run longer should be given - // lower priority (higher numerical values). - _uclockTimer.priority(0); -#endif + #if defined(TEENSYDUINO) + _uclockTimer.begin(uclockISR, init_clock); + + // Set the interrupt priority level, controlling which other interrupts + // this timer is allowed to interrupt. Lower numbers are higher priority, + // with 0 the highest and 255 the lowest. Most other interrupts default to 128. + // As a general guideline, interrupt routines that run longer should be given + // lower priority (higher numerical values). + _uclockTimer.priority(0); + #endif -#if defined(SEEED_XIAO_M0) - _uclockTimer.initialize(init_clock); + #if defined(SEEED_XIAO_M0) + _uclockTimer.initialize(init_clock); - // attach to generic uclock ISR - _uclockTimer.attachInterrupt(uclockISR); -#endif + // attach to generic uclock ISR + _uclockTimer.attachInterrupt(uclockISR); + #endif } #endif diff --git a/src/uClock.h b/src/uClock.h index 083f1f8..46c667d 100755 --- a/src/uClock.h +++ b/src/uClock.h @@ -1,10 +1,10 @@ /*! * @file uClock.h * Project BPM clock generator for Arduino - * @brief A Library to implement BPM clock tick calls using hardware timer interruption. Tested on ATmega168/328, ATmega16u4/32u4 and ATmega2560 and Teensy LC. - * @version 1.0.0 + * @brief A Library to implement BPM clock tick calls using hardware timer interruption. Tested on ATmega168/328, ATmega16u4/32u4, ATmega2560, Teensy ARM boards and Seedstudio XIAO M0 + * @version 1.1.0 * @author Romulo Silva - * @date 01/04/2022 + * @date 04/03/2022 * @license MIT - (c) 2022 - Romulo Silva - contact@midilab.co * * Permission is hereby granted, free of charge, to any person obtaining a @@ -34,25 +34,25 @@ namespace umodular { namespace clock { -#define AVR_CLOCK_FREQ 16000000 - -#define PHASE_FACTOR 16 - -#define PLL_X 220 - // for smooth slave tempo calculate display you should raise this value // in between 64 to 128. // note: this doesn't impact on sync time, only display time getTempo() // if you dont want to use it, set it to 1 for memory save #define EXT_INTERVAL_BUFFER_SIZE 24 +#define MIN_BPM 1 +#define MAX_BPM 300 + +// want a different avr clock support? +#define AVR_CLOCK_FREQ 16000000 + +#define PHASE_FACTOR 16 +#define PLL_X 220 + #define SECS_PER_MIN (60UL) #define SECS_PER_HOUR (3600UL) #define SECS_PER_DAY (SECS_PER_HOUR * 24L) -#define MIN_BPM 1 -#define MAX_BPM 300 - #define ATOMIC(X) noInterrupts(); X; interrupts(); class uClockClass { From a6da23104ba4d12bfb29ac223414bf6a5d4637cc Mon Sep 17 00:00:00 2001 From: midilab Date: Wed, 4 May 2022 06:51:09 -0300 Subject: [PATCH 05/11] @mightycoco implementation changes for XIAO m0 --- src/uClock.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 1f9572b..a22bc56 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -38,7 +38,6 @@ IntervalTimer _uclockTimer; // Seedstudio XIAO M0 port #if defined(SEEED_XIAO_M0) #include -TimerTCC0 _uclockTimer; #endif #if defined(ARDUINO_ARCH_AVR) @@ -78,10 +77,10 @@ void uclockInitTimer() #endif #if defined(SEEED_XIAO_M0) - _uclockTimer.initialize(init_clock); + TimerTcc0.initialize(init_clock); // attach to generic uclock ISR - _uclockTimer.attachInterrupt(uclockISR); + TimerTcc0.attachInterrupt(uclockISR); #endif } #endif @@ -207,7 +206,7 @@ void uClockClass::setTimerTempo(float bpm) #endif #if defined(SEEED_XIAO_M0) - _uclockTimer.setPeriod(tick_us_interval); + TimerTcc0.setPeriod(tick_us_interval); #endif #endif } From 9932baf93735f6650f10c4b2a7cc15e097c7f84e Mon Sep 17 00:00:00 2001 From: midilab Date: Wed, 4 May 2022 07:14:55 -0300 Subject: [PATCH 06/11] volatile tempo var and handling --- src/uClock.cpp | 11 +++++++---- src/uClock.h | 3 --- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index a22bc56..b4a8572 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -166,8 +166,8 @@ void uClockClass::pause() void uClockClass::setTimerTempo(float bpm) { // 96 ppqn resolution - tick_us_interval = (60000000 / 24 / bpm); - tick_hertz_interval = 1/((float)tick_us_interval/1000000); + uint32_t tick_us_interval = (60000000 / 24 / bpm); + float tick_hertz_interval = 1/((float)tick_us_interval/1000000); #if defined(ARDUINO_ARCH_AVR) uint32_t ocr; @@ -221,9 +221,12 @@ void uClockClass::setTempo(float bpm) return; } - setTimerTempo(bpm); + ATOMIC( + tempo = bpm + ) - tempo = bpm; + setTimerTempo(tempo); + } float inline uClockClass::freqToBpm(uint32_t freq) diff --git a/src/uClock.h b/src/uClock.h index 46c667d..59a56b8 100755 --- a/src/uClock.h +++ b/src/uClock.h @@ -84,9 +84,6 @@ class uClockClass { uint32_t last_interval; uint32_t sync_interval; - uint32_t tick_us_interval; - float tick_hertz_interval; - float tempo; uint32_t start_timer; uint8_t mode; From 8e1d7d2ed82b6b37348524ceb5e34306f4120c61 Mon Sep 17 00:00:00 2001 From: midilab Date: Wed, 4 May 2022 07:18:17 -0300 Subject: [PATCH 07/11] fix variable declaration outside his usage scope --- src/uClock.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index b4a8572..fff27e2 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -167,9 +167,10 @@ void uClockClass::setTimerTempo(float bpm) { // 96 ppqn resolution uint32_t tick_us_interval = (60000000 / 24 / bpm); - float tick_hertz_interval = 1/((float)tick_us_interval/1000000); #if defined(ARDUINO_ARCH_AVR) + float tick_hertz_interval = 1/((float)tick_us_interval/1000000); + uint32_t ocr; uint8_t tccr = 0; From 1767b06bb9955c915305b125326d9b1376b0968c Mon Sep 17 00:00:00 2001 From: midilab Date: Wed, 4 May 2022 07:20:08 -0300 Subject: [PATCH 08/11] avoid volatile warnings for setTimerTempo --- src/uClock.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index fff27e2..0ff9b21 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -226,7 +226,7 @@ void uClockClass::setTempo(float bpm) tempo = bpm ) - setTimerTempo(tempo); + setTimerTempo(bpm); } @@ -373,7 +373,7 @@ void uClockClass::handleTimerInt() if (bpm != tempo) { if (bpm >= MIN_BPM && bpm <= MAX_BPM) { tempo = bpm; - setTimerTempo(tempo); + setTimerTempo(bpm); } } } From f208593f6d4c7551d424ca28eea2b8250240d2aa Mon Sep 17 00:00:00 2001 From: midilab Date: Mon, 9 May 2022 09:37:47 -0300 Subject: [PATCH 09/11] added xiao master sync box example test --- .../XiaoUsbMasterMidiClock.ino | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 examples/XiaoUsbMasterMidiClock/XiaoUsbMasterMidiClock.ino diff --git a/examples/XiaoUsbMasterMidiClock/XiaoUsbMasterMidiClock.ino b/examples/XiaoUsbMasterMidiClock/XiaoUsbMasterMidiClock.ino new file mode 100644 index 0000000..66d5fb0 --- /dev/null +++ b/examples/XiaoUsbMasterMidiClock/XiaoUsbMasterMidiClock.ino @@ -0,0 +1,81 @@ +/* USB MIDI Sync Box + * + * This example demonstrates how to change the USB MIDI + * device name on Teensy LC and 3.x. When creating more + * that one MIDI device, custom names are much easier to + * use when selecting each device in MIDI software on + * your PC or Mac. The custom name is in the "name.c" tab. + * + * Windows and Macintosh systems often cache USB info. + * After changing the name, you may need to test on a + * different computer to observe the new name, or take + * steps to get your operating system to "forget" the + * cached info. (TODO: wanted... can anyone contribute + * instructions for these systems) + * + * This example code is in the public domain. + */ +#include +#include + +Adafruit_USBD_MIDI usb_midi; +MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, 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, HIGH); + } else if ( !(tick % (24)) ) { // each quarter led on + digitalWrite(LED_BUILTIN, HIGH); + } else if ( !(tick % bpm_blink_timer) ) { // get led off + digitalWrite(LED_BUILTIN, LOW); + bpm_blink_timer = 1; + } +} +*/ + +// Internal clock handlers +void ClockOut96PPQN(uint32_t tick) { + // Send MIDI_CLOCK to external gears + //MIDI.sendRealTime(MIDI.Clock); + //handle_bpm_led(tick); +} + +void onClockStart() { + //MIDI.sendRealTime(MIDI.Start); +} + +void onClockStop() { + //MIDI.sendRealTime(MIDI.Stop); +} + +void setup() { + MIDI.begin(MIDI_CHANNEL_OMNI); + + // A led to count bpms + //pinMode(LED_BUILTIN, OUTPUT); + + // Setup our clock system + // Inits the clock + uClock.init(); + // Set the callback function for the clock output to send MIDI Sync message. + uClock.setClock96PPQNOutput(ClockOut96PPQN); + // Set the callback function for MIDI Start and Stop messages. + uClock.setOnClockStartOutput(onClockStart); + uClock.setOnClockStopOutput(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() { + +} From d93b2c131aa8ff541c6d1b2c8092a44c98013c6a Mon Sep 17 00:00:00 2001 From: midilab Date: Tue, 17 May 2022 17:37:12 -0300 Subject: [PATCH 10/11] added timer tc3 for tests --- src/uClock.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 0ff9b21..44e83ea 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -37,7 +37,10 @@ IntervalTimer _uclockTimer; #endif // Seedstudio XIAO M0 port #if defined(SEEED_XIAO_M0) -#include +#include +#define _uclockTimer TimerTc3 +//#include +//#define _uclockTimer TimerTcc0 #endif #if defined(ARDUINO_ARCH_AVR) @@ -77,10 +80,10 @@ void uclockInitTimer() #endif #if defined(SEEED_XIAO_M0) - TimerTcc0.initialize(init_clock); + _uclockTimer.initialize(init_clock); // attach to generic uclock ISR - TimerTcc0.attachInterrupt(uclockISR); + _uclockTimer.attachInterrupt(uclockISR); #endif } #endif @@ -207,7 +210,7 @@ void uClockClass::setTimerTempo(float bpm) #endif #if defined(SEEED_XIAO_M0) - TimerTcc0.setPeriod(tick_us_interval); + _uclockTimer.setPeriod(tick_us_interval); #endif #endif } From 82d293ba606af7b9bbd5b8aad1861f38417f4c1b Mon Sep 17 00:00:00 2001 From: midilab Date: Wed, 18 May 2022 05:12:49 -0300 Subject: [PATCH 11/11] revert tcc0 as main timer for xiao. uncomment tc3 and comment tcc0 at begining of uClock.cpp to change it --- src/uClock.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 44e83ea..40a117d 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -37,10 +37,12 @@ IntervalTimer _uclockTimer; #endif // Seedstudio XIAO M0 port #if defined(SEEED_XIAO_M0) -#include -#define _uclockTimer TimerTc3 -//#include -//#define _uclockTimer TimerTcc0 +// 24 bits timer +#include +#define _uclockTimer TimerTcc0 +// 16 bits timer +//#include +//#define _uclockTimer TimerTc3 #endif #if defined(ARDUINO_ARCH_AVR)