TeensyTimerTool

Thanks for spotting this, updated the config documentation. I'll add the ARDUINO_TEENSY41 #define in a later version (need to spot all the relevant places frist)

Cool. Any current place with _teensy40 should map to also _teensy41 as all the current 4.0 pins are unchanged using the same 1062. Going forward some _teensy41 specific additions may work as it seems few new pins will be added when the board gets two more "edge inches".
 
Cool. Any current place with _teensy40 should map to also _teensy41 as all the current 4.0 pins are unchanged using the same 1062. Going forward some _teensy41 specific additions may work as it seems few new pins will be added when the board gets two more "edge inches".

Just to be clear, all of the normal pins (0-23 external pins) are the same. The first 2 sets of solder pads in the Teensy 4.0 (pads 24-33) do map into the new pins on the outer rows on the Teensy 4.1. However, the pads for the SD card (34-39 in Teensy 4.0) got relocated to pins 42-47 in the Teensy 4.1.
 
Just to be clear, all of the normal pins (0-23 external pins) are the same. The first 2 sets of solder pads (pads 24-33) do map into the new pins on the outer rows. But the pads for the SD card (34-39 in Teensy 4.0) got relocated to pins 42-47 in the Teensy 4.1.

Confused. Does that mean the printout of the referenced script is not correct for the T4.1? Didn't have a chance to test it with a 4.1 but defragster did generate some data using the script with a 4.1. Here a link to the (maybe wrong?) table https://github.com/luni64/TeensyTimerTool/wiki/Avoid-PWM-timer-clashes#teensy-41
 
Thanks, very useful to me that lib. Just integrated into my project.

Glad you like it. Let me know if something is not working as expected. The code base is relatively new, so there still might be some bugs...
 
Confused. Does that mean the printout of the referenced script is not correct for the T4.1? Didn't have a chance to test it with a 4.1 but defragster did generate some data using the script with a 4.1. Here a link to the (maybe wrong?) table https://github.com/luni64/TeensyTimerTool/wiki/Avoid-PWM-timer-clashes#teensy-41

No, the print out is correct. What I was pointing out that pin #34 and above on the Teensy 4.1 are different pins on the Teensy 4.0.

On the Teensy 4.1, pin #34 connects to GPIO7_29, and does not have PWM capability. Pin 34 is the second to the last pin on the outside row of pins on the left side (with the USB port facing up).

On the Teensy 4.0, pin #34 connects to GPIO8_15, and uses the FLEX_PWM1 timer for PWM. On the Teensy 4.0, pin #34 is the first solder pad underneath the Teensy 4.0 on the left side in the first row of solder pads of the Teensy 4.0. That row of solder pads is made for bringing out a micro-SD card reader. On some of the breakout boards for the Teensy 4.0, these pins are brought out so that you could connect your own micro-SD card reader.

The reason for this is that Teensy 4.1 added 20 more external pins, growing the length of the PCB from 1.4" to 2.4". Of those 20 extra pins, there is a 3.3v and ground pin. Then there are 9 pins on one side, and 9 pins on the other. Paul numbered these pins sequentially. Pins 24-32 on the right side are the same pins that are provided in solder pads in the Teensy 4.0. There is also pin 33 on the left side that is a pin brought out with a solder pad in the Teensy 4.0. This leaves 8 more pins, that on the Teensy 4.1 are numbered pin 34-41.

In addition to the 48 pins on the edges, the Teensy 4.1 has a micro-SD card reader, similar to the Teensy 3.5/3.6. On the Teensy 4.1, the micro-SD card reader pins uses pins 42-47 for the micro-SD reader.

Other Teensies have similar pin naming challenges. On the Teensy 3.1, and 3.2 the analog pin in the back row that provides digital to analog conversion (i.e. DAC, it can be used for mono sound output) is pin A14. On the Teensy LC, the DAC pin in the same place is A12, not A14. On the Teensy 3.5 and 3.6, A14 is a normal analog input and digital pin that is on the left end of the Teensy, and the two DAC pins are A21/A22. The Teensy 4.0 does not have an A14 pin, and it also does not have a DAC pin at all. The Teensy 4.1 does have an A14 pin, and it is on the left side. Like the Teensy 4.0, there is no DAC pin.
 
I just needed a periodic timer with callback and this fits and works perfectly.

Just noticed that it might not be work exactly perfectly all the time. But i think the issue is, the periodic timer and callback gets called from an interrupt and i modify a shared datastructure in the callback.

What would be the preferred way to protect this datastructure using teensyduino?

- disable irqs around the non-callback modifications
- some kind of mutex? what are available?

Any suggestions are appreciated.
 
Disabling interrupts when accessing the data structure will certainly work. Maybe the Tick Timers are an option for you? They use the cycle counter for timing and their callbacks don't run in an interrupt context which might remove some complexity...

BTW: I was also looking for mutexes some weeks ago but didn't find something usable. In case you have more luck I'd be very interested.
 
You can always check by disabling interrupts when you access the structure. If this doesn't remove the problem it probably is related to something else.

Thanks for the link, I'll give that a try.
 
One thing put into use in Teensy4 micros() code is here : github.com/PaulStoffregen/cores/blob/master/teensy4/delay.c#L67

Putting this around a block of code will repeat if any interrupt occurs during execution:
Code:
#include "arm_math.h"	// micros() synchronization
uint32_t systick_safe_read;	 // micros() synchronization
// … [B]systick_safe_read[/B] is just a ref var of no consequence
uint32_t micros(void)
{
	uint32_t smc, scc;
	do {
		[B]__LDREXW[/B](&systick_safe_read);
[B][COLOR="#FF0000"]		smc = systick_millis_count;
		scc = systick_cycle_count;
[/COLOR][/B]	} while ( [B]__STREXW[/B](1, &systick_safe_read));
// ...

It works in the case of micros() as all the needed data is just copied to local vars - but must be an updated value if the systick _isr() updates that so the two values are in sync.

ARM support for this is in the T_3.x and T_4.x MCU's - not sure if I checked the T_LC.

To get a 'current/atomic' copy of the "shared datastructure" for local use this would work without stopping interrupts. Any interrupt would just cause the copy to repeat. Any data changes like "count++" in that block would also repeat so it may not work for this case if not 'read only'.
 
Last edited:
Just added to p#163 code : #include "arm_math.h" // micros() synchronization

From the linked github - it is needed to compile.

The micros() was working close to 40 cycles on average - Paul added the 'asm' and a refinement to prevent 'overflow increment' and that completes in more like 36-38 cycles now.

Seemed to be effective and indeed a useful pattern without much overhead or bad side effects. interrupts never stopped and only if _isr fires is the code re-runs.

Funny the linked "4.19. Semaphores and Mutual Exclusives (Mutex) " uses the same pattern. It seems to be the only generally usable one:
Code:
Example 7. Simple code for getting a lock
void get_lock(volatile int *Lock_Variable)
{ // Note: __LDREXW and __STREXW are CMSIS functions
int status = 0;
do {
while (__LDREXW(&Lock_Variable) != 0); // Wait until
// Lock_Variable is free
status = __STREXW(1, &Lock_Variable); // Try to set
// Lock_Variable
} while (status!=0); //retry until lock successfully
__DMB();		// Do not start any other memory access
// until memory barrier is completed
return;
}

Indeed that would keep it safe for change across interrupts - but if locked out would need care not to deadlock. A counter in the loop() could break if failing to get the semaphore were handled.
Code:
int get_lock(volatile int *Lock_Variable)
{ // Note: __LDREXW and __STREXW are CMSIS functions
int status = 0[B], cnt=0[/B];
do {
while (__LDREXW(&Lock_Variable) != 0); // [B][COLOR="#FF0000"]Wait until Lock_Variable is free[/COLOR][/B]
status = __STREXW(1, &Lock_Variable); // Try to set
[B]if ( ++cnt > 5 ) status = -1;[/B]
// Lock_Variable
} while (status!=0); //retry until lock successfully
__DMB();		// Do not start any other memory access
// until memory barrier is completed
[B]return status;[/B]
}
The cnt of retry could be tracked - would a timeout on first while( Lock_Variable ); allow a graceful fail?
 
With a Teens 3.2, I am trying to use the new ability to set FTM_DEFAULT_PSC in userConfig.h to change the FTM timer prescaler. But when I run the code you provided to print the max period and resolution, there is no change when I change FTM_DEFAULT_PSC.

Second question: Is it possible to set the prescaler for the FTM0, FTM1 and FTM2 timers to different values?
 
I'll have a look later today. The second one is a bit tricky but should be possible with some changes in the lib.
 
I implemented the possibility to choose the prescaler for each FTM timer in the config file

Here the updated config section with some prescaler settings:
Code:
...
//--------------------------------------------------------------------------------------------
// 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_1,
        /*FTM2*/ PSC_64,
        /*FTM3*/ PSC_128
    };
...

Here some test code (Teensy 3.6)

Code:
#include "TeensyTimerTool.h"
using namespace TeensyTimerTool;

OneShotTimer t1(FTM0), t2(FTM1), t3(FTM2), t4(FTM3);

void setup()
{
    while (!Serial) {}
    attachErrFunc(ErrorHandler(Serial));

    t1.begin([] {}); // do nothing. We need to "begin" the timers to print the periods below
    t2.begin([] {});
    t3.begin([] {});
    t4.begin([] {});

    Serial.printf("max period: %0.5f s (FTM0)\n", t1.getMaxPeriod(), 5);
    Serial.printf("max period: %0.5f s (FTM1)\n", t2.getMaxPeriod(), 5);
    Serial.printf("max period: %0.5f s (FTM2)\n", t3.getMaxPeriod(), 5);
    Serial.printf("max period: %0.5f s (FTM3)\n", t4.getMaxPeriod(), 5);

    t1.trigger(1'000'000); // this will generate an overflow warning
}

void loop()
{
}

And here the output:

Code:
max period: 0.03495 s (FTM0)
max period: 0.00109 s (FTM1)
max period: 0.06990 s (FTM2)
max period: 0.13981 s (FTM3)
W-100: Period overflow, set to maximum


In case you are using the Arduino builder, using the user config file needs some preparation first. See here: https://github.com/luni64/TeensyTimerTool/wiki/Configuration (Project Scope Settings) for instructions. For PlatformIO and VisualTeensy it should run out of the box. -> To avoid confusion it might be best do test the new setting by writing them into defaultConfig.h first and if that works test the userConfig.h functionality.

I'll wait for your feedback before merging this into master.

EDIT: the code is in branch feature/ftmPrescale
 
I implemented the possibility to choose the prescaler for each FTM timer in the config file

It works great. And the problem I asked about was due to using userConfig.h with the Arduino IDE. It works fine in PlatformIO. Thank you.
 
Hello Luni,

I've just tried arduino 1.8.13, teensyduino 1.53b1 and TeensytimerTool v1.0.9. From an old project that work well with 1.8.12/1.5.2, with the new environment I have an error when I try to compile =>

Code:
D:\Mes documents\Arduino\libraries\TeensyTimerTool\src\Teensy\TCK\TCK.cpp: In function 'void yield()':
D:\Mes documents\Arduino\libraries\TeensyTimerTool\src\Teensy\TCK\TCK.cpp:72:67: error: 'processSerialEvents' is not a member of 'HardwareSerial'
                 if (HardwareSerial::serial_event_handlers_active) HardwareSerial::processSerialEvents();

This is with Teensy 4.0 board.

When using Teensy 3.2 all is OK.

Thank you,
Manu
 
Hi Luni,

i think the lib could benefit from a

Code:
#ifndef YIELD_TYPE
#define YIELD_TYPE YIELD_STANDARD
#endif

So that you can #define the YIELD_TYPE before you include the library.
 
Back
Top