parent
5f92dd7844
commit
eb8e483801
@ -1,69 +0,0 @@ |
||||
#include <Audio.h> |
||||
#include "synth_dexed.h" |
||||
|
||||
uint8_t fmpiano_sysex[156] = { |
||||
95, 29, 20, 50, 99, 95, 00, 00, 41, 00, 19, 00, 00, 03, 00, 06, 79, 00, 01, 00, 14, // OP6 eg_rate_1-4, level_1-4, kbd_lev_scl_brk_pt, kbd_lev_scl_lft_depth, kbd_lev_scl_rht_depth, kbd_lev_scl_lft_curve, kbd_lev_scl_rht_curve, kbd_rate_scaling, amp_mod_sensitivity, key_vel_sensitivity, operator_output_level, osc_mode, osc_freq_coarse, osc_freq_fine, osc_detune
|
||||
95, 20, 20, 50, 99, 95, 00, 00, 00, 00, 00, 00, 00, 03, 00, 00, 99, 00, 01, 00, 00, // OP5
|
||||
95, 29, 20, 50, 99, 95, 00, 00, 00, 00, 00, 00, 00, 03, 00, 06, 89, 00, 01, 00, 07, // OP4
|
||||
95, 20, 20, 50, 99, 95, 00, 00, 00, 00, 00, 00, 00, 03, 00, 02, 99, 00, 01, 00, 07, // OP3
|
||||
95, 50, 35, 78, 99, 75, 00, 00, 00, 00, 00, 00, 00, 03, 00, 07, 58, 00, 14, 00, 07, // OP2
|
||||
96, 25, 25, 67, 99, 75, 00, 00, 00, 00, 00, 00, 00, 03, 00, 02, 99, 00, 01, 00, 10, // OP1
|
||||
94, 67, 95, 60, 50, 50, 50, 50, // 4 * pitch EG rates, 4 * pitch EG level
|
||||
04, 06, 00, // algorithm, feedback, osc sync
|
||||
34, 33, 00, 00, 00, 04, // lfo speed, lfo delay, lfo pitch_mod_depth, lfo_amp_mod_depth, lfo_sync, lfo_waveform
|
||||
03, 24, // pitch_mod_sensitivity, transpose
|
||||
70, 77, 45, 80, 73, 65, 78, 79, 00, 00 // 10 * char for name ("DEFAULT ")
|
||||
}; // FM-Piano
|
||||
|
||||
AudioSynthDexed dexed(4,SAMPLE_RATE); // 4 voices max
|
||||
AudioOutputI2S i2s1; |
||||
AudioControlSGTL5000 sgtl5000_1; |
||||
AudioConnection patchCord1(dexed, 0, i2s1, 0); |
||||
AudioConnection patchCord2(dexed, 0, i2s1, 1); |
||||
|
||||
void setup() |
||||
{ |
||||
AudioMemory(32); |
||||
|
||||
sgtl5000_1.enable(); |
||||
sgtl5000_1.lineOutLevel(29); |
||||
sgtl5000_1.dacVolumeRamp(); |
||||
sgtl5000_1.dacVolume(1.0); |
||||
sgtl5000_1.unmuteHeadphone(); |
||||
sgtl5000_1.unmuteLineout(); |
||||
sgtl5000_1.volume(0.8, 0.8); // Headphone volume
|
||||
} |
||||
|
||||
void loop() |
||||
{ |
||||
static uint8_t count; |
||||
|
||||
if (count % 2 == 0) |
||||
{ |
||||
dexed.loadInitVoice(); |
||||
} |
||||
else |
||||
{ |
||||
dexed.loadVoiceParameters(fmpiano_sysex); |
||||
dexed.setTranspose(36); |
||||
} |
||||
|
||||
Serial.println("Key-Down"); |
||||
dexed.keydown(48, 100); |
||||
delay(100); |
||||
dexed.keydown(52, 100); |
||||
delay(100); |
||||
dexed.keydown(55, 100); |
||||
delay(100); |
||||
dexed.keydown(60, 100); |
||||
delay(2000); |
||||
|
||||
Serial.println("Key-Up"); |
||||
dexed.keyup(48); |
||||
dexed.keyup(52); |
||||
dexed.keyup(55); |
||||
dexed.keyup(60); |
||||
delay(2000); |
||||
|
||||
count++; |
||||
} |
@ -0,0 +1,165 @@ |
||||
####################################### |
||||
# Syntax Coloring Map For Synth_Dexed |
||||
####################################### |
||||
|
||||
####################################### |
||||
# Datatypes (KEYWORD1) |
||||
####################################### |
||||
|
||||
Dexed KEYWORD1 |
||||
AudioSynthDexed KEYWORD1 |
||||
|
||||
####################################### |
||||
# Methods and Functions (KEYWORD2) |
||||
####################################### |
||||
|
||||
# Global methods |
||||
activate KEYWORD2 |
||||
deactivate KEYWORD2 |
||||
getMonoMode KEYWORD2 |
||||
setMonoMode KEYWORD2 |
||||
setRefreshMode KEYWORD2 |
||||
setMaxNotes KEYWORD2 |
||||
getMaxNotes KEYWORD2 |
||||
doRefreshVoice KEYWORD2 |
||||
setOPAll KEYWORD2 |
||||
decodeVoice KEYWORD2 |
||||
encodeVoice KEYWORD2 |
||||
getVoiceData KEYWORD2 |
||||
setVoiceDataElement KEYWORD2 |
||||
getVoiceDataElement KEYWORD2 |
||||
loadInitVoice KEYWORD2 |
||||
loadVoiceParameters KEYWORD2 |
||||
getNumNotesPlaying KEYWORD2 |
||||
uint32_t getXRun KEYWORD2 |
||||
uint16_t getRenderTimeMax KEYWORD2 |
||||
resetRenderTimeMax KEYWORD2 |
||||
ControllersRefresh KEYWORD2 |
||||
|
||||
# Sound methods KEYWORD2 |
||||
keyup KEYWORD2 |
||||
keydown KEYWORD2 |
||||
setSustain KEYWORD2 |
||||
getSustain KEYWORD2 |
||||
panic KEYWORD2 |
||||
notesOff KEYWORD2 |
||||
resetControllers KEYWORD2 |
||||
setMasterTune KEYWORD2 |
||||
int8_t getMasterTune KEYWORD2 |
||||
setPortamentoMode KEYWORD2 |
||||
setPBController KEYWORD2 |
||||
setMWController KEYWORD2 |
||||
setFCController KEYWORD2 |
||||
setBCController KEYWORD2 |
||||
setATController KEYWORD2 |
||||
setModWheel KEYWORD2 |
||||
getModWheel KEYWORD2 |
||||
setBreathController KEYWORD2 |
||||
getBreathController KEYWORD2 |
||||
setFootController KEYWORD2 |
||||
getFootController KEYWORD2 |
||||
setAftertouch KEYWORD2 |
||||
getAftertouch KEYWORD2 |
||||
setPitchbend KEYWORD2 |
||||
getPitchbend KEYWORD2 |
||||
setPitchbendRange KEYWORD2 |
||||
getPitchbendRange KEYWORD2 |
||||
setPitchbendStep KEYWORD2 |
||||
getPitchbendStep KEYWORD2 |
||||
setModWheelRange KEYWORD2 |
||||
getModWheelRange KEYWORD2 |
||||
setModWheelTarget KEYWORD2 |
||||
getModWheelTarget KEYWORD2 |
||||
setFootControllerRange KEYWORD2 |
||||
getFootControllerRange KEYWORD2 |
||||
setFootControllerTarget KEYWORD2 |
||||
getFootControllerTarget KEYWORD2 |
||||
setBreathControllerRange KEYWORD2 |
||||
getBreathControllerRange KEYWORD2 |
||||
setBreathControllerTarget KEYWORD2 |
||||
getBreathControllerTarget KEYWORD2 |
||||
setAftertouchRange KEYWORD2 |
||||
getAftertouchRange KEYWORD2 |
||||
setAftertouchTarget KEYWORD2 |
||||
getAftertouchTarget KEYWORD2 |
||||
setFilterCutoff KEYWORD2 |
||||
float getFilterCutoff KEYWORD2 |
||||
setFilterResonance KEYWORD2 |
||||
float getFilterResonance KEYWORD2 |
||||
setGain KEYWORD2 |
||||
float getGain KEYWORD2 |
||||
|
||||
# Voice configuration methods KEYWORD2 |
||||
setOPRateAll KEYWORD2 |
||||
setOPLevelAll KEYWORD2 |
||||
setOPRateAllCarrier KEYWORD2 |
||||
setOPLevelAllCarrier KEYWORD2 |
||||
setOPRateAllModulator KEYWORD2 |
||||
setOPLevelAllModulator KEYWORD2 |
||||
setOPRate KEYWORD2 |
||||
getOPRate KEYWORD2 |
||||
setOPLevel KEYWORD2 |
||||
getOPLevel KEYWORD2 |
||||
setOPKeyboardLevelScalingBreakPoint KEYWORD2 |
||||
getOPKeyboardLevelScalingBreakPoint KEYWORD2 |
||||
setOPKeyboardLevelScalingDepthLeft KEYWORD2 |
||||
getOPKeyboardLevelScalingDepthLeft KEYWORD2 |
||||
setOPKeyboardLevelScalingDepthRight KEYWORD2 |
||||
getOPKeyboardLevelScalingDepthRight KEYWORD2 |
||||
setOPKeyboardLevelScalingCurveLeft KEYWORD2 |
||||
getOPKeyboardLevelScalingCurveLeft KEYWORD2 |
||||
setOPKeyboardLevelScalingCurveRight KEYWORD2 |
||||
getOPKeyboardLevelScalingCurveRight KEYWORD2 |
||||
setOPKeyboardRateScale KEYWORD2 |
||||
getOPKeyboardRateScale KEYWORD2 |
||||
setOPAmpModulationSensity KEYWORD2 |
||||
getOPAmpModulationSensity KEYWORD2 |
||||
setOPKeyboardVelocitySensity KEYWORD2 |
||||
getOPKeyboardVelocitySensity KEYWORD2 |
||||
setOPOutputLevel KEYWORD2 |
||||
getOPOutputLevel KEYWORD2 |
||||
setOPMode KEYWORD2 |
||||
getOPMode KEYWORD2 |
||||
setOPFrequencyCoarse KEYWORD2 |
||||
getOPFrequencyCoarse KEYWORD2 |
||||
setOPFrequencyFine KEYWORD2 |
||||
getOPFrequencyFine KEYWORD2 |
||||
setOPDetune KEYWORD2 |
||||
getOPDetune KEYWORD2 |
||||
setPitchRate KEYWORD2 |
||||
getPitchRate KEYWORD2 |
||||
setPitchLevel KEYWORD2 |
||||
getPitchLevel KEYWORD2 |
||||
setAlgorithm KEYWORD2 |
||||
getAlgorithm KEYWORD2 |
||||
setFeedback KEYWORD2 |
||||
getFeedback KEYWORD2 |
||||
setOscillatorSync KEYWORD2 |
||||
getOscillatorSync KEYWORD2 |
||||
setLFOSpeed KEYWORD2 |
||||
getLFOSpeed KEYWORD2 |
||||
setLFODelay KEYWORD2 |
||||
getLFODelay KEYWORD2 |
||||
setLFOPitchModulationDepth KEYWORD2 |
||||
getLFOPitchModulationDepth KEYWORD2 |
||||
setLFOAmpModulationDepth KEYWORD2 |
||||
getLFOAmpModulationDepth KEYWORD2 |
||||
setLFOSync KEYWORD2 |
||||
getLFOSync KEYWORD2 |
||||
setLFOWaveform KEYWORD2 |
||||
getLFOWaveform KEYWORD2 |
||||
setLFOPitchModulationSensitivity KEYWORD2 |
||||
getLFOPitchModulationSensitivity KEYWORD2 |
||||
setTranspose KEYWORD2 |
||||
getTranspose KEYWORD2 |
||||
setName KEYWORD2 |
||||
getName KEYWORD2 |
||||
|
||||
####################################### |
||||
# Instances (KEYWORD2) |
||||
####################################### |
||||
|
||||
####################################### |
||||
# Constants (LITERAL1) |
||||
####################################### |
||||
|
@ -0,0 +1,33 @@ |
||||
// Uses the built in Real Time Clock (RTC) as timebase.
|
||||
// The sketch calculates the relative drift of the main 24MHz crystal relative to the 32.768kHz RTC crystal.
|
||||
// Requires a T4.x board
|
||||
|
||||
#include "Arduino.h" |
||||
#include "TeensyTimerTool.h" |
||||
using namespace TeensyTimerTool; |
||||
|
||||
PeriodicTimer t1(TCK_RTC); |
||||
|
||||
constexpr uint32_t period = 500'000; //µs
|
||||
|
||||
void callback() |
||||
{ |
||||
static uint32_t start = micros(); |
||||
static uint32_t idx = 0; |
||||
|
||||
uint32_t now = micros() - start; |
||||
uint32_t expected = idx++ * period; |
||||
int32_t delta = now - expected; |
||||
float drift = 1E6 * delta / expected; // ppm
|
||||
|
||||
Serial.printf("t: %d µs, rel. drift: %.2f ppm\n", now, drift); |
||||
} |
||||
|
||||
void setup() |
||||
{ |
||||
t1.begin(callback, period); |
||||
} |
||||
|
||||
void loop() |
||||
{ |
||||
} |
@ -0,0 +1,10 @@ |
||||
#include "timer.h" |
||||
#include "config.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
Timer::Timer(TimerGenerator *generator) |
||||
: BaseTimer(generator, true) |
||||
{ |
||||
} |
||||
} // namespace TeensyTimerTool
|
@ -0,0 +1,30 @@ |
||||
#include "baseTimer.h" |
||||
//#include "Arduino.h"
|
||||
#include "types.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
|
||||
BaseTimer::BaseTimer(TimerGenerator *generator, bool periodic) |
||||
: timerGenerator(generator) |
||||
{ |
||||
this->timerGenerator = generator; |
||||
this->timerChannel = nullptr; |
||||
this->isPeriodic = periodic; |
||||
} |
||||
|
||||
BaseTimer::~BaseTimer() |
||||
{ |
||||
if (timerChannel != nullptr) |
||||
{ |
||||
delete timerChannel; |
||||
} |
||||
} |
||||
|
||||
errorCode BaseTimer::setPrescaler(int psc) |
||||
{ |
||||
this->prescaler = psc; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -0,0 +1,57 @@ |
||||
#pragma once |
||||
|
||||
#include "ErrorHandling/error_codes.h" |
||||
#include "baseTimer.h" |
||||
#include "type_traits" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class OneShotTimer : public BaseTimer |
||||
{ |
||||
public: |
||||
inline OneShotTimer(TimerGenerator *generator = nullptr); |
||||
|
||||
inline errorCode begin(callback_t cb); |
||||
template <typename T> errorCode trigger(T delay); |
||||
template <typename T> errorCode triggerDirect(T reload); |
||||
template <typename T> errorCode getTriggerReload(float delay, T *reload); |
||||
}; |
||||
|
||||
// Implementation ================================================
|
||||
|
||||
OneShotTimer::OneShotTimer(TimerGenerator *generator) |
||||
: BaseTimer(generator, false) |
||||
{} |
||||
|
||||
errorCode OneShotTimer::begin(callback_t callback) |
||||
{ |
||||
return BaseTimer::begin(callback, 0, false); |
||||
} |
||||
|
||||
template <typename period_t> |
||||
errorCode OneShotTimer::trigger(period_t delay) |
||||
{ |
||||
if (timerChannel) |
||||
return postError(timerChannel->trigger(period2us(delay))); |
||||
|
||||
return postError(errorCode::notInitialized); |
||||
} |
||||
|
||||
template <typename T> |
||||
errorCode OneShotTimer::triggerDirect(T reload) |
||||
{ |
||||
if (timerChannel) |
||||
return postError(timerChannel->triggerDirect(reload)); |
||||
|
||||
return postError(errorCode::notInitialized); |
||||
} |
||||
|
||||
template <typename T> |
||||
errorCode OneShotTimer::getTriggerReload(float delay, T *reload) |
||||
{ |
||||
if (timerChannel) |
||||
return postError(timerChannel->getTriggerReload(delay, reload)); |
||||
|
||||
return postError(errorCode::notInitialized); |
||||
} |
||||
} // namespace TeensyTimerTool
|
@ -0,0 +1,21 @@ |
||||
#pragma once |
||||
|
||||
#include "baseTimer.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class PeriodicTimer : public BaseTimer |
||||
{ |
||||
public: |
||||
PeriodicTimer(TimerGenerator *generator = nullptr) : BaseTimer(generator, true) {} |
||||
|
||||
template <typename period_t> |
||||
inline errorCode setPeriod(period_t p) { return postError(timerChannel->setPeriod(period2us(p))); }; |
||||
|
||||
template <typename period_t> |
||||
inline errorCode setNextPeriod(period_t p) { return postError(timerChannel->setNextPeriod(period2us(p))); }; |
||||
}; |
||||
|
||||
// IMPLEMENTATION =====================================================================
|
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,17 +0,0 @@ |
||||
#ifdef ESP32 |
||||
|
||||
#include "../../TeensyTimerTool.h" |
||||
|
||||
#if defined(HAS_TCK) and defined(ESP32) |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
bool TCK_t::isInitialized = false; |
||||
TckChannel* TCK_t::channels[maxTckChannels]; |
||||
} |
||||
|
||||
void yield() { TeensyTimerTool::TCK_t::tick(); } |
||||
|
||||
#endif |
||||
|
||||
#endif |
@ -1,79 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "TckChannel.h" |
||||
#include <Arduino.h> |
||||
#include <cstdint> |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
constexpr unsigned maxTckChannels = 20; |
||||
|
||||
class TCK_t |
||||
{ |
||||
public: |
||||
static inline ITimerChannel* getTimer(); |
||||
static inline void removeTimer(TckChannel*); |
||||
static inline void tick(); |
||||
|
||||
protected: |
||||
static bool isInitialized;
|
||||
static TckChannel* channels[maxTckChannels]; |
||||
}; |
||||
|
||||
// IMPLEMENTATION ==================================================================
|
||||
|
||||
ITimerChannel* TCK_t::getTimer() |
||||
{ |
||||
Serial.printf("TCK getTimer()\n"); |
||||
|
||||
if (!isInitialized) |
||||
{ |
||||
for (unsigned chNr = 0; chNr < maxTckChannels; chNr++) |
||||
{ |
||||
channels[chNr] = nullptr; |
||||
} |
||||
isInitialized = true; |
||||
} |
||||
|
||||
for (unsigned chNr = 0; chNr < maxTckChannels; chNr++) |
||||
{ |
||||
if (channels[chNr] == nullptr) |
||||
{ |
||||
channels[chNr] = new TckChannel(); |
||||
return channels[chNr]; |
||||
} |
||||
} |
||||
|
||||
return nullptr; |
||||
} |
||||
|
||||
void TCK_t::removeTimer(TckChannel* channel) |
||||
{ |
||||
for (unsigned chNr = 0; chNr < maxTckChannels; chNr++) |
||||
{ |
||||
if (channels[chNr] == channel) |
||||
{ |
||||
channels[chNr] = nullptr; |
||||
delete channel; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void TCK_t::tick() |
||||
{ |
||||
digitalWriteFast(12,HIGH); |
||||
for(unsigned i = 0; i < maxTckChannels; i++) |
||||
{ |
||||
if (channels[i] != nullptr ) |
||||
{ |
||||
channels[i]->tick(); |
||||
} |
||||
} |
||||
digitalWriteFast(12,LOW); |
||||
} |
||||
|
||||
|
||||
constexpr TimerGenerator* TCK = TCK_t::getTimer; |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,89 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "../ITimerChannel.h" |
||||
#include "../types.h" |
||||
#include "Arduino.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class TCK_t; |
||||
|
||||
class TckChannel : public ITimerChannel |
||||
{ |
||||
public: |
||||
inline TckChannel() { triggered = false; } |
||||
inline virtual ~TckChannel(){}; |
||||
|
||||
inline void begin(callback_t cb, unsigned period, bool periodic) |
||||
{ |
||||
Serial.println("begin"); |
||||
|
||||
triggered = false; |
||||
this->periodic = periodic; |
||||
this->period = period * (F_CPU / 1'000'000); |
||||
this->callback = cb; |
||||
|
||||
startCNT = ARM_DWT_CYCCNT;
|
||||
} |
||||
|
||||
inline void start() |
||||
{ |
||||
Serial.println("start"); |
||||
|
||||
this->startCNT = ARM_DWT_CYCCNT; |
||||
this->triggered = true; |
||||
} |
||||
|
||||
inline void stop() |
||||
{ |
||||
this->triggered = false; |
||||
} |
||||
|
||||
// inline void setPeriod(uint32_t microSeconds);
|
||||
inline uint32_t getPeriod(void); |
||||
|
||||
inline void trigger(uint32_t delay) // µs
|
||||
{ |
||||
this->startCNT = ARM_DWT_CYCCNT; |
||||
this->period = delay * (F_CPU / 1'000'000) - 68; |
||||
this->triggered = true; |
||||
} |
||||
|
||||
protected: |
||||
uint32_t startCNT, period; |
||||
callback_t callback; |
||||
bool triggered; |
||||
bool periodic; |
||||
|
||||
inline void tick(); |
||||
bool block = false; |
||||
|
||||
friend TCK_t; |
||||
}; |
||||
|
||||
// IMPLEMENTATION ==============================================
|
||||
|
||||
void TckChannel::tick() |
||||
{ |
||||
static bool lock = false;
|
||||
|
||||
if (!lock && period != 0 && triggered && (ARM_DWT_CYCCNT - startCNT) >= period) |
||||
{ |
||||
lock = true; |
||||
startCNT = ARM_DWT_CYCCNT; |
||||
triggered = periodic; // i.e., stays triggerd if periodic, stops if oneShot
|
||||
callback(); |
||||
lock = false; |
||||
}
|
||||
} |
||||
|
||||
// void TckChannel::setPeriod(uint32_t microSeconds)
|
||||
// {
|
||||
// period = microSeconds * (F_CPU / 1'000'000) ;
|
||||
// }
|
||||
uint32_t TckChannel::getPeriod() |
||||
{ |
||||
return period * (1'000'000.0f / F_CPU); |
||||
} |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,110 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "boardDef.h" |
||||
#include <algorithm> |
||||
|
||||
// All information in this header is calculated at compile time.
|
||||
// FTM_Info will not generate any code
|
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
typedef struct // FTM & TPM Channels
|
||||
{ |
||||
volatile uint32_t SC; |
||||
volatile uint32_t CV; |
||||
} FTM_CH_t; |
||||
|
||||
typedef struct // FTM register block (this layout is compatible to a TPM register block)
|
||||
{ |
||||
volatile uint32_t SC; |
||||
volatile uint32_t CNT; |
||||
volatile uint32_t MOD; |
||||
FTM_CH_t CH[8]; |
||||
volatile uint32_t CNTIN; |
||||
volatile uint32_t STATUS; |
||||
volatile uint32_t MODE; |
||||
volatile uint32_t SYNC; |
||||
volatile uint32_t OUTINIT; |
||||
volatile uint32_t OUTMASK; |
||||
volatile uint32_t COMBINE; |
||||
volatile uint32_t DEADTIME; |
||||
volatile uint32_t EXTTRIG; |
||||
volatile uint32_t POL; |
||||
volatile uint32_t FMS; |
||||
volatile uint32_t FILTER; |
||||
volatile uint32_t FLTCTRL; |
||||
volatile uint32_t QDCTRL; |
||||
volatile uint32_t CONF; |
||||
volatile uint32_t FLTPOL; |
||||
volatile uint32_t SYNCONF; |
||||
volatile uint32_t INVCTRL; |
||||
volatile uint32_t SWOCTRL; |
||||
volatile uint32_t PWMLOAD; |
||||
} FTM_r_t; |
||||
|
||||
//=======================================================================
|
||||
// using a static class instead of namespace here to reduce namespace pollution
|
||||
// (anonymous namespace doesn't make sense for header only class)
|
||||
|
||||
template<unsigned module> |
||||
class FTM_Info |
||||
{ |
||||
private: |
||||
#if defined(ARDUINO_TEENSYLC) |
||||
static constexpr unsigned boardNr = 0; |
||||
#elif defined(ARDUINO_TEENSY30) |
||||
static constexpr unsigned boardNr = 1; |
||||
#elif defined(ARDUINO_TEENSY31) || defined(ARDUINO_TEENSY32) |
||||
static constexpr unsigned boardNr = 2; |
||||
#elif defined(ARDUINO_TEENSY35) |
||||
static constexpr unsigned boardNr = 3; |
||||
#elif defined(ARDUINO_TEENSY36) |
||||
static constexpr unsigned boardNr = 4; |
||||
#else |
||||
#error Board not valid |
||||
#endif |
||||
|
||||
static constexpr int IRQ_Numbers[][4] |
||||
{ //FTM0 FTM1 FTM2 FTM3
|
||||
{ 0, 0, 0, 0 }, // Teensy LC
|
||||
{ 25, 26, 0, 0 }, // Teensy 3.0
|
||||
{ 62, 63, 64, 0 }, // Teensy 3.1/3.2
|
||||
{ 42, 43, 44, 71 }, // Teensy 3.5
|
||||
{ 42, 43, 44, 71 }, // Teensy 3.6
|
||||
}; |
||||
|
||||
static constexpr int FTM_NrOfChannels[] |
||||
{ |
||||
8, // FTM0
|
||||
2, // FTM1
|
||||
2, // FTM2
|
||||
8, // FTM3
|
||||
}; |
||||
|
||||
static constexpr uintptr_t FTM_BaseAdr[] // can't use defines from kinetis.h since, depending on board, not all are always defined.
|
||||
{ |
||||
0x4003'8000, // FTM0
|
||||
0x4003'9000, // FTM1
|
||||
0x400B'8000, // FTM2
|
||||
0x400B'9000, // FTM3
|
||||
}; |
||||
|
||||
static constexpr unsigned FTM_Prescale = |
||||
FTM_DEFAULT_PSC[module] < 0 || FTM_DEFAULT_PSC[module] > 7 ? // prescale value to roughly get 2 ticks per µs
|
||||
( |
||||
F_BUS > 120'000'000 ? 0b111 : |
||||
F_BUS > 60'000'000 ? 0b110 : |
||||
F_BUS > 30'000'000 ? 0b101 : |
||||
F_BUS > 15'000'000 ? 0b100 : |
||||
F_BUS > 8'000'000 ? 0b011 : |
||||
F_BUS > 4'000'000 ? 0b010 : |
||||
F_BUS > 2'000'000 ? 0b001 : 0b000 |
||||
):FTM_DEFAULT_PSC[module]; |
||||
|
||||
public: |
||||
static constexpr uintptr_t baseAdr = FTM_BaseAdr[module]; |
||||
static constexpr IRQ_NUMBER_t irqNumber = (IRQ_NUMBER_t)IRQ_Numbers[boardNr][module]; |
||||
static constexpr unsigned nrOfChannels = FTM_NrOfChannels[module]; |
||||
static constexpr unsigned prescale = FTM_Prescale; |
||||
}; |
||||
} |
@ -1,32 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <cstdint> |
||||
#include <imxrt.h> |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
// struct IMXRT_GPT_t
|
||||
// {
|
||||
// //51.7.1 GPT Control Register
|
||||
// volatile uint32_t CR;
|
||||
// //51.7.2 GPT Prescaler Register(GPTx_PR)
|
||||
// volatile uint32_t PR;
|
||||
// //51.7.3 GPT Status Register(GPTx_SR)
|
||||
// volatile uint32_t SR;
|
||||
// //51.7.4 GPT Interrupt Register(GPTx_IR)
|
||||
// volatile uint32_t IR;
|
||||
// //51.7.5 GPT Output Compare Register (GPTx_OCR1)
|
||||
// volatile uint32_t OCR1;
|
||||
// //51.7.6 GPT Output Compare Register (GPTx_OCR2)
|
||||
// volatile uint32_t OCR2;
|
||||
// //51.7.7 GPT Output Compare Register (GPTx_OCR3)
|
||||
// volatile uint32_t OCR3;
|
||||
// //51.7.8 GPT Input Capture Register 1 (GPTx_ICR1)
|
||||
// volatile uint32_t ICR1;
|
||||
// //51.7.9 GPT Input Capture Register 1 (GPTx_ICR2)
|
||||
// volatile uint32_t ICR2;
|
||||
// //51.7.10 GPT Counter Register (GPTx_CNT)
|
||||
// volatile uint32_t CNT;
|
||||
// };
|
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,41 +0,0 @@ |
||||
#include "../../config.h" |
||||
|
||||
#if defined(TEENSYDUINO) |
||||
|
||||
#include "TCK.h" |
||||
namespace TeensyTimerTool |
||||
{ |
||||
bool TCK_t::isInitialized = false; |
||||
TckChannelBase* TCK_t::channels[NR_OF_TCK_TIMERS]; |
||||
} |
||||
|
||||
//----------------------------------------------------------------------
|
||||
#if YIELD_TYPE == YIELD_OPTIMIZED |
||||
|
||||
void yield() |
||||
{ |
||||
TeensyTimerTool::TCK_t::tick(); |
||||
} |
||||
|
||||
//----------------------------------------------------------------------
|
||||
#elif YIELD_TYPE == YIELD_STANDARD |
||||
|
||||
#include "EventResponder.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
static EventResponder er; |
||||
|
||||
void initYieldHook() |
||||
{ |
||||
er.attach([](EventResponderRef r) |
||||
{ |
||||
TeensyTimerTool::TCK_t::tick(); |
||||
r.triggerEvent(); |
||||
}); |
||||
er.triggerEvent(); |
||||
} |
||||
} |
||||
#endif |
||||
#endif |
||||
//#endif
|
@ -1,336 +0,0 @@ |
||||
#pragma once |
||||
|
||||
//#include "Arduino.h"
|
||||
#include "ErrorHandling/error_codes.h" |
||||
#include "TckChannelBase.h" |
||||
#include "core_pins.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class TCK_t; |
||||
|
||||
#if !defined(ARDUINO_TEENSYLC) // T-LC doesn't have a cycle counter, nees special treatment
|
||||
|
||||
template <typename CounterType> |
||||
class TckChannel : public TckChannelBase |
||||
{ |
||||
public: |
||||
TckChannel(); |
||||
virtual ~TckChannel(){}; //TBD
|
||||
|
||||
inline errorCode begin(callback_t cb, float period, bool periodic) override; |
||||
inline errorCode start() override; |
||||
inline errorCode stop() override; |
||||
|
||||
inline errorCode trigger(float delay_us) override; |
||||
inline errorCode triggerDirect(CounterType reload) override; |
||||
inline errorCode getTriggerReload(float delay, CounterType* reload) override |
||||
{ |
||||
*reload = microsecondToCycles(delay); |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
float getMaxPeriod() const override { return getMaxMicros() / 1E6; } // seconds
|
||||
|
||||
CounterType getCycleCounter() { postError(errorCode::wrongType); } |
||||
|
||||
// inline errorCode setPeriod(uint32_t microSeconds) override;
|
||||
// inline errorCode setPeriod(uint32_t microSeconds) override;
|
||||
// inline errorCode setNextPeriod(uint32_t microSeconds) override;
|
||||
|
||||
protected: |
||||
inline CounterType microsecondToCycles(const float microSecond) const; |
||||
float getMaxMicros() const; |
||||
|
||||
inline bool tick(); |
||||
callback_t callback; |
||||
|
||||
bool periodic; |
||||
bool triggered; |
||||
|
||||
// bool block = false;
|
||||
|
||||
CounterType startCnt, currentPeriod, nextPeriod; |
||||
|
||||
uint32_t lastCyCnt; |
||||
uint32_t curHIGH; |
||||
|
||||
float clock; |
||||
|
||||
friend TCK_t; |
||||
|
||||
// inline uint32_t CPUCyclesToMicroseond(const uint32_t cpuCycles);
|
||||
// inline errorCode _setCurrentPeriod(const uint32_t period);
|
||||
// inline void _setNextPeriod(const uint32_t period);
|
||||
}; |
||||
|
||||
// IMPLEMENTATION ==============================================
|
||||
|
||||
template <typename T> |
||||
TckChannel<T>::TckChannel() |
||||
{ |
||||
triggered = false; |
||||
clock = F_CPU / 1'000'000.0f; |
||||
} |
||||
|
||||
template <typename T> |
||||
errorCode TckChannel<T>::begin(callback_t cb, float period, bool periodic) |
||||
{ |
||||
this->triggered = false; |
||||
|
||||
this->periodic = periodic; |
||||
if (periodic) |
||||
{ |
||||
this->currentPeriod = microsecondToCycles(period); |
||||
this->nextPeriod = this->currentPeriod; |
||||
} |
||||
this->callback = cb; |
||||
|
||||
return errorCode::OK; |
||||
} |
||||
|
||||
template <typename T> |
||||
errorCode TckChannel<T>::start() |
||||
{ |
||||
this->startCnt = getCycleCounter(); |
||||
this->triggered = true; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
template <typename T> |
||||
errorCode TckChannel<T>::stop() |
||||
{ |
||||
this->triggered = false; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
template <typename CounterType> |
||||
errorCode TckChannel<CounterType>::triggerDirect(CounterType reload) |
||||
{ |
||||
this->startCnt = getCycleCounter(); |
||||
this->nextPeriod = reload; |
||||
this->currentPeriod = this->nextPeriod; |
||||
this->triggered = true; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
template <typename T> |
||||
errorCode TckChannel<T>::trigger(float delay) // µs
|
||||
{ |
||||
return triggerDirect(microsecondToCycles(delay)); |
||||
} |
||||
|
||||
template <typename counter_t> |
||||
bool TckChannel<counter_t>::tick() |
||||
{ |
||||
static bool lock = false; |
||||
counter_t now = getCycleCounter(); |
||||
if (!lock && this->currentPeriod != 0 && this->triggered && (now - this->startCnt) >= this->currentPeriod) |
||||
{ |
||||
lock = true; |
||||
//this->startCnt = now;
|
||||
this->startCnt += currentPeriod; |
||||
this->triggered = this->periodic; // i.e., stays triggerd if periodic, stops if oneShot
|
||||
callback(); |
||||
lock = false; |
||||
return true; |
||||
} else |
||||
{ |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
template <typename CounterType> |
||||
CounterType TckChannel<CounterType>::microsecondToCycles(float microSecond) const |
||||
{ |
||||
if (microSecond > getMaxMicros()) |
||||
{ |
||||
microSecond = getMaxMicros(); |
||||
postError(errorCode::periodOverflow); |
||||
} |
||||
return (CounterType)(microSecond * clock); |
||||
} |
||||
|
||||
// SPECIALIZATIONS =================================================================================
|
||||
// 32bit Counter -------------------------------------------------------------------------
|
||||
|
||||
template <> |
||||
inline uint32_t TckChannel<uint32_t>::getCycleCounter() |
||||
{ |
||||
return ARM_DWT_CYCCNT; //directly use the cycle counter for uint32_t
|
||||
} |
||||
|
||||
template <> |
||||
inline float TckChannel<uint32_t>::getMaxMicros() const |
||||
{ |
||||
return 0xF000'0000 / clock; // don't use full range otherwise tick might miss the turnover for large periods
|
||||
} |
||||
|
||||
// 64bit Counter -------------------------------------------------------------------------
|
||||
|
||||
template <> |
||||
inline uint64_t TckChannel<uint64_t>::getCycleCounter() |
||||
{ |
||||
uint32_t now = ARM_DWT_CYCCNT; // (extend the cycle counter to 64 bit)
|
||||
if (now < lastCyCnt) |
||||
{ |
||||
curHIGH++; |
||||
} |
||||
lastCyCnt = now; |
||||
return (((uint64_t)curHIGH << 32) | now); |
||||
} |
||||
|
||||
template <> |
||||
inline float TckChannel<uint64_t>::getMaxMicros() const |
||||
{ |
||||
return 0xFFFF'FFFF; // currently limited to 2^32 µs (71.6h). Could be extended to 2^64 but would require change of interface
|
||||
} |
||||
|
||||
// template <typename ct>
|
||||
// uint32_t TckChannel<ct>::CPUCyclesToMicroseond(const uint32_t cpuCycles)
|
||||
// {
|
||||
// return (1'000'000.0f / F_CPU) * cpuCycles;
|
||||
// }
|
||||
|
||||
// template <typename ct>
|
||||
// void TckChannel<ct>::_setNextPeriod(const uint32_t period)
|
||||
// {
|
||||
// this->nextPeriod = period;
|
||||
// }
|
||||
|
||||
// template <typename ct>
|
||||
// errorCode TckChannel<ct>::_setCurrentPeriod(const uint32_t period)
|
||||
// {
|
||||
// this->currentPeriod = period;
|
||||
// const bool hasTicked = this->tick();
|
||||
|
||||
// if (hasTicked)
|
||||
// {
|
||||
// return errorCode::triggeredLate;
|
||||
// } else
|
||||
// {
|
||||
// return errorCode::OK;
|
||||
// }
|
||||
// }
|
||||
|
||||
// template <typename ct>
|
||||
// errorCode TckChannel<ct>::setPeriod(uint32_t microSeconds)
|
||||
// {
|
||||
// const uint32_t period = microsecondToCPUCycles(microSeconds);
|
||||
|
||||
// this->_setNextPeriod(period);
|
||||
// return this->_setCurrentPeriod(period);
|
||||
// }
|
||||
|
||||
// template <typename ct>
|
||||
// errorCode TckChannel<ct>::setPeriod(uint32_t microSeconds)
|
||||
// {
|
||||
// const uint32_t period = microsecondToCPUCycles(microSeconds);
|
||||
// return this->_setCurrentPeriod(period);
|
||||
// }
|
||||
|
||||
// template <typename ct>
|
||||
// errorCode TckChannel<ct>::setNextPeriod(uint32_t microSeconds)
|
||||
// {
|
||||
// const uint32_t period = microsecondToCPUCycles(microSeconds);
|
||||
// this->_setNextPeriod(period);
|
||||
// return errorCode::OK;
|
||||
// }
|
||||
|
||||
#else // TeensyLC
|
||||
|
||||
// Quick hack only, needs to be improved
|
||||
|
||||
template <typename uint32_64_t> |
||||
class TckChannel : public TckChannelBase |
||||
{ |
||||
public: |
||||
TckChannel() { triggered = false; } |
||||
virtual ~TckChannel(){}; |
||||
|
||||
errorCode begin(callback_t cb, float period, bool periodic) override |
||||
{ |
||||
triggered = false; |
||||
this->periodic = periodic; |
||||
this->period = (uint32_t)period; |
||||
this->callback = cb; |
||||
|
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode start() |
||||
{ |
||||
this->startCNT = micros(); |
||||
this->triggered = true; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode stop() |
||||
{ |
||||
this->triggered = false; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
inline errorCode setPeriod(uint32_t microSeconds) override; |
||||
inline uint32_t getPeriod(void); |
||||
|
||||
inline errorCode trigger(float delay) // µs
|
||||
{ |
||||
this->startCNT = micros(); |
||||
this->period = (uint32_t)delay; |
||||
this->triggered = true; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
float getMaxPeriod() const override { return getMaxMicros() / 1E6; } // seconds
|
||||
|
||||
protected: |
||||
static constexpr float clock = F_CPU / 1'000'000.0f; |
||||
float getMaxMicros() const { return 0xF000'0000 / clock; } // don't use full range otherwise tick might miss the turnover for large periods
|
||||
|
||||
uint32_t startCNT, period; |
||||
callback_t callback; |
||||
bool triggered; |
||||
bool periodic; |
||||
|
||||
inline bool tick(); |
||||
bool block = false; |
||||
|
||||
friend TCK_t; |
||||
}; |
||||
|
||||
// IMPLEMENTATION ==============================================
|
||||
|
||||
template <typename ct> |
||||
bool TckChannel<ct>::tick() |
||||
{ |
||||
static bool lock = false; |
||||
|
||||
if (!lock && period != 0 && triggered && (micros() - startCNT) >= period) |
||||
{ |
||||
lock = true; |
||||
startCNT = micros(); |
||||
triggered = periodic; // i.e., stays triggerd if periodic, stops if oneShot
|
||||
callback(); |
||||
lock = false; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
template <typename ct> |
||||
errorCode TckChannel<ct>::setPeriod(uint32_t microSeconds) |
||||
{ |
||||
period = microSeconds; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
template <typename ct> |
||||
uint32_t TckChannel<ct>::getPeriod() |
||||
{ |
||||
return period; |
||||
} |
||||
|
||||
#endif |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,9 +1,9 @@ |
||||
#pragma once |
||||
|
||||
#include "config.h" |
||||
#include "timer.h" |
||||
#include "periodicTimer.h" |
||||
#include "oneShotTimer.h" |
||||
#include "API/oneShotTimer.h" |
||||
#include "API/periodicTimer.h" |
||||
#include "API/timer.h" |
||||
#include "ErrorHandling/error_handler.h" |
||||
#include "config.h" |
||||
|
||||
static_assert(TEENSYDUINO >= 150, "This library requires Teensyduino > 1.5"); |
@ -1,10 +0,0 @@ |
||||
#include "timer.h" |
||||
#include "config.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
Timer::Timer(TimerGenerator* generator) |
||||
:BaseTimer(generator, true) |
||||
{ |
||||
} |
||||
} |
@ -1,9 +1,9 @@ |
||||
#pragma once |
||||
|
||||
#include "../../ITimerChannel.h" |
||||
#include "Arduino.h" |
||||
#include "FTM_ChannelInfo.h" |
||||
#include "FTM_Info.h" |
||||
#include "ITimerChannel.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
@ -0,0 +1,109 @@ |
||||
#pragma once |
||||
|
||||
#include "boardDef.h" |
||||
#include <algorithm> |
||||
|
||||
// All information in this header is calculated at compile time.
|
||||
// FTM_Info will not generate any code
|
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
typedef struct // FTM & TPM Channels
|
||||
{ |
||||
volatile uint32_t SC; |
||||
volatile uint32_t CV; |
||||
} FTM_CH_t; |
||||
|
||||
typedef struct // FTM register block (this layout is compatible to a TPM register block)
|
||||
{ |
||||
volatile uint32_t SC; |
||||
volatile uint32_t CNT; |
||||
volatile uint32_t MOD; |
||||
FTM_CH_t CH[8]; |
||||
volatile uint32_t CNTIN; |
||||
volatile uint32_t STATUS; |
||||
volatile uint32_t MODE; |
||||
volatile uint32_t SYNC; |
||||
volatile uint32_t OUTINIT; |
||||
volatile uint32_t OUTMASK; |
||||
volatile uint32_t COMBINE; |
||||
volatile uint32_t DEADTIME; |
||||
volatile uint32_t EXTTRIG; |
||||
volatile uint32_t POL; |
||||
volatile uint32_t FMS; |
||||
volatile uint32_t FILTER; |
||||
volatile uint32_t FLTCTRL; |
||||
volatile uint32_t QDCTRL; |
||||
volatile uint32_t CONF; |
||||
volatile uint32_t FLTPOL; |
||||
volatile uint32_t SYNCONF; |
||||
volatile uint32_t INVCTRL; |
||||
volatile uint32_t SWOCTRL; |
||||
volatile uint32_t PWMLOAD; |
||||
} FTM_r_t; |
||||
|
||||
//=======================================================================
|
||||
// using a static class instead of namespace here to reduce namespace pollution
|
||||
// (anonymous namespace doesn't make sense for header only class)
|
||||
|
||||
template <unsigned module> |
||||
class FTM_Info |
||||
{ |
||||
private: |
||||
#if defined(ARDUINO_TEENSYLC) |
||||
static constexpr unsigned boardNr = 0; |
||||
#elif defined(ARDUINO_TEENSY30) |
||||
static constexpr unsigned boardNr = 1; |
||||
#elif defined(ARDUINO_TEENSY31) || defined(ARDUINO_TEENSY32) |
||||
static constexpr unsigned boardNr = 2; |
||||
#elif defined(ARDUINO_TEENSY35) |
||||
static constexpr unsigned boardNr = 3; |
||||
#elif defined(ARDUINO_TEENSY36) |
||||
static constexpr unsigned boardNr = 4; |
||||
#else |
||||
#error Board not valid |
||||
#endif |
||||
|
||||
static constexpr int IRQ_Numbers[][4]{ |
||||
//FTM0 FTM1 FTM2 FTM3
|
||||
{0, 0, 0, 0}, // Teensy LC
|
||||
{25, 26, 0, 0}, // Teensy 3.0
|
||||
{62, 63, 64, 0}, // Teensy 3.1/3.2
|
||||
{42, 43, 44, 71}, // Teensy 3.5
|
||||
{42, 43, 44, 71}, // Teensy 3.6
|
||||
}; |
||||
|
||||
static constexpr int FTM_NrOfChannels[]{ |
||||
8, // FTM0
|
||||
2, // FTM1
|
||||
2, // FTM2
|
||||
8, // FTM3
|
||||
}; |
||||
|
||||
static constexpr uintptr_t FTM_BaseAdr[] // can't use defines from kinetis.h since, depending on board, not all are always defined.
|
||||
{ |
||||
0x4003'8000, // FTM0
|
||||
0x4003'9000, // FTM1
|
||||
0x400B'8000, // FTM2
|
||||
0x400B'9000, // FTM3
|
||||
}; |
||||
|
||||
static constexpr unsigned FTM_Prescale = |
||||
FTM_DEFAULT_PSC[module] < 0 || FTM_DEFAULT_PSC[module] > 7 ? // prescale value to roughly get 2 ticks per µs
|
||||
( |
||||
F_BUS > 120'000'000 ? 0b111 : F_BUS > 60'000'000 ? 0b110 |
||||
: F_BUS > 30'000'000 ? 0b101 |
||||
: F_BUS > 15'000'000 ? 0b100 |
||||
: F_BUS > 8'000'000 ? 0b011 |
||||
: F_BUS > 4'000'000 ? 0b010 |
||||
: F_BUS > 2'000'000 ? 0b001 |
||||
: 0b000) |
||||
: FTM_DEFAULT_PSC[module]; |
||||
|
||||
public: |
||||
static constexpr uintptr_t baseAdr = FTM_BaseAdr[module]; |
||||
static constexpr IRQ_NUMBER_t irqNumber = (IRQ_NUMBER_t)IRQ_Numbers[boardNr][module]; |
||||
static constexpr unsigned nrOfChannels = FTM_NrOfChannels[module]; |
||||
static constexpr unsigned prescale = FTM_Prescale; |
||||
}; |
||||
} // namespace TeensyTimerTool
|
@ -0,0 +1,24 @@ |
||||
#if defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY_MICROMOD) |
||||
|
||||
#include "GPTChannel.h" |
||||
#include "GPT.h" |
||||
//#include "Arduino.h"
|
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
GptChannel::~GptChannel() |
||||
{ |
||||
stop(); |
||||
setCallback(nullptr); |
||||
|
||||
if (regs == (IMXRT_GPT_t *)&IMXRT_GPT1) |
||||
GPT_t<0>::end(); |
||||
|
||||
else if (regs == (IMXRT_GPT_t *)&IMXRT_GPT2) |
||||
GPT_t<1>::end(); |
||||
else |
||||
postError(errorCode::GTP_err); |
||||
} |
||||
} // namespace TeensyTimerTool
|
||||
|
||||
#endif |
@ -1,7 +1,7 @@ |
||||
#pragma once |
||||
|
||||
#include "imxrt.h" |
||||
#include <cstdint> |
||||
#include <imxrt.h> |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
@ -1,8 +1,7 @@ |
||||
#pragma once |
||||
|
||||
#include "../../ITimerChannel.h" |
||||
#include "Arduino.h" |
||||
#include "PITMap.h" |
||||
#include "ITimerChannel.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
@ -0,0 +1,40 @@ |
||||
#include "config.h" |
||||
|
||||
#if defined(TEENSYDUINO) |
||||
|
||||
#include "TCK.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
bool TCK_t::isInitialized = false; |
||||
TckChannelBase *TCK_t::channels[NR_OF_TCK_TIMERS]; |
||||
} // namespace TeensyTimerTool
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
#if YIELD_TYPE == YIELD_OPTIMIZED |
||||
|
||||
void yield() |
||||
{ |
||||
TeensyTimerTool::TCK_t::tick(); |
||||
} |
||||
|
||||
//----------------------------------------------------------------------
|
||||
#elif YIELD_TYPE == YIELD_STANDARD |
||||
|
||||
#include "EventResponder.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
static EventResponder er; |
||||
|
||||
void initYieldHook() |
||||
{ |
||||
er.attach([](EventResponderRef r) { |
||||
TeensyTimerTool::TCK_t::tick(); |
||||
r.triggerEvent(); |
||||
}); |
||||
er.triggerEvent(); |
||||
} |
||||
} // namespace TeensyTimerTool
|
||||
#endif |
||||
#endif |
@ -0,0 +1,144 @@ |
||||
#pragma once |
||||
|
||||
//#include "Arduino.h"
|
||||
#include "ErrorHandling/error_codes.h" |
||||
#include "TckChannelBase.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
template <typename tckCounter> // tckCounter is the underlying counter, e.g. 32bit cycle counter, RTC counter, micros counter etc
|
||||
class TckChannel : public TckChannelBase |
||||
{ |
||||
using counter_t = typename tckCounter::counter_t; // use the counter type (uint32_t, unit64_t...) of the used tckCounter class
|
||||
|
||||
public: |
||||
TckChannel(); |
||||
|
||||
inline errorCode begin(callback_t cb, float period, bool periodic) override; |
||||
inline errorCode start() override; |
||||
inline errorCode stop() override; |
||||
|
||||
inline errorCode trigger(float delay_us) override; |
||||
inline errorCode triggerDirect(counter_t reload) override; |
||||
inline errorCode getTriggerReload(float delay, counter_t *reload) override; |
||||
|
||||
inline errorCode setNextPeriod(float us) override; |
||||
inline errorCode setPeriod(float us) override; |
||||
|
||||
float getMaxPeriod() const override { return tckCounter::getMaxMicros() / 1E6f; } // seconds
|
||||
|
||||
protected: |
||||
inline bool tick(); |
||||
callback_t callback; |
||||
counter_t startCnt, currentPeriod, nextPeriod; |
||||
|
||||
bool periodic; |
||||
bool triggered; |
||||
}; |
||||
|
||||
// IMPLEMENTATION ==============================================
|
||||
|
||||
template <typename tckCounter> |
||||
TckChannel<tckCounter>::TckChannel() |
||||
{ |
||||
triggered = false; |
||||
} |
||||
|
||||
template <typename tckCounter> |
||||
errorCode TckChannel<tckCounter>::begin(callback_t cb, float period, bool periodic) |
||||
{ |
||||
this->triggered = false; |
||||
|
||||
this->periodic = periodic; |
||||
if (periodic) |
||||
{ |
||||
this->currentPeriod = tckCounter::us2ticks(period); |
||||
this->nextPeriod = this->currentPeriod; |
||||
} |
||||
this->callback = cb; |
||||
|
||||
return errorCode::OK; |
||||
} |
||||
|
||||
template <typename tckCounter> |
||||
errorCode TckChannel<tckCounter>::start() |
||||
{ |
||||
this->startCnt = tckCounter::getCount(); |
||||
this->triggered = true; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
template <typename tckCounter> |
||||
errorCode TckChannel<tckCounter>::stop() |
||||
{ |
||||
this->triggered = false; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
template <typename tckCounter> |
||||
errorCode TckChannel<tckCounter>::triggerDirect(counter_t reload) |
||||
{ |
||||
this->startCnt = tckCounter::getCount(); |
||||
this->nextPeriod = reload; |
||||
this->currentPeriod = this->nextPeriod; |
||||
this->triggered = true; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
template <typename tckCounter> |
||||
errorCode TckChannel<tckCounter>::trigger(float delay) // µs
|
||||
{ |
||||
return triggerDirect(tckCounter::us2ticks(delay)); |
||||
} |
||||
|
||||
template <typename tckCounter> |
||||
errorCode TckChannel<tckCounter>::getTriggerReload(float delay, counter_t *reload) |
||||
{ |
||||
*reload = tckCounter::us2ticks(delay); |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
template <typename tckCounter> |
||||
errorCode TckChannel<tckCounter>::setNextPeriod(float us) |
||||
{ |
||||
nextPeriod = tckCounter::us2ticks(us); |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
template <typename tckCounter> |
||||
errorCode TckChannel<tckCounter>::setPeriod(float us) |
||||
{ |
||||
counter_t newPeriod = tckCounter::us2ticks(us); |
||||
counter_t now = tckCounter::getCount(); |
||||
|
||||
if (now - startCnt >= newPeriod) // new period already expired
|
||||
{ //
|
||||
startCnt = now; // -> restart cycle but,
|
||||
callback(); // since expired, invoke callback now
|
||||
} //
|
||||
currentPeriod = newPeriod; // in any case next callback will
|
||||
nextPeriod = newPeriod; // be invoked after newly set period
|
||||
return errorCode::OK; |
||||
} |
||||
|
||||
template <typename tckCounter> |
||||
bool TckChannel<tckCounter>::tick() |
||||
{ |
||||
static bool lock = false; |
||||
counter_t now = tckCounter::getCount(); |
||||
if (!lock && this->currentPeriod != 0 && this->triggered && (now - this->startCnt) >= this->currentPeriod) |
||||
{ |
||||
lock = true; |
||||
this->startCnt += currentPeriod; |
||||
this->currentPeriod = nextPeriod; // update period if it was changed during current cycle.
|
||||
this->triggered = this->periodic; // i.e., stays triggerd if periodic, stops if oneShot
|
||||
callback(); |
||||
lock = false; |
||||
return true; |
||||
} else |
||||
{ |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -0,0 +1,15 @@ |
||||
#if defined(TEENSYDUINO) |
||||
|
||||
#include "TckChannelBase.h" |
||||
#include "Arduino.h" |
||||
#include "TCK.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
TckChannelBase::~TckChannelBase() |
||||
{ |
||||
TCK_t::removeTimer(this); |
||||
} |
||||
} // namespace TeensyTimerTool
|
||||
|
||||
#endif |
@ -0,0 +1,108 @@ |
||||
|
||||
#include "tickCounters.h" |
||||
#include "Arduino.h" |
||||
#include "boardDef.h" |
||||
|
||||
#if defined(TTT_TEENSY4X) |
||||
#define TTT_F_CPU F_CPU_ACTUAL |
||||
#else |
||||
#define TTT_F_CPU F_CPU |
||||
#endif |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
//---------------------------------------------------------------------
|
||||
// CycleCounter32
|
||||
|
||||
uint32_t CycleCounter32::getCount() |
||||
{ |
||||
return ARM_DWT_CYCCNT; |
||||
} |
||||
|
||||
uint32_t CycleCounter32::us2ticks(float us) |
||||
{ |
||||
return us * (TTT_F_CPU / 1E6f); |
||||
} |
||||
|
||||
float CycleCounter32::getMaxMicros() |
||||
{ |
||||
return 5E6; //Can't use full 2^32 *1.66ns =7.2s range since we need some headroom to detect reaching target. This works if we call tick() at least once per 2 seconds
|
||||
} |
||||
|
||||
//---------------------------------------------------------------------
|
||||
// CycleCounter64
|
||||
|
||||
uint64_t CycleCounter64::getCount() |
||||
{ |
||||
static uint32_t lastCyCnt = ARM_DWT_CYCCNT; |
||||
static uint32_t curHIGH = 0; |
||||
|
||||
uint32_t now = ARM_DWT_CYCCNT; |
||||
if (now < lastCyCnt) |
||||
{ |
||||
curHIGH++; |
||||
} |
||||
lastCyCnt = now; |
||||
return ((uint64_t)curHIGH << 32) | now; |
||||
} |
||||
|
||||
uint64_t CycleCounter64::us2ticks(float us) |
||||
{ |
||||
return us * (TTT_F_CPU / 1E6f); |
||||
} |
||||
|
||||
float CycleCounter64::getMaxMicros() |
||||
{ |
||||
return 2E16f; //~630 years can't use full 2^64 *1.66ns range since we need some headroom to detect reaching target.
|
||||
} |
||||
|
||||
//------------------------------------------------------------------
|
||||
// MicrosCounter
|
||||
|
||||
uint32_t MicrosCounter::getCount() |
||||
{ |
||||
return micros(); |
||||
} |
||||
|
||||
uint32_t MicrosCounter::us2ticks(float us) |
||||
{ |
||||
return us; |
||||
} |
||||
|
||||
float MicrosCounter::getMaxMicros() |
||||
{ |
||||
return 70 * 60 * 1E6; // 70min, can't use full 2^32 µs = 72min range since we need some headroom to detect reaching target. This works if we call tick() at least once per 2min
|
||||
} |
||||
|
||||
#if defined(TTT_TEENSY4X) |
||||
//------------------------------------------------------------------
|
||||
// RtcCounter
|
||||
|
||||
uint64_t RtcCounter::getCount() |
||||
{ |
||||
uint32_t hi1 = SNVS_HPRTCMR, lo1 = SNVS_HPRTCLR; |
||||
while (true) |
||||
{ |
||||
uint32_t hi2 = SNVS_HPRTCMR, lo2 = SNVS_HPRTCLR; |
||||
if (lo1 == lo2 && hi1 == hi2) |
||||
{ |
||||
return (uint64_t)hi2 << 32 | lo2; |
||||
} |
||||
hi1 = hi2; |
||||
lo1 = lo2; |
||||
} |
||||
} |
||||
|
||||
uint64_t RtcCounter::us2ticks(float us) |
||||
{ |
||||
return us * (32'768 / 1E6f); |
||||
} |
||||
|
||||
float RtcCounter::getMaxMicros() |
||||
{ |
||||
return 2E16f; // ~630 years
|
||||
} |
||||
|
||||
#endif |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -0,0 +1,68 @@ |
||||
#pragma once |
||||
|
||||
#include <cstdint> |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class CycleCounterBase |
||||
{ |
||||
protected: |
||||
CycleCounterBase(); |
||||
}; |
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Software counter based on the 32bit ARM cycle counter
|
||||
// Resolution 1/FCPU_ACTUAL (1.66ns @600MHz)
|
||||
//
|
||||
struct CycleCounter32 : CycleCounterBase |
||||
{ |
||||
using counter_t = uint32_t; |
||||
|
||||
static counter_t getCount(); |
||||
static uint32_t us2ticks(float us); |
||||
static float getMaxMicros(); |
||||
}; |
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Software counter based on a 64bit extension of
|
||||
// the ARM cycle counter
|
||||
// Resolution 1/FCPU_ACTUAL (6.66ns @600MHz)
|
||||
//
|
||||
struct CycleCounter64 : CycleCounterBase |
||||
{ |
||||
using counter_t = uint64_t; |
||||
|
||||
static uint64_t getCount(); |
||||
static uint64_t us2ticks(float us); |
||||
static float getMaxMicros(); |
||||
}; |
||||
|
||||
//------------------------------------------------------------------
|
||||
// Software counter based on the 64bit period counter
|
||||
// of the built in real time clock (RTC).
|
||||
// Resolution: 1/32768s (30.5 µs)
|
||||
//
|
||||
struct RtcCounter |
||||
{ |
||||
using counter_t = uint64_t; |
||||
|
||||
static counter_t getCount(); |
||||
static counter_t us2ticks(float us); |
||||
static float getMaxMicros(); |
||||
}; |
||||
|
||||
//------------------------------------------------------------------
|
||||
// Fallback counter for boards without cycle counter
|
||||
// E.g. Teensy LC
|
||||
// Resolution: 1 µs
|
||||
//
|
||||
struct MicrosCounter |
||||
{ |
||||
using counter_t = uint32_t; |
||||
|
||||
static counter_t getCount(); |
||||
static counter_t us2ticks(float us); |
||||
static float getMaxMicros(); |
||||
}; |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,14 +0,0 @@ |
||||
//#include "../../TeensyTimerTool.h"
|
||||
#include "../../config.h" |
||||
|
||||
#if defined(HAS_TCK) and defined(UNO) |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
bool TCK_t::isInitialized = false; |
||||
TckChannel* TCK_t::channels[maxTckChannels]; |
||||
} |
||||
|
||||
void yield() { TeensyTimerTool::TCK_t::tick(); } |
||||
|
||||
#endif |
@ -1,79 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "TckChannel.h" |
||||
#include <Arduino.h> |
||||
#include <cstdint> |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
constexpr unsigned maxTckChannels = 20; |
||||
|
||||
class TCK_t |
||||
{ |
||||
public: |
||||
static inline ITimerChannel* getTimer(); |
||||
static inline void removeTimer(TckChannel*); |
||||
static inline void tick(); |
||||
|
||||
protected: |
||||
static bool isInitialized;
|
||||
static TckChannel* channels[maxTckChannels]; |
||||
}; |
||||
|
||||
// IMPLEMENTATION ==================================================================
|
||||
|
||||
ITimerChannel* TCK_t::getTimer() |
||||
{ |
||||
Serial.printf("TCK getTimer()\n"); |
||||
|
||||
if (!isInitialized) |
||||
{ |
||||
for (unsigned chNr = 0; chNr < maxTckChannels; chNr++) |
||||
{ |
||||
channels[chNr] = nullptr; |
||||
} |
||||
isInitialized = true; |
||||
} |
||||
|
||||
for (unsigned chNr = 0; chNr < maxTckChannels; chNr++) |
||||
{ |
||||
if (channels[chNr] == nullptr) |
||||
{ |
||||
channels[chNr] = new TckChannel(); |
||||
return channels[chNr]; |
||||
} |
||||
} |
||||
|
||||
return nullptr; |
||||
} |
||||
|
||||
void TCK_t::removeTimer(TckChannel* channel) |
||||
{ |
||||
for (unsigned chNr = 0; chNr < maxTckChannels; chNr++) |
||||
{ |
||||
if (channels[chNr] == channel) |
||||
{ |
||||
channels[chNr] = nullptr; |
||||
delete channel; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void TCK_t::tick() |
||||
{ |
||||
digitalWriteFast(12,HIGH); |
||||
for(unsigned i = 0; i < maxTckChannels; i++) |
||||
{ |
||||
if (channels[i] != nullptr ) |
||||
{ |
||||
channels[i]->tick(); |
||||
} |
||||
} |
||||
digitalWriteFast(12,LOW); |
||||
} |
||||
|
||||
|
||||
//constexpr TimerGenerator* TCK = TCK_t::getTimer;
|
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,89 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "../ITimerChannel.h" |
||||
#include "../types.h" |
||||
#include "Arduino.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class TCK_t; |
||||
|
||||
class TckChannel : public ITimerChannel |
||||
{ |
||||
public: |
||||
inline TckChannel() { triggered = false; } |
||||
inline virtual ~TckChannel(){}; |
||||
|
||||
inline void begin(callback_t cb, unsigned period, bool periodic) |
||||
{ |
||||
Serial.println("begin"); |
||||
|
||||
triggered = false; |
||||
this->periodic = periodic; |
||||
this->period = period * (F_CPU / 1'000'000); |
||||
this->callback = cb; |
||||
|
||||
startCNT = ARM_DWT_CYCCNT;
|
||||
} |
||||
|
||||
inline void start() |
||||
{ |
||||
Serial.println("start"); |
||||
|
||||
this->startCNT = ARM_DWT_CYCCNT; |
||||
this->triggered = true; |
||||
} |
||||
|
||||
inline void stop() |
||||
{ |
||||
this->triggered = false; |
||||
} |
||||
|
||||
// inline void setPeriod(uint32_t microSeconds);
|
||||
inline uint32_t getPeriod(void); |
||||
|
||||
inline void trigger(uint32_t delay) // µs
|
||||
{ |
||||
this->startCNT = ARM_DWT_CYCCNT; |
||||
this->period = delay * (F_CPU / 1'000'000) - 68; |
||||
this->triggered = true; |
||||
} |
||||
|
||||
protected: |
||||
uint32_t startCNT, period; |
||||
callback_t callback; |
||||
bool triggered; |
||||
bool periodic; |
||||
|
||||
inline void tick(); |
||||
bool block = false; |
||||
|
||||
friend TCK_t; |
||||
}; |
||||
|
||||
// IMPLEMENTATION ==============================================
|
||||
|
||||
void TckChannel::tick() |
||||
{ |
||||
static bool lock = false;
|
||||
|
||||
if (!lock && period != 0 && triggered && (ARM_DWT_CYCCNT - startCNT) >= period) |
||||
{ |
||||
lock = true; |
||||
startCNT = ARM_DWT_CYCCNT; |
||||
triggered = periodic; // i.e., stays triggerd if periodic, stops if oneShot
|
||||
callback(); |
||||
lock = false; |
||||
}
|
||||
} |
||||
|
||||
// void TckChannel::setPeriod(uint32_t microSeconds)
|
||||
// {
|
||||
// period = microSeconds * (F_CPU / 1'000'000) ;
|
||||
// }
|
||||
uint32_t TckChannel::getPeriod() |
||||
{ |
||||
return period * (1'000'000.0f / F_CPU); |
||||
} |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,22 +0,0 @@ |
||||
#include "baseTimer.h" |
||||
#include "Arduino.h" |
||||
#include "types.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
|
||||
BaseTimer::BaseTimer(TimerGenerator* generator, bool periodic) |
||||
: timerGenerator(generator) |
||||
{ |
||||
this->timerGenerator = generator; |
||||
this->timerChannel = nullptr; |
||||
this->isPeriodic = periodic; |
||||
} |
||||
|
||||
errorCode BaseTimer::setPrescaler(int psc) |
||||
{ |
||||
this->prescaler = psc; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,41 @@ |
||||
#pragma once |
||||
|
||||
#include "config.h" |
||||
#include <type_traits> |
||||
|
||||
#if defined(USE_TIME_LITERALS) |
||||
#include "frequency.h" |
||||
#include <chrono> |
||||
#endif |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
//--------------------------------------------------------------
|
||||
// Transform arithmetic, period and frequency values to float
|
||||
// For constant inputs the transformations are calculated at compile time
|
||||
|
||||
// Arithmetic types
|
||||
template <class period_t, std::enable_if_t<std::is_arithmetic<period_t>::value, int> * = nullptr> |
||||
float constexpr period2us(period_t v) |
||||
{ |
||||
return (float)v; |
||||
} |
||||
|
||||
#if defined(USE_TIME_LITERALS) |
||||
|
||||
// Duration types (s, ms, ns...)
|
||||
template <class period_t, std::enable_if_t<std::chrono::__is_duration<period_t>::value, int> * = nullptr> |
||||
float constexpr period2us(period_t v) |
||||
{ |
||||
return (duration_cast<duration<float, std::micro>>(v).count()); |
||||
} |
||||
|
||||
// Frequency types (Hz, MHz...)
|
||||
template <class period_t, std::enable_if_t<TeensyTimerTool::__is_frequency<period_t>::value, int> * = nullptr> |
||||
float constexpr period2us(period_t v) |
||||
{ |
||||
return 1'000'000 / duration_cast<hertz>(v).count(); |
||||
} |
||||
#endif |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,66 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "ErrorHandling/error_codes.h" |
||||
#include "baseTimer.h" |
||||
#include "type_traits" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class OneShotTimer : public BaseTimer |
||||
{ |
||||
public: |
||||
inline OneShotTimer(TimerGenerator* generator = nullptr); |
||||
|
||||
inline errorCode begin(callback_t cb); |
||||
template <typename T> errorCode trigger(T delay); |
||||
template <typename T> errorCode triggerDirect(T reload); |
||||
template <typename T> errorCode getTriggerReload(float delay, T* reload); |
||||
|
||||
#if defined(USE_TIME_LITERALS) |
||||
template <typename T, typename ratio> |
||||
errorCode trigger(duration<T, ratio> _delay) |
||||
{ |
||||
T delay = duration_cast<microseconds>(_delay).count(); |
||||
return trigger(delay); |
||||
} |
||||
#endif |
||||
}; |
||||
|
||||
// Implementation ================================================
|
||||
|
||||
OneShotTimer::OneShotTimer(TimerGenerator* generator) |
||||
: BaseTimer(generator, false) |
||||
{} |
||||
|
||||
errorCode OneShotTimer::begin(callback_t callback) |
||||
{ |
||||
return BaseTimer::begin(callback, 0, false); |
||||
} |
||||
|
||||
template <typename T> |
||||
errorCode OneShotTimer::trigger(T delay) |
||||
{ |
||||
static_assert(std::is_integral<T>() || std::is_floating_point<T>(), "Only floating point or integral types allowed"); |
||||
|
||||
errorCode result; |
||||
|
||||
if (std::is_floating_point<T>()) |
||||
result = timerChannel->trigger((float)delay); |
||||
else |
||||
result = timerChannel->trigger((uint32_t)delay); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
template <typename T> |
||||
errorCode OneShotTimer::triggerDirect(T reload) |
||||
{ |
||||
return timerChannel->triggerDirect(reload); |
||||
} |
||||
|
||||
template <typename T> |
||||
errorCode OneShotTimer::getTriggerReload(float delay, T* reload) |
||||
{ |
||||
return timerChannel->getTriggerReload(delay, reload); |
||||
} |
||||
} |
@ -1,22 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "baseTimer.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class PeriodicTimer : public BaseTimer |
||||
{ |
||||
public: |
||||
PeriodicTimer(TimerGenerator* generator = nullptr) |
||||
: BaseTimer(generator, true) {} |
||||
|
||||
template <class T, std::enable_if_t<std::is_arithmetic<T>::value, int>* = nullptr> |
||||
errorCode setPeriod(T p) { return postError(timerChannel->setPeriod((float)p)); } |
||||
|
||||
template <class T, std::enable_if_t<std::is_arithmetic<T>::value, int>* = nullptr> |
||||
errorCode setNextPeriod(T p) { return postError(timerChannel->setNextPeriod((float)p)); } |
||||
}; |
||||
|
||||
// IMPLEMENTATION =====================================================================
|
||||
|
||||
} |
Loading…
Reference in new issue