- library interface suggestions for generic fallback support.

pull/35/head
midilab 3 weeks ago
parent 4c7590dbd0
commit c2cc95e30e
  1. 17
      README.md
  2. 2
      library.json
  3. 2
      library.properties
  4. 8
      src/platforms/software.h
  5. 47
      src/uClock.cpp
  6. 5
      src/uClock.h

@ -17,22 +17,23 @@ The uClock library API operates through attached callback functions mechanism:
4. **setOnClockStart(onClockStartCallback) > onClockStartCallback()** on uClock Start event 4. **setOnClockStart(onClockStartCallback) > onClockStartCallback()** on uClock Start event
5. **setOnClockStop(onClockStopCallback) > onClockStopCallback()** on uClock Stop event 5. **setOnClockStop(onClockStopCallback) > onClockStopCallback()** on uClock Stop event
### (optional) Generic mode - for unsupported boards (or avoiding usage of interrupts) ### (optional) Software Timer mode - for unsupported boards (or avoiding usage of interrupts)
If a supported board isn't detected during compilation then a generic fallback approach will be used. This does not utilise any interrupts and so does not ensure accurate timekeeping. This can be useful to port your projects to boards that do not have support in uClock yet, or to test if suspected bugs in your code are related to interactions with interrupts or task handling. If a supported board isn't detected during compilation then a generic fallback approach will be used. This does not utilise any interrupts and so does not ensure accurate timekeeping. This can be useful to port your projects to boards that do not have support in uClock yet, or to test if suspected bugs in your code are related to interactions with interrupts or task handling.
You can force this non-interrupt "generic mode" even on supported boards by defining the build flag `USE_UCLOCK_GENERIC`. You can force this non-interrupt "software timer mode" even on supported boards by defining the build flag `USE_UCLOCK_SOFTWARE_TIMER`.
In order for generic mode to work, you need to add a call to your `loop()` function to process ticks. For example, In order for software timer mode to work, you need to add a call to your `loop()` function to process ticks. For example,
```c++ ```c++
// pre-declare this function somewhere, so that compiler knows about it.
void uClockCheckTime(uint32_t micros_time);
void loop() { void loop() {
uClockCheckTime(micros()); uClock.run();
// do anything else you need to do inside loop()... // do anything else you need to do inside loop()...
// you can intercalate your main processing with other uClock.run() calls to avoid timming accuracy loss.
//uClock.run();
// do anything other inside loop()...
//uClock.run();
// the faster you can call uClock.run() without blocking the better and accurate timming you can achieve.
} }
``` ```

@ -1,6 +1,6 @@
{ {
"name": "uClock", "name": "uClock",
"version": "2.1.0", "version": "2.2.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, STM32XX, ESP32, Raspberry Pico, Seedstudio XIAO M0 and RP2040)", "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, STM32XX, ESP32, Raspberry Pico, Seedstudio XIAO M0 and RP2040)",
"keywords": "bpm, clock, timing, tick, music, generator", "keywords": "bpm, clock, timing, tick, music, generator",
"repository": "repository":

@ -1,5 +1,5 @@
name=uClock name=uClock
version=2.1.0 version=2.2.0
author=Romulo Silva <contact@midilab.co> author=Romulo Silva <contact@midilab.co>
maintainer=Romulo Silva <contact@midilab.co> maintainer=Romulo Silva <contact@midilab.co>
sentence=BPM clock generator for Arduino platform. sentence=BPM clock generator for Arduino platform.

@ -3,8 +3,10 @@
/* /*
Generic fallback approach that doesn't rely on any particular MCU's interrupts or RTOS threads etc. Generic fallback approach that doesn't rely on any particular MCU's interrupts or RTOS threads etc.
Simply checks micros() and compares last time tick happened and interval size to determine when a tick is due. Simply checks micros() and compares last time tick happened and interval size to determine when a tick is due.
requires calling uClockCheckTime(micros()); inside loop() in order to trigger tick processing. requires calling softwareTimerHandler(micros()); inside loop() in order to trigger tick processing.
function signature: void uClockCheckTime(uint32_t micros_time); function signature: void softwareTimerHandler(uint32_t micros_time);
@author Doctea
*/ */
#define ATOMIC(X) X; #define ATOMIC(X) X;
@ -16,7 +18,7 @@ uint32_t uclock_last_time_ticked;
uint32_t uclock_us_interval; uint32_t uclock_us_interval;
// call this as often as possible to tick the uClock // call this as often as possible to tick the uClock
void uClockCheckTime(uint32_t micros_time) { void softwareTimerHandler(uint32_t micros_time) {
if (micros_time - uclock_last_time_ticked >= uclock_us_interval) { if (micros_time - uclock_last_time_ticked >= uclock_us_interval) {
uclock_last_time_ticked = micros_time; uclock_last_time_ticked = micros_time;
uClockHandler(); uClockHandler();

@ -2,7 +2,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 interruption. Supported and tested on AVR boards(ATmega168/328, ATmega16u4/32u4 and ATmega2560) and ARM boards(RPI2040, Teensy, Seedstudio XIAO M0 and ESP32) * @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 * @version 2.2.0
* @author Romulo Silva * @author Romulo Silva
* @date 10/06/2017 * @date 10/06/2017
* @license MIT - (c) 2024 - Romulo Silva - contact@midilab.co * @license MIT - (c) 2024 - Romulo Silva - contact@midilab.co
@ -27,10 +27,8 @@
*/ */
#include "uClock.h" #include "uClock.h"
// // no hardware timer clock? use USE_UCLOCK_SOFTWARE_TIMER
// Generic, board-agnostic, not-accurate, no-interrupt, software-only port #if !defined(USE_UCLOCK_SOFTWARE_TIMER)
//
#if !defined(USE_UCLOCK_GENERIC)
// //
// General Arduino AVRs port // General Arduino AVRs port
// //
@ -66,17 +64,21 @@
#include "platforms/stm32.h" #include "platforms/stm32.h"
#define UCLOCK_PLATFORM_FOUND #define UCLOCK_PLATFORM_FOUND
#endif #endif
#endif
#if !defined(UCLOCK_PLATFORM_FOUND)
#pragma message ("NOTE: uClock is using the 'generic' approach instead of specific board support, because board is not supported or because of USE_UCLOCK_GENERIC build flag.")
#include "platforms/generic.h"
#endif
// //
// RP2040 (Raspberry Pico) family // RP2040 (Raspberry Pico) family
// //
#if defined(ARDUINO_ARCH_RP2040) #if defined(ARDUINO_ARCH_RP2040)
#include "platforms/rp2040.h" #include "platforms/rp2040.h"
#define UCLOCK_PLATFORM_FOUND
#endif
#endif
//
// Software Timer for generic, board-agnostic, not-accurate, no-interrupt, software-only port
//
#if !defined(UCLOCK_PLATFORM_FOUND)
#pragma message ("NOTE: uClock is using the 'software timer' approach instead of specific board interrupted support, because board is not supported or because of USE_UCLOCK_SOFTWARE_TIMER build flag. Remember to call uClock.run() inside your loop().")
#include "platforms/software.h"
#endif #endif
@ -209,13 +211,6 @@ void uClockClass::setTempo(float bpm)
setTimerTempo(bpm); setTimerTempo(bpm);
} }
// this function is based on sync24PPQN
float inline uClockClass::freqToBpm(uint32_t freq)
{
float usecs = 1/((float)freq/1000000.0);
return (float)((float)(usecs/(float)24) * 60.0);
}
float uClockClass::getTempo() float uClockClass::getTempo()
{ {
if (mode == EXTERNAL_CLOCK) { if (mode == EXTERNAL_CLOCK) {
@ -234,6 +229,22 @@ float uClockClass::getTempo()
return tempo; return tempo;
} }
// for software timer implementation(fallback for no board support)
void uClockClass::run()
{
#if !defined(UCLOCK_PLATFORM_FOUND)
// call software timer implementation of software
softwareTimerHandler(micros());
#endif
}
// this function is based on sync24PPQN
float inline uClockClass::freqToBpm(uint32_t freq)
{
float usecs = 1/((float)freq/1000000.0);
return (float)((float)(usecs/(float)24) * 60.0);
}
void uClockClass::setMode(SyncMode tempo_mode) void uClockClass::setMode(SyncMode tempo_mode)
{ {
mode = tempo_mode; mode = tempo_mode;

@ -2,7 +2,7 @@
* @file uClock.h * @file uClock.h
* Project BPM clock generator for Arduino * 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(RPI2040, Teensy, Seedstudio XIAO M0 and ESP32) * @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 * @version 2.2.0
* @author Romulo Silva * @author Romulo Silva
* @date 10/06/2017 * @date 10/06/2017
* @license MIT - (c) 2024 - Romulo Silva - contact@midilab.co * @license MIT - (c) 2024 - Romulo Silva - contact@midilab.co
@ -130,6 +130,9 @@ class uClockClass {
void setTempo(float bpm); void setTempo(float bpm);
float getTempo(); float getTempo();
// for software timer implementation(fallback for no board support)
void run();
// external timming control // external timming control
void setMode(SyncMode tempo_mode); void setMode(SyncMode tempo_mode);
SyncMode getMode(); SyncMode getMode();

Loading…
Cancel
Save