parent
ebde14e11d
commit
dd97c55117
@ -1,21 +0,0 @@ |
||||
MIT License |
||||
|
||||
Copyright (c) 2019 Lutz Niggl |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
@ -1,7 +0,0 @@ |
||||
# TeensyTimerTool |
||||
|
||||
The TeensyTimerTool is a library that provides a generic, easy to use interface to the hardware timers 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. |
||||
|
||||
- This way to the corresponding PJRC **[forum post](https://forum.pjrc.com/threads/59112-TeensyTimerTool)** |
||||
- This way to the documentation in the **[TeensyTimerTool WIKI](https://github.com/luni64/TeensyTimerTool/wiki)** |
||||
|
Before Width: | Height: | Size: 96 KiB |
@ -1,31 +0,0 @@ |
||||
#include "TeensyTimerTool.h" |
||||
using namespace TeensyTimerTool; |
||||
|
||||
|
||||
|
||||
//Timer t[]{FTM0, FTM0, FTM2}; // two channels from FTM0, one from FTM2
|
||||
//Timer t[3]; // use 3 timers from the pool
|
||||
OneShotTimer t[]{FTM0, FTM0, FTM0, FTM0, FTM0, FTM0, FTM0, FTM0}; // all 8 channels of FTM0
|
||||
|
||||
constexpr unsigned nrOfTimers = sizeof(t) / sizeof(t[0]); |
||||
|
||||
void setup() |
||||
{ |
||||
// setup timers, use lambdas as callbacks
|
||||
for (unsigned i = 0; i < nrOfTimers; i++) |
||||
{ |
||||
pinMode(i, OUTPUT); |
||||
t[i].begin([i] { digitalWriteFast(i, LOW); }); // callback resets pin to LOW
|
||||
} |
||||
} |
||||
|
||||
|
||||
void loop() |
||||
{ |
||||
for (unsigned i = 0; i < nrOfTimers; i++) |
||||
{ |
||||
digitalWriteFast(i, HIGH); |
||||
t[i].trigger(50 * (i + 1)); // 50, 100, 150 ... µs
|
||||
} |
||||
delay(1); |
||||
} |
@ -1,3 +0,0 @@ |
||||
Measured output of the example sketch |
||||
|
||||
![Output](./../../assets/FTM0_8CH.jpg) |
@ -1,26 +0,0 @@ |
||||
#include "Arduino.h" |
||||
#include "TeensyTimerTool.h" |
||||
|
||||
using namespace TeensyTimerTool; |
||||
|
||||
void callback() |
||||
{ |
||||
digitalWriteFast(LED_BUILTIN, LOW); // switch off LED
|
||||
} |
||||
|
||||
|
||||
OneShotTimer timer1; // generate a timer from the pool (Pool: 2xGPT, 16xTMR(QUAD), 20xTCK)
|
||||
|
||||
void setup() |
||||
{ |
||||
pinMode(LED_BUILTIN,OUTPUT); |
||||
timer1.begin(callback); |
||||
} |
||||
|
||||
void loop() |
||||
{ |
||||
digitalWriteFast(LED_BUILTIN, HIGH); |
||||
timer1.trigger(10'000); // switch of after 10ms
|
||||
|
||||
delay(500); |
||||
} |
@ -1,29 +0,0 @@ |
||||
/********************************************************
|
||||
* Basic usage of the timer |
||||
* |
||||
* Generates a timer from the timer pool and |
||||
* starts it with a period of 250ms. |
||||
* The timer callback simply toggles the built in LED |
||||
* |
||||
********************************************************/ |
||||
|
||||
#include "TeensyTimerTool.h" |
||||
|
||||
using namespace TeensyTimerTool; |
||||
|
||||
void callback() |
||||
{ |
||||
digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN)); |
||||
} |
||||
|
||||
PeriodicTimer t1; // generate a timer from the pool (Pool: 2xGPT, 16xTMR(QUAD), 20xTCK)
|
||||
|
||||
void setup() |
||||
{ |
||||
pinMode(LED_BUILTIN,OUTPUT); |
||||
t1.begin(callback, 250'000); // 250ms
|
||||
} |
||||
|
||||
void loop() |
||||
{ |
||||
} |
@ -1,55 +0,0 @@ |
||||
//-----------------------
|
||||
// REQUIRES T4.x
|
||||
//-----------------------
|
||||
|
||||
#include "TeensyTimerTool.h" |
||||
|
||||
using namespace TeensyTimerTool; |
||||
|
||||
PeriodicTimer t1(TCK); // Tick-Timer does not use any hardware timer (20 32bit channels)
|
||||
PeriodicTimer t2(TMR1); // First channel on TMR1 aka QUAD timer module. (TMR1 - TMR4, four 16bit channels each)
|
||||
PeriodicTimer t3(GPT1); // GPT1 module (one 32bit channel per module)
|
||||
OneShotTimer t4(TMR1); // Second channel on TMR1
|
||||
|
||||
// Callbacks ===================================================================================
|
||||
|
||||
void pulse200ns() |
||||
{ |
||||
digitalWriteFast(1, HIGH); |
||||
delayNanoseconds(200); |
||||
digitalWriteFast(1, LOW); |
||||
} |
||||
|
||||
void pulse400ns() |
||||
{ |
||||
digitalWriteFast(2, HIGH); |
||||
delayNanoseconds(400); |
||||
digitalWriteFast(2, LOW); |
||||
} |
||||
|
||||
void LED_ON() |
||||
{ |
||||
digitalWriteFast(LED_BUILTIN, HIGH); // LED On
|
||||
t4.trigger(10'000); // trigger t4 to switch of after 10ms
|
||||
} |
||||
|
||||
void LED_OFF() |
||||
{ |
||||
digitalWriteFast(LED_BUILTIN, LOW); |
||||
} |
||||
|
||||
//================================================================================================
|
||||
|
||||
void setup() |
||||
{ |
||||
for (unsigned pin = 0; pin <= 13; pin++) pinMode(pin, OUTPUT); |
||||
|
||||
t1.begin(pulse200ns, 50'000); // 200ns pulse every 500 ms
|
||||
t2.begin(pulse400ns, 100); // 400ns pulse every 100 µs
|
||||
t3.begin(LED_ON, 1'000'000); // Switch LED on every second
|
||||
t4.begin(LED_OFF); // One shot timer to switch LED Off
|
||||
} |
||||
|
||||
void loop() |
||||
{ |
||||
} |
@ -1,33 +0,0 @@ |
||||
// 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() |
||||
{ |
||||
} |
@ -1,34 +0,0 @@ |
||||
#include "TeensyTimerTool.h" |
||||
using namespace TeensyTimerTool; |
||||
|
||||
PeriodicTimer t1(TCK); |
||||
PeriodicTimer t2(TCK); |
||||
|
||||
void isr1() |
||||
{ |
||||
Serial.printf("called @: %u ms\n", millis()); |
||||
} |
||||
|
||||
void isr2() |
||||
{ |
||||
digitalToggleFast(LED_BUILTIN); |
||||
} |
||||
|
||||
void isr3() |
||||
{ |
||||
digitalWriteFast(0,HIGH); |
||||
delayMicroseconds(10); |
||||
digitalWriteFast(0, LOW); |
||||
} |
||||
|
||||
void setup() |
||||
{ |
||||
pinMode(LED_BUILTIN, OUTPUT); |
||||
|
||||
t1.begin(isr1, 5.02s); // instead of 5020000 (µs)
|
||||
t2.begin(isr2, 25ms); // instead of 25000 (µs)
|
||||
} |
||||
|
||||
void loop() |
||||
{ |
||||
} |
@ -1,33 +0,0 @@ |
||||
#include "TeensyTimerTool.h" |
||||
using namespace TeensyTimerTool; |
||||
|
||||
OneShotTimer timer[]{TCK, TCK, TCK, TCK}; // 4 one-shot-timers
|
||||
PeriodicTimer pt1; // 1 periodic timer
|
||||
unsigned t_0; // start time
|
||||
|
||||
void isr() |
||||
{ |
||||
Serial.printf("called @: %u ms\n", millis() - t_0); |
||||
} |
||||
|
||||
void setup() |
||||
{ |
||||
while (!Serial) {} // wait for PC to connect the virtual serial port
|
||||
|
||||
for (OneShotTimer& t : timer) // for the sake of simplicity, attach the same isr to all timers in array
|
||||
{ |
||||
t.begin(isr); |
||||
} |
||||
|
||||
timer[0].trigger(10ms); // 10 ms
|
||||
timer[1].trigger(0.5s + 10ms); // 510 ms
|
||||
timer[2].trigger(2.5 * 0.3s + 20'000us / 2); // 760 ms
|
||||
timer[3].trigger(milliseconds(50) + microseconds(5000)); // 55ms
|
||||
t_0 = millis(); |
||||
|
||||
pt1.begin([] { digitalToggleFast(LED_BUILTIN); }, 0.5s); |
||||
} |
||||
|
||||
void loop() |
||||
{ |
||||
} |
@ -1,29 +0,0 @@ |
||||
#include "TeensyTimerTool.h" |
||||
|
||||
using namespace TeensyTimerTool; |
||||
|
||||
void callback(int& someInt, int cnt) // this callback has context, i.e. parameter
|
||||
{ |
||||
for (int i = 0; i < cnt; i++) // when called, print out someInt cnt times
|
||||
{ |
||||
Serial.print(someInt); |
||||
Serial.print(" | "); |
||||
} |
||||
Serial.println(); |
||||
} |
||||
|
||||
//==============================================================
|
||||
|
||||
PeriodicTimer t; |
||||
int number = 0; |
||||
|
||||
void setup() |
||||
{ |
||||
t.begin([] { callback(number, 5); }, 50ms); |
||||
} |
||||
|
||||
void loop() |
||||
{ |
||||
number++; // change every second
|
||||
delay(1000); |
||||
} |
@ -1,21 +0,0 @@ |
||||
|
||||
#include "TeensyTimerTool.h" |
||||
#include "pins.h" |
||||
|
||||
using namespace TeensyTimerTool; |
||||
using namespace pins; |
||||
|
||||
pin<13> LED(OUTPUT); |
||||
OneShotTimer timer; |
||||
|
||||
void setup() |
||||
{ |
||||
timer.begin([] { LED = LOW; }); |
||||
} |
||||
|
||||
void loop() |
||||
{ |
||||
LED = HIGH; |
||||
timer.trigger(25'000); |
||||
delay(1'000); |
||||
} |
@ -1,253 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
#include <core_pins.h> |
||||
#include <type_traits> |
||||
|
||||
namespace pins |
||||
{ |
||||
namespace // private
|
||||
{ |
||||
enum boards { |
||||
notDefined = -1, |
||||
T_LC, |
||||
T3_0_1_2, |
||||
T3_5_6, |
||||
}; |
||||
|
||||
#if defined(__MKL26Z64__) |
||||
constexpr boards board = boards::T_LC; |
||||
#elif defined(__MK20DX128__) || defined(__MK20DX256__) |
||||
constexpr boards board = boards::T3_0_1_2; |
||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) |
||||
constexpr boards board = boards::T3_5_6; |
||||
#else |
||||
constexpr boards board = boards::notDefined; |
||||
#endif |
||||
static_assert(board != boards::notDefined, "Error in Pin.h"); |
||||
|
||||
// Indices into GPIOx and PORT arrays below
|
||||
enum portList { |
||||
na = -1, Port_A, Port_B, Port_C, Port_D, Port_E |
||||
}; |
||||
|
||||
//Base adresses of the GPIOx register blocks
|
||||
constexpr uintptr_t GPIOx_PDOR[] = |
||||
{ |
||||
(uintptr_t)&(GPIOA_PDOR), |
||||
(uintptr_t)&(GPIOB_PDOR), |
||||
(uintptr_t)&(GPIOC_PDOR), |
||||
(uintptr_t)&(GPIOD_PDOR), |
||||
(uintptr_t)&(GPIOE_PDOR), |
||||
}; |
||||
|
||||
// Base adresses of the Pin Control Registers
|
||||
constexpr uintptr_t PORTx_PCR0[] = |
||||
{ |
||||
(uintptr_t)&(PORTA_PCR0), |
||||
(uintptr_t)&(PORTB_PCR0), |
||||
(uintptr_t)&(PORTC_PCR0), |
||||
(uintptr_t)&(PORTD_PCR0), |
||||
(uintptr_t)&(PORTE_PCR0), |
||||
}; |
||||
|
||||
//----------------------------------------------------------------
|
||||
// Translate Teensy pin number to port and bitnr
|
||||
// The map will be used by the complier only, no code will be generated
|
||||
|
||||
struct pinInfo { |
||||
const portList port; |
||||
const int pin; |
||||
}; |
||||
|
||||
constexpr pinInfo pinMap[][3] = |
||||
{ // T-LC T3.0/1/2 T3.5/6
|
||||
/* Pin 0 */{ { Port_B, 16 },{ Port_B, 16 },{ Port_B, 16 } }, |
||||
/* Pin 1 */{ { Port_B, 17 },{ Port_B, 17 },{ Port_B, 17 } }, |
||||
/* Pin 2 */{ { Port_D, 0 },{ Port_D, 0 },{ Port_D, 0 } }, |
||||
/* Pin 3 */{ { Port_A, 1 },{ Port_A, 12 },{ Port_A, 12 } }, |
||||
/* Pin 4 */{ { Port_A, 2 },{ Port_A, 13 },{ Port_A, 13 } }, |
||||
/* Pin 5 */{ { Port_D, 7 },{ Port_D, 7 },{ Port_D, 7 } }, |
||||
/* Pin 6 */{ { Port_D, 4 },{ Port_D, 4 },{ Port_D, 4 } }, |
||||
/* Pin 7 */{ { Port_D, 2 },{ Port_D, 2 },{ Port_D, 2 } }, |
||||
/* Pin 8 */{ { Port_D, 3 },{ Port_D, 3 },{ Port_D, 3 } }, |
||||
/* Pin 9 */{ { Port_C, 3 },{ Port_C, 3 },{ Port_C, 3 } }, |
||||
/* Pin 10*/{ { Port_C, 4 },{ Port_C, 4 },{ Port_C, 4 } }, |
||||
/* Pin 11*/{ { Port_C, 6 },{ Port_C, 6 },{ Port_C, 6 } }, |
||||
/* Pin 12*/{ { Port_C, 7 },{ Port_C, 7 },{ Port_C, 7 } }, |
||||
/* Pin 13*/{ { Port_C, 5 },{ Port_C, 5 },{ Port_C, 5 } }, |
||||
/* Pin 14*/{ { Port_D, 1 },{ Port_D, 1 },{ Port_D, 1 } }, |
||||
/* Pin 15*/{ { Port_C, 0 },{ Port_C, 0 },{ Port_C, 0 } }, |
||||
/* Pin 16*/{ { Port_B, 0 },{ Port_B, 0 },{ Port_B, 0 } }, |
||||
/* Pin 17*/{ { Port_B, 1 },{ Port_B, 1 },{ Port_B, 1 } }, |
||||
/* Pin 18*/{ { Port_B, 3 },{ Port_B, 3 },{ Port_B, 3 } }, |
||||
/* Pin 19*/{ { Port_B, 2 },{ Port_B, 2 },{ Port_B, 2 } }, |
||||
/* Pin 20*/{ { Port_D, 5 },{ Port_D, 5 },{ Port_D, 5 } }, |
||||
/* Pin 21*/{ { Port_D, 6 },{ Port_D, 6 },{ Port_D, 6 } }, |
||||
/* Pin 22*/{ { Port_C, 1 },{ Port_C, 1 },{ Port_C, 1 } }, |
||||
/* Pin 23*/{ { Port_C, 2 },{ Port_C, 2 },{ Port_C, 2 } }, |
||||
/* Pin 24*/{ { Port_E, 20 },{ Port_A, 5 },{ Port_E, 26 } }, |
||||
/* Pin 25*/{ { Port_E, 21 },{ Port_B, 19 },{ Port_A, 5 } }, |
||||
/* Pin 26*/{ { Port_E, 30 },{ Port_E, 1 },{ Port_A, 14 } }, |
||||
/* Pin 27*/{ { na, -1 },{ Port_C, 9 },{ Port_A, 15 } }, |
||||
/* Pin 28*/{ { na, -1 },{ Port_C, 8 },{ Port_A, 16 } }, |
||||
/* Pin 29*/{ { na, -1 },{ Port_C, 10 },{ Port_B, 18 } }, |
||||
/* Pin 30*/{ { na, -1 },{ Port_C, 5 },{ Port_B, 19 } }, |
||||
/* Pin 31*/{ { na, -1 },{ Port_E, 6 },{ Port_B, 10 } }, |
||||
/* Pin 32*/{ { na, -1 },{ Port_B, 1 },{ Port_B, 11 } }, |
||||
/* Pin 33*/{ { na, -1 },{ Port_A, 2 },{ Port_E, 24 } }, |
||||
/* Pin 34*/{ { na, -1 },{ na, -1 },{ Port_E, 25 } }, |
||||
/* Pin 35*/{ { na, -1 },{ na, -1 },{ Port_C, 8 } }, |
||||
/* Pin 36*/{ { na, -1 },{ na, -1 },{ Port_C, 9 } }, |
||||
/* Pin 37*/{ { na, -1 },{ na, -1 },{ Port_C, 10 } }, |
||||
/* Pin 38*/{ { na, -1 },{ na, -1 },{ Port_C, 11 } }, |
||||
/* Pin 39*/{ { na, -1 },{ na, -1 },{ Port_A, 17 } }, |
||||
/* Pin 40*/{ { na, -1 },{ na, -1 },{ Port_A, 28 } }, |
||||
/* Pin 41*/{ { na, -1 },{ na, -1 },{ Port_A, 29 } }, |
||||
/* Pin 42*/{ { na, -1 },{ na, -1 },{ Port_A, 26 } }, |
||||
/* Pin 43*/{ { na, -1 },{ na, -1 },{ Port_B, 20 } }, |
||||
/* Pin 44*/{ { na, -1 },{ na, -1 },{ Port_B, 22 } }, |
||||
/* Pin 45*/{ { na, -1 },{ na, -1 },{ Port_B, 23 } }, |
||||
/* Pin 46*/{ { na, -1 },{ na, -1 },{ Port_B, 21 } }, |
||||
/* Pin 47*/{ { na, -1 },{ na, -1 },{ Port_D, 8 } }, |
||||
/* Pin 48*/{ { na, -1 },{ na, -1 },{ Port_D, 9 } }, |
||||
/* Pin 49*/{ { na, -1 },{ na, -1 },{ Port_B, 4 } }, |
||||
/* Pin 50*/{ { na, -1 },{ na, -1 },{ Port_B, 5 } }, |
||||
/* Pin 51*/{ { na, -1 },{ na, -1 },{ Port_D, 14 } }, |
||||
/* Pin 52*/{ { na, -1 },{ na, -1 },{ Port_D, 13 } }, |
||||
/* Pin 53*/{ { na, -1 },{ na, -1 },{ Port_D, 12 } }, |
||||
/* Pin 54*/{ { na, -1 },{ na, -1 },{ Port_D, 15 } }, |
||||
/* Pin 55*/{ { na, -1 },{ na, -1 },{ Port_D, 11 } }, |
||||
/* Pin 56*/{ { na, -1 },{ na, -1 },{ Port_E, 10 } }, |
||||
/* Pin 57*/{ { na, -1 },{ na, -1 },{ Port_E, 11 } }, |
||||
/* Pin 58*/{ { na, -1 },{ na, -1 },{ Port_E, 0 } }, |
||||
/* Pin 59*/{ { na, -1 },{ na, -1 },{ Port_E, 1 } }, |
||||
/* Pin 60*/{ { na, -1 },{ na, -1 },{ Port_E, 2 } }, |
||||
/* Pin 61*/{ { na, -1 },{ na, -1 },{ Port_E, 3 } }, |
||||
/* Pin 62*/{ { na, -1 },{ na, -1 },{ Port_E, 4 } }, |
||||
/* Pin 63*/{ { na, -1 },{ na, -1 },{ Port_E, 5 } }, |
||||
}; |
||||
} |
||||
|
||||
// Pin Mux constants
|
||||
enum pinMux |
||||
{ |
||||
ALT0 = 0, |
||||
ALT1, ALT2, ALT3, ALT4, ALT5, ALT6, ALT7 |
||||
}; |
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// Pin class
|
||||
// all methods static, no instances will be generated in code
|
||||
|
||||
template <unsigned pinNr> |
||||
class pin |
||||
{ |
||||
private: |
||||
// Calculate the adress of the pin control register
|
||||
static constexpr uintptr_t get_PORTx_PCRn_addr() |
||||
{ |
||||
static_assert(pinMap[pinNr][board].port != na && pinMap[pinNr][board].pin != -1, "Pin not supported by board"); |
||||
return PORTx_PCR0[(pinMap[pinNr][board]).port] + 4 * pinMap[pinNr][board].pin; |
||||
} |
||||
|
||||
// Calculate the adress of the bit banded GPIO registers of the pin
|
||||
static constexpr uintptr_t getPDORAdr() |
||||
{ |
||||
return 0x42000000 + 32 * (GPIOx_PDOR[pinMap[pinNr][board].port] - 0x40000000) + 4 * pinMap[pinNr][board].pin; |
||||
} |
||||
|
||||
static constexpr uintptr_t pcr = get_PORTx_PCRn_addr(); // Pin Control Register
|
||||
static constexpr uintptr_t pdorBB = getPDORAdr(); // Bitband adress of GPIOx_PDOR
|
||||
static constexpr uintptr_t psorBB = pdorBB + 4 * 32; // GPIOx_PSOR = GPIOx_PDOR + 4
|
||||
static constexpr uintptr_t pcorBB = psorBB + 4 * 32; // GPIOx_PCOR = GPIOx_PDOR + 8
|
||||
static constexpr uintptr_t ptorBB = pcorBB + 4 * 32; // GPIOx_PTOR = GPIOx_PDOR + 12
|
||||
static constexpr uintptr_t pdirBB = ptorBB + 4 * 32; // GPIOx_PDIR = GPIOx_PDOR + 16
|
||||
static constexpr uintptr_t pddrBB = pdirBB + 4 * 32; // GPIOx_PDDR = GPIOx_PDOR + 20
|
||||
|
||||
public: |
||||
// Construction (class contains only static members)
|
||||
pin() {} |
||||
pin(int i) { pinMode(i); } |
||||
|
||||
pin(const pin&) = delete; // disable copy constructor
|
||||
|
||||
// Setting and getting the pin value
|
||||
template<class T, typename = typename std::enable_if<std::is_integral<T>::value>::type> |
||||
operator T() const { return *reinterpret_cast<volatile uint32_t*>(pdirBB); } |
||||
operator bool() const { return *reinterpret_cast<volatile uint32_t*>(pdirBB) & 1; } |
||||
inline void operator = (const bool v) const { *reinterpret_cast<volatile uint32_t*>(pdorBB) = v; } // assignment --> somePin = HIGH
|
||||
inline void operator = (const pin& v) const = delete; // disable copying
|
||||
|
||||
// Pin operations
|
||||
static inline void toggle() { *reinterpret_cast<volatile uint32_t*>(ptorBB) = 1; } // toggles pin
|
||||
//static inline int getValue() { return *reinterpret_cast<volatile uint32_t*>(pdirBB); } // returns pin value (usefull for static calls)
|
||||
//static inline void setValue(const int v) { *reinterpret_cast<volatile uint32_t*>(pdorBB) = v; } // sets value (usefull for static calls)
|
||||
//static inline void setHIGH() { *reinterpret_cast<volatile uint32_t*>(psorBB) = 1; } // sets pin to HIGH (usefull for static calls)
|
||||
//static inline void setLOW() { *reinterpret_cast<volatile uint32_t*>(pcorBB) = 1; } // sets pin to LOW (usefull for static calls)
|
||||
|
||||
// Pin configuration
|
||||
static inline void pinMode(int mode) |
||||
{ |
||||
// replace by a call to pinMode(pinNr,mode) ??? TBD
|
||||
switch (mode) |
||||
{ |
||||
case OUTPUT: |
||||
*reinterpret_cast<volatile uint32_t*>(pddrBB) = 1; //Pin direction register
|
||||
*reinterpret_cast<volatile uint32_t*>(pcr) = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); //Pin control register
|
||||
break; |
||||
case OUTPUT_OPENDRAIN: |
||||
*reinterpret_cast<volatile uint32_t*>(pddrBB) = 1; |
||||
*reinterpret_cast<volatile uint32_t*>(pcr) = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1) | PORT_PCR_ODE; |
||||
break; |
||||
case INPUT: |
||||
*reinterpret_cast<volatile uint32_t*>(pddrBB) = 0; |
||||
*reinterpret_cast<volatile uint32_t*>(pcr) = PORT_PCR_MUX(1); |
||||
break; |
||||
case INPUT_PULLUP: |
||||
*reinterpret_cast<volatile uint32_t*>(pddrBB) = 0; |
||||
*reinterpret_cast<volatile uint32_t*>(pcr) = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; |
||||
break; |
||||
case INPUT_PULLDOWN: |
||||
*reinterpret_cast<volatile uint32_t*>(pddrBB) = 0; |
||||
*reinterpret_cast<volatile uint32_t*>(pcr) = PORT_PCR_MUX(1) | PORT_PCR_PE; |
||||
break; |
||||
case INPUT_DISABLE: |
||||
*reinterpret_cast<volatile uint32_t*>(pcr) = 0; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
static inline void driveStrengthEnable(bool enable) |
||||
{ |
||||
//TBD static_assert: pin has DSE capability
|
||||
if (enable) { |
||||
*reinterpret_cast<uint32_t*>(pcr) |= PORT_PCR_DSE; |
||||
} |
||||
else { |
||||
*reinterpret_cast<uint32_t*>(pcr) &= ~PORT_PCR_DSE; |
||||
} |
||||
} |
||||
|
||||
static inline void slowSlewRateEnable(bool enable) |
||||
{ |
||||
//TBD static_assert: pin has SRE capability
|
||||
if (enable) { |
||||
*reinterpret_cast<uint32_t*>(pcr) |= PORT_PCR_SRE; |
||||
} |
||||
else { |
||||
*reinterpret_cast<uint32_t*>(pcr) &= ~PORT_PCR_SRE; |
||||
} |
||||
} |
||||
|
||||
static inline void setMUX(pinMux altFunc) |
||||
{ |
||||
*reinterpret_cast<uint32_t*>(pcr) = (*reinterpret_cast<uint32_t*>(pcr) & ~PORT_PCR_MUX_MASK) | PORT_PCR_MUX(altFunc); |
||||
} |
||||
|
||||
static inline void attachInterrupt(void(*function)(void), int mode) |
||||
{ |
||||
::attachInterrupt(pinNr, function, mode); |
||||
} |
||||
}; |
||||
} |
@ -1,38 +0,0 @@ |
||||
#include "SystemController.h" |
||||
|
||||
// --> Uncomment if you have a control voltage on the pot pin <--
|
||||
// #include "ResponsiveAnalogRead.h"
|
||||
// constexpr unsigned potPin = A0;
|
||||
// ResponsiveAnalogRead pot(potPin, false);
|
||||
|
||||
SystemController sysControl; |
||||
|
||||
void setup() |
||||
{ |
||||
sysControl.begin(); |
||||
|
||||
sysControl.setExposureDelay(250); // set exposure delay (time between two exposures) to 250 µs
|
||||
sysControl.shoot(); // do a manual exposure
|
||||
delay(10); |
||||
sysControl.setExposureDelay(500); // same with 500µs delay between exposures
|
||||
sysControl.shoot(); |
||||
|
||||
sysControl.continuosMode(true); // start continuously shooting
|
||||
delay(1000); |
||||
sysControl.continuosMode(false); // stop after one second
|
||||
|
||||
delay(500); |
||||
sysControl.continuosMode(true); // start again
|
||||
} |
||||
|
||||
void loop() |
||||
{ |
||||
// --> Uncomment if you have a control voltage on the pot pin <--
|
||||
// pot.update();
|
||||
// if (pot.hasChanged())
|
||||
// {
|
||||
// unsigned expDelay = map(pot.getValue(), 0, 1023, 100, 500); // 0-3.3V analog value, maps to 100-500
|
||||
// controller.setExposureDelay(expDelay);
|
||||
// Serial.printf("Exposure Delay: %u µs\n", expDelay);
|
||||
// }
|
||||
} |
@ -1,32 +0,0 @@ |
||||
#pragma once |
||||
#include "PulseGenerator.h" |
||||
#include "TeensyTimerTool.h" |
||||
|
||||
class LaserController |
||||
{ |
||||
public: |
||||
void begin(unsigned preTriggerPin, unsigned triggerPin, unsigned camPin); |
||||
void shoot(); |
||||
|
||||
protected: |
||||
PulseGenerator preTrigger, trigger, camera; |
||||
}; |
||||
|
||||
void LaserController::begin(unsigned preTriggerPin, unsigned triggerPin, unsigned camPin) |
||||
{ |
||||
preTrigger.begin(preTriggerPin); |
||||
trigger.begin(triggerPin); |
||||
camera.begin(camPin); |
||||
} |
||||
|
||||
void LaserController::shoot() |
||||
{ |
||||
constexpr float t_warmup = 140 - 5.5; |
||||
constexpr float t_p = 10 - 3; |
||||
constexpr float t_camDelay = 130 - 7.5; |
||||
constexpr float t_int = 30 - 3; |
||||
|
||||
preTrigger.schedulePulse(0, t_p); // immediately generate the pretrigger pulse
|
||||
trigger.schedulePulse(t_warmup, t_p); // schedule the trigger pulse to start after the warmup time
|
||||
camera.schedulePulse(t_camDelay, t_int); // schedule the cam pulse after the camDelay time
|
||||
} |
@ -1,61 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "Arduino.h" |
||||
#include "TeensyTimerTool.h" |
||||
|
||||
class PulseGenerator |
||||
{ |
||||
public: |
||||
PulseGenerator(); // constructor, initializes non hardware related stuff
|
||||
void begin(unsigned pin); // initializes hardware related stuff
|
||||
void schedulePulse(float delay, float width); // schedules a 'width µs' wide pulse after a waiting time of 'delay µs'. Non blocking.
|
||||
|
||||
protected: |
||||
TeensyTimerTool::OneShotTimer pulseTimer; // used for generating the pulses
|
||||
void callback(); |
||||
|
||||
uint32_t pin; |
||||
float width; |
||||
}; |
||||
|
||||
|
||||
|
||||
void PulseGenerator::begin(unsigned pin) |
||||
{ |
||||
this->pin = pin; |
||||
pinMode(pin, OUTPUT); |
||||
digitalWriteFast(pin, LOW); |
||||
|
||||
pulseTimer.begin([this] { this->callback(); }); |
||||
} |
||||
|
||||
void PulseGenerator::schedulePulse(float delay, float _width) |
||||
{ |
||||
width = _width; // the timer callback needs to know the pulse width to generate the pulse
|
||||
|
||||
if (delay != 0) |
||||
{ |
||||
pulseTimer.trigger(delay); // this triggers the oneShot timer to fire after 'delay µs'
|
||||
} |
||||
else //delay == 0, directly generate the pulse
|
||||
{ |
||||
digitalWriteFast(pin, HIGH); |
||||
pulseTimer.trigger(width); // this triggers the oneShotTimer to fire after 'width µs'
|
||||
} |
||||
} |
||||
|
||||
void PulseGenerator::callback() |
||||
{ |
||||
if (digitalReadFast(pin) == LOW) |
||||
{ |
||||
digitalWriteFast(pin, HIGH); |
||||
pulseTimer.trigger(width); // re-trigger
|
||||
} else |
||||
{ |
||||
digitalWriteFast(pin, LOW); |
||||
} |
||||
} |
||||
|
||||
PulseGenerator::PulseGenerator() |
||||
: pulseTimer(TeensyTimerTool::FTM0) // use one of the 8 FTM0 channels
|
||||
{} |
@ -1 +0,0 @@ |
||||
### See https://github.com/luni64/TeensyTimerTool/wiki/Double-Exposure-Laser-Illuminator for a description of this example. |
@ -1,62 +0,0 @@ |
||||
#pragma once |
||||
#include "LaserController.h" |
||||
#include "TeensyTimerTool.h" |
||||
|
||||
class SystemController |
||||
{ |
||||
public: |
||||
SystemController(); |
||||
inline void begin(); |
||||
inline void shoot(); |
||||
|
||||
inline void continuosMode(bool on); |
||||
inline void setExposureDelay(unsigned delay); |
||||
|
||||
protected: |
||||
TeensyTimerTool::PeriodicTimer mainTimer; |
||||
LaserController lCtrl1, lCtrl2; |
||||
unsigned exposureDelay = 300; |
||||
}; |
||||
|
||||
SystemController::SystemController() |
||||
: mainTimer(TeensyTimerTool::TCK) {} // construct the main 15Hz timer, we use a TCK here
|
||||
|
||||
void SystemController::begin() |
||||
{ |
||||
constexpr unsigned repetitionRate = 15; // Hz
|
||||
|
||||
constexpr unsigned preTrig1_pin = 1; |
||||
constexpr unsigned trig1_pin = 2; |
||||
constexpr unsigned preTrig2_pin = 3; |
||||
constexpr unsigned trig2_pin = 4; |
||||
constexpr unsigned cam_pin = 5; |
||||
|
||||
lCtrl1.begin(preTrig1_pin, trig1_pin, cam_pin); |
||||
lCtrl2.begin(preTrig2_pin, trig2_pin, cam_pin); |
||||
|
||||
mainTimer.begin([this] { this->shoot(); }, 1E6 / repetitionRate, false); // attach callback but don't start yet
|
||||
} |
||||
|
||||
void SystemController::shoot() |
||||
{ |
||||
elapsedMicros stopwatch = 0; |
||||
lCtrl1.shoot(); |
||||
while (stopwatch < exposureDelay) { yield(); } |
||||
lCtrl2.shoot(); |
||||
} |
||||
|
||||
void SystemController::continuosMode(bool on) |
||||
{ |
||||
if (on) |
||||
{ |
||||
mainTimer.start(); |
||||
} else |
||||
{ |
||||
mainTimer.stop(); |
||||
} |
||||
} |
||||
|
||||
void SystemController::setExposureDelay(unsigned delay) |
||||
{ |
||||
exposureDelay = max(100u, min(500u, delay)); // limit to 100-500 µs
|
||||
} |
@ -1,39 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "core_pins.h" |
||||
#include <cstdint> |
||||
|
||||
struct GPIO_Info_t |
||||
{ |
||||
inline GPIO_Info_t(unsigned pin); |
||||
const uintptr_t pinCfg; |
||||
const unsigned gpioPortNr; |
||||
const unsigned gpioBitNr; |
||||
|
||||
char name[20]; |
||||
}; |
||||
|
||||
//======================================================================================
|
||||
#if defined(KINETISK) || defined(KINETISL) |
||||
|
||||
GPIO_Info_t::GPIO_Info_t(unsigned pin) |
||||
: pinCfg((uintptr_t)digital_pin_to_info_PGM[pin].config), // address of pin config register
|
||||
gpioPortNr((pinCfg - (uintptr_t)&PORTA_PCR0) / 0x1000), // cfg base addresses are 4kB aligned staring with PORTA_PCR0
|
||||
gpioBitNr((pinCfg & 0xFFF) / 4) // each bit has to 4 consecutive 32bit cfg registers
|
||||
{ |
||||
snprintf(name, 20, "GPIO%d_%02d", gpioPortNr, gpioBitNr); |
||||
} |
||||
|
||||
//======================================================================================
|
||||
#elif defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY_MICROMOD) |
||||
|
||||
|
||||
GPIO_Info_t::GPIO_Info_t(unsigned pin) |
||||
: pinCfg((uintptr_t)digital_pin_to_info_PGM[pin].reg), // address of pin config register
|
||||
gpioPortNr((pinCfg - (uintptr_t)&IMXRT_GPIO6) / 0x4000 + 6), // cfg base addresses are 4kB aligned staring with PORTA_PCR0
|
||||
gpioBitNr(__builtin_ffs(digital_pin_to_info_PGM[pin].mask) - 1) // each bit has to 4 consecutive 32bit cfg registers
|
||||
{ |
||||
snprintf(name, 20, "GPIO%d_%02d", gpioPortNr, gpioBitNr); |
||||
} |
||||
|
||||
#endif |
@ -1,213 +0,0 @@ |
||||
#include "core_pins.h" |
||||
|
||||
/*****
|
||||
* Unlike Teensy 4.x there is no information array in the core for the T3.x series |
||||
* We thus build the corresponding array from copies of the pin definitions in core_pins.h |
||||
*****/ |
||||
|
||||
|
||||
#if defined(ARDUINO_TEENSYLC) |
||||
|
||||
const int PwmTimerModule[CORE_NUM_DIGITAL] = { |
||||
[0 ... CORE_NUM_DIGITAL - 1] = -1, |
||||
[CORE_TPM0_CH0_PIN] = 0, |
||||
[CORE_TPM0_CH1_PIN] = 0, |
||||
[CORE_TPM0_CH2_PIN] = 0, |
||||
[CORE_TPM0_CH3_PIN] = 0, |
||||
[CORE_TPM0_CH4_PIN] = 0, |
||||
[CORE_TPM0_CH5_PIN] = 0, |
||||
[CORE_TPM1_CH0_PIN] = 1, |
||||
[CORE_TPM1_CH1_PIN] = 1, |
||||
[CORE_TPM2_CH0_PIN] = 2, |
||||
[CORE_TPM2_CH1_PIN] = 2, |
||||
}; |
||||
|
||||
const int PwmTimerType[CORE_NUM_DIGITAL] = { |
||||
[0 ... CORE_NUM_DIGITAL - 1] = 0, |
||||
[CORE_TPM0_CH0_PIN] = 2, |
||||
[CORE_TPM0_CH1_PIN] = 2, |
||||
[CORE_TPM0_CH2_PIN] = 2, |
||||
[CORE_TPM0_CH3_PIN] = 2, |
||||
[CORE_TPM0_CH4_PIN] = 2, |
||||
[CORE_TPM0_CH5_PIN] = 2, |
||||
[CORE_TPM1_CH0_PIN] = 2, |
||||
[CORE_TPM1_CH1_PIN] = 2, |
||||
[CORE_TPM2_CH0_PIN] = 2, |
||||
[CORE_TPM2_CH1_PIN] = 2, |
||||
}; |
||||
|
||||
//===========================================================================================
|
||||
#elif defined(ARDUINO_TEENSY30) |
||||
|
||||
const int PwmTimerModule[CORE_NUM_DIGITAL] = { |
||||
[0 ... CORE_NUM_DIGITAL - 1] = -1, |
||||
[CORE_FTM0_CH0_PIN] = 0, |
||||
[CORE_FTM0_CH1_PIN] = 0, |
||||
[CORE_FTM0_CH2_PIN] = 0, |
||||
[CORE_FTM0_CH3_PIN] = 0, |
||||
[CORE_FTM0_CH4_PIN] = 0, |
||||
[CORE_FTM0_CH5_PIN] = 0, |
||||
[CORE_FTM0_CH6_PIN] = 0, |
||||
[CORE_FTM0_CH7_PIN] = 0, |
||||
[CORE_FTM1_CH0_PIN] = 1, |
||||
[CORE_FTM1_CH1_PIN] = 1, |
||||
}; |
||||
|
||||
const int PwmTimerType[CORE_NUM_DIGITAL] = { |
||||
[0 ... CORE_NUM_DIGITAL - 1] = 0, |
||||
[CORE_FTM0_CH0_PIN] = 1, |
||||
[CORE_FTM0_CH1_PIN] = 1, |
||||
[CORE_FTM0_CH2_PIN] = 1, |
||||
[CORE_FTM0_CH3_PIN] = 1, |
||||
[CORE_FTM0_CH4_PIN] = 1, |
||||
[CORE_FTM0_CH5_PIN] = 1, |
||||
[CORE_FTM0_CH6_PIN] = 1, |
||||
[CORE_FTM0_CH7_PIN] = 1, |
||||
[CORE_FTM1_CH0_PIN] = 1, |
||||
[CORE_FTM1_CH1_PIN] = 1, |
||||
}; |
||||
|
||||
//===========================================================================================
|
||||
#elif defined(__MK20DX256__) |
||||
const int PwmTimerModule[CORE_NUM_DIGITAL] = { |
||||
[0 ... CORE_NUM_DIGITAL - 1] = -1, |
||||
[CORE_FTM0_CH0_PIN] = 0, |
||||
[CORE_FTM0_CH1_PIN] = 0, |
||||
[CORE_FTM0_CH0_PIN] = 0, |
||||
[CORE_FTM0_CH1_PIN] = 0, |
||||
[CORE_FTM0_CH2_PIN] = 0, |
||||
[CORE_FTM0_CH3_PIN] = 0, |
||||
[CORE_FTM0_CH4_PIN] = 0, |
||||
[CORE_FTM0_CH5_PIN] = 0, |
||||
[CORE_FTM0_CH6_PIN] = 0, |
||||
[CORE_FTM0_CH7_PIN] = 0, |
||||
[CORE_FTM1_CH0_PIN] = 1, |
||||
[CORE_FTM1_CH1_PIN] = 1, |
||||
[CORE_FTM2_CH0_PIN] = 2, |
||||
[CORE_FTM2_CH1_PIN] = 2, |
||||
}; |
||||
|
||||
//===========================================================================================
|
||||
const int PwmTimerType[CORE_NUM_DIGITAL] = { |
||||
[0 ... CORE_NUM_DIGITAL - 1] = 0, |
||||
[CORE_FTM0_CH0_PIN] = 1, |
||||
[CORE_FTM0_CH1_PIN] = 1, |
||||
[CORE_FTM0_CH0_PIN] = 1, |
||||
[CORE_FTM0_CH1_PIN] = 1, |
||||
[CORE_FTM0_CH2_PIN] = 1, |
||||
[CORE_FTM0_CH3_PIN] = 1, |
||||
[CORE_FTM0_CH4_PIN] = 1, |
||||
[CORE_FTM0_CH5_PIN] = 1, |
||||
[CORE_FTM0_CH6_PIN] = 1, |
||||
[CORE_FTM0_CH7_PIN] = 1, |
||||
[CORE_FTM1_CH0_PIN] = 1, |
||||
[CORE_FTM1_CH1_PIN] = 1, |
||||
[CORE_FTM2_CH0_PIN] = 1, |
||||
[CORE_FTM2_CH1_PIN] = 1, |
||||
}; |
||||
|
||||
//===========================================================================================
|
||||
#elif defined(ARDUINO_TEENSY35) |
||||
const int PwmTimerModule[CORE_NUM_DIGITAL] = { |
||||
[0 ... CORE_NUM_DIGITAL - 1] = -1, |
||||
[CORE_FTM0_CH0_PIN] = 0, |
||||
[CORE_FTM0_CH1_PIN] = 0, |
||||
[CORE_FTM0_CH2_PIN] = 0, |
||||
[CORE_FTM0_CH3_PIN] = 0, |
||||
[CORE_FTM0_CH4_PIN] = 0, |
||||
[CORE_FTM0_CH5_PIN] = 0, |
||||
[CORE_FTM0_CH6_PIN] = 0, |
||||
[CORE_FTM0_CH7_PIN] = 0, |
||||
[CORE_FTM1_CH0_PIN] = 1, |
||||
[CORE_FTM1_CH1_PIN] = 1, |
||||
[CORE_FTM2_CH0_PIN] = 2, |
||||
[CORE_FTM2_CH1_PIN] = 2, |
||||
[CORE_FTM3_CH0_PIN] = 3, |
||||
[CORE_FTM3_CH1_PIN] = 3, |
||||
[CORE_FTM3_CH2_PIN] = 3, |
||||
[CORE_FTM3_CH3_PIN] = 3, |
||||
[CORE_FTM3_CH4_PIN] = 3, |
||||
[CORE_FTM3_CH5_PIN] = 3, |
||||
[CORE_FTM3_CH6_PIN] = 3, |
||||
[CORE_FTM3_CH7_PIN] = 3, |
||||
}; |
||||
|
||||
const int PwmTimerType[CORE_NUM_DIGITAL] = { |
||||
[0 ... CORE_NUM_DIGITAL - 1] = 0, |
||||
[CORE_FTM0_CH0_PIN] = 1, |
||||
[CORE_FTM0_CH1_PIN] = 1, |
||||
[CORE_FTM0_CH2_PIN] = 1, |
||||
[CORE_FTM0_CH3_PIN] = 1, |
||||
[CORE_FTM0_CH4_PIN] = 1, |
||||
[CORE_FTM0_CH5_PIN] = 1, |
||||
[CORE_FTM0_CH6_PIN] = 1, |
||||
[CORE_FTM0_CH7_PIN] = 1, |
||||
[CORE_FTM1_CH0_PIN] = 1, |
||||
[CORE_FTM1_CH1_PIN] = 1, |
||||
[CORE_FTM2_CH0_PIN] = 1, |
||||
[CORE_FTM2_CH1_PIN] = 1, |
||||
[CORE_FTM3_CH0_PIN] = 1, |
||||
[CORE_FTM3_CH1_PIN] = 1, |
||||
[CORE_FTM3_CH2_PIN] = 1, |
||||
[CORE_FTM3_CH3_PIN] = 1, |
||||
[CORE_FTM3_CH4_PIN] = 1, |
||||
[CORE_FTM3_CH5_PIN] = 1, |
||||
[CORE_FTM3_CH6_PIN] = 1, |
||||
[CORE_FTM3_CH7_PIN] = 1, |
||||
}; |
||||
|
||||
//===========================================================================================
|
||||
#elif defined(ARDUINO_TEENSY36) |
||||
const int PwmTimerModule[CORE_NUM_DIGITAL] = { |
||||
[0 ... CORE_NUM_DIGITAL - 1] = -1, |
||||
[CORE_FTM0_CH0_PIN] = 0, |
||||
[CORE_FTM0_CH1_PIN] = 0, |
||||
[CORE_FTM0_CH2_PIN] = 0, |
||||
[CORE_FTM0_CH3_PIN] = 0, |
||||
[CORE_FTM0_CH4_PIN] = 0, |
||||
[CORE_FTM0_CH5_PIN] = 0, |
||||
[CORE_FTM0_CH6_PIN] = 0, |
||||
[CORE_FTM0_CH7_PIN] = 0, |
||||
[CORE_FTM1_CH0_PIN] = 1, |
||||
[CORE_FTM1_CH1_PIN] = 1, |
||||
[CORE_FTM2_CH0_PIN] = 2, |
||||
[CORE_FTM2_CH1_PIN] = 2, |
||||
[CORE_FTM3_CH0_PIN] = 3, |
||||
[CORE_FTM3_CH1_PIN] = 3, |
||||
[CORE_FTM3_CH2_PIN] = 3, |
||||
[CORE_FTM3_CH3_PIN] = 3, |
||||
[CORE_FTM3_CH4_PIN] = 3, |
||||
[CORE_FTM3_CH5_PIN] = 3, |
||||
[CORE_FTM3_CH6_PIN] = 3, |
||||
[CORE_FTM3_CH7_PIN] = 3, |
||||
[CORE_TPM1_CH0_PIN] = 1, |
||||
[CORE_TPM1_CH1_PIN] = 1, |
||||
}; |
||||
|
||||
const int PwmTimerType[CORE_NUM_DIGITAL] = { |
||||
[0 ... CORE_NUM_DIGITAL - 1] = 0, |
||||
[CORE_FTM0_CH0_PIN] = 1, |
||||
[CORE_FTM0_CH1_PIN] = 1, |
||||
[CORE_FTM0_CH2_PIN] = 1, |
||||
[CORE_FTM0_CH3_PIN] = 1, |
||||
[CORE_FTM0_CH4_PIN] = 1, |
||||
[CORE_FTM0_CH5_PIN] = 1, |
||||
[CORE_FTM0_CH6_PIN] = 1, |
||||
[CORE_FTM0_CH7_PIN] = 1, |
||||
[CORE_FTM1_CH0_PIN] = 1, |
||||
[CORE_FTM1_CH1_PIN] = 1, |
||||
[CORE_FTM2_CH0_PIN] = 1, |
||||
[CORE_FTM2_CH1_PIN] = 1, |
||||
[CORE_FTM3_CH0_PIN] = 1, |
||||
[CORE_FTM3_CH1_PIN] = 1, |
||||
[CORE_FTM3_CH2_PIN] = 1, |
||||
[CORE_FTM3_CH3_PIN] = 1, |
||||
[CORE_FTM3_CH4_PIN] = 1, |
||||
[CORE_FTM3_CH5_PIN] = 1, |
||||
[CORE_FTM3_CH6_PIN] = 1, |
||||
[CORE_FTM3_CH7_PIN] = 1, |
||||
[CORE_TPM1_CH0_PIN] = 2, |
||||
[CORE_TPM1_CH1_PIN] = 2, |
||||
}; |
||||
|
||||
#endif |
@ -1,62 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "core_pins.h" |
||||
#include <cstdio> |
||||
|
||||
struct PWM_TimerInfo_t |
||||
{ |
||||
inline PWM_TimerInfo_t(unsigned _pin = 0); |
||||
unsigned type; |
||||
unsigned module; |
||||
char name[20]; |
||||
}; |
||||
|
||||
//===========================================================================================================
|
||||
#if defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY_MICROMOD) |
||||
|
||||
// holds core info about used pwm timers. Struct is defined in pwm.c.
|
||||
// There is no header declaring it. So, we need to do this here:
|
||||
struct pwm_pin_info_struct |
||||
{ |
||||
uint8_t type; // 0=no pwm, 1=flexpwm, 2=quad
|
||||
uint8_t module; // 0-3, 0-3
|
||||
uint8_t channel; // 0=X, 1=A, 2=B
|
||||
uint8_t muxval; //
|
||||
}; |
||||
extern pwm_pin_info_struct pwm_pin_info[]; // This array holds the pwm timer info
|
||||
|
||||
PWM_TimerInfo_t::PWM_TimerInfo_t(unsigned pin) |
||||
{ |
||||
constexpr char timerNames[][9] = {"FLEX_PWM", "QUAD"}; |
||||
|
||||
type = pwm_pin_info[pin].type; |
||||
module = (pwm_pin_info[pin].module >> 4) + 1; |
||||
|
||||
if (type != 0) |
||||
snprintf(name, 20, "%s%d", timerNames[type - 1], module); |
||||
else |
||||
snprintf(name, 20, "no pwm"); |
||||
} |
||||
|
||||
//===========================================================================================================
|
||||
#elif defined(ARDUINO_TEENSYLC) || \ |
||||
defined(ARDUINO_TEENSY30) || defined(ARDUINO_TEENSY32) || \
|
||||
defined(ARDUINO_TEENSY35) || defined(ARDUINO_TEENSY36) |
||||
|
||||
extern "C" const int PwmTimerModule[CORE_NUM_DIGITAL]; |
||||
extern "C" const int PwmTimerType[CORE_NUM_DIGITAL]; |
||||
|
||||
PWM_TimerInfo_t::PWM_TimerInfo_t(unsigned pin) |
||||
{ |
||||
constexpr char timerNames[][9] = {"FTM", "TPM"}; |
||||
|
||||
type = PwmTimerType[pin]; |
||||
module = PwmTimerModule[pin]; |
||||
|
||||
if (type != 0) |
||||
snprintf(name, 20, "%s%d", timerNames[type - 1], module); |
||||
else |
||||
snprintf(name, 20, "none"); |
||||
} |
||||
|
||||
#endif |
@ -1,17 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "GPIO_Info.h" |
||||
#include "PWM_TimerInfo.h" |
||||
|
||||
struct PinInfo |
||||
{ |
||||
inline PinInfo(unsigned _pin) |
||||
: pin(_pin), |
||||
gpioInfo(pin), |
||||
pwmTimerInfo(pin) |
||||
{} |
||||
|
||||
const unsigned pin; |
||||
const GPIO_Info_t gpioInfo; |
||||
const PWM_TimerInfo_t pwmTimerInfo; |
||||
}; |
@ -1,57 +0,0 @@ |
||||
#include "Arduino.h" |
||||
|
||||
#include "PinInfo.h" |
||||
#include <algorithm> |
||||
|
||||
void printPins(PinInfo* pins[], unsigned nrOfPins); |
||||
|
||||
void setup() |
||||
{ |
||||
while (!Serial) {} |
||||
|
||||
// setup an array containing info for all digital pins
|
||||
PinInfo* pins[CORE_NUM_DIGITAL]; |
||||
for (unsigned i = 0; i < CORE_NUM_DIGITAL; i++) |
||||
{ |
||||
pins[i] = new PinInfo(i); |
||||
} |
||||
|
||||
// Print out info sorted by pin numbers
|
||||
Serial.println("-------------------------------"); |
||||
Serial.println(" Sorted by pin number"); |
||||
printPins(pins, CORE_NUM_DIGITAL); |
||||
|
||||
Serial.println("\n-------------------------------"); |
||||
Serial.println(" Sorted by PWM timer"); |
||||
std::sort(pins, pins + CORE_NUM_DIGITAL, [](PinInfo* a, PinInfo* b) { |
||||
if (a->pwmTimerInfo.type < b->pwmTimerInfo.type) return false; |
||||
if (a->pwmTimerInfo.type > b->pwmTimerInfo.type) return true; |
||||
if (a->pwmTimerInfo.module < b->pwmTimerInfo.module) return true; |
||||
return false; |
||||
}); |
||||
printPins(pins, CORE_NUM_DIGITAL); |
||||
|
||||
Serial.println("\n-------------------------------"); |
||||
Serial.println(" Sorted by GPIO register: "); |
||||
std::sort(pins, pins + CORE_NUM_DIGITAL, [](PinInfo* a, PinInfo* b) { |
||||
if (a->gpioInfo.gpioPortNr < b->gpioInfo.gpioPortNr) return true; |
||||
if (a->gpioInfo.gpioPortNr > b->gpioInfo.gpioPortNr) return false; |
||||
if (a->gpioInfo.gpioBitNr < b->gpioInfo.gpioBitNr) return true; |
||||
return false; |
||||
}); |
||||
printPins(pins, CORE_NUM_DIGITAL); |
||||
} |
||||
|
||||
void loop() {} |
||||
|
||||
// Helpers -------------------------------------------------------
|
||||
|
||||
void printPins(PinInfo* pins[], unsigned nrOfPins) |
||||
{ |
||||
Serial.println("Pin | GPIO Reg | PWM timer"); |
||||
Serial.println("----|------------|-------------"); |
||||
for (unsigned i = 0; i < nrOfPins; i++) |
||||
{ |
||||
Serial.printf("%02d | %-9s | %-10s\n", pins[i]->pin, pins[i]->gpioInfo.name, pins[i]->pwmTimerInfo.name); |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,20 +0,0 @@ |
||||
{ |
||||
"name": "TeensyTimerTool", |
||||
"keywords": "teensy, pjrc, timer, quad, gpt, tmr, pit, imxrt1062", |
||||
"description": "TeensyTimerTool is a library that provides a generic, easy to use interface to the hardware timers 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.", |
||||
"repository": |
||||
{ |
||||
"type": "git", |
||||
"url": "https://github.com/luni64/TeensyTimerTool" |
||||
}, |
||||
"authors": |
||||
{ |
||||
"name": "luni64", |
||||
"url": "https://github.com/luni64", |
||||
"maintainer": true |
||||
}, |
||||
"homepage": "https://github.com/luni64/TeensyTimerTool", |
||||
"version": "1.0.0", |
||||
"frameworks": "arduino", |
||||
"platforms": "Teensy" |
||||
} |
@ -1,10 +0,0 @@ |
||||
name=TeensyTimerTool |
||||
version=1.0.0 |
||||
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 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=* |
||||
includes=TeensyTimerTool.h |
@ -1,10 +0,0 @@ |
||||
#include "timer.h" |
||||
#include "config.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
Timer::Timer(TimerGenerator *generator) |
||||
: BaseTimer(generator, true) |
||||
{ |
||||
} |
||||
} // namespace TeensyTimerTool
|
@ -1,30 +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; |
||||
} |
||||
|
||||
BaseTimer::~BaseTimer() |
||||
{ |
||||
if (timerChannel != nullptr) |
||||
{ |
||||
delete timerChannel; |
||||
} |
||||
} |
||||
|
||||
errorCode BaseTimer::setPrescaler(int psc) |
||||
{ |
||||
this->prescaler = psc; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,115 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#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 |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class BaseTimer |
||||
{ |
||||
public: |
||||
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(); |
||||
inline errorCode stop(); |
||||
|
||||
inline float getMaxPeriod() const; |
||||
inline float getRemainingTime() const; |
||||
|
||||
protected: |
||||
BaseTimer(TimerGenerator *generator, bool periodic); |
||||
virtual ~BaseTimer(); |
||||
|
||||
TimerGenerator *timerGenerator; |
||||
ITimerChannel *timerChannel; |
||||
bool isPeriodic; |
||||
uint32_t prescaler = 0; |
||||
}; |
||||
|
||||
// INLINE IMPLEMENTATION ================================================
|
||||
|
||||
template <typename period_t> |
||||
errorCode BaseTimer::begin(callback_t callback, period_t p, bool start) |
||||
{ |
||||
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); |
||||
|
||||
if (timerChannel == nullptr) |
||||
{ |
||||
if (timerGenerator != nullptr) // use timer passed in during construction
|
||||
{ |
||||
timerChannel = timerGenerator(); |
||||
if (timerChannel == nullptr) return postError(errorCode::noFreeChannel); |
||||
} else //find the next free timer
|
||||
{ |
||||
for (unsigned i = 0; timerChannel == nullptr && i < timerCnt; i++) |
||||
{ |
||||
timerChannel = timerPool[i](); |
||||
} |
||||
} |
||||
if (timerChannel == nullptr) return postError(errorCode::noFreeModule); |
||||
} |
||||
|
||||
errorCode result = timerChannel->begin(callback, period, isPeriodic); |
||||
|
||||
if (result == errorCode::OK) |
||||
{ |
||||
if (isPeriodic && start) timerChannel->start(); |
||||
} |
||||
return postError(result); |
||||
} |
||||
|
||||
errorCode BaseTimer::end() |
||||
{ |
||||
return postError(errorCode::notImplemented); |
||||
} |
||||
|
||||
errorCode BaseTimer::start() |
||||
{ |
||||
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 NAN; |
||||
} |
||||
|
||||
float BaseTimer::getRemainingTime() const |
||||
{ |
||||
if (timerChannel != nullptr) |
||||
return timerChannel->getRemainingTime(); |
||||
|
||||
postError(errorCode::notInitialized); |
||||
return NAN; |
||||
} |
||||
} // namespace TeensyTimerTool
|
@ -1,57 +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); |
||||
}; |
||||
|
||||
// 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
|
@ -1,21 +0,0 @@ |
||||
#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,33 +0,0 @@ |
||||
#pragma once |
||||
#include "ErrorHandling/error_codes.h" |
||||
#include "ITimerChannel.h" |
||||
#include "baseTimer.h" |
||||
#include "types.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class [[deprecated("Consider using PeriodicTimer or OneShotTimer instead")]] Timer : public BaseTimer |
||||
{ |
||||
public: |
||||
Timer(TimerGenerator *gen = nullptr); |
||||
|
||||
inline errorCode beginPeriodic(callback_t cb, uint32_t period) |
||||
{ |
||||
isPeriodic = true; |
||||
return BaseTimer::begin(cb, period, true); |
||||
} |
||||
inline errorCode beginOneShot(callback_t cb) |
||||
{ |
||||
isPeriodic = false; |
||||
return BaseTimer::begin(cb, 0, false); |
||||
} |
||||
inline void trigger(uint32_t delay); |
||||
}; |
||||
|
||||
// IMPLEMENTATION =======================================================
|
||||
|
||||
void Timer::trigger(const uint32_t delay) |
||||
{ |
||||
timerChannel->trigger(delay); |
||||
} |
||||
} // namespace TeensyTimerTool
|
@ -1,38 +0,0 @@ |
||||
#pragma once |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
enum class errorCode { |
||||
OK = 0, |
||||
|
||||
// Warnings
|
||||
periodOverflow = -100, |
||||
wrongType = -101, |
||||
triggeredLate = -102, //warn if new setted period is shorter than elapsed time
|
||||
|
||||
//General errors
|
||||
argument = 100, |
||||
callback = 101, |
||||
reload = 102, |
||||
noFreeModule = 103, |
||||
noFreeChannel = 104, // requested module has no free channel
|
||||
notImplemented = 105, // timer does not support this feature
|
||||
notInitialized = 106, |
||||
|
||||
// GTP Errors
|
||||
GTP_err = 200, |
||||
GTP_err2 = 201, |
||||
|
||||
//TMR Errors
|
||||
TMR_err = 300, |
||||
TMR_err2 = 301, |
||||
|
||||
//FTM Errors
|
||||
FTM_err = 400, |
||||
FTM_err2 = 401, |
||||
|
||||
//TCK Errors
|
||||
TCK_err = 900, |
||||
TCK_err2 = 901, |
||||
}; |
||||
} |
@ -1,79 +0,0 @@ |
||||
#include "error_handler.h" |
||||
#include "core_pins.h" |
||||
#include "types.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
ErrorHandler::ErrorHandler(Stream &s) : stream(s) |
||||
{ |
||||
pinMode(LED_BUILTIN, OUTPUT); |
||||
} |
||||
|
||||
void ErrorHandler::operator()(errorCode code) const |
||||
{ |
||||
const char *txt; |
||||
|
||||
switch (code) |
||||
{ |
||||
case errorCode::OK: |
||||
txt = "OK"; |
||||
break; |
||||
|
||||
// warnings
|
||||
case errorCode::periodOverflow: |
||||
txt = "Period overflow. Period was set to maximum value"; |
||||
break; |
||||
case errorCode::wrongType: |
||||
txt = "Wrong parameter type"; |
||||
break; |
||||
|
||||
// general errors
|
||||
case errorCode::reload: |
||||
txt = "Period must not be zero"; |
||||
break; |
||||
case errorCode::noFreeChannel: |
||||
txt = "Timer module has no free channel"; |
||||
break; |
||||
case errorCode::noFreeModule: |
||||
txt = "Timer pool contains no free timer"; |
||||
break; |
||||
case errorCode::notImplemented: |
||||
txt = "Function not implemented for this timer"; |
||||
break; |
||||
case errorCode::notInitialized: |
||||
txt = "Timer not initialized or available. Did you call begin?"; |
||||
break; |
||||
|
||||
default: |
||||
txt = "Unknown error"; |
||||
break; |
||||
} |
||||
|
||||
if ((int)code < 0) // in case of warnings we return after printing
|
||||
{ |
||||
stream.printf("W-%i: %s\n", -(int)code, txt); |
||||
return; |
||||
} |
||||
|
||||
stream.printf("E-%i: %s\n", (int)code, txt); // in case of errors we don't return
|
||||
while (true) |
||||
{ |
||||
digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN)); |
||||
delay(50); |
||||
} |
||||
} |
||||
|
||||
errorFunc_t errFunc; |
||||
|
||||
errorCode postError(errorCode e) |
||||
{ |
||||
if (errFunc != nullptr && e != errorCode::OK) errFunc(e); |
||||
return e; |
||||
} |
||||
|
||||
void attachErrFunc(errorFunc_t _errFunc) |
||||
{ |
||||
errFunc = _errFunc; |
||||
} |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,17 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "Stream.h" |
||||
#include "error_codes.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class ErrorHandler |
||||
{ |
||||
public: |
||||
ErrorHandler(Stream &s); |
||||
void operator()(errorCode code) const; |
||||
|
||||
protected: |
||||
Stream &stream; |
||||
}; |
||||
} // namespace TeensyTimerTool
|
@ -1,50 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "types.h" |
||||
#include <cmath> |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class ITimerChannel |
||||
{ |
||||
public: |
||||
virtual errorCode begin(callback_t callback, float period, bool oneShot) = 0; |
||||
virtual errorCode trigger(float delay) = 0; |
||||
virtual errorCode triggerDirect(uint32_t reload) { return postError(errorCode::notImplemented); }; |
||||
virtual errorCode triggerDirect(uint64_t reload) { return postError(errorCode::notImplemented); }; |
||||
virtual errorCode getTriggerReload(float delay, uint32_t *reload) { return postError(errorCode::notImplemented); }; |
||||
virtual errorCode getTriggerReload(float delay, uint64_t *reload) { return postError(errorCode::notImplemented); }; |
||||
|
||||
virtual errorCode start() = 0; |
||||
virtual errorCode stop() = 0; |
||||
|
||||
virtual errorCode setPrescaler(int psc) { return postError(errorCode::notImplemented); } |
||||
|
||||
virtual float getMaxPeriod() const = 0; |
||||
virtual float getRemainingTime() const { postError(errorCode::notImplemented); return NAN; } |
||||
virtual errorCode setPeriod(float 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; |
||||
}; |
||||
|
||||
// IMPLEMENTATION ====================================================
|
||||
|
||||
ITimerChannel::ITimerChannel(callback_t *cbStorage) |
||||
{ |
||||
this->pCallback = cbStorage; |
||||
} |
||||
|
||||
void ITimerChannel::setCallback(callback_t cb) |
||||
{ |
||||
*pCallback = cb; |
||||
} |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,9 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#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,95 +0,0 @@ |
||||
#pragma once |
||||
#include "FTM_Channel.h" |
||||
#include "FTM_Info.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
template <unsigned moduleNr> |
||||
class FTM_t |
||||
{ |
||||
public: |
||||
inline static ITimerChannel *getTimer(); |
||||
FTM_t() = delete; |
||||
|
||||
private: |
||||
static bool isInitialized; |
||||
inline static void isr() FASTRUN; |
||||
|
||||
static constexpr unsigned maxChannel = FTM_Info<moduleNr>::nrOfChannels; |
||||
static FTM_ChannelInfo channelInfo[maxChannel]; |
||||
static FTM_r_t * const r; |
||||
|
||||
static_assert(moduleNr < 4, "Module number < 4 required"); |
||||
}; |
||||
|
||||
// IMPLEMENTATION ==================================================================
|
||||
|
||||
template <unsigned moduleNr> |
||||
ITimerChannel *FTM_t<moduleNr>::getTimer() |
||||
{ |
||||
if (!isInitialized) |
||||
{ |
||||
r->SC = FTM_SC_CLKS(0b00); // Disable clock
|
||||
r->MOD = 0xFFFF; // Set full counter range
|
||||
r->CNT = 0; |
||||
|
||||
for (unsigned chNr = 0; chNr < maxChannel; chNr++) // init channels
|
||||
{ |
||||
channelInfo[chNr].isReserved = false; |
||||
channelInfo[chNr].callback = nullptr; |
||||
channelInfo[chNr].chRegs = &r->CH[chNr]; |
||||
channelInfo[chNr].ticksPerMicrosecond = 1E-6f * F_BUS / (1 << FTM_Info<moduleNr>::prescale); |
||||
|
||||
r->CH[chNr].SC &= ~FTM_CSC_CHF; // FTM requires to clear flag by setting bit to 0
|
||||
r->CH[chNr].SC &= ~FTM_CSC_CHIE; // Disable channel interupt
|
||||
r->CH[chNr].SC = FTM_CSC_MSA; |
||||
} |
||||
r->SC = FTM_SC_CLKS(0b01) | FTM_SC_PS(FTM_Info<moduleNr>::prescale); // Start clock
|
||||
attachInterruptVector(FTM_Info<moduleNr>::irqNumber, isr); // prepare isr and nvic, don't yet enable interrupts
|
||||
NVIC_ENABLE_IRQ(FTM_Info<moduleNr>::irqNumber); |
||||
isInitialized = true; |
||||
} |
||||
|
||||
for (unsigned chNr = 0; chNr < maxChannel; chNr++) |
||||
{ |
||||
if (!channelInfo[chNr].isReserved) |
||||
{ |
||||
channelInfo[chNr].isReserved = true; |
||||
return new FTM_Channel(r, &channelInfo[chNr]); |
||||
} |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
template <unsigned m> |
||||
void FTM_t<m>::isr() |
||||
{ |
||||
for (unsigned i = 0; i < maxChannel; i++) |
||||
{ |
||||
FTM_ChannelInfo *ci = &channelInfo[i]; // pre resolving the references turns out to be slightly faster
|
||||
FTM_CH_t *cr = ci->chRegs; |
||||
if ((cr->SC & (FTM_CSC_CHIE | FTM_CSC_CHF)) == (FTM_CSC_CHIE | FTM_CSC_CHF)) // only handle if channel is active (CHIE set) and overflowed (CHF set)
|
||||
{ |
||||
if (ci->isPeriodic) |
||||
{ |
||||
cr->SC &= ~FTM_CSC_CHF; // clear channel flag
|
||||
cr->CV = r->CNT + ci->reload; // set compare value to 'reload' counts ahead of counter
|
||||
} else |
||||
{ |
||||
cr->SC &= ~FTM_CSC_CHIE; //disable interrupt in on shot mode
|
||||
} |
||||
ci->callback(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
template <unsigned m> |
||||
FTM_ChannelInfo FTM_t<m>::channelInfo[maxChannel]; |
||||
|
||||
template <unsigned m> |
||||
bool FTM_t<m>::isInitialized = false; |
||||
|
||||
template <unsigned m> |
||||
FTM_r_t* const FTM_t<m>::r = (FTM_r_t *)FTM_Info<m>::baseAdr; |
||||
} // namespace TeensyTimerTool
|
||||
|
@ -1,121 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "Arduino.h" |
||||
#include "FTM_ChannelInfo.h" |
||||
#include "FTM_Info.h" |
||||
#include "ITimerChannel.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class FTM_Channel : public ITimerChannel |
||||
{ |
||||
public: |
||||
inline FTM_Channel(FTM_r_t *regs, FTM_ChannelInfo *ci); |
||||
inline virtual ~FTM_Channel(); |
||||
|
||||
inline float getMaxPeriod() const override; |
||||
|
||||
inline errorCode begin(callback_t cb, float period, bool periodic) { return doBegin(cb, period, periodic); } ///hacky improve in later version
|
||||
inline errorCode begin(callback_t cb, uint32_t period, bool periodic) { return doBegin(cb, period, periodic); }; |
||||
|
||||
inline errorCode trigger(float tcnt) override FASTRUN; |
||||
inline errorCode triggerDirect(uint32_t reload) override FASTRUN; |
||||
inline errorCode getTriggerReload(float delay, uint32_t *reload) override; |
||||
|
||||
inline errorCode start() override; |
||||
inline errorCode stop() override; |
||||
|
||||
inline uint16_t ticksFromMicros(float micros); |
||||
|
||||
// inline void setPeriod(uint32_t) {}
|
||||
|
||||
protected: |
||||
FTM_ChannelInfo *ci; |
||||
FTM_r_t *regs; |
||||
callback_t *pCallback = nullptr; |
||||
|
||||
template <typename period_t> |
||||
inline errorCode doBegin(callback_t cb, period_t period, bool periodic); |
||||
}; |
||||
|
||||
// IMPLEMENTATION ==============================================
|
||||
|
||||
FTM_Channel::FTM_Channel(FTM_r_t *regs, FTM_ChannelInfo *channelInfo) |
||||
: ITimerChannel(nullptr) |
||||
{ |
||||
this->regs = regs; |
||||
this->ci = channelInfo; |
||||
} |
||||
|
||||
template <typename period_t> |
||||
errorCode FTM_Channel::doBegin(callback_t callback, period_t period, bool periodic) |
||||
{ |
||||
ci->isPeriodic = periodic; |
||||
ci->reload = ticksFromMicros(period); |
||||
ci->callback = callback; |
||||
|
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode FTM_Channel::start() |
||||
{ |
||||
ci->chRegs->CV = regs->CNT + ci->reload; // compare value (current counter + pReload)
|
||||
ci->chRegs->SC &= ~FTM_CSC_CHF; // reset timer flag
|
||||
ci->chRegs->SC = FTM_CSC_MSA | FTM_CSC_CHIE; // enable interrupts
|
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode FTM_Channel::stop() |
||||
{ |
||||
ci->chRegs->SC &= ~FTM_CSC_CHIE; // enable interrupts
|
||||
ci->chRegs->SC &= ~FTM_CSC_CHF; // reset timer flag
|
||||
|
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode FTM_Channel::getTriggerReload(float delay, uint32_t *reload) |
||||
{ |
||||
*reload = ticksFromMicros(delay); |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode FTM_Channel::trigger(float delay) |
||||
{ |
||||
return triggerDirect(ticksFromMicros(delay)); |
||||
} |
||||
|
||||
errorCode FTM_Channel::triggerDirect(uint32_t reload) |
||||
{ |
||||
uint32_t cv = regs->CNT + reload + 1; // calc early to minimize error
|
||||
ci->chRegs->SC &= ~FTM_CSC_CHF; // Reset timer flag
|
||||
//
|
||||
regs->SC &= ~FTM_SC_CLKS_MASK; // need to switch off clock to immediately set new CV
|
||||
ci->chRegs->CV = cv; // compare value (current counter + pReload)
|
||||
regs->SC |= FTM_SC_CLKS(0b01); // restart clock
|
||||
//
|
||||
ci->chRegs->SC = FTM_CSC_MSA | FTM_CSC_CHIE; // enable interrupts
|
||||
|
||||
return errorCode::OK; |
||||
} |
||||
|
||||
float FTM_Channel::getMaxPeriod() const |
||||
{ |
||||
return (0xFFFF * 1E-6f) / ci->ticksPerMicrosecond; // max period in seconds
|
||||
} |
||||
|
||||
uint16_t FTM_Channel::ticksFromMicros(float micros) |
||||
{ |
||||
uint32_t rl = ci->ticksPerMicrosecond * micros; |
||||
if (rl > 0xFFFF) |
||||
{ |
||||
postError(errorCode::periodOverflow); // warning only, continues with clipped value
|
||||
rl = 0xFFFF; |
||||
} |
||||
return rl; |
||||
} |
||||
|
||||
FTM_Channel::~FTM_Channel() |
||||
{ |
||||
} |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,17 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "FTM_Info.h" |
||||
#include "types.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
struct FTM_ChannelInfo |
||||
{ |
||||
bool isReserved; |
||||
bool isPeriodic; |
||||
callback_t callback; |
||||
uint32_t reload; |
||||
FTM_CH_t *chRegs; |
||||
float ticksPerMicrosecond; |
||||
}; |
||||
} // namespace TeensyTimerTool
|
@ -1,109 +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; |
||||
}; |
||||
} // namespace TeensyTimerTool
|
@ -1,89 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "GPTChannel.h" |
||||
//#include "Arduino.h"
|
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
template <unsigned moduleNr> |
||||
class GPT_t |
||||
{ |
||||
public: |
||||
static ITimerChannel *getTimer(); |
||||
static void end(); |
||||
|
||||
protected: |
||||
static bool isInitialized; |
||||
static void isr(); |
||||
static callback_t callback; |
||||
static GptChannel *channel; |
||||
|
||||
// the following is calculated at compile time
|
||||
static constexpr IRQ_NUMBER_t irq = moduleNr == 0 ? IRQ_GPT1 : IRQ_GPT2; |
||||
static IMXRT_GPT_t *const pGPT; |
||||
static_assert(moduleNr < 2, "Wrong GPT Number"); |
||||
}; |
||||
|
||||
// IMPLEMENTATION ===========================================================================
|
||||
|
||||
template <unsigned moduleNr> |
||||
IMXRT_GPT_t *const GPT_t<moduleNr>::pGPT = reinterpret_cast<IMXRT_GPT_t *>(moduleNr == 0 ? &IMXRT_GPT1 : &IMXRT_GPT2); |
||||
|
||||
template <unsigned moduleNr> |
||||
ITimerChannel *GPT_t<moduleNr>::getTimer() |
||||
{ |
||||
if (!isInitialized) |
||||
{ |
||||
isInitialized = true; |
||||
|
||||
if (moduleNr == 0) // GPT1 clock settings
|
||||
CCM_CCGR1 |= CCM_CCGR1_GPT1_BUS(CCM_CCGR_ON) | CCM_CCGR1_GPT1_SERIAL(CCM_CCGR_ON); //
|
||||
else // GPT2
|
||||
CCM_CCGR0 |= CCM_CCGR0_GPT2_BUS(CCM_CCGR_ON) | CCM_CCGR0_GPT2_SERIAL(CCM_CCGR_ON); //
|
||||
//
|
||||
if (USE_GPT_PIT_150MHz) // timer clock setting from config.h
|
||||
CCM_CSCMR1 &= ~CCM_CSCMR1_PERCLK_CLK_SEL; // use F_BUS
|
||||
else //
|
||||
CCM_CSCMR1 |= CCM_CSCMR1_PERCLK_CLK_SEL; // use 24MHz
|
||||
//
|
||||
pGPT->CR = GPT_CR_CLKSRC(0x001) | GPT_CR_ENMOD; // stopped, restart mode and peripheral clock source
|
||||
|
||||
attachInterruptVector(irq, isr); |
||||
NVIC_ENABLE_IRQ(irq); |
||||
|
||||
channel = new GptChannel(pGPT, &callback); |
||||
return channel; |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
template <unsigned tmoduleNr> |
||||
void GPT_t<tmoduleNr>::isr() |
||||
{ |
||||
if (!channel->periodic) |
||||
pGPT->CR &= ~GPT_CR_EN; // stop timer in one shot mode
|
||||
//
|
||||
pGPT->SR = 0x3F; // reset all interrupt flags
|
||||
callback(); // we only enabled the OF1 interrupt-> no need to find out which interrupt was actually called
|
||||
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; |
||||
|
||||
template <unsigned m> |
||||
callback_t GPT_t<m>::callback = nullptr; |
||||
|
||||
template <unsigned m> |
||||
GptChannel *GPT_t<m>::channel = nullptr; |
||||
} // namespace TeensyTimerTool
|
@ -1,24 +0,0 @@ |
||||
#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,129 +0,0 @@ |
||||
#pragma once |
||||
#include "Arduino.h" |
||||
#include "GPTmap.h" |
||||
#include "ITimerChannel.h" |
||||
#include "core_pins.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class GptChannel : public ITimerChannel |
||||
{ |
||||
public: |
||||
inline GptChannel(IMXRT_GPT_t *, callback_t *); |
||||
virtual ~GptChannel(); |
||||
|
||||
inline errorCode begin(callback_t cb, float tcnt, bool periodic) override; |
||||
inline errorCode start() override; |
||||
inline errorCode stop() override; |
||||
|
||||
inline errorCode trigger(float delay) override; |
||||
inline errorCode triggerDirect(uint32_t delay) override; |
||||
inline errorCode getTriggerReload(float delay, uint32_t *reload) override; |
||||
|
||||
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 us2ticks(float micros) const; |
||||
inline float getMaxMicros() const; |
||||
|
||||
IMXRT_GPT_t *regs; |
||||
//uint32_t reload;
|
||||
float clock; |
||||
}; |
||||
|
||||
// IMPLEMENTATION ==============================================
|
||||
|
||||
GptChannel::GptChannel(IMXRT_GPT_t *registers, callback_t *cbStorage) |
||||
: ITimerChannel(cbStorage), regs(registers) |
||||
{ |
||||
clock = (CCM_CSCMR1 & CCM_CSCMR1_PERCLK_CLK_SEL) ? 24 : (F_BUS_ACTUAL / 1000000); |
||||
} |
||||
|
||||
errorCode GptChannel::begin(callback_t cb, float period, bool periodic) |
||||
{ |
||||
this->periodic = periodic; |
||||
if (periodic) |
||||
{ |
||||
regs->OCR1 = us2ticks(period); |
||||
} |
||||
setCallback(cb); |
||||
|
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode GptChannel::start() |
||||
{ |
||||
regs->SR = 0x3F; // clear all interupt flags
|
||||
regs->IR = GPT_IR_OF1IE; // enable OF1 interrupt
|
||||
regs->CR |= GPT_CR_EN; // enable timer
|
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode GptChannel::stop() |
||||
{ |
||||
regs->CR &= ~GPT_CR_EN; // disable timer
|
||||
regs->IR = 0; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode GptChannel::trigger(float delay) //should be optimized somehow
|
||||
{ |
||||
return triggerDirect(us2ticks(delay)); |
||||
} |
||||
|
||||
errorCode GptChannel::triggerDirect(uint32_t reload) |
||||
{ |
||||
regs->SR = 0x3F; // clear all interupt flags
|
||||
regs->IR = GPT_IR_OF1IE; // enable OF1 interrupt
|
||||
regs->OCR1 = reload; // set overflow value
|
||||
regs->CR |= GPT_CR_EN; // enable timer
|
||||
|
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode GptChannel::getTriggerReload(float delay, uint32_t *reload) |
||||
{ |
||||
*reload = us2ticks(delay); |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
uint32_t GptChannel::us2ticks(float micros) const |
||||
{ |
||||
if (micros > getMaxMicros()) |
||||
{ |
||||
micros = getMaxPeriod(); |
||||
postError(errorCode::periodOverflow); |
||||
} |
||||
return (uint32_t)(clock * micros) - 1; |
||||
} |
||||
|
||||
float GptChannel::getMaxMicros() const |
||||
{ |
||||
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,32 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "imxrt.h" |
||||
#include <cstdint> |
||||
|
||||
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,13 +0,0 @@ |
||||
#if defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY_MICROMOD) |
||||
|
||||
#include "PIT.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
bool PIT_t::isInitialized = false; |
||||
PITChannel PIT_t::channel[4] = {{0}, {1}, {2}, {3}}; |
||||
|
||||
uint32_t PITChannel::clockFactor = 1; |
||||
} // namespace TeensyTimerTool
|
||||
|
||||
#endif |
@ -1,70 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "PITChannel.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class PIT_t |
||||
{ |
||||
public: |
||||
inline static ITimerChannel *getTimer(); |
||||
|
||||
protected: |
||||
static bool isInitialized; |
||||
static void isr(); |
||||
static PITChannel channel[4]; |
||||
}; |
||||
|
||||
// IMPLEMENTATION ===========================================================================
|
||||
|
||||
ITimerChannel *PIT_t::getTimer() |
||||
{ |
||||
if (!isInitialized) |
||||
{ |
||||
isInitialized = true; |
||||
|
||||
CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_ON); |
||||
PIT_MCR = 1; |
||||
|
||||
if (USE_GPT_PIT_150MHz) // timer clock setting from config.h
|
||||
CCM_CSCMR1 &= ~CCM_CSCMR1_PERCLK_CLK_SEL; // FBus (usually 150MHz)
|
||||
else |
||||
CCM_CSCMR1 |= CCM_CSCMR1_PERCLK_CLK_SEL; // 24MHz
|
||||
|
||||
attachInterruptVector(IRQ_PIT, isr); |
||||
NVIC_ENABLE_IRQ(IRQ_PIT); |
||||
} |
||||
|
||||
for (unsigned i = 0; i < 4; i++) |
||||
{ |
||||
if (channel[i].callback == nullptr) return &channel[i]; |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
inline void PIT_t::isr() |
||||
{ |
||||
if (IMXRT_PIT_CHANNELS[0].TFLG) |
||||
{ |
||||
IMXRT_PIT_CHANNELS[0].TFLG = 1; |
||||
channel[0].isr(); |
||||
} |
||||
if (IMXRT_PIT_CHANNELS[1].TFLG) |
||||
{ |
||||
IMXRT_PIT_CHANNELS[1].TFLG = 1; |
||||
channel[1].isr(); |
||||
} |
||||
if (IMXRT_PIT_CHANNELS[2].TFLG) |
||||
{ |
||||
IMXRT_PIT_CHANNELS[2].TFLG = 1; |
||||
channel[2].isr(); |
||||
} |
||||
if (IMXRT_PIT_CHANNELS[3].TFLG) |
||||
{ |
||||
IMXRT_PIT_CHANNELS[3].TFLG = 1; |
||||
channel[3].isr(); |
||||
} |
||||
|
||||
asm volatile("dsb"); //wait until register changes propagated through the cache
|
||||
} |
||||
} // namespace TeensyTimerTool
|
@ -1,151 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "Arduino.h" |
||||
#include "ITimerChannel.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class PIT_t; |
||||
|
||||
class PITChannel : public ITimerChannel |
||||
{ |
||||
public: |
||||
inline PITChannel(unsigned nr); |
||||
inline virtual ~PITChannel(); |
||||
|
||||
inline errorCode begin(callback_t cb, float tcnt, bool periodic) override; |
||||
//inline errorCode begin(callback_t cb, uint32_t tcnt, bool periodic) override;
|
||||
inline errorCode start() override; |
||||
inline errorCode stop() override; |
||||
|
||||
//inline errorCode trigger(uint32_t) override;
|
||||
inline errorCode trigger(float) override; |
||||
inline errorCode setNextPeriod(float us) override; |
||||
inline errorCode setPeriod(float us) override; |
||||
|
||||
inline float getMaxPeriod() const override; |
||||
|
||||
bool isPeriodic; |
||||
|
||||
protected: |
||||
//IMXRT_GPT_t* regs;
|
||||
//uint32_t reload;
|
||||
|
||||
inline void isr(); |
||||
|
||||
PITChannel() = delete; |
||||
PITChannel(const PITChannel &) = delete; |
||||
|
||||
const unsigned chNr; |
||||
callback_t callback = nullptr; |
||||
|
||||
static uint32_t clockFactor; |
||||
|
||||
friend PIT_t; |
||||
}; |
||||
|
||||
// IMPLEMENTATION ==============================================
|
||||
|
||||
PITChannel::PITChannel(unsigned nr) |
||||
: ITimerChannel(nullptr), chNr(nr) |
||||
{ |
||||
callback = nullptr; |
||||
clockFactor = (CCM_CSCMR1 & CCM_CSCMR1_PERCLK_CLK_SEL) ? 24 : (F_BUS_ACTUAL / 1000000); |
||||
} |
||||
|
||||
errorCode PITChannel::begin(callback_t cb, float micros, bool periodic) |
||||
{ |
||||
isPeriodic = periodic; |
||||
callback = cb; |
||||
|
||||
if (isPeriodic) |
||||
{ |
||||
IMXRT_PIT_CHANNELS[chNr].TCTRL = 0; |
||||
IMXRT_PIT_CHANNELS[chNr].TFLG = 1; |
||||
|
||||
setNextPeriod(micros); |
||||
// float tmp = micros * clockFactor;
|
||||
// if (tmp > 0xFFFF'FFFF)
|
||||
// {
|
||||
// postError(errorCode::periodOverflow);
|
||||
// IMXRT_PIT_CHANNELS[chNr].LDVAL = 0xFFFF'FFFE;
|
||||
// } else
|
||||
// {
|
||||
// IMXRT_PIT_CHANNELS[chNr].LDVAL = (uint32_t)tmp - 1;
|
||||
// }
|
||||
} |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode PITChannel::start() |
||||
{ |
||||
IMXRT_PIT_CHANNELS[chNr].TCTRL = PIT_TCTRL_TEN | PIT_TCTRL_TIE; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode PITChannel::stop() |
||||
{ |
||||
IMXRT_PIT_CHANNELS[chNr].TCTRL = 0; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode PITChannel::setNextPeriod(float us) |
||||
{ |
||||
float cts = us * clockFactor; |
||||
if (cts > 0xFFFF'FFFF) |
||||
{ |
||||
postError(errorCode::periodOverflow); |
||||
IMXRT_PIT_CHANNELS[chNr].LDVAL = 0xFFFF'FFFE; |
||||
} else |
||||
{ |
||||
IMXRT_PIT_CHANNELS[chNr].LDVAL = (uint32_t)cts - 1; |
||||
} |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode PITChannel::setPeriod(float us) |
||||
{ |
||||
stop(); // need to stop/start timer to change current period (see ch 53.9.5.4)
|
||||
setNextPeriod(us); |
||||
start(); |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
void PITChannel::isr() |
||||
{ |
||||
if (callback != nullptr) |
||||
{ |
||||
callback(); |
||||
if (!isPeriodic) IMXRT_PIT_CHANNELS[chNr].TCTRL = 0; // switch off timer
|
||||
} |
||||
} |
||||
|
||||
PITChannel::~PITChannel() |
||||
{ |
||||
callback = nullptr; |
||||
} |
||||
|
||||
errorCode PITChannel::trigger(float delay) //should be optimized somehow
|
||||
{ |
||||
IMXRT_PIT_CHANNELS[chNr].TCTRL = 0; |
||||
IMXRT_PIT_CHANNELS[chNr].TFLG = 1; |
||||
|
||||
float tmp = delay * clockFactor; |
||||
if (tmp > 0xFFFF'FFFF) |
||||
{ |
||||
postError(errorCode::periodOverflow); |
||||
IMXRT_PIT_CHANNELS[chNr].LDVAL = 0xFFFF'FFFE; |
||||
} else |
||||
IMXRT_PIT_CHANNELS[chNr].LDVAL = (uint32_t)tmp - 1; |
||||
|
||||
start(); |
||||
|
||||
return errorCode::OK; |
||||
} |
||||
|
||||
float PITChannel::getMaxPeriod() const |
||||
{ |
||||
return (float)0xFFFF'FFFE / clockFactor / 1'000'000; |
||||
} |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,40 +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]; |
||||
} // 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,83 +0,0 @@ |
||||
#pragma once |
||||
|
||||
//#include "Arduino.h"
|
||||
#include "TckChannel.h" |
||||
#include "core_pins.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
extern const unsigned NR_OF_TCK_TIMERS; |
||||
|
||||
class TCK_t |
||||
{ |
||||
public: |
||||
template <typename counterType> |
||||
static inline ITimerChannel *getTimer(); |
||||
static inline void removeTimer(TckChannelBase *); |
||||
static inline void tick(); |
||||
|
||||
protected: |
||||
static bool isInitialized; |
||||
static TckChannelBase *channels[NR_OF_TCK_TIMERS]; |
||||
}; |
||||
|
||||
// IMPLEMENTATION ==================================================================
|
||||
|
||||
template <typename counterType> |
||||
ITimerChannel *TCK_t::getTimer() |
||||
{ |
||||
if (!isInitialized) |
||||
{ |
||||
for (unsigned chNr = 0; chNr < NR_OF_TCK_TIMERS; chNr++) |
||||
{ |
||||
channels[chNr] = nullptr; |
||||
} |
||||
isInitialized = true; |
||||
|
||||
// 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 |
||||
extern void initYieldHook(); |
||||
initYieldHook(); |
||||
#endif |
||||
} |
||||
for (unsigned chNr = 0; chNr < NR_OF_TCK_TIMERS; chNr++) |
||||
{ |
||||
if (channels[chNr] == nullptr) |
||||
{ |
||||
channels[chNr] = new TckChannel<counterType>(); |
||||
return channels[chNr]; |
||||
} |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
void TCK_t::removeTimer(TckChannelBase *channel) |
||||
{ |
||||
for (unsigned chNr = 0; chNr < NR_OF_TCK_TIMERS; chNr++) |
||||
{ |
||||
if (channels[chNr] == channel) |
||||
{ |
||||
channels[chNr] = nullptr; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void TCK_t::tick() |
||||
{ |
||||
for (unsigned i = 0; i < NR_OF_TCK_TIMERS; i++) |
||||
{ |
||||
if (channels[i] != nullptr) |
||||
{ |
||||
channels[i]->tick(); |
||||
} |
||||
} |
||||
} |
||||
} // namespace TeensyTimerTool
|
@ -1,145 +0,0 @@ |
||||
#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
|
||||
float getRemainingTime() const override { return (currentPeriod - (tckCounter::getCount() - startCnt)) / (float)TTT_F_CPU; } |
||||
|
||||
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
|
@ -1,15 +0,0 @@ |
||||
#if defined(TEENSYDUINO) |
||||
|
||||
#include "TckChannelBase.h" |
||||
#include "Arduino.h" |
||||
#include "TCK.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
TckChannelBase::~TckChannelBase() |
||||
{ |
||||
TCK_t::removeTimer(this); |
||||
} |
||||
} // namespace TeensyTimerTool
|
||||
|
||||
#endif |
@ -1,13 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "../../ITimerChannel.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class TckChannelBase : public ITimerChannel |
||||
{ |
||||
public: |
||||
virtual bool tick() = 0; |
||||
virtual ~TckChannelBase(); |
||||
}; |
||||
} |
@ -1,103 +0,0 @@ |
||||
|
||||
#include "tickCounters.h" |
||||
#include "Arduino.h" |
||||
#include "types.h" |
||||
#include "boardDef.h" |
||||
|
||||
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
|
@ -1,68 +0,0 @@ |
||||
#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,104 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "TMRChannel.h" |
||||
#include "imxrt.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
template <unsigned moduleNr> |
||||
class TMR_t |
||||
{ |
||||
public: |
||||
static ITimerChannel *getTimer(); |
||||
|
||||
protected: |
||||
static bool isInitialized; |
||||
static void isr(); |
||||
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 IMXRT_TMR_t *const pTMR; |
||||
static IMXRT_TMR_CH_t *const pCH0; |
||||
static IMXRT_TMR_CH_t *const pCH1; |
||||
static IMXRT_TMR_CH_t *const pCH2; |
||||
static IMXRT_TMR_CH_t *const pCH3; |
||||
|
||||
static_assert(moduleNr < 4, "Module number < 4 required"); |
||||
}; |
||||
|
||||
// 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_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]; |
||||
template <unsigned moduleNr> IMXRT_TMR_CH_t *const TMR_t<moduleNr>::pCH3 = &pTMR->CH[3]; |
||||
|
||||
template <unsigned moduleNr> |
||||
ITimerChannel *TMR_t<moduleNr>::getTimer() |
||||
{ |
||||
if (!isInitialized) |
||||
{ |
||||
for (unsigned chNr = 0; chNr < 4; chNr++) |
||||
{ |
||||
pTMR->CH[chNr].CTRL = 0x0000; |
||||
callbacks[chNr] = nullptr; |
||||
} |
||||
attachInterruptVector(irq, isr); // start
|
||||
NVIC_ENABLE_IRQ(irq); |
||||
isInitialized = true; |
||||
return new TMRChannel(pCH0, &callbacks[0]); |
||||
} |
||||
|
||||
for (unsigned chNr = 0; chNr < 4; chNr++) |
||||
{ |
||||
IMXRT_TMR_CH_t *pCh = &pTMR->CH[chNr]; |
||||
if (pCh->CTRL == 0x0000) |
||||
{ |
||||
return new TMRChannel(pCh, &callbacks[chNr]); |
||||
} |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
template <unsigned m> |
||||
void TMR_t<m>::isr() |
||||
{ |
||||
// no loop to gain some time by avoiding indirections and pointer calculations
|
||||
if (callbacks[0] != nullptr && pCH0->CSCTRL & TMR_CSCTRL_TCF1) |
||||
{ |
||||
pCH0->CSCTRL &= ~TMR_CSCTRL_TCF1; |
||||
callbacks[0](); |
||||
} |
||||
|
||||
if (callbacks[1] != nullptr && pCH1->CSCTRL & TMR_CSCTRL_TCF1) |
||||
{ |
||||
pCH1->CSCTRL &= ~TMR_CSCTRL_TCF1; |
||||
callbacks[1](); |
||||
} |
||||
|
||||
if (callbacks[2] != nullptr && pCH2->CSCTRL & TMR_CSCTRL_TCF1) |
||||
{ |
||||
pCH2->CSCTRL &= ~TMR_CSCTRL_TCF1; |
||||
callbacks[2](); |
||||
} |
||||
|
||||
if (callbacks[3] != nullptr && pCH3->CSCTRL & TMR_CSCTRL_TCF1) |
||||
{ |
||||
pCH3->CSCTRL &= ~TMR_CSCTRL_TCF1; |
||||
callbacks[3](); |
||||
} |
||||
asm volatile("dsb"); //wait until register changes propagated through the cache
|
||||
} |
||||
|
||||
template <unsigned m> |
||||
bool TMR_t<m>::isInitialized = false; |
||||
|
||||
template <unsigned m> |
||||
callback_t TMR_t<m>::callbacks[4]; |
||||
} // namespace TeensyTimerTool
|
@ -1,188 +0,0 @@ |
||||
#pragma once |
||||
#include "../../ITimerChannel.h" |
||||
//#include "Arduino.h"
|
||||
#include "ErrorHandling/error_codes.h" |
||||
#include "config.h" |
||||
#include "imxrt.h" |
||||
#include <cmath> |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class TMRChannel : public ITimerChannel |
||||
{ |
||||
public: |
||||
inline TMRChannel(IMXRT_TMR_CH_t *regs, callback_t *cbStorage); |
||||
inline virtual ~TMRChannel(); |
||||
|
||||
inline errorCode begin(callback_t cb, float tcnt, bool periodic) override; |
||||
inline errorCode start() override; |
||||
inline errorCode stop() override; |
||||
|
||||
inline errorCode trigger(float tcnt) override; |
||||
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: |
||||
IMXRT_TMR_CH_t *regs; |
||||
callback_t **pCallback = nullptr; |
||||
float pscValue; |
||||
uint32_t pscBits; |
||||
|
||||
errorCode us2Ticks(const float us, uint16_t *ticks) const; |
||||
inline float_t counterToMicrosecond(const float_t cnt) const; |
||||
}; |
||||
|
||||
// IMPLEMENTATION ==============================================
|
||||
|
||||
TMRChannel::TMRChannel(IMXRT_TMR_CH_t *regs, callback_t *cbStorage) |
||||
: ITimerChannel(cbStorage) |
||||
{ |
||||
this->regs = regs; |
||||
setPrescaler(TMR_DEFAULT_PSC); |
||||
} |
||||
|
||||
TMRChannel::~TMRChannel() |
||||
{ |
||||
regs->CTRL = 0x0000; // stop timer and mark it free
|
||||
} |
||||
|
||||
errorCode TMRChannel::start() |
||||
{ |
||||
regs->CNTR = 0x0000; |
||||
|
||||
regs->CSCTRL &= ~TMR_CSCTRL_TCF1; |
||||
regs->CSCTRL |= TMR_CSCTRL_TCF1EN; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode TMRChannel::stop() |
||||
{ |
||||
regs->CSCTRL &= ~TMR_CSCTRL_TCF1EN; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
errorCode TMRChannel::begin(callback_t cb, float period, bool periodic) |
||||
{ |
||||
uint16_t reload; |
||||
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) |
||||
regs->CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(pscBits) | TMR_CTRL_ONCE | TMR_CTRL_LENGTH; |
||||
|
||||
else |
||||
regs->CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(pscBits) | TMR_CTRL_LENGTH; |
||||
|
||||
start(); |
||||
return status; |
||||
} |
||||
|
||||
errorCode TMRChannel::trigger(float us) // quick and dirty, should be optimized
|
||||
{ |
||||
// 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; |
||||
regs->COMP1 = reload; |
||||
regs->CMPLD1 = reload; |
||||
regs->CNTR = 0x0000; |
||||
|
||||
regs->CSCTRL &= ~TMR_CSCTRL_TCF1; |
||||
regs->CSCTRL |= TMR_CSCTRL_TCF1EN; |
||||
|
||||
regs->CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(pscBits) | TMR_CTRL_ONCE | TMR_CTRL_LENGTH; |
||||
|
||||
return status; |
||||
} |
||||
|
||||
void TMRChannel::setPrescaler(uint32_t psc) // psc 0..7 -> prescaler: 1..128
|
||||
{ |
||||
pscValue = 1 << (psc & 0b0111); |
||||
pscBits = 0b1000 | (psc & 0b0111); |
||||
} |
||||
|
||||
float TMRChannel::getMaxPeriod() const |
||||
{ |
||||
return pscValue / 150'000'000.0f * 0xFFFE; |
||||
} |
||||
|
||||
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)
|
||||
// {
|
||||
|
||||
// regs->COMP1 = cnt;
|
||||
|
||||
// //Do we need to wait some cycle for IP bus to update here / cache flush?
|
||||
// //asm volatile("dsb");
|
||||
|
||||
// if (regs->CNTR > cnt)
|
||||
// {
|
||||
// //if counter alrready went over setted value force a triggering
|
||||
// regs->CNTR = cnt;
|
||||
// return errorCode::triggeredLate;
|
||||
// }
|
||||
|
||||
// else
|
||||
// {
|
||||
// return errorCode::OK;
|
||||
// }
|
||||
// }
|
||||
|
||||
errorCode TMRChannel::setPeriod(float us) |
||||
{ |
||||
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 tmpTicks = us * 150.0f / pscValue; |
||||
if (tmpTicks > maxTicks) |
||||
{ |
||||
*ticks = maxTicks; |
||||
return errorCode::periodOverflow; |
||||
} |
||||
*ticks = (uint16_t)tmpTicks; |
||||
return errorCode::OK; |
||||
} |
||||
|
||||
float_t TMRChannel::counterToMicrosecond(const float_t cnt) const |
||||
{ |
||||
return cnt * pscValue / 150.0f; |
||||
} |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,67 +0,0 @@ |
||||
#pragma once |
||||
#include <cstdint> |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
class ITimerChannel; |
||||
using TimerGenerator = ITimerChannel*(); //returns a pointer to a free timer channel or nullptr
|
||||
|
||||
// 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; |
||||
|
||||
#elif defined(ARDUINO_TEENSY30) |
||||
extern TimerGenerator *const FTM0, * const FTM1; |
||||
extern TimerGenerator *const TCK, * const TCK32, * const TCK64; |
||||
|
||||
#elif defined(ARDUINO_TEENSY31) || defined(ARDUINO_TEENSY32) |
||||
extern TimerGenerator *const FTM0, * const FTM1, * const FTM2; |
||||
extern TimerGenerator *const TCK, * const TCK32, * const TCK64; |
||||
|
||||
|
||||
#elif defined(ARDUINO_TEENSY35) |
||||
extern TimerGenerator *const FTM0, * const FTM1, * const FTM2, * const FTM3, * const FTM4; |
||||
extern TimerGenerator *const TCK, * const TCK32, * const TCK64; |
||||
|
||||
#elif defined(ARDUINO_TEENSY36) |
||||
extern TimerGenerator *const FTM0, *const FTM1, *const FTM2, *const FTM3, *const FTM4; |
||||
extern TimerGenerator *const TCK, * const TCK32, * const TCK64; |
||||
|
||||
#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, *const TCK_RTC; |
||||
|
||||
#else |
||||
#error BOARD NOT SUPPORTED |
||||
#endif |
||||
|
||||
#define YIELD_NONE 0 |
||||
#define YIELD_STANDARD 1 |
||||
#define YIELD_OPTIMIZED 2 |
||||
|
||||
constexpr int PSC_AUTO = -1; |
||||
constexpr int PSC_1 = 0; |
||||
constexpr int PSC_2 = 1; |
||||
constexpr int PSC_4 = 2; |
||||
constexpr int PSC_8 = 3; |
||||
constexpr int PSC_16 = 4; |
||||
constexpr int PSC_32 = 5; |
||||
constexpr int PSC_64 = 6; |
||||
constexpr int PSC_128 = 7; |
||||
|
||||
extern void(* const tick)(); |
||||
|
||||
|
||||
#else |
||||
# error "Board not supported" |
||||
#endif |
||||
} |
@ -1,88 +0,0 @@ |
||||
#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 "TimerModules/GPT/GPT.h" |
||||
#include "TimerModules/PIT4/PIT.h" |
||||
#include "TimerModules/TMR/TMR.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
TimerGenerator *const TMR1 = TMR_t<0>::getTimer; |
||||
TimerGenerator *const TMR2 = TMR_t<1>::getTimer; |
||||
TimerGenerator *const TMR3 = TMR_t<2>::getTimer; |
||||
TimerGenerator *const TMR4 = TMR_t<3>::getTimer; |
||||
|
||||
TimerGenerator *const GPT1 = GPT_t<0>::getTimer; |
||||
TimerGenerator *const GPT2 = GPT_t<1>::getTimer; |
||||
|
||||
TimerGenerator *const PIT = PIT_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 TCK_RTC = TCK_t::getTimer<RtcCounter>; |
||||
|
||||
constexpr tick_t tick = &TCK_t::tick; |
||||
} // namespace TeensyTimerTool
|
||||
|
||||
#elif defined(ARDUINO_TEENSY35) || defined(ARDUINO_TEENSY36) |
||||
#include "TimerModules/FTM/FTM.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
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; |
||||
TimerGenerator *const FTM3 = FTM_t<3>::getTimer; |
||||
TimerGenerator *const FTM4 = FTM_t<3>::getTimer; |
||||
|
||||
constexpr tick_t tick = &TCK_t::tick; |
||||
} // namespace TeensyTimerTool
|
||||
|
||||
#elif defined(ARDUINO_TEENSY31) || defined(ARDUINO_TEENSY32) |
||||
#include "TimerModules/FTM/FTM.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
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 "TimerModules/FTM/FTM.h" |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
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) |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
TimerGenerator *const TCK = TCK_t::getTimer<MicrosCounter>; |
||||
constexpr tick_t tick = &TCK_t::tick; |
||||
} // namespace TeensyTimerTool
|
||||
|
||||
#endif |
@ -1,7 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#if __has_include("userConfig.h") |
||||
#include "userConfig.h" |
||||
#else |
||||
#include "defaultConfig.h" |
||||
#endif |
@ -1,92 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "boardDef.h" |
||||
namespace TeensyTimerTool |
||||
{ |
||||
//--------------------------------------------------------------------------------------------
|
||||
// Timer pool defintion
|
||||
// Add, and sort and remove to define the timer pool. Timers will be allocted from left to right
|
||||
|
||||
#if defined(ARDUINO_TEENSY_MICROMOD) |
||||
TimerGenerator* const timerPool[] = {GPT1, GPT2, TMR1, TMR2, TMR3, TMR4, TCK}; |
||||
|
||||
#elif defined(ARDUINO_TEENSY40) |
||||
TimerGenerator* const timerPool[] = {GPT1, GPT2, TMR1, TMR2, TMR3, TMR4, TCK}; |
||||
|
||||
#elif defined(ARDUINO_TEENSY41) |
||||
TimerGenerator* const timerPool[] = {GPT1, GPT2, TMR1, TMR2, TMR3, TMR4, TCK}; |
||||
|
||||
#elif defined(ARDUINO_TEENSY36) |
||||
TimerGenerator* const timerPool[] = {FTM0, FTM1, FTM2, FTM3, FTM4, TCK}; |
||||
|
||||
#elif defined(ARDUINO_TEENSY35) |
||||
TimerGenerator* const timerPool[] = {FTM0, FTM1, FTM2, FTM3, TCK}; |
||||
|
||||
#elif defined(ARDUINO_TEENSY31) || defined(ARDUINO_TEENSY32) |
||||
TimerGenerator* const timerPool[] = {FTM0, FTM1, FTM2, TCK}; |
||||
|
||||
#elif defined(ARDUINO_TEENSY30) |
||||
TimerGenerator* const timerPool[] = {FTM0, FTM1, TCK}; |
||||
|
||||
#elif defined(ARDUINO_TEENSYLC) |
||||
TimerGenerator* const timerPool[] = {TCK}; |
||||
|
||||
#elif defined(ESP32) |
||||
TimerGenerator* const timerPool[] = {TCK}; |
||||
|
||||
#elif defined(UNO) |
||||
TimerGenerator* const timerPool[] = {TCK}; |
||||
#endif |
||||
constexpr unsigned timerCnt = sizeof(timerPool) / sizeof(timerPool[0]); |
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// Default settings for various timers
|
||||
|
||||
// TMR (QUAD)
|
||||
constexpr int TMR_DEFAULT_PSC = PSC_128; // Allowed prescaling values: PSC_1, PSC_2, PSC_4 ... PSC_128, clock = 150MHz
|
||||
|
||||
// FTM
|
||||
constexpr int FTM_DEFAULT_PSC[] = // Allowed prescaling values: PSC_AUTO, PSC_1, PSC_2, PSC_4 ... PSC_128, clock = FBUS
|
||||
{ // (PSC_AUTO adjusts prescaler to get roughly 2 timer ticks per µs)
|
||||
/*FTM0*/ PSC_AUTO, |
||||
/*FTM1*/ PSC_AUTO, |
||||
/*FTM2*/ PSC_AUTO, |
||||
/*FTM3*/ PSC_AUTO |
||||
}; |
||||
|
||||
|
||||
// GPT & PID
|
||||
constexpr bool USE_GPT_PIT_150MHz = false;// changes the clock source for GPT and PIT from 24MHz (standard) to 150MHz, might have side effects!
|
||||
|
||||
// TCK
|
||||
constexpr unsigned NR_OF_TCK_TIMERS = 20; // How many TCK timers shall be available
|
||||
|
||||
#define YIELD_TYPE YIELD_STANDARD // Select the required yield strategy from the list below
|
||||
// YIELD_NONE: lib doesn't touch yield. Make sure to call TeensyTimerTool::tick as often as possible
|
||||
// YIELD_STANDARD: uses the standard yield function and adds a call to TeensyTimerTool::tick(). Lots of overhead in yield...
|
||||
// YIELD_OPTIMIZED: generate an optimized yield which only calls TeensyTimerTool::Tick() (recommended if you don't use SerialEvents)
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// Callback type
|
||||
// Uncomment if you prefer function pointer callbacks instead of std::function callbacks
|
||||
|
||||
// #define PLAIN_VANILLA_CALLBACKS
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// Use c++14 time literals (e.g. 3.4s, 50ms, _kHz...) for time inputs. Periods without literals are
|
||||
// interpreted as microseconds.
|
||||
// Comment the following line if you don't want this.
|
||||
|
||||
#define USE_TIME_LITERALS |
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// Advanced Features
|
||||
// Uncomment if you need access to advanced features
|
||||
|
||||
// #define ENABLE_ADVANCED_FEATURES
|
||||
} |
@ -1,406 +0,0 @@ |
||||
// <chrono> -*- C++ -*-
|
||||
|
||||
// Copyright (C) 2008-2015 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// Under Section 7 of GPL version 3, you are granted additional
|
||||
// permissions described in the GCC Runtime Library Exception, version
|
||||
// 3.1, as published by the Free Software Foundation.
|
||||
|
||||
// You should have received a copy of the GNU General Public License and
|
||||
// a copy of the GCC Runtime Library Exception along with this program;
|
||||
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once |
||||
|
||||
#include <chrono> |
||||
#include <limits> |
||||
#include <ratio> |
||||
#include <type_traits> |
||||
|
||||
using std::common_type; |
||||
using std::enable_if; |
||||
using std::is_convertible; |
||||
using std::ratio; |
||||
using std::ratio_divide; |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
template <typename _Rep, typename _Period = ratio<1>> |
||||
struct frequency; |
||||
|
||||
template <typename _CT, typename _Period1, typename _Period2> |
||||
struct __frequency_common_type_wrapper |
||||
{ |
||||
private: |
||||
typedef std::__static_gcd<_Period1::num, _Period2::num> __gcd_num; |
||||
typedef std::__static_gcd<_Period1::den, _Period2::den> __gcd_den; |
||||
typedef typename _CT::type __cr; |
||||
typedef ratio<__gcd_num::value, |
||||
(_Period1::den / __gcd_den::value) * _Period2::den> |
||||
__r; |
||||
|
||||
public: |
||||
typedef std::__success_type<TeensyTimerTool::frequency<__cr, __r>> type; |
||||
}; |
||||
|
||||
template <typename _Period1, typename _Period2> |
||||
struct __frequency_common_type_wrapper<std::__failure_type, _Period1, _Period2> |
||||
{ |
||||
typedef std::__failure_type type; |
||||
}; |
||||
} |
||||
|
||||
namespace std |
||||
{ |
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
struct common_type<TeensyTimerTool::frequency<_Rep1, _Period1>, TeensyTimerTool::frequency<_Rep2, _Period2>> |
||||
: public TeensyTimerTool::__frequency_common_type_wrapper<typename __member_type_wrapper<std::common_type<_Rep1, _Rep2>>::type, _Period1, _Period2>::type |
||||
{ |
||||
}; |
||||
} |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
using namespace std::chrono; |
||||
|
||||
// Primary template for frequency_cast impl.
|
||||
template <typename _ToDur, typename _CF, typename _CR, |
||||
bool _NumIsOne = false, bool _DenIsOne = false> |
||||
struct __frequency_cast_impl |
||||
{ |
||||
template <typename _Rep, typename _Period> |
||||
static constexpr _ToDur |
||||
__cast(const frequency<_Rep, _Period>& __d) |
||||
{ |
||||
typedef typename _ToDur::rep __to_rep; |
||||
return _ToDur(static_cast<__to_rep>(static_cast<_CR>(__d.count()) * static_cast<_CR>(_CF::num) / static_cast<_CR>(_CF::den))); |
||||
} |
||||
}; |
||||
|
||||
template <typename _ToDur, typename _CF, typename _CR> |
||||
struct __frequency_cast_impl<_ToDur, _CF, _CR, true, true> |
||||
{ |
||||
template <typename _Rep, typename _Period> |
||||
static constexpr _ToDur |
||||
__cast(const frequency<_Rep, _Period>& __d) |
||||
{ |
||||
typedef typename _ToDur::rep __to_rep; |
||||
return _ToDur(static_cast<__to_rep>(__d.count())); |
||||
} |
||||
}; |
||||
|
||||
template <typename _ToDur, typename _CF, typename _CR> |
||||
struct __frequency_cast_impl<_ToDur, _CF, _CR, true, false> |
||||
{ |
||||
template <typename _Rep, typename _Period> |
||||
static constexpr _ToDur |
||||
__cast(const frequency<_Rep, _Period>& __d) |
||||
{ |
||||
typedef typename _ToDur::rep __to_rep; |
||||
return _ToDur(static_cast<__to_rep>( |
||||
static_cast<_CR>(__d.count()) / static_cast<_CR>(_CF::den))); |
||||
} |
||||
}; |
||||
|
||||
template <typename _ToDur, typename _CF, typename _CR> |
||||
struct __frequency_cast_impl<_ToDur, _CF, _CR, false, true> |
||||
{ |
||||
template <typename _Rep, typename _Period> |
||||
static constexpr _ToDur |
||||
__cast(const frequency<_Rep, _Period>& __d) |
||||
{ |
||||
typedef typename _ToDur::rep __to_rep; |
||||
return _ToDur(static_cast<__to_rep>( |
||||
static_cast<_CR>(__d.count()) * static_cast<_CR>(_CF::num))); |
||||
} |
||||
}; |
||||
|
||||
template <typename _Tp> |
||||
struct __is_frequency |
||||
: std::false_type |
||||
{ |
||||
}; |
||||
|
||||
template <typename _Rep, typename _Period> |
||||
struct __is_frequency<frequency<_Rep, _Period>> |
||||
: std::true_type |
||||
{ |
||||
}; |
||||
|
||||
/// duration_cast
|
||||
template <typename _ToDur, typename _Rep, typename _Period> |
||||
constexpr typename enable_if<__is_frequency<_ToDur>::value, _ToDur>::type duration_cast(const frequency<_Rep, _Period>& __d) |
||||
{ |
||||
typedef typename _ToDur::period __to_period; |
||||
typedef typename _ToDur::rep __to_rep; |
||||
typedef ratio_divide<_Period, __to_period> __cf; |
||||
typedef typename common_type<__to_rep, _Rep, intmax_t>::type __cr; |
||||
typedef __frequency_cast_impl<_ToDur, __cf, __cr, __cf::num == 1, __cf::den == 1> __dc; |
||||
|
||||
return __dc::__cast(__d); |
||||
} |
||||
|
||||
/// frequency
|
||||
template <typename _Rep, typename _Period> |
||||
struct frequency |
||||
{ |
||||
typedef _Rep rep; |
||||
typedef _Period period; |
||||
|
||||
static_assert(!__is_frequency<_Rep>::value, "rep cannot be a frequency"); |
||||
static_assert(std::chrono::__is_ratio<_Period>::value, "period must be a specialization of ratio"); |
||||
static_assert(_Period::num > 0, "period must be positive"); |
||||
|
||||
// 20.11.5.1 construction / copy / destroy
|
||||
constexpr frequency() = default; |
||||
|
||||
// NB: Make constexpr implicit. This cannot be explicitly
|
||||
// constexpr, as any UDT that is not a literal type with a
|
||||
// constexpr copy constructor will be ill-formed.
|
||||
frequency(const frequency&) = default; |
||||
|
||||
template <typename _Rep2, typename = typename enable_if<is_convertible<_Rep2, rep>::value && (std::chrono::treat_as_floating_point<rep>::value || !std::chrono::treat_as_floating_point<_Rep2>::value)>::type> |
||||
constexpr explicit frequency(const _Rep2& __rep) |
||||
: __r(static_cast<rep>(__rep)) |
||||
{ |
||||
} |
||||
|
||||
template <typename _Rep2, typename _Period2, typename = typename enable_if<treat_as_floating_point<rep>::value || (ratio_divide<_Period2, period>::den == 1 && !treat_as_floating_point<_Rep2>::value)>::type> |
||||
constexpr frequency(const frequency<_Rep2, _Period2>& __d) |
||||
: __r(duration_cast<frequency>(__d).count()) {} |
||||
|
||||
~frequency() = default; |
||||
frequency& operator=(const frequency&) = default; |
||||
|
||||
// 20.11.5.2 observer
|
||||
constexpr rep count() const { return __r; } |
||||
|
||||
constexpr frequency operator+() const { return *this; } |
||||
constexpr frequency operator-() const { return frequency(-__r); } |
||||
|
||||
frequency& operator++() |
||||
{ |
||||
++__r; |
||||
return *this; |
||||
} |
||||
|
||||
frequency operator++(int) |
||||
{ |
||||
return frequency(__r++); |
||||
} |
||||
|
||||
frequency& operator--() |
||||
{ |
||||
--__r; |
||||
return *this; |
||||
} |
||||
|
||||
frequency |
||||
operator--(int) |
||||
{ |
||||
return frequency(__r--); |
||||
} |
||||
|
||||
frequency& |
||||
operator+=(const frequency& __d) |
||||
{ |
||||
__r += __d.count(); |
||||
return *this; |
||||
} |
||||
|
||||
frequency& |
||||
operator-=(const frequency& __d) |
||||
{ |
||||
__r -= __d.count(); |
||||
return *this; |
||||
} |
||||
|
||||
frequency& |
||||
operator*=(const rep& __rhs) |
||||
{ |
||||
__r *= __rhs; |
||||
return *this; |
||||
} |
||||
|
||||
frequency& |
||||
operator/=(const rep& __rhs) |
||||
{ |
||||
__r /= __rhs; |
||||
return *this; |
||||
} |
||||
|
||||
// DR 934.
|
||||
template <typename _Rep2 = rep> |
||||
typename enable_if<!treat_as_floating_point<_Rep2>::value, |
||||
frequency&>::type |
||||
operator%=(const rep& __rhs) |
||||
{ |
||||
__r %= __rhs; |
||||
return *this; |
||||
} |
||||
|
||||
template <typename _Rep2 = rep> |
||||
typename enable_if<!treat_as_floating_point<_Rep2>::value, |
||||
frequency&>::type |
||||
operator%=(const frequency& __d) |
||||
{ |
||||
__r %= __d.count(); |
||||
return *this; |
||||
} |
||||
|
||||
// 20.11.5.4 special values
|
||||
static constexpr frequency |
||||
zero() |
||||
{ |
||||
return frequency(duration_values<rep>::zero()); |
||||
} |
||||
|
||||
static constexpr frequency |
||||
min() |
||||
{ |
||||
return frequency(duration_values<rep>::min()); |
||||
} |
||||
|
||||
static constexpr frequency |
||||
max() |
||||
{ |
||||
return frequency(duration_values<rep>::max()); |
||||
} |
||||
|
||||
private: |
||||
rep __r; |
||||
}; |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr typename common_type<frequency<_Rep1, _Period1>, frequency<_Rep2, _Period2>>::type operator+(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
typedef frequency<_Rep1, _Period1> __dur1; |
||||
typedef frequency<_Rep2, _Period2> __dur2; |
||||
typedef typename common_type<__dur1, __dur2>::type __cd; |
||||
return __cd(__cd(__lhs).count() + __cd(__rhs).count()); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr typename common_type<frequency<_Rep1, _Period1>, frequency<_Rep2, _Period2>>::type operator-(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
typedef frequency<_Rep1, _Period1> __dur1; |
||||
typedef frequency<_Rep2, _Period2> __dur2; |
||||
typedef typename common_type<__dur1, __dur2>::type __cd; |
||||
return __cd(__cd(__lhs).count() - __cd(__rhs).count()); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period, typename _Rep2> |
||||
constexpr frequency<typename __common_rep_type<_Rep1, _Rep2>::type, _Period> operator*(const frequency<_Rep1, _Period>& __d, const _Rep2& __s) |
||||
{ |
||||
typedef frequency<typename common_type<_Rep1, _Rep2>::type, _Period> __cd; |
||||
return __cd(__cd(__d).count() * __s); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Rep2, typename _Period> |
||||
constexpr frequency<typename __common_rep_type<_Rep2, _Rep1>::type, _Period> operator*(const _Rep1& __s, const frequency<_Rep2, _Period>& __d) |
||||
{ |
||||
return __d * __s; |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period, typename _Rep2> |
||||
constexpr frequency<typename __common_rep_type<_Rep1, typename enable_if<!__is_frequency<_Rep2>::value, _Rep2>::type>::type, _Period> operator/(const frequency<_Rep1, _Period>& __d, const _Rep2& __s) |
||||
{ |
||||
typedef frequency<typename common_type<_Rep1, _Rep2>::type, _Period> __cd; |
||||
return __cd(__cd(__d).count() / __s); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr typename common_type<_Rep1, _Rep2>::type operator/(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
typedef frequency<_Rep1, _Period1> __dur1; |
||||
typedef frequency<_Rep2, _Period2> __dur2; |
||||
typedef typename common_type<__dur1, __dur2>::type __cd; |
||||
return __cd(__lhs).count() / __cd(__rhs).count(); |
||||
} |
||||
|
||||
// DR 934.
|
||||
template <typename _Rep1, typename _Period, typename _Rep2> |
||||
constexpr frequency<typename __common_rep_type<_Rep1, typename enable_if<!__is_frequency<_Rep2>::value, _Rep2>::type>::type, _Period> operator%(const frequency<_Rep1, _Period>& __d, const _Rep2& __s) |
||||
{ |
||||
typedef frequency<typename common_type<_Rep1, _Rep2>::type, _Period> __cd; |
||||
return __cd(__cd(__d).count() % __s); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr typename common_type<frequency<_Rep1, _Period1>, frequency<_Rep2, _Period2>>::type operator%(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
typedef frequency<_Rep1, _Period1> __dur1; |
||||
typedef frequency<_Rep2, _Period2> __dur2; |
||||
typedef typename common_type<__dur1, __dur2>::type __cd; |
||||
return __cd(__cd(__lhs).count() % __cd(__rhs).count()); |
||||
} |
||||
|
||||
// comparisons
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr bool operator==(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
typedef frequency<_Rep1, _Period1> __dur1; |
||||
typedef frequency<_Rep2, _Period2> __dur2; |
||||
typedef typename common_type<__dur1, __dur2>::type __ct; |
||||
return __ct(__lhs).count() == __ct(__rhs).count(); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr bool operator<(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
typedef frequency<_Rep1, _Period1> __dur1; |
||||
typedef frequency<_Rep2, _Period2> __dur2; |
||||
typedef typename common_type<__dur1, __dur2>::type __ct; |
||||
return __ct(__lhs).count() < __ct(__rhs).count(); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr bool operator!=(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
return !(__lhs == __rhs); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr bool operator<=(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
return !(__rhs < __lhs); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr bool operator>(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
return __rhs < __lhs; |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr bool operator>=(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
return !(__lhs < __rhs); |
||||
} |
||||
|
||||
using hertz = frequency<float>; |
||||
using kilohertz = frequency<float, std::kilo>; |
||||
using megahertz = frequency<float, std::mega>; |
||||
using gigahertz = frequency<float, std::giga>; |
||||
|
||||
constexpr hertz operator""_Hz(long double hz) { return hertz{hz}; } |
||||
constexpr hertz operator""_Hz(uint64_t hz) { return hertz{hz}; } |
||||
constexpr kilohertz operator""_kHz(long double kHz) { return kilohertz{kHz}; } |
||||
constexpr kilohertz operator""_kHz(uint64_t kHz) { return kilohertz{kHz}; } |
||||
constexpr megahertz operator""_MHz(long double MHz) { return megahertz{MHz}; } |
||||
constexpr megahertz operator""_MHz(uint64_t MHz) { return megahertz{MHz}; } |
||||
constexpr gigahertz operator""_GHz(long double GHz) { return gigahertz{GHz}; } |
||||
constexpr gigahertz operator""_GHz(uint64_t GHz) { return gigahertz{GHz}; } |
||||
} |
@ -1,406 +0,0 @@ |
||||
// <chrono> -*- C++ -*- |
||||
|
||||
// Copyright (C) 2008-2015 Free Software Foundation, Inc. |
||||
// |
||||
// This file is part of the GNU ISO C++ Library. This library is free |
||||
// software; you can redistribute it and/or modify it under the |
||||
// terms of the GNU General Public License as published by the |
||||
// Free Software Foundation; either version 3, or (at your option) |
||||
// any later version. |
||||
|
||||
// This library is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
|
||||
// Under Section 7 of GPL version 3, you are granted additional |
||||
// permissions described in the GCC Runtime Library Exception, version |
||||
// 3.1, as published by the Free Software Foundation. |
||||
|
||||
// You should have received a copy of the GNU General Public License and |
||||
// a copy of the GCC Runtime Library Exception along with this program; |
||||
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
||||
// <http://www.gnu.org/licenses/>. |
||||
|
||||
#pragma once |
||||
|
||||
#include <chrono> |
||||
#include <limits> |
||||
#include <ratio> |
||||
#include <type_traits> |
||||
|
||||
using std::common_type; |
||||
using std::enable_if; |
||||
using std::is_convertible; |
||||
using std::ratio; |
||||
using std::ratio_divide; |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
template <typename _Rep, typename _Period = ratio<1>> |
||||
struct frequency; |
||||
|
||||
template <typename _CT, typename _Period1, typename _Period2> |
||||
struct __frequency_common_type_wrapper |
||||
{ |
||||
private: |
||||
typedef std::__static_gcd<_Period1::num, _Period2::num> __gcd_num; |
||||
typedef std::__static_gcd<_Period1::den, _Period2::den> __gcd_den; |
||||
typedef typename _CT::type __cr; |
||||
typedef ratio<__gcd_num::value, |
||||
(_Period1::den / __gcd_den::value) * _Period2::den> |
||||
__r; |
||||
|
||||
public: |
||||
typedef std::__success_type<TeensyTimerTool::frequency<__cr, __r>> type; |
||||
}; |
||||
|
||||
template <typename _Period1, typename _Period2> |
||||
struct __frequency_common_type_wrapper<std::__failure_type, _Period1, _Period2> |
||||
{ |
||||
typedef std::__failure_type type; |
||||
}; |
||||
} |
||||
|
||||
namespace std |
||||
{ |
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
struct common_type<TeensyTimerTool::frequency<_Rep1, _Period1>, TeensyTimerTool::frequency<_Rep2, _Period2>> |
||||
: public TeensyTimerTool::__frequency_common_type_wrapper<typename __member_type_wrapper<std::common_type<_Rep1, _Rep2>>::type, _Period1, _Period2>::type |
||||
{ |
||||
}; |
||||
} |
||||
|
||||
namespace TeensyTimerTool |
||||
{ |
||||
using namespace std::chrono; |
||||
|
||||
// Primary template for frequency_cast impl. |
||||
template <typename _ToDur, typename _CF, typename _CR, |
||||
bool _NumIsOne = false, bool _DenIsOne = false> |
||||
struct __frequency_cast_impl |
||||
{ |
||||
template <typename _Rep, typename _Period> |
||||
static constexpr _ToDur |
||||
__cast(const frequency<_Rep, _Period>& __d) |
||||
{ |
||||
typedef typename _ToDur::rep __to_rep; |
||||
return _ToDur(static_cast<__to_rep>(static_cast<_CR>(__d.count()) * static_cast<_CR>(_CF::num) / static_cast<_CR>(_CF::den))); |
||||
} |
||||
}; |
||||
|
||||
template <typename _ToDur, typename _CF, typename _CR> |
||||
struct __frequency_cast_impl<_ToDur, _CF, _CR, true, true> |
||||
{ |
||||
template <typename _Rep, typename _Period> |
||||
static constexpr _ToDur |
||||
__cast(const frequency<_Rep, _Period>& __d) |
||||
{ |
||||
typedef typename _ToDur::rep __to_rep; |
||||
return _ToDur(static_cast<__to_rep>(__d.count())); |
||||
} |
||||
}; |
||||
|
||||
template <typename _ToDur, typename _CF, typename _CR> |
||||
struct __frequency_cast_impl<_ToDur, _CF, _CR, true, false> |
||||
{ |
||||
template <typename _Rep, typename _Period> |
||||
static constexpr _ToDur |
||||
__cast(const frequency<_Rep, _Period>& __d) |
||||
{ |
||||
typedef typename _ToDur::rep __to_rep; |
||||
return _ToDur(static_cast<__to_rep>( |
||||
static_cast<_CR>(__d.count()) / static_cast<_CR>(_CF::den))); |
||||
} |
||||
}; |
||||
|
||||
template <typename _ToDur, typename _CF, typename _CR> |
||||
struct __frequency_cast_impl<_ToDur, _CF, _CR, false, true> |
||||
{ |
||||
template <typename _Rep, typename _Period> |
||||
static constexpr _ToDur |
||||
__cast(const frequency<_Rep, _Period>& __d) |
||||
{ |
||||
typedef typename _ToDur::rep __to_rep; |
||||
return _ToDur(static_cast<__to_rep>( |
||||
static_cast<_CR>(__d.count()) * static_cast<_CR>(_CF::num))); |
||||
} |
||||
}; |
||||
|
||||
template <typename _Tp> |
||||
struct __is_frequency |
||||
: std::false_type |
||||
{ |
||||
}; |
||||
|
||||
template <typename _Rep, typename _Period> |
||||
struct __is_frequency<frequency<_Rep, _Period>> |
||||
: std::true_type |
||||
{ |
||||
}; |
||||
|
||||
/// duration_cast |
||||
template <typename _ToDur, typename _Rep, typename _Period> |
||||
constexpr typename enable_if<__is_frequency<_ToDur>::value, _ToDur>::type duration_cast(const frequency<_Rep, _Period>& __d) |
||||
{ |
||||
typedef typename _ToDur::period __to_period; |
||||
typedef typename _ToDur::rep __to_rep; |
||||
typedef ratio_divide<_Period, __to_period> __cf; |
||||
typedef typename common_type<__to_rep, _Rep, intmax_t>::type __cr; |
||||
typedef __frequency_cast_impl<_ToDur, __cf, __cr, __cf::num == 1, __cf::den == 1> __dc; |
||||
|
||||
return __dc::__cast(__d); |
||||
} |
||||
|
||||
/// frequency |
||||
template <typename _Rep, typename _Period> |
||||
struct frequency |
||||
{ |
||||
typedef _Rep rep; |
||||
typedef _Period period; |
||||
|
||||
static_assert(!__is_frequency<_Rep>::value, "rep cannot be a frequency"); |
||||
static_assert(std::chrono::__is_ratio<_Period>::value, "period must be a specialization of ratio"); |
||||
static_assert(_Period::num > 0, "period must be positive"); |
||||
|
||||
// 20.11.5.1 construction / copy / destroy |
||||
constexpr frequency() = default; |
||||
|
||||
// NB: Make constexpr implicit. This cannot be explicitly |
||||
// constexpr, as any UDT that is not a literal type with a |
||||
// constexpr copy constructor will be ill-formed. |
||||
frequency(const frequency&) = default; |
||||
|
||||
template <typename _Rep2, typename = typename enable_if<is_convertible<_Rep2, rep>::value && (std::chrono::treat_as_floating_point<rep>::value || !std::chrono::treat_as_floating_point<_Rep2>::value)>::type> |
||||
constexpr explicit frequency(const _Rep2& __rep) |
||||
: __r(static_cast<rep>(__rep)) |
||||
{ |
||||
} |
||||
|
||||
template <typename _Rep2, typename _Period2, typename = typename enable_if<treat_as_floating_point<rep>::value || (ratio_divide<_Period2, period>::den == 1 && !treat_as_floating_point<_Rep2>::value)>::type> |
||||
constexpr frequency(const frequency<_Rep2, _Period2>& __d) |
||||
: __r(duration_cast<frequency>(__d).count()) {} |
||||
|
||||
~frequency() = default; |
||||
frequency& operator=(const frequency&) = default; |
||||
|
||||
// 20.11.5.2 observer |
||||
constexpr rep count() const { return __r; } |
||||
|
||||
constexpr frequency operator+() const { return *this; } |
||||
constexpr frequency operator-() const { return frequency(-__r); } |
||||
|
||||
frequency& operator++() |
||||
{ |
||||
++__r; |
||||
return *this; |
||||
} |
||||
|
||||
frequency operator++(int) |
||||
{ |
||||
return frequency(__r++); |
||||
} |
||||
|
||||
frequency& operator--() |
||||
{ |
||||
--__r; |
||||
return *this; |
||||
} |
||||
|
||||
frequency |
||||
operator--(int) |
||||
{ |
||||
return frequency(__r--); |
||||
} |
||||
|
||||
frequency& |
||||
operator+=(const frequency& __d) |
||||
{ |
||||
__r += __d.count(); |
||||
return *this; |
||||
} |
||||
|
||||
frequency& |
||||
operator-=(const frequency& __d) |
||||
{ |
||||
__r -= __d.count(); |
||||
return *this; |
||||
} |
||||
|
||||
frequency& |
||||
operator*=(const rep& __rhs) |
||||
{ |
||||
__r *= __rhs; |
||||
return *this; |
||||
} |
||||
|
||||
frequency& |
||||
operator/=(const rep& __rhs) |
||||
{ |
||||
__r /= __rhs; |
||||
return *this; |
||||
} |
||||
|
||||
// DR 934. |
||||
template <typename _Rep2 = rep> |
||||
typename enable_if<!treat_as_floating_point<_Rep2>::value, |
||||
frequency&>::type |
||||
operator%=(const rep& __rhs) |
||||
{ |
||||
__r %= __rhs; |
||||
return *this; |
||||
} |
||||
|
||||
template <typename _Rep2 = rep> |
||||
typename enable_if<!treat_as_floating_point<_Rep2>::value, |
||||
frequency&>::type |
||||
operator%=(const frequency& __d) |
||||
{ |
||||
__r %= __d.count(); |
||||
return *this; |
||||
} |
||||
|
||||
// 20.11.5.4 special values |
||||
static constexpr frequency |
||||
zero() |
||||
{ |
||||
return frequency(duration_values<rep>::zero()); |
||||
} |
||||
|
||||
static constexpr frequency |
||||
min() |
||||
{ |
||||
return frequency(duration_values<rep>::min()); |
||||
} |
||||
|
||||
static constexpr frequency |
||||
max() |
||||
{ |
||||
return frequency(duration_values<rep>::max()); |
||||
} |
||||
|
||||
private: |
||||
rep __r; |
||||
}; |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr typename common_type<frequency<_Rep1, _Period1>, frequency<_Rep2, _Period2>>::type operator+(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
typedef frequency<_Rep1, _Period1> __dur1; |
||||
typedef frequency<_Rep2, _Period2> __dur2; |
||||
typedef typename common_type<__dur1, __dur2>::type __cd; |
||||
return __cd(__cd(__lhs).count() + __cd(__rhs).count()); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr typename common_type<frequency<_Rep1, _Period1>, frequency<_Rep2, _Period2>>::type operator-(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
typedef frequency<_Rep1, _Period1> __dur1; |
||||
typedef frequency<_Rep2, _Period2> __dur2; |
||||
typedef typename common_type<__dur1, __dur2>::type __cd; |
||||
return __cd(__cd(__lhs).count() - __cd(__rhs).count()); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period, typename _Rep2> |
||||
constexpr frequency<typename __common_rep_type<_Rep1, _Rep2>::type, _Period> operator*(const frequency<_Rep1, _Period>& __d, const _Rep2& __s) |
||||
{ |
||||
typedef frequency<typename common_type<_Rep1, _Rep2>::type, _Period> __cd; |
||||
return __cd(__cd(__d).count() * __s); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Rep2, typename _Period> |
||||
constexpr frequency<typename __common_rep_type<_Rep2, _Rep1>::type, _Period> operator*(const _Rep1& __s, const frequency<_Rep2, _Period>& __d) |
||||
{ |
||||
return __d * __s; |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period, typename _Rep2> |
||||
constexpr frequency<typename __common_rep_type<_Rep1, typename enable_if<!__is_frequency<_Rep2>::value, _Rep2>::type>::type, _Period> operator/(const frequency<_Rep1, _Period>& __d, const _Rep2& __s) |
||||
{ |
||||
typedef frequency<typename common_type<_Rep1, _Rep2>::type, _Period> __cd; |
||||
return __cd(__cd(__d).count() / __s); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr typename common_type<_Rep1, _Rep2>::type operator/(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
typedef frequency<_Rep1, _Period1> __dur1; |
||||
typedef frequency<_Rep2, _Period2> __dur2; |
||||
typedef typename common_type<__dur1, __dur2>::type __cd; |
||||
return __cd(__lhs).count() / __cd(__rhs).count(); |
||||
} |
||||
|
||||
// DR 934. |
||||
template <typename _Rep1, typename _Period, typename _Rep2> |
||||
constexpr frequency<typename __common_rep_type<_Rep1, typename enable_if<!__is_frequency<_Rep2>::value, _Rep2>::type>::type, _Period> operator%(const frequency<_Rep1, _Period>& __d, const _Rep2& __s) |
||||
{ |
||||
typedef frequency<typename common_type<_Rep1, _Rep2>::type, _Period> __cd; |
||||
return __cd(__cd(__d).count() % __s); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr typename common_type<frequency<_Rep1, _Period1>, frequency<_Rep2, _Period2>>::type operator%(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
typedef frequency<_Rep1, _Period1> __dur1; |
||||
typedef frequency<_Rep2, _Period2> __dur2; |
||||
typedef typename common_type<__dur1, __dur2>::type __cd; |
||||
return __cd(__cd(__lhs).count() % __cd(__rhs).count()); |
||||
} |
||||
|
||||
// comparisons |
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr bool operator==(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
typedef frequency<_Rep1, _Period1> __dur1; |
||||
typedef frequency<_Rep2, _Period2> __dur2; |
||||
typedef typename common_type<__dur1, __dur2>::type __ct; |
||||
return __ct(__lhs).count() == __ct(__rhs).count(); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr bool operator<(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
typedef frequency<_Rep1, _Period1> __dur1; |
||||
typedef frequency<_Rep2, _Period2> __dur2; |
||||
typedef typename common_type<__dur1, __dur2>::type __ct; |
||||
return __ct(__lhs).count() < __ct(__rhs).count(); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr bool operator!=(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
return !(__lhs == __rhs); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr bool operator<=(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
return !(__rhs < __lhs); |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr bool operator>(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
return __rhs < __lhs; |
||||
} |
||||
|
||||
template <typename _Rep1, typename _Period1, typename _Rep2, typename _Period2> |
||||
constexpr bool operator>=(const frequency<_Rep1, _Period1>& __lhs, const frequency<_Rep2, _Period2>& __rhs) |
||||
{ |
||||
return !(__lhs < __rhs); |
||||
} |
||||
|
||||
using hertz = frequency<float>; |
||||
using kilohertz = frequency<float, std::kilo>; |
||||
using megahertz = frequency<float, std::mega>; |
||||
using gigahertz = frequency<float, std::giga>; |
||||
|
||||
constexpr hertz operator""_Hz(long double hz) { return hertz{hz}; } |
||||
constexpr hertz operator""_Hz(uint64_t hz) { return hertz{hz}; } |
||||
constexpr kilohertz operator""_kHz(long double kHz) { return kilohertz{kHz}; } |
||||
constexpr kilohertz operator""_kHz(uint64_t kHz) { return kilohertz{kHz}; } |
||||
constexpr megahertz operator""_MHz(long double MHz) { return megahertz{MHz}; } |
||||
constexpr megahertz operator""_MHz(uint64_t MHz) { return megahertz{MHz}; } |
||||
constexpr gigahertz operator""_GHz(long double GHz) { return gigahertz{GHz}; } |
||||
constexpr gigahertz operator""_GHz(uint64_t GHz) { return gigahertz{GHz}; } |
||||
} |
@ -1,36 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include "config.h" |
||||
#include <type_traits> |
||||
|
||||
#if defined(USE_TIME_LITERALS) |
||||
#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) |
||||
{ |
||||
using namespace std::chrono; |
||||
return (duration_cast<duration<float, std::micro>>(v).count()); |
||||
} |
||||
|
||||
|
||||
#endif |
||||
|
||||
} // namespace TeensyTimerTool
|
@ -1,36 +0,0 @@ |
||||
#pragma once |
||||
#include "ErrorHandling/error_codes.h" |
||||
#include "config.h" |
||||
#include "Arduino.h" |
||||
|
||||
#if not defined(PLAIN_VANILLA_CALLBACKS) |
||||
|
||||
#include <functional> |
||||
inline void std::__throw_bad_function_call() |
||||
{ |
||||
while (1) {} // do whatever you want to do instead of an exception
|
||||
} |
||||
namespace TeensyTimerTool |
||||
{ |
||||
using callback_t = std::function<void(void)>; |
||||
using errorFunc_t = std::function<void(errorCode)>; |
||||
|
||||
extern void attachErrFunc(errorFunc_t); |
||||
extern errorCode postError(errorCode); |
||||
} // namespace TeensyTimerTool
|
||||
#else |
||||
namespace TeensyTimerTool |
||||
{ |
||||
using callback_t = void (*)(); |
||||
using errorFunc_t = void (*)(errorCode); |
||||
|
||||
extern void attachErrFunc(errorFunc_t); |
||||
extern errorCode postError(errorCode); |
||||
} // namespace TeensyTimerTool
|
||||
#endif |
||||
|
||||
#if defined(TTT_TEENSY4X) |
||||
#define TTT_F_CPU F_CPU_ACTUAL |
||||
#else |
||||
#define TTT_F_CPU F_CPU |
||||
#endif |
@ -1,17 +0,0 @@ |
||||
#include "Arduino.h" |
||||
|
||||
// General =============================================================================================
|
||||
//#include "../lib/TeensyTimerTool/examples/01_Basic/HelloPeriodic/HelloPeriodic.ino"
|
||||
//#include "../lib/TeensyTimerTool/examples/01_Basic/HelloOneShot/HelloOneShot.ino"
|
||||
//#include "../lib/TeensyTimerTool/examples/01_Basic/UsingChronoDurations1/UsingChronoDurations1.ino"
|
||||
//#include "../lib/TeensyTimerTool/examples/01_Basic/UsingChronoDurations2/UsingChronoDurations2.ino"
|
||||
//#include "../lib/TeensyTimerTool/examples/02_Advanced/CallbackWithParams/CallbackWithParams.ino"
|
||||
//#include "../lib/TeensyTimerTool/examples/02_Advanced/UsingLambdas/UsingLambdas.ino"
|
||||
|
||||
//T3.x ================================================================================================
|
||||
//#include "../lib/TeensyTimerTool/examples/03_Applications/DoubleExposure/DoubleExposure.ino"
|
||||
|
||||
//T4.x ================================================================================================
|
||||
//#include "../lib/TeensyTimerTool/examples/01_Basic/MoreTimers/MoreTimers.ino"
|
||||
//#include "../lib/TeensyTimerTool/examples/01_Basic/RTC_Timer/RTC_Timer.ino"
|
||||
//#include "../lib/TeensyTimerTool/examples/99_Misc/PinInformation/PinInformation.ino"
|
@ -1 +0,0 @@ |
||||
Subproject commit 526c3e75aa2f23d1c51f6a5b443af6a2aac4955e |
Loading…
Reference in new issue