Tristan Rowley 2 months ago committed by GitHub
commit 51c8d17c90
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 28
      README.md
  2. 35
      src/platforms/generic.h
  3. 70
      src/uClock.cpp

@ -2,7 +2,9 @@
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)**.
(See also the generic fallback mode)
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.
@ -17,9 +19,29 @@ The uClock library API operates through attached callback functions mechanism:
4. **setOnClockStart(onClockStartCallback) > onClockStartCallback()** on uClock Start event
5. **setOnClockStop(onClockStopCallback) > onClockStopCallback()** on uClock Stop event
### (optional) Generic 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.
You can force this non-interrupt "generic mode" even on supported boards by defining the build flag `USE_UCLOCK_GENERIC`.
In order for generic mode to work, you need to add a call to your `loop()` function to process ticks. For example,
```c++
// pre-declare this function somewhere, so that compiler knows about it.
void uClockCheckTime(uint32_t micros_time);
void loop() {
uClockCheckTime(micros());
// do anything else you need to do inside loop()...
}
```
## uClock v2.0 Breaking Changes
If you are coming from uClock version < 2.0 versions pay attention to the breaking changes so you can update your code to reflect the new API interface:
If you are coming from uClock version < 2.0 versions, pay attention to the breaking changes so you can update your code to reflect the new API interface:
### setCallback function name changes
@ -49,7 +71,7 @@ Furthermore, it is possible to utilize all three resolutions simultaneously, all
### Example
You will find more complete examples on examples/ folder:
You will find more complete examples on examples/ folder.
```c++
#include <uClock.h>

@ -0,0 +1,35 @@
#include <Arduino.h>
/*
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.
requires calling uClockCheckTime(micros()); inside loop() in order to trigger tick processing.
function signature: void uClockCheckTime(uint32_t micros_time);
*/
#define ATOMIC(X) X;
// forward declaration of ISR
void uClockHandler();
uint32_t uclock_last_time_ticked;
uint32_t uclock_us_interval;
// call this as often as possible to tick the uClock
void uClockCheckTime(uint32_t micros_time) {
if (micros_time - uclock_last_time_ticked >= uclock_us_interval) {
uclock_last_time_ticked = micros_time;
uClockHandler();
}
}
void initTimer(uint32_t init_clock)
{
// basically nothing to do for software-implemented version..?
uclock_last_time_ticked = micros();
}
void setTimer(uint32_t us_interval)
{
uclock_us_interval = us_interval;
}

@ -28,36 +28,52 @@
#include "uClock.h"
//
// General Arduino AVRs port
// Generic, board-agnostic, not-accurate, no-interrupt, software-only port
//
#if defined(ARDUINO_ARCH_AVR)
#include "platforms/avr.h"
#endif
//
// Teensyduino ARMs port
//
#if defined(TEENSYDUINO)
#include "platforms/teensy.h"
#endif
//
// Seedstudio XIAO M0 port
//
#if defined(SEEED_XIAO_M0)
#include "platforms/samd.h"
#if !defined(USE_UCLOCK_GENERIC)
//
// General Arduino AVRs port
//
#if defined(ARDUINO_ARCH_AVR)
#include "platforms/avr.h"
#define UCLOCK_PLATFORM_FOUND
#endif
//
// Teensyduino ARMs port
//
#if defined(TEENSYDUINO)
#include "platforms/teensy.h"
#define UCLOCK_PLATFORM_FOUND
#endif
//
// Seedstudio XIAO M0 port
//
#if defined(SEEED_XIAO_M0)
#include "platforms/samd.h"
#define UCLOCK_PLATFORM_FOUND
#endif
//
// ESP32 family
//
#if defined(ARDUINO_ARCH_ESP32) || defined(ESP32)
#include "platforms/esp32.h"
#define UCLOCK_PLATFORM_FOUND
#endif
//
// STM32XX family
//
#if defined(ARDUINO_ARCH_STM32)
#include "platforms/stm32.h"
#define UCLOCK_PLATFORM_FOUND
#endif
#endif
//
// ESP32 family
//
#if defined(ARDUINO_ARCH_ESP32) || defined(ESP32)
#include "platforms/esp32.h"
#endif
//
// STM32XX family
//
#if defined(ARDUINO_ARCH_STM32)
#include "platforms/stm32.h"
#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
//
// Platform specific timer setup/control
//
@ -119,7 +135,7 @@ void uClockClass::init()
uint32_t uClockClass::bpmToMicroSeconds(float bpm)
{
return (60000000 / ppqn / bpm);
return (60000000.0f / (float)ppqn / bpm);
}
void uClockClass::setPPQN(PPQNResolution resolution)

Loading…
Cancel
Save