Accessing timer registers Teensy 3

Status
Not open for further replies.

cchouard

Member
Hello,
Despite having browsed through this forum, I am unsuccessful understanding how to access the Teensy processor internal timer registers, such as FTM1_MOD, FTM1_CH0_PIN, FTM1_SC, FTM1_CNT from an Arduino code.
Also, i need to access the F_TIMER variable invoked by analogWriteFrequency() in pins_teensy.c
What should my Arduino sketch include or start with so that those register names and variable are recognised by the Arduino IDE compiler ?
Thank you !
 
Not sure what you are asking here, but assuming you include the correct header files, like Arduino.h, which a sketch (.INO file) does, than you can simply just use them.
If you are talking about .c or .cpp files, you need to directly or indirectly include kiinetis.h

Examples are in several libraries included with teensyduino. Example tlc_servos.h
Code:
...
    FTM1_CNT = 0;
    FTM1_MOD = TLC_TIMER_TEENSY3_SERVO_MOD;
    FTM1_C0V = TLC_TIMER_TEENSY3_SERVO_MOD - TLC_TIMER_TEENSY3_SERVO_CV;
    FTM1_C1V = TLC_TIMER_TEENSY3_SERVO_MOD - TLC_TIMER_TEENSY3_SERVO_CV - 1;
    FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_CPWMS | TLC_TIMER_TEENSY3_SERVO_PS;


Note: for some parts of the system, you must enable access to memory associated with different hardware things, like these timers, or Usarts, or SPI, or I2C or...

I believe in this case the early on system init code has enabled access to these registers. If it had not, you would need to have a line of code that looks something like:
Code:
SIM_SCGC6 |= SIM_SCGC6_FTM1;
 
These are all global #defines and constants, defined in the Teensyduino core files, so that developers will not have to look up physical device addresses in the reference manual all the time. It's a kind of mental hardware abstraction layer, so that library code might easier to re-use for different CPUs. By using FTM1_MOD, you don't have to care about the fact that a specific hardware register is at 0x4000C400 in the Teensy LC and at 0x4002D000 in the Teensy 3.2, for example. The #define and constant names are chosen to correspond to the register denominations used in the Kinetis reference manuals for the different Teensys. Thus, studying these will make you understand better these names.

Or you look at the files pins_teensy.c and those which are #included there, in the Teensyduino core files

For example, to set the FTM1 mod to 30000, simply write FTM1_MOD = 30000; in your code.

F_TIMER is also not a variable but a compile time constant. You might only read it, for example with Serial.println(F_TIMER);

FTM1_CH0_PIN is also a fixed #define, and points towards pin3 of the actual Teensys, which is PJRC's design decision.

You might use these #defines for your convenience, but you aren't forced to. You might for example "manually" reconfigure the pin mux in a way that Channel 0 of FTM1 is rerouted from PTA12 (Pin3) to PTB0 (Pin16).
 
Most of hardware registers for Teensy ARM are defined in hardware/teensy/avr/cores/teensy3/kinetis.h
the names are pretty close to the register names in the MCU reference manual/data sheet.
kinetis.h is available by default to the IDE sketches, so you can just write
Serial.println(FTM1_MOD,HEX);
 
Thank you all for your quick responses, much appreciated !
Serial.println(FTM1_MOD) works, no problem.
But both Serial.println(F_TIMER) and Serial.println(FTM1_CH0_PIN) generate a «*not declared in this scope*» compile error.
And #include <kinetis.h> before void setup() does not solve the issue.
What should I do to be able to read those «*compile constants*» (rather than «*variables*», agreed) ?
 
But both Serial.println(F_TIMER) and Serial.println(FTM1_CH0_PIN) generate a «*not declared in this scope*
.....
What should I do to be able to read those

Find their defines in pins_teensy.c and copy them into your code. Or just put those numbers into your code. F_TIMER is usually the same as F_BUS on Teensy 3.x, but it's 48 MHz on Teensy LC, even when F_BUS is 24 MHz. So you can use F_BUS, or just put a number like 48000000 into your code.

For FTM1_CH0_PIN, again you can find and copy the define. Or you can just use the pin number. You do know which pin you've connected, right?

This stuff really isn't that complicated. But the path to success looks like actually thinking about what these numbers really mean. Just copying the code from pins_teensy.c might work too, but blindly copying stuff without even a basic understanding of what the numbers really mean probably isn't going to work out well.
 
OK, Paul, thank you, I thought that there could be ways to access these numbers without having to copy-paste them into the sketch, that is fine.
I see your point that FTP1_CH0_PIN does not need to be read from a sketch.
As far as F_TIMER is concerned, browsing the pins_teensy.c and kinetis.h files, I can see that in most cases F_TIMER = F_BUS, and F_BUS is defined as a function of F_CPU (half of it).
It is strange to see that both Serial.println(F_BUS) and Serial.println(F_CPU) work, but not Serial.println(F_TIMER).
 
NOTE: some registers are only accessible in freeze mode, meaning, you need to enter their respective config mode before reading or writing them. Not doing so could also hard lock the MCU as well. Always follow the datasheet notes
 
OK,
As far as F_TIMER is concerned, browsing the pins_teensy.c and kinetis.h files, I can see that in most cases F_TIMER = F_BUS, and F_BUS is defined as a function of F_CPU (half of it).
It is strange to see that both Serial.println(F_BUS) and Serial.println(F_CPU) work, but not Serial.println(F_TIMER).
The key point is, that F_TIMER is only defined within the pins_teensy.c, which is not a header file so it is only accessible within that source file.

Although actually it is also defined in several libraries like TimerOne, TimerThree, a Header file within an example Snooze program... So maybe it might be nice to put into a central spot...
 
Status
Not open for further replies.
Back
Top