mirror of https://github.com/midilab/uClock
added experimental support for stm32 boards using Hal library. organize platform independent code into a folder for easy time new ports and mantainance
parent
b00083014a
commit
152943f514
@ -0,0 +1,75 @@ |
||||
/* Uart MIDI Sync Box
|
||||
*
|
||||
* This example demonstrates how to send MIDI data via Uart
|
||||
* interface on STM32 family.
|
||||
*
|
||||
* This example code is in the public domain. |
||||
*
|
||||
* ... |
||||
*
|
||||
*/ |
||||
#include <uClock.h> |
||||
|
||||
// MIDI clock, start and stop byte definitions - based on MIDI 1.0 Standards.
|
||||
#define MIDI_CLOCK 0xF8 |
||||
#define MIDI_START 0xFA |
||||
#define MIDI_STOP 0xFC |
||||
|
||||
// the blue led
|
||||
#define LED_BUILTIN 2 |
||||
|
||||
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
|
||||
bpm_blink_timer = 1; |
||||
digitalWrite(LED_BUILTIN, HIGH); |
||||
} else if ( !(tick % bpm_blink_timer) ) { // get led off
|
||||
digitalWrite(LED_BUILTIN, LOW); |
||||
} |
||||
} |
||||
|
||||
// Internal clock handlers
|
||||
void ClockOut96PPQN(uint32_t tick) { |
||||
// Send MIDI_CLOCK to external gears
|
||||
Serial.write(MIDI_CLOCK); |
||||
handle_bpm_led(tick); |
||||
} |
||||
|
||||
void onClockStart() { |
||||
Serial.write(MIDI_START); |
||||
} |
||||
|
||||
void onClockStop() { |
||||
Serial.write(MIDI_STOP); |
||||
} |
||||
|
||||
void setup() { |
||||
// Initialize serial communication at 31250 bits per second, the default MIDI serial speed communication:
|
||||
Serial.begin(31250); |
||||
|
||||
// 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() { |
||||
|
||||
} |
@ -1,10 +1,10 @@ |
||||
name=uClock |
||||
version=1.2.0 |
||||
version=1.3.0 |
||||
author=Romulo Silva <contact@midilab.co> |
||||
maintainer=Romulo Silva <contact@midilab.co> |
||||
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 and ESP32) |
||||
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) |
||||
category=Timing |
||||
url=https://github.com/midilab/uClock |
||||
architectures=avr,arm,samd,esp32 |
||||
architectures=avr,arm,samd,stm32,esp32 |
||||
includes=uClock.h |
||||
|
@ -0,0 +1,62 @@ |
||||
#include <Arduino.h> |
||||
|
||||
#define ATOMIC(X) noInterrupts(); X; interrupts(); |
||||
|
||||
// want a different avr clock support?
|
||||
// TODO: we should do this using macro guards for avrs different clocks
|
||||
#define AVR_CLOCK_FREQ 16000000 |
||||
|
||||
void initTimer(uint32_t init_clock) |
||||
{ |
||||
ATOMIC( |
||||
// 16bits Timer1 init
|
||||
// begin at 120bpm (48.0007680122882 Hz)
|
||||
TCCR1A = 0; // set entire TCCR1A register to 0
|
||||
TCCR1B = 0; // same for TCCR1B
|
||||
TCNT1 = 0; // initialize counter value to 0
|
||||
// set compare match register for 48.0007680122882 Hz increments
|
||||
OCR1A = 41665; // = 16000000 / (8 * 48.0007680122882) - 1 (must be <65536)
|
||||
// turn on CTC mode
|
||||
TCCR1B |= (1 << WGM12); |
||||
// Set CS12, CS11 and CS10 bits for 8 prescaler
|
||||
TCCR1B |= (0 << CS12) | (1 << CS11) | (0 << CS10); |
||||
// enable timer compare interrupt
|
||||
TIMSK1 |= (1 << OCIE1A); |
||||
) |
||||
} |
||||
|
||||
void setTimer(uint32_t us_interval) |
||||
{ |
||||
float tick_hertz_interval = 1/((float)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; |
||||
) |
||||
} |
@ -0,0 +1,29 @@ |
||||
#include <Arduino.h> |
||||
|
||||
#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); |
||||
|
||||
// forward declaration of ISR
|
||||
void ARDUINO_ISR_ATTR uclockISR(); |
||||
|
||||
void initTimer(uint32_t init_clock) |
||||
{ |
||||
_uclockTimer = timerBegin(TIMER_ID, 80, true); |
||||
|
||||
// attach to generic uclock ISR
|
||||
timerAttachInterrupt(_uclockTimer, &uclockISR, true); |
||||
|
||||
// init clock tick time
|
||||
timerAlarmWrite(_uclockTimer, init_clock, true);
|
||||
|
||||
// activate it!
|
||||
timerAlarmEnable(_uclockTimer); |
||||
} |
||||
|
||||
void setTimer(uint32_t us_interval) |
||||
{ |
||||
timerAlarmWrite(_uclockTimer, us_interval, true);
|
||||
} |
@ -0,0 +1,27 @@ |
||||
#include <Arduino.h> |
||||
|
||||
// 24 bits timer
|
||||
#include <TimerTCC0.h> |
||||
// uses TimerTcc0
|
||||
// 16 bits timer
|
||||
//#include <TimerTC3.h>
|
||||
// uses TimerTc3
|
||||
#define ATOMIC(X) noInterrupts(); X; interrupts(); |
||||
|
||||
IntervalTimer _uclockTimer; |
||||
|
||||
// forward declaration of ISR
|
||||
void uclockISR(); |
||||
|
||||
void initTimer(uint32_t init_clock) |
||||
{ |
||||
TimerTcc0.initialize(init_clock); |
||||
|
||||
// attach to generic uclock ISR
|
||||
TimerTcc0.attachInterrupt(uclockISR); |
||||
} |
||||
|
||||
void setTimer(uint32_t us_interval) |
||||
{ |
||||
TimerTcc0.setPeriod(us_interval); |
||||
} |
@ -0,0 +1,65 @@ |
||||
#include <Arduino.h> |
||||
|
||||
static TIM_HandleTypeDef s_TimerInstance = {0}; |
||||
|
||||
typedef void (*timer_callback_t)(void); |
||||
timer_callback_t timer_callback = NULL; |
||||
|
||||
#define ATOMIC(X) noInterrupts(); X; interrupts(); |
||||
|
||||
// forward declaration of ISR
|
||||
void uclockISR(); |
||||
|
||||
void timer_attachInterrupt(TIM_TypeDef *tim, uint32_t microseconds, timer_callback_t callback) |
||||
{ |
||||
// Enable timer clock
|
||||
if (tim == TIM2) __HAL_RCC_TIM2_CLK_ENABLE(); |
||||
else if (tim == TIM3) __HAL_RCC_TIM3_CLK_ENABLE(); |
||||
else if (tim == TIM4) __HAL_RCC_TIM4_CLK_ENABLE(); |
||||
|
||||
// Calculate the prescaler value
|
||||
uint32_t prescaler = (SystemCoreClock / 1000000UL) - 1; |
||||
|
||||
// Calculate the period value
|
||||
uint32_t period = (microseconds * 2UL) - 1UL; |
||||
|
||||
// Set up the timer instance
|
||||
s_TimerInstance.Instance = tim; |
||||
s_TimerInstance.Init.Prescaler = prescaler; |
||||
s_TimerInstance.Init.CounterMode = TIM_COUNTERMODE_UP; |
||||
s_TimerInstance.Init.Period = period; |
||||
s_TimerInstance.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; |
||||
|
||||
// Configure the timer instance
|
||||
HAL_TIM_Base_Init(&s_TimerInstance); |
||||
HAL_TIM_Base_Start_IT(&s_TimerInstance); |
||||
|
||||
// Save the callback function
|
||||
timer_callback = callback; |
||||
} |
||||
|
||||
void TIM2_IRQHandler() |
||||
{ |
||||
// Call the callback function
|
||||
timer_callback(); |
||||
|
||||
// Clear the interrupt flag
|
||||
__HAL_TIM_CLEAR_FLAG(&s_TimerInstance, TIM_FLAG_UPDATE); |
||||
} |
||||
|
||||
void initTimer(uint32_t us_interval) |
||||
{ |
||||
// Set up the timer to call the callback function every us_interval microseconds
|
||||
timer_attachInterrupt(TIM2, us_interval, uclockISR); |
||||
} |
||||
|
||||
void setTimer(uint32_t us_interval) |
||||
{ |
||||
// Calculate the period value
|
||||
uint32_t period = (us_interval * 2UL) - 1UL; |
||||
|
||||
// Update the timer instance with the new period value
|
||||
s_TimerInstance.Init.Period = period; |
||||
HAL_TIM_Base_Init(&s_TimerInstance); |
||||
} |
||||
|
@ -0,0 +1,25 @@ |
||||
#include <Arduino.h> |
||||
|
||||
#define ATOMIC(X) noInterrupts(); X; interrupts(); |
||||
|
||||
IntervalTimer _uclockTimer; |
||||
|
||||
// forward declaration of ISR
|
||||
void uclockISR(); |
||||
|
||||
void initTimer(uint32_t init_clock) |
||||
{ |
||||
_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(80); |
||||
} |
||||
|
||||
void setTimer(uint32_t us_interval) |
||||
{ |
||||
_uclockTimer.update(us_interval); |
||||
} |
Loading…
Reference in new issue