initial engine rewrited for avr and arm platforms. missing the sync part

pull/5/head
midilab 3 years ago
parent 82c13c4e21
commit 635c42de41
  1. 148
      src/uClock.cpp
  2. 6
      src/uClock.h

@ -1,8 +1,7 @@
/*! /*!
* @file uClock.cpp * @file uClock.cpp
* Project BPM clock generator for Arduino * Project BPM clock generator for Arduino
* @brief A Library to implement BPM clock tick calls using hardware timer1 interruption. Tested on ATmega168/328, ATmega16u4/32u4 and ATmega2560. * @brief A Library to implement BPM clock tick calls using hardware timer interruption. Tested on ATmega168/328, ATmega16u4/32u4 and ATmega2560.
* Derived work from mididuino MidiClock class. (c) 2008 - 2011 - Manuel Odendahl - wesen@ruinwesen.com
* @version 0.10.6 * @version 0.10.6
* @author Romulo Silva * @author Romulo Silva
* @date 13/03/2022 * @date 13/03/2022
@ -28,16 +27,6 @@
*/ */
#include "uClock.h" #include "uClock.h"
// pickup a avr timer to make use.
// pickup only one!
// try to avoid timer0, only use it if you know what you are doing.
// 0 = delay(), millis() e micros()
// 1 = Servo.h library(any other?)
// 2 = tone()
//#define AVR_TIMER_0
#define AVR_TIMER_1
//#define AVR_TIMER_2
// //
// Timer setup for work clock // Timer setup for work clock
// //
@ -46,68 +35,37 @@ IntervalTimer _uclockTimer;
void uclockISR(); void uclockISR();
void uclockInitTimer() void uclockInitTimer()
{ {
_uclockTimer.begin(uclockISR, 16); ATOMIC(
// begin at 120bpm (20833us)
_uclockTimer.begin(uclockISR, 20833);
// Set the interrupt priority level, controlling which other interrupts // Set the interrupt priority level, controlling which other interrupts
// this timer is allowed to interrupt. Lower numbers are higher priority, // 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. // 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 // As a general guideline, interrupt routines that run longer should be given
// lower priority (higher numerical values). // lower priority (higher numerical values).
_uclockTimer.priority(0); _uclockTimer.priority(0);
)
} }
#else #else
void uclockInitTimer() void uclockInitTimer()
{ {
#if defined(AVR_TIMER_0)
ATOMIC(
// Timer0 init
TCCR0A = 0;
TCCR0B = 0;
TCNT0 = 0;
// set compare match register for 62500 Hz increments
// = 16000000 / (1 * 62500) - 1 (must be <256)
OCR0A = 255;
// turn on CTC mode
TCCR0B |= (1 << WGM02);
// Set CS02, CS01 and CS00 bits for 1 prescaler
TCCR0B |= (0 << CS02) | (0 << CS01) | (1 << CS00);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
)
#endif
#if defined(AVR_TIMER_1)
ATOMIC( ATOMIC(
// Timer1 init // Timer1 init
TCCR1A = 0; // begin at 120bpm (48.0007680122882 Hz)
TCCR1B = 0; TCCR1A = 0; // set entire TCCR1A register to 0
TCNT1 = 0; TCCR1B = 0; // same for TCCR1B
// set compare match register for 62500 Hz increments TCNT1 = 0; // initialize counter value to 0
// = 16000000 / (1 * 62500) - 1 (must be <65536) // set compare match register for 48.0007680122882 Hz increments
OCR1A = 255; OCR1A = 41665; // = 16000000 / (8 * 48.0007680122882) - 1 (must be <65536)
// turn on CTC mode // turn on CTC mode
TCCR1B |= (1 << WGM12); TCCR1B |= (1 << WGM12);
// Set CS12, CS11 and CS10 bits for 1 prescaler // Set CS12, CS11 and CS10 bits for 8 prescaler
TCCR1B |= (0 << CS12) | (0 << CS11) | (1 << CS10); TCCR1B |= (0 << CS12) | (1 << CS11) | (0 << CS10);
// enable timer compare interrupt // enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A); TIMSK1 |= (1 << OCIE1A);
) )
#endif
#if defined(AVR_TIMER_2)
ATOMIC(
// Timer2 init
TCCR2A = 0;
TCCR2B = 0;
TCNT2 = 0;
// set compare match register for 62500 Hz increments
// = 16000000 / (1 * 62500) - 1 (must be <256)
OCR2A = 255;
// turn on CTC mode
TCCR2B |= (1 << WGM22);
// Set CS22, CS21 and CS20 bits for 1 prescaler
TCCR2B |= (0 << CS22) | (0 << CS21) | (1 << CS20);
// enable timer compare interrupt
TIMSK2 |= (1 << OCIE2A);
)
#endif
} }
#endif #endif
@ -195,6 +153,50 @@ void uClockClass::pause()
} }
} }
void uClockClass::setTimerTempo(float bpm)
{
// 96 ppqn resolution
uint32_t tick_us_interval = (60000000 / 96 / bpm)*4;
#if defined(TEENSYDUINO) && !defined(__AVR_ATmega32U4__)
ATOMIC(
_uclockTimer.update(tick_us_interval);
)
#else
float tick_hertz_interval = 1/((float)tick_us_interval/1000000);
uint32_t ocr;
uint8_t tccr = 0;
// 16bits avr timer setup
if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 1 )) < 65535) {
// Set CS12, CS11 and CS10 bits for 1 prescaler
tccr |= (0 << CS12) | (0 << CS11) | (1 << CS10);
} else if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 8 )) < 65535) {
// Set CS12, CS11 and CS10 bits for 8 prescaler
tccr |= (0 << CS12) | (1 << CS11) | (0 << CS10);
} else if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 64 )) < 65535) {
// Set CS12, CS11 and CS10 bits for 64 prescaler
tccr |= (0 << CS12) | (1 << CS11) | (1 << CS10);
} else if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 256 )) < 65535) {
// Set CS12, CS11 and CS10 bits for 256 prescaler
tccr |= (1 << CS12) | (0 << CS11) | (0 << CS10);
} else if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 1024 )) < 65535) {
// Set CS12, CS11 and CS10 bits for 1024 prescaler
tccr |= (1 << CS12) | (0 << CS11) | (1 << CS10);
} else {
// tempo not achiavable
return;
}
ATOMIC(
TCCR1B = 0;
OCR1A = ocr-1;
TCCR1B |= (1 << WGM12);
TCCR1B |= tccr;
)
#endif
}
void uClockClass::setTempo(float bpm) void uClockClass::setTempo(float bpm)
{ {
if (mode == EXTERNAL_CLOCK) { if (mode == EXTERNAL_CLOCK) {
@ -205,13 +207,9 @@ void uClockClass::setTempo(float bpm)
return; return;
} }
tempo = bpm; setTimerTempo(bpm);
ATOMIC( tempo = bpm;
//interval = (freq_resolution / (tempo * 24 / 60)) - drift;
//interval = 62500 / (tempo * 24 / 60) - drift;
interval = (uint16_t)((156250.0 / tempo) - drift);
)
} }
float uClockClass::getTempo() float uClockClass::getTempo()
@ -223,9 +221,9 @@ float uClockClass::getTempo()
} }
if (acc != 0) { if (acc != 0) {
// get average interval, because MIDI sync world is a wild place... // get average interval, because MIDI sync world is a wild place...
//tempo = (((float)freq_resolution/24) * 60) / (float)(acc / EXT_INTERVAL_BUFFER_SIZE); ////tempo = (float)((((float)FREQ_RESOLUTION/24) * 60) / (float)(acc / EXT_INTERVAL_BUFFER_SIZE));
// derivated one time calc value = ( freq_resolution / 24 ) * 60 // derivated one time calc value = ( freq_resolution / 24 ) * 60
tempo = (float)(156250.0 / (acc / EXT_INTERVAL_BUFFER_SIZE)); //tempo = (float)(156250.0 / (acc / EXT_INTERVAL_BUFFER_SIZE));
} }
} }
return tempo; return tempo;
@ -350,7 +348,7 @@ void uClockClass::handleExternalClock()
void uClockClass::handleTimerInt() void uClockClass::handleTimerInt()
{ {
if (counter == 0) { //if (counter == 0) {
// update internal clock base counter // update internal clock base counter
counter = interval; counter = interval;
@ -400,9 +398,9 @@ void uClockClass::handleTimerInt()
mod6_counter = 0; mod6_counter = 0;
} }
} else { //} else {
counter--; // counter--;
} //}
} }
// elapsed time support // elapsed time support
@ -457,21 +455,13 @@ volatile uint32_t _timer = 0;
// //
// TIMER INTERRUPT HANDLER // TIMER INTERRUPT HANDLER
// Clocked at: 62.5kHz/16usec //
// //
#if defined(TEENSYDUINO) && !defined(__AVR_ATmega32U4__) #if defined(TEENSYDUINO) && !defined(__AVR_ATmega32U4__)
void uclockISR() void uclockISR()
#else #else
#if defined(AVR_TIMER_0)
ISR(TIMER0_COMPA_vect)
#endif
#if defined(AVR_TIMER_1)
ISR(TIMER1_COMPA_vect) ISR(TIMER1_COMPA_vect)
#endif #endif
#if defined(AVR_TIMER_2)
ISR(TIMER2_COMPA_vect)
#endif
#endif
{ {
// global timer counter // global timer counter
_timer = millis(); _timer = millis();

@ -35,6 +35,8 @@
namespace umodular { namespace clock { namespace umodular { namespace clock {
#define AVR_CLOCK_FREQ 16000000
#define PHASE_FACTOR 16 #define PHASE_FACTOR 16
#define EXT_INTERVAL_BUFFER_SIZE 24 #define EXT_INTERVAL_BUFFER_SIZE 24
@ -52,6 +54,8 @@ class uClockClass {
private: private:
void setTimerTempo(float bpm);
void (*onClock96PPQNCallback)(uint32_t * tick); void (*onClock96PPQNCallback)(uint32_t * tick);
void (*onClock32PPQNCallback)(uint32_t * tick); void (*onClock32PPQNCallback)(uint32_t * tick);
void (*onClock16PPQNCallback)(uint32_t * tick); void (*onClock16PPQNCallback)(uint32_t * tick);
@ -83,6 +87,7 @@ class uClockClass {
uint32_t ext_interval_acc; uint32_t ext_interval_acc;
uint16_t ext_interval_idx; uint16_t ext_interval_idx;
public: public:
enum { enum {
@ -153,7 +158,6 @@ class uClockClass {
uint8_t getNumberOfDays(uint32_t time); uint8_t getNumberOfDays(uint32_t time);
uint32_t getNowTimer(); uint32_t getNowTimer();
uint32_t getPlayTime(); uint32_t getPlayTime();
}; };
} } // end namespace umodular::clock } } // end namespace umodular::clock

Loading…
Cancel
Save