Adding newer libraries for Synth_Dexed and TeensyTimerTool.

dev
Holger Wirtz 3 years ago
parent 5f92dd7844
commit eb8e483801
  1. 69
      third-party/Synth_Dexed/examples/synth_dexed.ino
  2. 165
      third-party/Synth_Dexed/keywords.txt
  3. 31
      third-party/Synth_Dexed/src/synth_dexed.cpp
  4. 95
      third-party/Synth_Dexed/src/synth_dexed.h
  5. 33
      third-party/TeensyTimerTool/examples/01_Basic/RTC_Timer/RTC_Timer.ino
  6. 5
      third-party/TeensyTimerTool/library.json
  7. 8
      third-party/TeensyTimerTool/library.properties
  8. 10
      third-party/TeensyTimerTool/src/API/Timer.cpp
  9. 30
      third-party/TeensyTimerTool/src/API/baseTimer.cpp
  10. 49
      third-party/TeensyTimerTool/src/API/baseTimer.h
  11. 57
      third-party/TeensyTimerTool/src/API/oneShotTimer.h
  12. 21
      third-party/TeensyTimerTool/src/API/periodicTimer.h
  13. 5
      third-party/TeensyTimerTool/src/API/timer.h
  14. 17
      third-party/TeensyTimerTool/src/ESP32-dummy/TCK/TCK.cpp
  15. 79
      third-party/TeensyTimerTool/src/ESP32-dummy/TCK/TCK.h
  16. 89
      third-party/TeensyTimerTool/src/ESP32-dummy/TCK/TckChannel.h
  17. 4
      third-party/TeensyTimerTool/src/ErrorHandling/error_codes.h
  18. 6
      third-party/TeensyTimerTool/src/ErrorHandling/error_handler.cpp
  19. 4
      third-party/TeensyTimerTool/src/ErrorHandling/error_handler.h
  20. 4
      third-party/TeensyTimerTool/src/ITimerChannel.h
  21. 110
      third-party/TeensyTimerTool/src/Teensy/FTM/FTM_Info.h
  22. 32
      third-party/TeensyTimerTool/src/Teensy/PIT4/PITMap.h
  23. 41
      third-party/TeensyTimerTool/src/Teensy/TCK/TCK.cpp
  24. 336
      third-party/TeensyTimerTool/src/Teensy/TCK/TckChannel.h
  25. 8
      third-party/TeensyTimerTool/src/TeensyTimerTool.h
  26. 10
      third-party/TeensyTimerTool/src/Timer.cpp
  27. 2
      third-party/TeensyTimerTool/src/TimerModules/FTM/FTM.h
  28. 2
      third-party/TeensyTimerTool/src/TimerModules/FTM/FTM_Channel.h
  29. 4
      third-party/TeensyTimerTool/src/TimerModules/FTM/FTM_ChannelInfo.h
  30. 109
      third-party/TeensyTimerTool/src/TimerModules/FTM/FTM_Info.h
  31. 14
      third-party/TeensyTimerTool/src/TimerModules/GPT/GPT.h
  32. 24
      third-party/TeensyTimerTool/src/TimerModules/GPT/GPTChannel.cpp
  33. 51
      third-party/TeensyTimerTool/src/TimerModules/GPT/GPTChannel.h
  34. 2
      third-party/TeensyTimerTool/src/TimerModules/GPT/GPTmap.h
  35. 2
      third-party/TeensyTimerTool/src/TimerModules/PIT4/PIT.cpp
  36. 2
      third-party/TeensyTimerTool/src/TimerModules/PIT4/PIT.h
  37. 3
      third-party/TeensyTimerTool/src/TimerModules/PIT4/PITChannel.h
  38. 40
      third-party/TeensyTimerTool/src/TimerModules/TCK/TCK.cpp
  39. 15
      third-party/TeensyTimerTool/src/TimerModules/TCK/TCK.h
  40. 144
      third-party/TeensyTimerTool/src/TimerModules/TCK/TckChannel.h
  41. 15
      third-party/TeensyTimerTool/src/TimerModules/TCK/TckChannelBase.cpp
  42. 4
      third-party/TeensyTimerTool/src/TimerModules/TCK/TckChannelBase.h
  43. 108
      third-party/TeensyTimerTool/src/TimerModules/TCK/tickCounters.cpp
  44. 68
      third-party/TeensyTimerTool/src/TimerModules/TCK/tickCounters.h
  45. 10
      third-party/TeensyTimerTool/src/TimerModules/TMR/TMR.h
  46. 80
      third-party/TeensyTimerTool/src/TimerModules/TMR/TMRChannel.h
  47. 14
      third-party/TeensyTimerTool/src/Uno-dummy/TCK/TCK.cpp
  48. 79
      third-party/TeensyTimerTool/src/Uno-dummy/TCK/TCK.h
  49. 89
      third-party/TeensyTimerTool/src/Uno-dummy/TCK/TckChannel.h
  50. 22
      third-party/TeensyTimerTool/src/baseTimer.cpp
  51. 13
      third-party/TeensyTimerTool/src/boardDef.h
  52. 54
      third-party/TeensyTimerTool/src/config.cpp
  53. 41
      third-party/TeensyTimerTool/src/helpers.h
  54. 66
      third-party/TeensyTimerTool/src/oneShotTimer.h
  55. 22
      third-party/TeensyTimerTool/src/periodicTimer.h
  56. 5
      third-party/TeensyTimerTool/src/types.h

@ -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)
#######################################

@ -440,13 +440,14 @@ void Dexed::getSamples(uint16_t n_samples, int16_t* buffer)
}
}
#if defined(TEENSY3_5) || defined(TEENSY3_6) || defined(TEENSY4)
fx.process(sumbuf, n_samples); // Needed for fx.Gain()!!!
#ifdef USE_SIMPLE_COMPRESSOR
// mild compression
for (i = 0; i < n_samples; i++)
{
s = abs(sumbuf[i]);
s = fabs(sumbuf[i]);
if (s > vuSignal)
vuSignal = s;
//else if (vuSignal > 0.001f)
@ -460,6 +461,22 @@ void Dexed::getSamples(uint16_t n_samples, int16_t* buffer)
//arm_scale_f32(sumbuf, 0.00015, sumbuf, AUDIO_BLOCK_SAMPLES);
arm_float_to_q15(sumbuf, buffer, AUDIO_BLOCK_SAMPLES);
}
#elif defined(USE_CIRCLE)
}
void Dexed::getSamples(uint16_t n_samples, uint32_t* buffer)
{
int16_t* i16_buffer=new (HEAP_DMA30) int16_t[n_samples];
if(i16_buffer)
{
getSamples(n_samples,i16_buffer);
for(uint8_t i=0;i<n_samples;i++)
buffer[i]=i16_buffer[i]+0xffff;
delete(i16_buffer);
}
}
#endif
void Dexed::keydown(int16_t pitch, uint8_t velo) {
if ( velo == 0 ) {
@ -1744,6 +1761,7 @@ void Dexed::getName(char* buffer)
buffer[10] = '\0';
}
#if defined(TEENSY3_5) || defined(TEENSY3_6) || defined(TEENSY4)
void AudioSynthDexed::update(void)
{
if (in_update == true)
@ -1778,6 +1796,13 @@ void AudioSynthDexed::update(void)
in_update = false;
};
#elif defined(USE_CIRCLE)
unsigned AudioSynthDexed::GetChunk(u32 *pBuffer, unsigned nChunkSize)
{
getSamples(nChunkSize, pBuffer);
return(nChunkSize);
};
#endif
/*
// https://www.musicdsp.org/en/latest/Effects/169-compressor.html#
@ -2066,9 +2091,9 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Co
uint32_t pmd = pitchmoddepth_ * lfo_delay; // Q32
int32_t senslfo = pitchmodsens_ * (lfo_val - (1 << 23));
int32_t pmod_1 = (((int64_t) pmd) * (int64_t) senslfo) >> 39;
pmod_1 = abs(pmod_1);
pmod_1 = fabs(pmod_1);
int32_t pmod_2 = (int32_t)(((int64_t)ctrls->pitch_mod * (int64_t)senslfo) >> 14);
pmod_2 = abs(pmod_2);
pmod_2 = fabs(pmod_2);
int32_t pitch_mod = max(pmod_1, pmod_2);
pitch_mod = pitchenv_.getsample() + (pitch_mod * (senslfo < 0 ? -1 : 1));

@ -25,13 +25,91 @@
#pragma once
#include "teensy_board_detection.h"
#if defined(TEENSY3_5) || defined(TEENSY3_6) || defined(TEENSY4)
#include <Arduino.h>
#include <Audio.h>
#include "teensy_board_detection.h"
#define SAMPLE_RATE 44100
#else
//
// START DEFINITIONS FOR CIRCLE
//
#define USE_CIRCLE
// define only one
//#define USE_I2S
//#define USE_HDMI
#ifdef USE_I2S
#include <circle/i2ssoundbasedevice.h>
#define SOUND_CLASS CI2SSoundBaseDevice
#define SAMPLE_RATE 192000
#define CHUNK_SIZE 8192
#define DAC_I2C_ADDRESS 0 // I2C slave address of the DAC (0 for auto probing)
#elif defined (USE_HDMI)
#include <circle/hdmisoundbasedevice.h>
#define SOUND_CLASS CHDMISoundBaseDevice
#define SAMPLE_RATE 48000
#define CHUNK_SIZE (384 * 10)
#else
#include <circle/pwmsoundbasedevice.h>
#define SOUND_CLASS CPWMSoundBaseDevice
#define SAMPLE_RATE 48000
#define CHUNK_SIZE 2048
#endif
#include <string.h>
#include <stdint.h>
#include <math.h>
#include <circle/interrupt.h>
#include <circle/i2cmaster.h>
#include <circle/usb/usbmidi.h>
#include <circle/usb/usbkeyboard.h>
#include <circle/serial.h>
#include <circle/types.h>
#include <circle/timer.h>
#include <circle/new.h>
#define constrain(amt, low, high) ({ \
__typeof__(amt) _amt = (amt); \
__typeof__(low) _low = (low); \
__typeof__(high) _high = (high); \
(_amt < _low) ? _low : ((_amt > _high) ? _high : _amt); \
})
static inline int32_t signed_saturate_rshift(int32_t val, int bits, int rshift)
{
int32_t out, max;
out = val >> rshift;
max = 1 << (bits - 1);
if (out >= 0)
{
if (out > max - 1) out = max - 1;
}
else
{
if (out < -max) out = -max;
}
return out;
}
unsigned millis (void)
{
return CTimer::Get ()->GetClockTicks () / (CLOCKHZ / 1000);
}
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#define PROGMEM
//
// END DEFINITIONS FOR CIRCLE
//
#endif
#define SYNTH_DEXED_VERSION "1.0.0"
//#define DEBUG 1
#define SAMPLE_RATE 44100
#define MIDI_CONTROLLER_MODE_MAX 2
#define TRANSPOSE_FIX 24
@ -1294,20 +1372,31 @@ class Dexed
Lfo lfo;
FmCore* engineMsfa;
void getSamples(uint16_t n_samples, int16_t* buffer);
void getSamples(uint16_t n_samples, uint32_t* buffer);
};
//=====================================================
/*****************************************************
CODE: orig_code/synth_microdexed.h
*****************************************************/
#if defined(TEENSY3_5) || defined(TEENSY3_6) || defined(TEENSY4)
class AudioSynthDexed : public AudioStream, public Dexed
{
public:
AudioSynthDexed(uint8_t max_notes, uint16_t sample_rate) : AudioStream(0, NULL), Dexed(max_notes,sample_rate) { };
~AudioSynthDexed(void) { };
protected:
const uint16_t audio_block_time_us = 1000000 / (SAMPLE_RATE / AUDIO_BLOCK_SAMPLES);
volatile bool in_update = false;
void update(void);
};
#elif defined(USE_CIRCLE)
class AudioSynthDexed : public Dexed, public SOUND_CLASS
{
public:
AudioSynthDexed(uint8_t max_notes,uint16_t sample_rate,CInterruptSystem *pInterrupt, CI2CMaster *pI2CMaster);
~AudioSynthDexed(void);
unsigned GetChunk (u32 *pBuffer, unsigned nChunkSize);
};
#endif

@ -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()
{
}

@ -9,13 +9,12 @@
},
"authors":
{
"name": "Lutz Niggl",
"email": "lutz.niggl@lunoptics.com",
"name": "luni64",
"url": "https://github.com/luni64",
"maintainer": true
},
"homepage": "https://github.com/luni64/TeensyTimerTool",
"version": "0.3.5",
"version": "0.4.3",
"frameworks": "arduino",
"platforms": "Teensy"
}

@ -1,9 +1,9 @@
name=TeensyTimerTool
version=0.3.5
author=Lutz Niggl <lutz.niggl@lunoptics.com>
maintainer=Lutz Niggl <lutz.niggl@lunoptics.com>
version=0.4.3
author=luni64
maintainer=luni64
sentence=Generic Interface to Teensy Timers
paragraph= TeensyTimerTool is a library that provides a generic, easy to use interface to the hardware timers (FTM, GPT, QUAD, PIT) of the PJRC Teensy boards. In addition, it provides up to 20 highly efficient software timers that use the same interface. All timers can be used in periodic and one-shot mode. Currently the library supports the ARM T3.X and T4.0 boards. You can either pick a free timer from a pool or specify exactly which of the available hardware or software timer modules you want to use.
paragraph= TeensyTimerTool is a library that provides a generic, easy to use interface to the hardware timers (FTM, GPT, QUAD, PIT) of the PJRC Teensy boards. In addition, it provides up to 20 highly efficient software timers based on the cycle counter or the RTC (32 and 64bit) that use the same interface. All timers can be used in periodic and one-shot mode. Currently the library supports the ARM T3.X and T4.0 boards. You can either pick a free timer from a pool or specify exactly which of the available hardware or software timer modules you want to use.
category=Timing
url=https://github.com/luni64/TeensyTimerTool
architectures=*

@ -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

@ -1,13 +1,15 @@
#pragma once
//#include "Arduino.h"
#include "Arduino.h"
#include "ErrorHandling/error_codes.h"
#include "ITimerChannel.h"
#include "helpers.h"
#include <type_traits>
#if defined(USE_TIME_LITERALS)
#include "frequency.h"
#include <chrono>
#include <cmath>
using namespace std::chrono_literals;
using namespace std::chrono;
#endif
@ -17,8 +19,8 @@ namespace TeensyTimerTool
class BaseTimer
{
public:
template <typename T>
inline errorCode begin(callback_t callback, T period, bool start = true);
template <typename period_t>
inline errorCode begin(callback_t callback, period_t period, bool start = true);
inline errorCode setPrescaler(int psc);
inline errorCode end();
inline errorCode start();
@ -27,38 +29,21 @@ namespace TeensyTimerTool
inline float getMaxPeriod() const;
protected:
template <class T, std::enable_if_t<std::is_arithmetic<T>::value, int>* = nullptr>
T getPeriod(T v) { return v; }
BaseTimer(TimerGenerator *generator, bool periodic);
virtual ~BaseTimer();
TimerGenerator *timerGenerator;
ITimerChannel *timerChannel;
bool isPeriodic;
uint32_t prescaler = 0;
#if defined(USE_TIME_LITERALS)
public:
template <typename dur = seconds>
inline float getMaxDuration() const { return getMaxPeriod() * dur::period::den / dur::period::num; }
protected:
template <class T, std::enable_if_t<std::chrono::__is_duration<T>::value, int>* = nullptr>
float getPeriod(T v) { return (duration_cast<duration<float, std::micro>>(v).count()); }
template <class T, std::enable_if_t<TeensyTimerTool::__is_frequency<T>::value, int>* = nullptr>
float getPeriod(T v) { return 1'000'000 / duration_cast<hertz>(v).count(); }
#endif
};
// INLINE IMPLEMENTATION ================================================
template <typename T>
errorCode BaseTimer::begin(callback_t callback, T p, bool start)
template <typename period_t>
errorCode BaseTimer::begin(callback_t callback, period_t p, bool start)
{
auto period = getPeriod(p);
float period = period2us(p); // transform from any period type to microseconds (float)
if (callback == nullptr) return postError(errorCode::callback);
if (isPeriodic && period == 0) return postError(errorCode::reload);
@ -95,22 +80,26 @@ namespace TeensyTimerTool
errorCode BaseTimer::start()
{
timerChannel->start();
return errorCode::OK; // hack, implement return value in timer interface
if (timerChannel)
return postError(timerChannel->start());
return postError(errorCode::notInitialized);
}
errorCode BaseTimer::stop()
{
if (timerChannel)
return postError(timerChannel->stop());
return postError(errorCode::notInitialized);
}
float BaseTimer::getMaxPeriod() const
{
if (timerChannel != nullptr)
{
return timerChannel->getMaxPeriod();
}
postError(errorCode::notInitialized);
return 0;
}
return NAN;
}
} // 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

@ -6,8 +6,7 @@
namespace TeensyTimerTool
{
//class [[deprecated("Use PeriodicTimer or OneShotTimer instead")]] Timer : public BaseTimer
class Timer : public BaseTimer
class [[deprecated("Consider using PeriodicTimer or OneShotTimer instead")]] Timer : public BaseTimer
{
public:
Timer(TimerGenerator *gen = nullptr);
@ -31,4 +30,4 @@ namespace TeensyTimerTool
{
timerChannel->trigger(delay);
}
}
} // 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

@ -2,8 +2,7 @@
namespace TeensyTimerTool
{
enum class errorCode
{
enum class errorCode {
OK = 0,
// Warnings
@ -20,7 +19,6 @@ namespace TeensyTimerTool
notImplemented = 105, // timer does not support this feature
notInitialized = 106,
// GTP Errors
GTP_err = 200,
GTP_err2 = 201,

@ -21,7 +21,7 @@ namespace TeensyTimerTool
// warnings
case errorCode::periodOverflow:
txt = "Period overflow, set to maximum";
txt = "Period overflow. Period was set to maximum value";
break;
case errorCode::wrongType:
txt = "Wrong parameter type";
@ -41,7 +41,7 @@ namespace TeensyTimerTool
txt = "Function not implemented for this timer";
break;
case errorCode::notInitialized:
txt = "Timer not initialized or available";
txt = "Timer not initialized or available. Did you call begin?";
break;
default:
@ -76,4 +76,4 @@ namespace TeensyTimerTool
errFunc = _errFunc;
}
}
} // namespace TeensyTimerTool

@ -1,7 +1,7 @@
#pragma once
#include "error_codes.h"
#include "Stream.h"
#include "error_codes.h"
namespace TeensyTimerTool
{
@ -14,4 +14,4 @@ namespace TeensyTimerTool
protected:
Stream &stream;
};
}
} // namespace TeensyTimerTool

@ -20,14 +20,14 @@ namespace TeensyTimerTool
virtual errorCode setPrescaler(int psc) { return postError(errorCode::notImplemented); }
virtual float getMaxPeriod() const = 0;
//virtual errorCode setPeriod(uint32_t microSeconds) { return postError(errorCode::notImplemented); };
virtual errorCode setPeriod(float microSeconds) { return postError(errorCode::notImplemented); };
//virtual errorCode setNextPeriod(uint32_t microSeconds) { return postError(errorCode::notImplemented); };
virtual errorCode setNextPeriod(float microSeconds) { return postError(errorCode::notImplemented); };
virtual uint32_t getPeriod() { return 0; }
inline void setCallback(callback_t);
virtual ~ITimerChannel(){};
protected:
inline ITimerChannel(callback_t *cbStorage = nullptr);
callback_t *pCallback;

@ -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)
{
}
}

@ -88,4 +88,4 @@ namespace TeensyTimerTool
template <unsigned m>
bool FTM_t<m>::isInitialized = false;
}
} // namespace TeensyTimerTool

@ -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
{

@ -1,7 +1,7 @@
#pragma once
#include "FTM_Info.h"
#include "../../types.h"
#include "types.h"
namespace TeensyTimerTool
{
@ -14,4 +14,4 @@ namespace TeensyTimerTool
FTM_CH_t *chRegs;
float ticksPerMicrosecond;
};
}
} // 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

@ -1,6 +1,7 @@
#pragma once
#include "GPTChannel.h"
//#include "Arduino.h"
namespace TeensyTimerTool
{
@ -9,6 +10,7 @@ namespace TeensyTimerTool
{
public:
static ITimerChannel *getTimer();
static void end();
protected:
static bool isInitialized;
@ -66,6 +68,16 @@ namespace TeensyTimerTool
asm volatile("dsb"); // wait until register changes propagated through the cache
}
template <unsigned tmoduleNr>
void GPT_t<tmoduleNr>::end()
{
//Serial.printf("end %d\n", tmoduleNr);
NVIC_DISABLE_IRQ(irq);
pGPT->CR = 0;
callback = nullptr;
isInitialized = false;
}
template <unsigned m>
bool GPT_t<m>::isInitialized = false;
@ -74,4 +86,4 @@ namespace TeensyTimerTool
template <unsigned m>
GptChannel *GPT_t<m>::channel = nullptr;
}
} // 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 "../../ITimerChannel.h"
#include "Arduino.h"
#include "GPTmap.h"
#include "ITimerChannel.h"
#include "core_pins.h"
namespace TeensyTimerTool
@ -10,7 +10,7 @@ namespace TeensyTimerTool
{
public:
inline GptChannel(IMXRT_GPT_t *, callback_t *);
inline virtual ~GptChannel();
virtual ~GptChannel();
inline errorCode begin(callback_t cb, float tcnt, bool periodic) override;
inline errorCode start() override;
@ -20,18 +20,19 @@ namespace TeensyTimerTool
inline errorCode triggerDirect(uint32_t delay) override;
inline errorCode getTriggerReload(float delay, uint32_t *reload) override;
inline float getMaxPeriod() const override { return getMaxMicros() / 1E6; }
inline errorCode setNextPeriod(float us) override;
inline errorCode setPeriod(float us) override;
inline float getMaxPeriod() const override { return getMaxMicros() / 1E6; }
bool periodic;
protected:
inline uint32_t microsecondToCycles(float micros) const;
inline uint32_t us2ticks(float micros) const;
inline float getMaxMicros() const;
IMXRT_GPT_t *regs;
uint32_t reload;
//uint32_t reload;
float clock;
};
@ -48,8 +49,7 @@ namespace TeensyTimerTool
this->periodic = periodic;
if (periodic)
{
reload = microsecondToCycles(period);
regs->OCR1 = reload;
regs->OCR1 = us2ticks(period);
}
setCallback(cb);
@ -71,15 +71,9 @@ namespace TeensyTimerTool
return errorCode::OK;
}
GptChannel::~GptChannel()
{
stop();
setCallback(nullptr);
}
errorCode GptChannel::trigger(float delay) //should be optimized somehow
{
return triggerDirect(microsecondToCycles(delay));
return triggerDirect(us2ticks(delay));
}
errorCode GptChannel::triggerDirect(uint32_t reload)
@ -94,11 +88,11 @@ namespace TeensyTimerTool
errorCode GptChannel::getTriggerReload(float delay, uint32_t *reload)
{
*reload = microsecondToCycles(delay);
*reload = us2ticks(delay);
return errorCode::OK;
}
uint32_t GptChannel::microsecondToCycles(float micros) const
uint32_t GptChannel::us2ticks(float micros) const
{
if (micros > getMaxMicros())
{
@ -113,4 +107,23 @@ namespace TeensyTimerTool
return (float)0xFFFF'FFFE / clock;
}
errorCode GptChannel::setNextPeriod(float us)
{
return errorCode::notImplemented;
}
errorCode GptChannel::setPeriod(float us) // not good, will generate one too long period if called before cnt == oldPeriod
{ // need to redo the timing using free running timer to get setPeriod and setNewPeriod working correctly
uint32_t newPeriod = us2ticks(us);
// uint32_t now = regs->CNT;
// if (now > newPeriod)
// {
// (*pCallback)(); // might generate reentrance issues, not a good idea...
// }
regs->OCR1 = newPeriod;
return errorCode::OK;
}
} // namespace TeensyTimerTool

@ -1,7 +1,7 @@
#pragma once
#include "imxrt.h"
#include <cstdint>
#include <imxrt.h>
namespace TeensyTimerTool
{

@ -8,6 +8,6 @@ namespace TeensyTimerTool
PITChannel PIT_t::channel[4] = {{0}, {1}, {2}, {3}};
uint32_t PITChannel::clockFactor = 1;
}
} // namespace TeensyTimerTool
#endif

@ -67,4 +67,4 @@ namespace TeensyTimerTool
asm volatile("dsb"); //wait until register changes propagated through the cache
}
}
} // 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

@ -1,6 +1,6 @@
#pragma once
//#include "TckChannelBase.h"
//#include "Arduino.h"
#include "TckChannel.h"
#include "core_pins.h"
@ -11,7 +11,8 @@ namespace TeensyTimerTool
class TCK_t
{
public:
template<typename counterType> static inline ITimerChannel* getTimer();
template <typename counterType>
static inline ITimerChannel *getTimer();
static inline void removeTimer(TckChannelBase *);
static inline void tick();
@ -33,9 +34,12 @@ namespace TeensyTimerTool
}
isInitialized = true;
// enable the cycle counter
// start the cycle counter if not already running
if (ARM_DWT_CYCCNT == ARM_DWT_CYCCNT)
{
ARM_DEMCR |= ARM_DEMCR_TRCENA;
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
}
// initialize the yield hook
#if defined(TEENSYDUINO) && YIELD_TYPE == YIELD_STANDARD
@ -43,7 +47,6 @@ namespace TeensyTimerTool
initYieldHook();
#endif
}
for (unsigned chNr = 0; chNr < NR_OF_TCK_TIMERS; chNr++)
{
if (channels[chNr] == nullptr)
@ -52,7 +55,6 @@ namespace TeensyTimerTool
return channels[chNr];
}
}
return nullptr;
}
@ -63,7 +65,6 @@ namespace TeensyTimerTool
if (channels[chNr] == channel)
{
channels[chNr] = nullptr;
delete channel;
break;
}
}
@ -79,4 +80,4 @@ namespace TeensyTimerTool
}
}
}
}
} // namespace TeensyTimerTool

@ -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

@ -8,8 +8,6 @@ namespace TeensyTimerTool
{
public:
virtual bool tick() = 0;
virtual ~TckChannelBase() = 0;
virtual ~TckChannelBase();
};
inline TckChannelBase::~TckChannelBase() {}
}

@ -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

@ -17,7 +17,9 @@ namespace TeensyTimerTool
static callback_t callbacks[4];
// the following is calculated at compile time
static constexpr IRQ_NUMBER_t irq = moduleNr == 0 ? IRQ_QTIMER1 : moduleNr == 1 ? IRQ_QTIMER2 : moduleNr == 2 ? IRQ_QTIMER3 : IRQ_QTIMER4;
static constexpr IRQ_NUMBER_t irq = moduleNr == 0 ? IRQ_QTIMER1 : moduleNr == 1 ? IRQ_QTIMER2
: moduleNr == 2 ? IRQ_QTIMER3
: IRQ_QTIMER4;
static IMXRT_TMR_t *const pTMR;
static IMXRT_TMR_CH_t *const pCH0;
static IMXRT_TMR_CH_t *const pCH1;
@ -29,7 +31,9 @@ namespace TeensyTimerTool
// IMPLEMENTATION ==================================================================
template <unsigned moduleNr> IMXRT_TMR_t* const TMR_t<moduleNr>::pTMR = moduleNr == 0 ? &IMXRT_TMR1 : moduleNr == 1 ? &IMXRT_TMR2 : moduleNr == 2 ? &IMXRT_TMR3 : &IMXRT_TMR4;
template <unsigned moduleNr> IMXRT_TMR_t *const TMR_t<moduleNr>::pTMR = moduleNr == 0 ? &IMXRT_TMR1 : moduleNr == 1 ? &IMXRT_TMR2
: moduleNr == 2 ? &IMXRT_TMR3
: &IMXRT_TMR4;
template <unsigned moduleNr> IMXRT_TMR_CH_t *const TMR_t<moduleNr>::pCH0 = &pTMR->CH[0];
template <unsigned moduleNr> IMXRT_TMR_CH_t *const TMR_t<moduleNr>::pCH1 = &pTMR->CH[1];
template <unsigned moduleNr> IMXRT_TMR_CH_t *const TMR_t<moduleNr>::pCH2 = &pTMR->CH[2];
@ -97,4 +101,4 @@ namespace TeensyTimerTool
template <unsigned m>
callback_t TMR_t<m>::callbacks[4];
}
} // namespace TeensyTimerTool

@ -1,10 +1,10 @@
#pragma once
#include "../../ITimerChannel.h"
//#include "Arduino.h"
#include <cmath>
#include "ErrorHandling/error_codes.h"
#include "config.h"
#include "imxrt.h"
#include <cmath>
namespace TeensyTimerTool
{
@ -22,6 +22,7 @@ namespace TeensyTimerTool
inline float getMaxPeriod() const override;
inline errorCode setPeriod(float us) override;
inline errorCode setNextPeriod(float us) override;
inline void setPrescaler(uint32_t psc); // psc 0..7 -> prescaler: 1..128
protected:
@ -30,7 +31,7 @@ namespace TeensyTimerTool
float pscValue;
uint32_t pscBits;
inline float_t microsecondToCounter(const float_t us) const;
errorCode us2Ticks(const float us, uint16_t *ticks) const;
inline float_t counterToMicrosecond(const float_t cnt) const;
};
@ -45,6 +46,7 @@ namespace TeensyTimerTool
TMRChannel::~TMRChannel()
{
regs->CTRL = 0x0000; // stop timer and mark it free
}
errorCode TMRChannel::start()
@ -62,25 +64,17 @@ namespace TeensyTimerTool
return errorCode::OK;
}
errorCode TMRChannel::begin(callback_t cb, float tcnt, bool periodic)
errorCode TMRChannel::begin(callback_t cb, float period, bool periodic)
{
const float_t t = microsecondToCounter(tcnt);
uint16_t reload;
if (t > 0xFFFF)
{
postError(errorCode::periodOverflow);
reload = 0xFFFE;
} else
{
reload = (uint16_t)t - 1;
}
errorCode status = us2Ticks(period, &reload);
regs->CTRL = 0x0000;
regs->LOAD = 0x0000;
regs->COMP1 = reload;
regs->CMPLD1 = reload;
regs->CNTR = 0x0000;
regs->CSCTRL = TMR_CSCTRL_CL1(1);
setCallback(cb);
if (!periodic)
@ -90,14 +84,16 @@ namespace TeensyTimerTool
regs->CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(pscBits) | TMR_CTRL_LENGTH;
start();
return t > 0xFFFF ? errorCode::periodOverflow : errorCode::OK;
return status;
}
errorCode TMRChannel::trigger(float tcnt) // quick and dirty, should be optimized
errorCode TMRChannel::trigger(float us) // quick and dirty, should be optimized
{
const float_t t = microsecondToCounter(tcnt);
uint16_t reload = t > 0xFFFF ? 0xFFFF : (uint16_t)t;
// const float_t t = us2Ticks(tcnt);
// uint16_t reload = t > 0xFFFF ? 0xFFFF : (uint16_t)t;
uint16_t reload;
errorCode status = us2Ticks(us, &reload);
regs->CTRL = 0x0000;
regs->LOAD = 0x0000;
@ -110,7 +106,7 @@ namespace TeensyTimerTool
regs->CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(pscBits) | TMR_CTRL_ONCE | TMR_CTRL_LENGTH;
return errorCode::OK;
return status;
}
void TMRChannel::setPrescaler(uint32_t psc) // psc 0..7 -> prescaler: 1..128
@ -124,10 +120,13 @@ namespace TeensyTimerTool
return pscValue / 150'000'000.0f * 0xFFFE;
}
// void TMRChannel::_setNextPeriod(const uint16_t cnt)
// {
// regs->CMPLD1 = cnt;
// }
errorCode TMRChannel::setNextPeriod(float us)
{
uint16_t reload;
errorCode status = us2Ticks(us, &reload);
regs->CMPLD1 = reload;
return status;
}
// errorCode TMRChannel::_setCurrentPeriod(const uint16_t cnt)
// {
@ -152,22 +151,33 @@ namespace TeensyTimerTool
errorCode TMRChannel::setPeriod(float us)
{
//const float_t t = microsecondToCounter(us);
// if (t <= 0xFFFF)
// {
// return _setCurrentPeriod(t);
// } else
// {
// return errorCode::periodOverflow;
// }
return errorCode::notImplemented;
uint16_t newReload;
errorCode status = us2Ticks(us, &newReload);
regs->CMPLD1 = newReload; // counter will load this value to COMP1 at next trigger
//
noInterrupts(); // interrupting this code could lead to wrong cntr settings
if (regs->CNTR > newReload) // already too late for new period
regs->CNTR = regs->COMP1; // -> force trigger; will also load COMP1 with value from CMPLD1
else // not too late
regs->COMP1 = newReload; // -> change current compare value to new one (counter _might_ be > newReload in between.. watch and fix if necessary)
interrupts();
return status;
}
errorCode TMRChannel::us2Ticks(const float us, uint16_t *ticks) const
{
constexpr uint16_t maxTicks = 0xFFFE;
float_t TMRChannel::microsecondToCounter(const float_t us) const
float tmpTicks = us * 150.0f / pscValue;
if (tmpTicks > maxTicks)
{
return us * 150.0f / pscValue;
*ticks = maxTicks;
return errorCode::periodOverflow;
}
*ticks = (uint16_t)tmpTicks;
return errorCode::OK;
}
float_t TMRChannel::counterToMicrosecond(const float_t cnt) const

@ -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;
}
}

@ -8,6 +8,11 @@ namespace TeensyTimerTool
// TEENSYDUINO ==========================================================================
#if defined(TEENSYDUINO)
#if defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY_MICROMOD)
#define TTT_TEENSY4X
#elif defined(ARDUINO_TEENSY30) || defined(ARDUINO_TEENSY31) || defined(ARDUINO_TEENSY32) || defined(ARDUINO_TEENSY35) || defined(ARDUINO_TEENSY36)
#define TTT_TEENSY3X
#endif
#if defined(ARDUINO_TEENSYLC)
extern TimerGenerator *const TCK;
@ -29,11 +34,11 @@ namespace TeensyTimerTool
extern TimerGenerator *const FTM0, *const FTM1, *const FTM2, *const FTM3, *const FTM4;
extern TimerGenerator *const TCK, * const TCK32, * const TCK64;
#elif defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY_MICROMOD)
#elif defined(TTT_TEENSY4X)
extern TimerGenerator *const TMR1, *const TMR2, *const TMR3, *const TMR4;
extern TimerGenerator *const GPT1, *const GPT2;
extern TimerGenerator *const PIT;
extern TimerGenerator *const TCK, * const TCK32, * const TCK64;
extern TimerGenerator *const TCK, * const TCK32, * const TCK64, *const TCK_RTC;
#else
#error BOARD NOT SUPPORTED
@ -56,10 +61,6 @@ namespace TeensyTimerTool
extern void(* const tick)();
// ESP32 ==========================================================================
#elif defined(ESP32)
//...
#else
# error "Board not supported"
#endif

@ -1,13 +1,14 @@
#include "config.h"
#include "TimerModules/TCK/TCK.h"
#include "TimerModules/TCK/tickCounters.h"
#include "boardDef.h"
using tick_t = void (*)();
#if defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY_MICROMOD)
#include "Teensy/TMR/TMR.h"
#include "Teensy/GPT/GPT.h"
#include "Teensy/PIT4/PIT.h"
#include "Teensy/TCK/TCK.h"
#include "TimerModules/GPT/GPT.h"
#include "TimerModules/PIT4/PIT.h"
#include "TimerModules/TMR/TMR.h"
namespace TeensyTimerTool
{
@ -21,22 +22,22 @@ using tick_t = void (*) ();
TimerGenerator *const PIT = PIT_t::getTimer;
TimerGenerator* const TCK = TCK_t::getTimer<uint32_t>;
TimerGenerator* const TCK32 = TCK_t::getTimer<uint32_t>; // same as TCK
TimerGenerator* const TCK64 = TCK_t::getTimer<uint64_t>;
TimerGenerator *const TCK = TCK_t::getTimer<CycleCounter32>;
TimerGenerator *const TCK32 = TCK_t::getTimer<CycleCounter32>; // same as TCK
TimerGenerator *const TCK64 = TCK_t::getTimer<CycleCounter64>;
TimerGenerator *const TCK_RTC = TCK_t::getTimer<RtcCounter>;
constexpr tick_t tick = &TCK_t::tick;
}
} // namespace TeensyTimerTool
#elif defined(ARDUINO_TEENSY35) || defined(ARDUINO_TEENSY36)
#include "Teensy/FTM/FTM.h"
#include "Teensy/TCK/TCK.h"
#include "TimerModules/FTM/FTM.h"
namespace TeensyTimerTool
{
TimerGenerator* const TCK = TCK_t::getTimer<uint32_t>;
TimerGenerator* const TCK32 = TCK_t::getTimer<uint32_t>; // same as TCK
TimerGenerator* const TCK64 = TCK_t::getTimer<uint64_t>;
TimerGenerator *const TCK = TCK_t::getTimer<CycleCounter32>;
TimerGenerator *const TCK32 = TCK_t::getTimer<CycleCounter32>; // same as TCK
TimerGenerator *const TCK64 = TCK_t::getTimer<CycleCounter64>;
TimerGenerator *const FTM0 = FTM_t<0>::getTimer;
TimerGenerator *const FTM1 = FTM_t<1>::getTimer;
@ -45,44 +46,43 @@ using tick_t = void (*) ();
TimerGenerator *const FTM4 = FTM_t<3>::getTimer;
constexpr tick_t tick = &TCK_t::tick;
}
} // namespace TeensyTimerTool
#elif defined(ARDUINO_TEENSY31) || defined(ARDUINO_TEENSY32)
#include "Teensy/FTM/FTM.h"
#include "Teensy/TCK/TCK.h"
#include "TimerModules/FTM/FTM.h"
namespace TeensyTimerTool
{
TimerGenerator* const TCK = TCK_t::getTimer<uint32_t>;
TimerGenerator* const TCK32 = TCK_t::getTimer<uint32_t>; // same as TCK
TimerGenerator* const TCK64 = TCK_t::getTimer<uint64_t>;
TimerGenerator *const TCK = TCK_t::getTimer<CycleCounter32>;
TimerGenerator *const TCK32 = TCK_t::getTimer<CycleCounter32>; // same as TCK
TimerGenerator *const TCK64 = TCK_t::getTimer<CycleCounter64>;
TimerGenerator *const FTM0 = FTM_t<0>::getTimer;
TimerGenerator *const FTM1 = FTM_t<1>::getTimer;
TimerGenerator *const FTM2 = FTM_t<2>::getTimer;
constexpr tick_t tick = &TCK_t::tick;
}
} // namespace TeensyTimerTool
#elif defined(ARDUINO_TEENSY30)
#include "Teensy/FTM/FTM.h"
#include "Teensy/TCK/TCK.h"
#include "TimerModules/FTM/FTM.h"
namespace TeensyTimerTool
{
TimerGenerator* const TCK = TCK_t::getTimer;
TimerGenerator *const TCK = TCK_t::getTimer<CycleCounter32>;
TimerGenerator *const TCK32 = TCK_t::getTimer<CycleCounter32>; // same as TCK
TimerGenerator *const TCK64 = TCK_t::getTimer<CycleCounter64>;
TimerGenerator *const FTM0 = FTM_t<0>::getTimer;
TimerGenerator *const FTM1 = FTM_t<1>::getTimer;
constexpr tick_t tick = &TCK_t::tick;
}
} // namespace TeensyTimerTool
#elif defined(ARDUINO_TEENSYLC)
#include "Teensy/TCK/TCK.h"
namespace TeensyTimerTool
{
TimerGenerator* const TCK = TCK_t::getTimer<uint32_t>;
TimerGenerator *const TCK = TCK_t::getTimer<MicrosCounter>;
constexpr tick_t tick = &TCK_t::tick;
}
} // namespace TeensyTimerTool
#endif

@ -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 =====================================================================
}

@ -16,7 +16,7 @@
extern void attachErrFunc(errorFunc_t);
extern errorCode postError(errorCode);
}
} // namespace TeensyTimerTool
#else
namespace TeensyTimerTool
{
@ -25,6 +25,5 @@
extern void attachErrFunc(errorFunc_t);
extern errorCode postError(errorCode);
}
} // namespace TeensyTimerTool
#endif

Loading…
Cancel
Save