Configuring TC module as frequency counter

Hello. I Have the same board and I am trying to do a frequency counter. I am not using the on board counters, mainly because I don't know how to. I actually got your code to work but I am not sure how to read it. I am just using a simple square wave to trigger pin 12. The period and pulse width, what does those numbers represent? Other than being period and pulse width. Is it in micro secs?

How would someone starting out learn how to work with coding these on-board counters. I think that is the best way for me to go.

Hi msloat450,

The best place to start is the SAMD21 datasheet, namely the TC timer chapter. However, initially the datasheet can be quite difficult, as often modules are inter-dependent without any overview of how everthing fits together. The example above uses generic clock, GPIO multiplexing, interrupts, event system and the TC timer itself.

In summary, the SAMD21 initially requires the TC timer to be attached to a clock source via the generic clock (GCLK) system. By default Arduino already assign some of the clock sources to generic clocks:

GCLK0 - DFLL48M 48Mhz Digital Frequency Locked Loop
GCLK1 - XOSC32K/OSC32K either external 32.768kHz crystal or internal 32.768kHz oscillator depending whether the board is CRYSTALLESS or not
GCLK2 - OSCULP32K internal Ultra Low Power 32.768kHz oscillator
GCLK3 - OSC8M 8MHz internal oscillator

It's possible to connect the TCx timer to any of the generic clocks: GCLK0 through to GCLK3, or alternatively setup and connect it to any of the remaining spare generic clock channels: GCLK4 to GCLK7. In the example above I've used GCLK5.

It's also possible to divide down the generic clock further, as in the above example:

GCLK->GENDIV.reg = GCLK_GENDIV_DIV(3) |    // Divide the 48MHz system clock by 3 = 16MHz

However, this will clock the whole TC timer peripheral and not just the timer output at a slower rate, meaning that register synchronization accesses will also be slower, which may or may not be an issue. Clocking peripherals at 32.768kHz, such as the RTC and WDT, can lead to some very slow register access times.

It's possbile to set-up and enable the timer only once it has been hooked up to a generic clock.

The TC timer's output is selected by activating the pin's peripheral mulitplexer in the PINCONFIG register and then selecting the required peripheral in the pin's PMUX register from the Port Function multiplexing table in the SAMD21 datasheet.

In the above example, the incoming pulses are routed on to the event system via the External Interrupt Controller (EIC) module. The event system is a 12-channel highway that allows for peripheral to peripheral communication with CPU intervention. The event system used asynchronously to allow the signals to pass through directly. The TC timer is set-up in period-pulsewidth (PPW) mode that times the high level of the event pulse and the interval between pulses.

As you mention, the timer is clocked with a 16MHz generic clock and divided by 16 with the timer's prescaler giving a timer tick of 1MHz (16MHz/16) or 1us.

The only other thing, is that I've just added an additional line to the interrupt code in the above example:

EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT3;        // Clear the interrupt flag on channel 3

This prevents the pin's interrupt service routine from being called when the input signal goes high, something I missed on earlier code that I posted.

Thank you.

If I wanted to find out time between pulses, which registers would you suggest I worry about in the code?

MartinL:
Hi msloat450,

The best place to start is the SAMD21 datasheet, namely the TC timer chapter. However, initially the datasheet can be quite difficult, as often modules are inter-dependent without any overview of how everthing fits together. The example above uses generic clock, GPIO multiplexing, interrupts, event system and the TC timer itself.

In summary, the SAMD21 initially requires the TC timer to be attached to a clock source via the generic clock (GCLK) system. By default Arduino already assign some of the clock sources to generic clocks:

GCLK0 - DFLL48M 48Mhz Digital Frequency Locked Loop
GCLK1 - XOSC32K/OSC32K either external 32.768kHz crystal or internal 32.768kHz oscillator depending whether the board is CRYSTALLESS or not
GCLK2 - OSCULP32K internal Ultra Low Power 32.768kHz oscillator
GCLK3 - OSC8M 8MHz internal oscillator

It's possible to connect the TCx timer to any of the generic clocks: GCLK0 through to GCLK3, or alternatively setup and connect it to any of the remaining spare generic clock channels: GCLK4 to GCLK7. In the example above I've used GCLK5.

It's also possible to divide down the generic clock further, as in the above example:

GCLK->GENDIV.reg = GCLK_GENDIV_DIV(3) |    // Divide the 48MHz system clock by 3 = 16MHz

However, this will clock the whole TC timer peripheral and not just the timer output at a slower rate, meaning that register synchronization accesses will also be slower, which may or may not be an issue. Clocking peripherals at 32.768kHz, such as the RTC and WDT, can lead to some very slow register access times.

It's possbile to set-up and enable the timer only once it has been hooked up to a generic clock.

The TC timer's output is selected by activating the pin's peripheral mulitplexer in the PINCONFIG register and then selecting the required peripheral in the pin's PMUX register from the Port Function multiplexing table in the SAMD21 datasheet.

In the above example, the incoming pulses are routed on to the event system via the External Interrupt Controller (EIC) module. The event system is a 12-channel highway that allows for peripheral to peripheral communication with CPU intervention. The event system used asynchronously to allow the signals to pass through directly. The TC timer is set-up in period-pulsewidth (PPW) mode that times the high level of the event pulse and the interval between pulses.

As you mention, the timer is clocked with a 16MHz generic clock and divided by 16 with the timer's prescaler giving a timer tick of 1MHz (16MHz/16) or 1us.

The only other thing, is that I've just added an additional line to the interrupt code in the above example:

EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT3;        // Clear the interrupt flag on channel 3

This prevents the pin's interrupt service routine from being called when the input signal goes high, something I missed on earlier code that I posted.

If I wanted to find out time between pulses, which registers would you suggest I worry about in the code?

In the example code above, the period variable gives the time between pulses in microseconds (us).

@msloat450

TOPIC SPLIT
DO NOT HIJACK / NECRO POST !

Could you take a few moments to Learn How To Use The Forum.
Other general help and troubleshooting advice can be found here.
It will help you get the best out of the forum in the future.