2.5 Timer Driver

2.5.1 Introduction

The MPLAB® Code Configurator (MCC) Timer Driver provides a portable API interface to assist a generic Timer interface that supports the MCC Melody Component concepts: configuration and firmware portability.

The Timer Driver will require a Peripheral LIBrary (PLIB) dependency, closely associated to a Timer hardware peripheral. On PIC® MCUs, the Timer Driver supports the following Timer PLIBs:

  • TCA
  • TCB

Timers are often used in timing and scheduling applications.

2.5.2 Required header files:

#include "mcc_generated_files/timer/tc[X][Y].h"

Note: Replace [X] with the selected Timer name and [Y] with the Timer instance number if necessary.

2.5.3 How to use the Timer Driver

The Timer driver generates a portable API interface. For examples of how to use the interface, refer to the examples linked below. Click the links to view the code snippets associated with each example:

2.5.4 Timer Driver

The Timer driver is an 8-bit, 16-bit or 32-bit timer that can operate as a free-running interval timer using PIC®, dsPIC® and AVR® microcontrollers (MCUs).

2.5.4.1 Module Documentation

2.5.4.1.1 Module description

The Timer driver is an 8-bit, 16-bit or 32-bit timer that can operate as a free-running interval timer using PIC®, dsPIC® and AVR® microcontrollers (MCUs).

Definitions
Note: The Timer Driver supports multiple Timer peripherals. "TCxy" is used to stand for the combination of the Timer Peripheral name (ie. TCA/TCB/TCD) and selected instance (ie. TCxy/TCA1).
Functions
Note: The Timer Driver supports multiple Timer peripherals. "TCxy" is used to stand for the combination of the Timer Peripheral name (ie. TCA/TCB/TCD) and selected instance (ie. TCA0/TCA1).

2.5.4.1.2 Definition Documentation

MYTIMER_CLOCK_FREQ

#define MYTIMER_CLOCK_FREQ TCxy_CLOCK_FREQ

Defines the Custom Name for the TCxy_CLOCK_FREQ.

myTimer_CounterGet

#define myTimer_CounterGet TCxy_CounterGet

Defines the Custom Name for the TCxy_CounterGet API.

myTimer_CounterSet

#define myTimer_CounterSet TCxy_CounterSet

Defines the Custom Name for the TCxy_CounterSet API.

myTimer_Deinitialize

#define myTimer_Deinitialize TCxy_Deinitialize

Defines the Custom Name for the TCxy_Deinitialize API.

myTimer_Initialize

#define myTimer_Initialize TCxy_Initialize

Defines the Custom Name for the TCxy_Initialize API.

MYTIMER_MAX_COUNT

#define MYTIMER_MAX_COUNT TCxy_MAX_COUNT

Defines the Custom Name for the TCxy_MAX_COUNT.

myTimer_MaxCountGet

#define myTimer_MaxCountGet TCxy_MaxCountGet

Defines the Custom Name for the TCxy_MaxCountGet API.

myTimer_OverflowCallbackRegister

#define myTimer_OverflowCallbackRegister TCxy_OverflowCallbackRegister

Defines the Custom Name for the TCxy_OverflowCallbackRegister API.

myTimer_PeriodGet

#define myTimer_PeriodGet TCxy_PeriodGet

Defines the Custom Name for the TCxy_PeriodGet API.

myTimer_PeriodSet

#define myTimer_PeriodSet TCxy_PeriodSet

Defines the Custom Name for the TCxy_PeriodSet API.

myTimer_Start

#define myTimer_Start TCxy_Start

Defines the Custom Name for the TCxy_Start API.

myTimer_Stop

#define myTimer_Stop TCxy_Stop

Defines the Custom Name for the TCxy_Stop API.

myTimer_Tasks

#define myTimer_Tasks TCxy_Tasks

Defines the Custom Name for the TCxy_Tasks API.

TCxy_CLOCK_FREQ

#define TCxy_CLOCK_FREQ (1000000UL)

Defines the timer prescaled clock frequency in hertz.

TCxy_MAX_COUNT

#define TCxy_MAX_COUNT (65535U)

Defines the maximum count of the timer.

TIMER_INTERRUPT_PRIORITY_SUPPORT

#define TIMER_INTERRUPT_PRIORITY_SUPPORT 0

The InterruptPrioritySet API is not supported.

TIMER_PERIODCOUNTSET_API_SUPPORT

#define TIMER_PERIODCOUNTSET_API_SUPPORT 0

Defines the deprecated SCCPx_Timer_PeriodCountSet or TMRx_PeriodCountSet API. Set it to 1 for backward compatibility for 16-bit MCUs only.

2.5.4.1.3 Function Documentation

The Timer Driver supports multiple Timer peripherals. "TCxy" is used to stand for the Timer Peripheral (ie. TCA/TCB/TCD) and selected instance (ie. TCA0/TCA1).

TCxy_Initialize()

void TCxy_Initialize (void )

Initializes the TCxy module. This routine must be called before any other TCxy routines.

Parameters:
None.
Returns:

None.

TCxy_Deinitialize()

void TCxy_Deinitialize (void )

Deinitializes the TCxy module.

Parameters:
None.
Returns:

None.

TCA0_Start()

void TCxy_Start (void )

Starts TCxy.

Precondition:

Initialize TCxy with TCxy_Initialize() before calling this API.

Parameters:
None.
Returns:

None.

Starts TCxy.

Parameters:
None.
Returns:

None.

TCxy_Stop()

void TCxy_Stop (void )

Stops TCxy.

Precondition:

Initialize TCxy with TCxy_Initialize() before calling this API.

Parameters:
None.
Returns:

None.

Stops TCxy.

Parameters:
None.
Returns:

None.

TCxy_CounterGet()

uint32_t TCxy_CounterGet (void )

Returns the current counter value.

Precondition:

Initialize TCxy with TCxy_Initialize() before calling this API.

Parameters:
None.
Returns:

Counter value

Parameters:
None.
Returns:

Current count value from the CNT register

TCxy_CounterSet()

void TCxy_CounterSet (uint32_t counterValue)

Sets the counter value.

Precondition:

Initialize TCxy with TCxy_Initialize() before calling this API.

Parameters:
counterValue

- Counter value to be written to the CNT register

Returns:

None.

TCxy_PeriodSet()

void TCxy_PeriodSet (uint32_t periodCount)

Sets the period count value.

Precondition:

Initialize TCxy with TCxy_Initialize() before calling this API.

Parameters:
periodCount

- Period count value to be written to the PER register

Returns:

None.

TCxy_PeriodGet()

uint32_t TCxy_PeriodGet (void )

Returns the current period value.

Precondition:

Initialize TCxy with TCxy_Initialize() before calling this API.

Parameters:
None.
Returns:

Period count value

Precondition:

Initialize the TCxy with TCxy_Initialize() before calling this API.

Parameters:
None.
Returns:

Period value from the PER register

TCxy_MaxCountGet()

uint32_t TCxy_MaxCountGet (void )

Returns the maximum count value.

Parameters:
None.
Returns:

Maximum count value

TCxy_Tasks()

void TCxy_Tasks (void )

Performs tasks to be executed during the TCxy overflow event.

Parameters:
None.
Returns:

None.

TCxy_OverflowCallbackRegister()

void TCxy_OverflowCallbackRegister (void(*)(void) CallbackHandler)

Registers a callback function for the TCxy overflow event.

Parameters:
CallbackHandler

- Address of the custom callback function

Returns:

None.

Registers a callback function for the TCA0 overflow event.

Parameters:
CallbackHandler

- Address to the custom callback function

Returns:

None.

2.5.4.2 Data Structure Documentation

2.5.4.2.1 TIMER_INTERFACE Struct Reference

Declares an instance of TIMER_INTERFACE for the TCA0 module.

Detailed Description

Declares an instance of TIMER_INTERFACE for the TCA0 module.

Structure containing the function pointers of the Timer driver.

#include <timer_interface.h>

Data Fields
  • void(* Initialize )(void)

    Pointer to MCCPx_Timer_Initialize, SCCPx_Timer_Initialize or TMRx_Initialize (e.g., SCCP1_Timer_Initialize or TMR1_Initialize).

  • void(* Deinitialize )(void)

    Pointer to MCCPx_Timer_Deinitialize, SCCPx_Timer_Deinitialize or TMRx_Deinitialize (e.g., SCCP1_Timer_Deinitialize or TMR1_Deinitialize).

  • void(* Start )(void)

    Pointer to MCCPx_Timer_Start, SCCPx_Timer_Start or TMRx_Start (e.g., SCCP1_Timer_Start or TMR1_Start).

  • void(* Stop )(void)

    Pointer to MCCPx_Timer_Stop, SCCPx_Timer_Stop or TMRx_Stop (e.g., SCCP1_Timer_Stop or TMR1_Stop).

  • void(* PeriodSet )(uint32_t count)

    Pointer to MCCPx_Timer_PeriodSet, SCCPx_Timer_PeriodSet or TMRx_PeriodSet (e.g., SCCP1_Timer_PeriodSet or TMR1_PeriodSet).

  • uint32_t(* PeriodGet )(void)

    Pointer to MCCPx_Timer_PeriodGet, SCCPx_Timer_PeriodGet or TMRx_PeriodGet (e.g., SCCP1_Timer_PeriodGet or TMR1_PeriodGet).

  • uint32_t(* CounterGet )(void)

    Pointer to MCCPx_Timer_CounterGet, SCCPx_Timer_CounterGet or TMRx_CounterGet (e.g., SCCP1_Timer_CounterGet or TMR1_CounterGet).

  • void(* CounterSet )(uint32_t count)

    Pointer to MCCPx_Timer_CounterSet, SCCPx_Timer_CounterSet or TMRx_CounterSet (e.g., SCCP1_Timer_CounterSet or TMR1_CounterSet).

  • uint32_t(* MaxCountGet )(void)

    Pointer to MCCPx_Timer_MaxCountGet, SCCPx_Timer_MaxCountGet or TMRx_MaxCountGet (e.g., SCCP1_Timer_MaxCountGet or TMR1_MaxCountGet).

  • void(* TimeoutCallbackRegister )(void(*CallbackHandler)(void))

    Pointer to MCCPx_TimeoutCallbackRegister, SCCPx_TimeoutCallbackRegister or TMRx_TimeoutCallbackRegister (e.g., SCCP1_TimeoutCallbackRegister or TMR1_TimeoutCallbackRegister).

  • void(* Tasks )(void)

    Pointer to MCCPx_Timer_Tasks, SCCPx_Timer_Tasks or TMRx_Tasks (e.g., SCCP1_Timer_Tasks or TMR1_Tasks, supported only in Polling mode).

Field Documentation

The documentation for this struct was generated from the following file:

source/

timer_interface.h

CounterGet

uint32_t(* CounterGet) (void)

Pointer to MCCPx_Timer_CounterGet, SCCPx_Timer_CounterGet or TMRx_CounterGet (e.g., SCCP1_Timer_CounterGet or TMR1_CounterGet).

CounterSet

void(* CounterSet) (uint32_t count)

Pointer to MCCPx_Timer_CounterSet, SCCPx_Timer_CounterSet or TMRx_CounterSet (e.g., SCCP1_Timer_CounterSet or TMR1_CounterSet).

Deinitialize

void(* Deinitialize) (void)

Pointer to MCCPx_Timer_Deinitialize, SCCPx_Timer_Deinitialize or TMRx_Deinitialize (e.g., SCCP1_Timer_Deinitialize or TMR1_Deinitialize).

Initialize

void(* Initialize) (void)

Pointer to MCCPx_Timer_Initialize, SCCPx_Timer_Initialize or TMRx_Initialize (e.g., SCCP1_Timer_Initialize or TMR1_Initialize).

MaxCountGet

uint32_t(* MaxCountGet) (void)

Pointer to MCCPx_Timer_MaxCountGet, SCCPx_Timer_MaxCountGet or TMRx_MaxCountGet (e.g., SCCP1_Timer_MaxCountGet or TMR1_MaxCountGet).

PeriodGet

uint32_t(* PeriodGet) (void)

Pointer to MCCPx_Timer_PeriodGet, SCCPx_Timer_PeriodGet or TMRx_PeriodGet (e.g., SCCP1_Timer_PeriodGet or TMR1_PeriodGet).

PeriodSet

void(* PeriodSet) (uint32_t count)

Pointer to MCCPx_Timer_PeriodSet, SCCPx_Timer_PeriodSet or TMRx_PeriodSet (e.g., SCCP1_Timer_PeriodSet or TMR1_PeriodSet).

Start

void(* Start) (void)

Pointer to MCCPx_Timer_Start, SCCPx_Timer_Start or TMRx_Start (e.g., SCCP1_Timer_Start or TMR1_Start).

Stop

void(* Stop) (void)

Pointer to MCCPx_Timer_Stop, SCCPx_Timer_Stop or TMRx_Stop (e.g., SCCP1_Timer_Stop or TMR1_Stop).

Tasks

void(* Tasks) (void)

Pointer to MCCPx_Timer_Tasks, SCCPx_Timer_Tasks or TMRx_Tasks (e.g., SCCP1_Timer_Tasks or TMR1_Tasks, supported only in Polling mode).

TimeoutCallbackRegister

void(* TimeoutCallbackRegister) (void(*CallbackHandler)(void))

Pointer to MCCPx_TimeoutCallbackRegister, SCCPx_TimeoutCallbackRegister or TMRx_TimeoutCallbackRegister (e.g., SCCP1_TimeoutCallbackRegister or TMR1_TimeoutCallbackRegister).

2.5.4.3 Timer Driver Examples

2.5.4.3.1 40 ms/80 ms Timer Period Change When Switch Is Pressed

This use case sets up a project which changes the time-out period between 40 ms and 80 ms, when a switch is pressed.

System Configuration
  • System>CLKCTRL:
    • Clock Selection: Internal high-frequency oscillator

    • Oscillator Frequency Selection: 4 MHz system clock (default)

  • System>Pins:
    • Pin Grid View: Select LED pin as output (Check the schematic for your board)

    • Pins: Rename Custom Name to "LED"

    • Pin Grid View: Select SWITCH pin as input (check the schematic for your board)

    • Pins: Rename Custom Name to "SW"

    • Enable Weak Pullup if needed

Timer Configuration
  • Drivers>Timer:
    • Timer PLIB Selector: TCA0

    • Timer Enable: False

    • Interrupt Driven: True

    • Requested Period: 100 ms

  • Drivers>TCA0:
    • Clock Select: System Clock/8

After configuring the components as described above, click 'Generate' to generate the code. Then add the following code snippets to your application:

#include "mcc_generated_files/system/system.h"
#include <util/delay.h>

/*
 * Development Board: AVR128DA48 Curiosity Nano Board
 * MCC Configuration:
 *     CLKCTRL module: Clock Selection - Internal high-frequency oscillator, Oscillator Frequency Selection - 4 MHz system clock (default)
 *     Timer module: Timer PLIB Selector - TCA0, Timer Enable - False, Interrupt Driven - True, Requested Timer Period - 100 ms
 *     TCA0 module: Clock Select - System Clock/8, Timer_PeriodSet() API Range - [2 us - 131.072 ms] (read-only)
 *     Pins module: RC6 - GPIO Output, CustomName - LED
 *                  RC7 - GPIO Input, CustomName - SW, Pull Up - Enable 
 */

#define SW_PRESSED 0U             // Switch - Active Low
#define SW_NOT_PRESSED 1U 
#define DEBONCE_DELAY_MS 20U      // Depends on hardware

#define MS_TO_TICKS(ms) (((TCA0_CLOCK_FREQ * (ms)) / 1000UL) - 1UL)
#define LED_40_MS (MS_TO_TICKS(40UL))           
#define LED_80_MS (MS_TO_TICKS(80UL))

static const struct TIMER_INTERFACE *Timer = &Timer0;

bool SW_StateGet(void)
{
    bool status = SW_NOT_PRESSED;
    if(SW_PRESSED == SW_GetValue())
    {
        _delay_ms(DEBONCE_DELAY_MS);
        if(SW_PRESSED == SW_GetValue())
        {
            status = SW_PRESSED;
        }        
    }
    return status;
}

void Timer_FrequencyChange(void)
{
    static volatile bool changePeriod = false;
    Timer->Stop();
    
    uint32_t maxCount = Timer->MaxCountGet();
    uint32_t newPeriod = changePeriod ? LED_40_MS:LED_80_MS;
    
    if(maxCount > newPeriod)
    {      
        Timer->PeriodSet(newPeriod);
    }
    else
    {
        // Invalid period
    }
    changePeriod = !changePeriod;
    Timer->Start(); 
}

void Timer_Callback(void)
{
    LED_Toggle();
}

int main(void)
{
    SYSTEM_Initialize();

    Timer->PeriodSet(LED_40_MS);
    Timer->TimeoutCallbackRegister(Timer_Callback);
    Timer->Start();    
  
    // Enable the Global Interrupts 
    sei(); 
    
    while(1)
    {
        if(SW_PRESSED == SW_StateGet())
        {
            Timer_FrequencyChange();
        }
    }    
}

2.5.4.3.2 A Simple Task Scheduler That Executes Two Different Tasks At Different Intervals Using Timer Interrupt

This use case sets up a project which executes two different tasks at different intervals using a timer interrupt.

System Configuration
  • System>CLKCTRL:
    • Clock Selection: Internal high-frequency oscillator

    • Oscillator Frequency Selection: 4 MHz system clock (default)

  • System>Pins:
    • Pin Grid View: Select LED1 pin as output (Check the schematic for your board)

    • Pins: Rename Custom Name to "LED1"

    • Pin Grid View: Select LED2 pin as output (Check the schematic for your board)

    • Pins: Rename Custom Name to "LED2"

Timer Configuration
  • Drivers>Timer:
    • Timer PLIB Selector: TCA0

    • Timer Enable: False

    • Interrupt Driven: True

    • Requested Period: 1 ms

After configuring the components as described above, click 'Generate' to generate the code. Then add the following code snippets to your application:

#include "mcc_generated_files/system/system.h"

/*
 * Development Board: AVR128DA48 Curiosity Nano Board
 * MCC Configuration:
 *     CLKCTRL module: Clock Selection - Internal high-frequency oscillator, Oscillator Frequency Selection - 4 MHz system clock (default) 
 *     Timer module: Timer PLIB Selector - TCA0, Timer Enable - False, Interrupt Driven - True, Requested Timer Period - 1 ms
 *     Pins module: PC5, PC6 - GPIO Output, CustomName - PC5->LED1, PC6->LED2 
 */

static void Task_A_2ms(void)
{
    LED1_SetHigh();
    NOP();
    NOP();
    LED1_SetLow();
    
    // Add your code here. E.g., LED Toggle
}
static void Task_B_5ms(void)
{
    LED2_SetHigh();
    NOP();
    NOP();
    LED2_SetLow();  
    
    // Add your code here. E.g., Read Sensor
}

static void Tasks_Scheduler(void)
{
    static volatile uint8_t oneMs_tickCounter =  0;
    
    oneMs_tickCounter++;
            
    if((oneMs_tickCounter % 2U) == 0U)
    {
        Task_A_2ms();    // Run at 2 ms, 4 ms, 6 ms, 8 ms, and 10 ms.
    }
    
    if((oneMs_tickCounter % 5U) == 0U)
    {
        Task_B_5ms();    // Run at 5 ms and 10 ms.
    }
    if(oneMs_tickCounter == 10U)
    {
        oneMs_tickCounter = 0;
    }
}

int main(void)
{
    const struct TIMER_INTERFACE *Timer = &Timer0;

    SYSTEM_Initialize();
 
    Timer->TimeoutCallbackRegister(Tasks_Scheduler);
    Timer->Start();
    
    // Enable the Global Interrupts 
    sei(); 

    while(1)
    {
    }   
}

2.5.4.3.3 4 ms/8 ms Timer Period Change During Each Interrupt Event

This use case configures the Timer module to use the TCA0 Peripheral Library (PLIB) to generate an overflow interrupt. The period of a timer is changed at run time during each interrupt event.

System Configuration
  • System>CLKCTRL:
    • Clock Selection: Internal high-frequency oscillator

    • Oscillator Frequency Selection: 4 MHz system clock (default)

  • System>Pins:
    • Pin Grid View: Select LED pin as output (Check the schematic for your board)

    • Pins: Rename Custom Name to "LED"

Timer Configuration
  • Drivers>Timer:
    • Timer PLIB Selector: TCA0

    • Timer Enable: False

    • Interrupt Driven: True

    • Requested Period: 10 ms

After configuring the components as described above, click 'Generate' to generate the code. Then add the following code snippets to your application:

#include "mcc_generated_files/system/system.h"

/*
 * Development Board: AVR128DA48 Curiosity Nano Board
 * MCC Configuration:
 *     CLKCTRL module: Clock Selection - Internal high-frequency oscillator, Oscillator Frequency Selection - 4 MHz system clock (default) (4 MHz)
 *     Timer module: Timer PLIB Selector - TCA0, Timer Enable - False, Interrupt Driven - True, Requested Timer Period - 10 ms 
 *     TCA0 module: Timer_PeriodSet() API Range - [250 ns - 16.384 ms] (read-only)
 *     Pins module: PC6 - GPIO Output, CustomName - LED 
 */
 
#define TIMER_TICK_FREQ TCA0_CLOCK_FREQ
#define MS_TO_TICKS(ms) (((TIMER_TICK_FREQ * (ms)) / 1000UL) - 1UL)
#define LED_4_MS MS_TO_TICKS(4UL)        // Set the period to be within the PeriodSet API range
#define LED_8_MS MS_TO_TICKS(8UL)

static const struct TIMER_INTERFACE *Timer = &Timer0;

static void Timer_PeriodChange(void)
{ 
    static volatile bool changePeriod = false;
    LED_Toggle();
    Timer->Stop();
    
    uint32_t maxCount = Timer->MaxCountGet();
    uint32_t newPeriod = changePeriod ? LED_4_MS : LED_8_MS;
    
    if(maxCount > newPeriod)
    {     
        Timer->PeriodSet(newPeriod);
    }
    else
    {
        // Invalid period       
    }
    
    changePeriod = !changePeriod;
    Timer->Start();
}


int main(void)
{
    SYSTEM_Initialize();
    
    Timer->PeriodSet(LED_4_MS);
    Timer->TimeoutCallbackRegister(Timer_PeriodChange);
    Timer->Start();
    
    // Enable the Global Interrupts 
    sei(); 
    
    while(1)
    {
    }    
}

2.5.4.3.4 500 ms Timer Period in Non-Interrupt Mode

This use case configures the Timer module to use the TCA0 PLIB to generate a specified timer period in Non-Interrupt mode.

System Configuration
  • System>CLKCTRL:
    • Clock Selection: Internal high-frequency oscillator

    • Oscillator Frequency Selection: 4 MHz system clock (default)

  • System>Pins:
    • Pin Grid View: Select LED pin as output (Check the schematic for your board)

    • Pins: Rename Custom Name to "LED"

Timer Configuration
  • Drivers>Timer:
    • Timer PLIB Selector: TCA0

    • Timer Enable: False

    • Interrupt Driven: False

    • Requested Period: 500 ms

  • Drivers>TCA0:
    • Clock Select: System Clock/64

After configuring the components as described above, click 'Generate' to generate the code. Then add the following code snippets to your application:

#include "mcc_generated_files/system/system.h"

/*
 * Development Board: AVR128DA48 Curiosity Nano Board
 * MCC Configuration:
 *     CLKCTRL module: Clock Selection - Internal high-frequency oscillator, Oscillator Frequency Selection - 4 MHz system clock (default)
 *     Timer module: Timer PLIB Selector - TCA0, Timer Enable - False, Interrupt Driven - False, Requested Timer Period - 500 ms 
 *     TCA0 module: Clock Selection - System Clock/64
 *     Pins module: PC6 - GPIO Output, CustomName - LED 
 */

static void Timer_Callback(void)
{
    LED_Toggle();   
}

int main(void)
{
    SYSTEM_Initialize();

    Timer0.TimeoutCallbackRegister(Timer_Callback);
    Timer0.Start();
    while(1)
    {
        Timer0.Tasks();
    }    
}

2.5.4.4 File Documentation

2.5.4.4.1 source/timer_interface.h File Reference

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
Detailed Description

TIMER Generated Driver Interface Header File