SAM L10/L11 Timer Counter (TC)

Last modified by Microchip on 2023/11/21 21:14

Overview

There are up to three Timer Counter (TC) peripheral instances. Each TC consists of a counter, a prescaler, compare/capture channels, and control logic. The counter can be set to count events or clock pulses. The counter, together with the compare/capture channels, can be configured to timestamp input events or I/O pin edges, allowing for capturing of frequency and/or pulse width. A TC can also perform waveform generation, such as frequency generation and pulse-width modulation.

Features

  • Selectable configuration
  • 8-, 16- or 32-bit TC operation, with compare/capture channels
  • Two compare/Capture Channels (CC) with:
    • Double buffered timer period setting (in 8-bit mode only)
    • Double buffered compare channel
  • Waveform generation
    • Frequency generation
    • Single-slope pulse-width modulation
  • Input capture
    • Event or I/O pin edge capture
    • Frequency capture
    • Pulse-width capture
    • Time-stamp capture
  • One input event
  • Interrupts/output events on:
    • Counter overflow/underflow
    • Compare match or capture
  • Internal prescaler
  • Direct Memory Access (DMA) support

Back to top

Block Diagram

SAM L10 timer counter block diagram

Each TC instance has up to two compare/capture channels (CC0 and CC1). The counter in the TC can either count events from the Event System, or clock ticks of the GCLK_TCx clock, which may be divided by the prescaler. The counter value is passed to the CCx where it can be either compared to user-defined values or captured. The CCx registers are using buffer registers (CCBUFx) for optimized timing. Each buffer register has a buffer valid (BUFV) flag that indicates when the buffer contains a new value.

The Counter register (COUNT) and the Compare and Capture registers with buffers (CCx and CCBUFx) can be configured as 8-, 16-, or 32-bit registers, according to max values. Mode settings (CTRLA.MODE) determine the maximum range of the Counter register. In 8-bit mode, a Period Value (PER) register and the Period Buffer Value (PERBUF) register are also available. The counter range and the operating frequency determine the maximum time resolution achievable with the TC peripheral.

The TC can be set to count up or down. Under normal operation, the counter value is continuously compared to the top or zero value to determine whether the counter has reached that value. On a comparison match, the TC can request DMA transactions or generate interrupts or events for the Event System. In compare operation, the counter value is continuously compared to the values in the CCx registers. In case of a match, the TC can request DMA transactions, or generate interrupts or events for the Event System.

In Waveform Generator mode, these comparisons are used to set the waveform period or pulse width. Capture operation can be enabled to perform input signal period and pulse width measurements, or to capture selectable edges from an I/O pin or internal event from Event System.

Back to top

Principle of Operation

In order to use the I/O lines of this peripheral, the I/O pins must be configured using the IO Pin Controller (PORT).

The TC bus clocks (CLK_TCx_APB) can be enabled and disabled in the Main Clock module. The default state of CLK_TCx_APB can be found in the Peripheral Clock Masking. The generic clocks (GCLK_TCx) are asynchronous to the user interface clock (CLK_TCx_APB). Due to this asynchronicity, accessing certain registers will require synchronization between the clock domains.

Two instances of the TC may share a peripheral clock channel. In this case, they cannot be set to different clock frequencies.

The DMA request lines are connected to the DMA Controller (DMAC). In order to use DMA requests with this peripheral, the DMAC must be configured first. The interrupt request line is connected to the Interrupt Controller. In order to use interrupt requests of this peripheral, the Interrupt Controller (NVIC) must be configured first.

The following registers are enable-protected, meaning that they can only be written when the TC is disabled (CTRLA.ENABLE = 0):

  • Control A register (CTRLA), except the Enable (ENABLE) and Software Reset (SWRST) bits
  • Drive Control register (DRVCTRL)
  • Wave register (WAVE)
  • Event Control register (EVCTRL)

Writing to Enable-Protected bits and setting the CTRLA.ENABLE bit can be performed in a single 32-bit access of the CTRLA register. Writing to Enable-Protected bits and clearing the CTRLA.ENABLE bit cannot be performed in a single 32-bit access.

Before enabling the TC, the peripheral must be configured by the following steps:

  1. Enable the TC bus clock (CLK_TCx_APB).
  2. Select 8-, 16- or 32-bit counter mode via the TC mode bit group in the Control A register (CTRLA.MODE). The default mode is 16-bit.
  3. Select one wave generation operation in the Waveform Generation Operation bit group in the WAVE register (WAVE.WAVEGEN).
  4. If desired, the GCLK_TCx clock can be prescaled via the Prescaler bit group in the Control A register (CTRLA.PRESCALER).
    • If the prescaler is used, select a prescaler synchronization operation via the prescaler and Counter Synchronization bit group in the Control A register (CTRLA.PRESYNC).
  5. If desired, select one-shot operation by writing a "1" to the One-Shot bit in the Control B Set register (CTRLBSET.ONESHOT).
  6. If desired, configure the counting direction down (starting from the TOP value) by writing a "1" to the Counter Direction bit in the Control B register (CTRLBSET.DIR).
  7. For capture operation, enable the individual channels to capture in the Capture Channel x Enable bit group in the Control A register (CTRLA.CAPTEN).
  8. If desired, enable inversion of the waveform output or IO pin input signal for individual channels via the Invert Enable bit group in the Drive Control register (DRVCTRL.INVEN).

Refer to the TC – Timer/Counter chapter from the product datasheet for more details.

Back to top

Code Example

/***
 *** The example has no copyright and can be used by anyone.
 *** The following example is based on Device File Package
 *** required to compile the macro definitions used.
 *** The Device File Package is available by downloading Atmel Studio 7.
 ***/


/***
 *** In this example,  The Timer Counter is used to generate PWM signals
 *** depending on condition set by the frequency period and duty cycle
 *** (freq, period, duty)          
 ***/

void InitPWM(uint16_t freq, uint16_t period, uint16_t duty)
{
/***
  *** Enable GCLK2 with XOSC32K
  *** as clock source for TC0 for ADC 1KHz Triggering
  ***/

 GCLK->GENCTRL[2].reg = GCLK_GENCTRL_DIV(1) | CURRENT_32KOSC |GCLK_GENCTRL_GENEN;
/*** (write synchronized) ***/
while((GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL2));
 GCLK->PCHCTRL[GCLK_TC0].reg = (GCLK_PCHCTRL_CHEN|GCLK_PCHCTRL_GEN_GCLK2);

/***
  *** Configure PORTS PA19 in TC2 WO[1] Peripheral E
  *** for waveform generation checking
  ***/

 PORT->Group[0].WRCONFIG.reg = (uint32_t)(PORT_WRCONFIG_HWSEL|
                                          PORT_WRCONFIG_WRPINCFG|
                                          PORT_WRCONFIG_WRPMUX|
                                          PORT_WRCONFIG_PINMASK(1<<3)|
                                          PORT_WRCONFIG_PMUXEN|
                                          PORT_WRCONFIG_PMUX(4));

/*** Enable TC2 GCLK with GCLK2 as source (XOSC32K) ***/
 GCLK->PCHCTRL[GCLK_TC2].reg = (GCLK_PCHCTRL_CHEN|GCLK_PCHCTRL_GEN_GCLK2);

/*** Disable TC2 (write synchronized) ***/
 TC2->COUNT16.CTRLA.bit.ENABLE = 0;
/*** (write synchronized) ***/
while(TC2->COUNT16.SYNCBUSY.reg & TC_SYNCBUSY_ENABLE);

    /***
   ***  TC2 in 16-bit counter with GLCK for synchronization
   *** and a DIV16 to get 1KHz event generation for the ADC
   ***/

     TC2->COUNT16.CTRLA.reg = (TC_CTRLA_MODE(TC_CTRLA_MODE_COUNT16_Val)|
                            TC_CTRLA_RUNSTDBY|
                            TC_CTRLA_ONDEMAND);    

/***
  *** TC2 Wave generator is configured as
  *** Match Pulse Width Modulation with
  *** a period to specify
  ***/

 TC2->COUNT16.WAVE.reg = (TC_WAVE_WAVEGEN_MPWM);
 TC2->COUNT16.CC[0].reg =    period;
/*** (write synchronized) ***/
while(TC2->COUNT16.SYNCBUSY.reg & TC_SYNCBUSY_CC0);

/*** The duty cycle is updated using CC1 register ***/
 TC2->COUNT16.CC[1].reg = duty;
/*** (write synchronized) ***/
while(TC2->COUNT16.SYNCBUSY.reg & TC_SYNCBUSY_CC1);

/*** enable interrupt
  *** for every period of the PWM signal
  *** This also allows to update the duty cycle
  ***/

 TC2->COUNT16.INTENSET.bit.MC0 = 1;

/*** Enable resready TC2 interrupt (ID 36) at core level ***/
 NVIC_EnableIRQ(TC2_IRQn);
 NVIC_SetPriority(TC2_IRQn,1);  

 Enable TC2 (write synchronized)
 TC2->COUNT16.CTRLA.bit.ENABLE = 1;
while(TC2->COUNT16.SYNCBUSY.reg & TC_SYNCBUSY_ENABLE);

}
/***
 *** Return the current duty cycle (# of clocks defining hi/low)
 ***/

uint16_t GetPWMDuty(void)
{
uint32_t duty_cycle;
/*** The duty cycle is updated using CC register ***/
    duty_cycle    = TC2->COUNT16.CC[1].reg;    //duty read        
return (uint16_t)duty_cycle;
}

/***
 *** Set the current duty cycle (# of clocks defining hi/low)
 ***/

void SetPWMDutyCycle(uint16_t duty)
{
/*** The duty cycle is updated using CC register ***/
 TC2->COUNT16.CC[1].reg    =    duty;
/*** (write synchronized) ***/
while(TC2->COUNT16.SYNCBUSY.reg & TC_SYNCBUSY_CC1);
}

/***
 *** Turn off the PWM
 ***/

void PWMOff(void)
{
/*** Disable TC2 ***/
    TC2->COUNT16.CTRLA.bit.ENABLE = 0;
/*** (write synchronized) ***/
   while(TC2->COUNT16.SYNCBUSY.reg & TC_SYNCBUSY_ENABLE);

/*** Configure PORTA for low power ***/
 PORT->Group[0].WRCONFIG.reg = (uint32_t)(PORT_WRCONFIG_HWSEL|
                                          PORT_WRCONFIG_WRPINCFG|
                                          PORT_WRCONFIG_WRPMUX|
                                          PORT_WRCONFIG_PINMASK(1<<3)|
                                          PORT_WRCONFIG_PMUX(0));

}

/***
 *** update the duty cycle in between pulses is done by calling this
 *** interrupt, like this example.
 ***/

void TC2_Handler(void)
{
/*** clear TC2 MC1 Interrupt FLAG register ***/
 TC2->COUNT16.INTFLAG.reg |=   TC_INTFLAG_MC0;
 updatePWMDutyCycle();
}

Back to top