Updated date:

How to Use Timers in dsPic Microcontrollers

The author completed his final year engineering project with the dsPic micro-controllers, gaining extensive insight in these devices.

A timer module is an important peripheral inside a dsPic micro controller and can be used in a variety of applications.

This tutorial will make use of ready C-language code examples, coded in MplabX® IDE and tested on a Microchip® dsPic30f4011 micro-controller to walk you through the process of initializing and configuring timers for your dsPic applications.

A dsPic30f4011 micro controller and its programmer in my experimental setup.

A dsPic30f4011 micro controller and its programmer in my experimental setup.

Introduction to the Timer Module in dsPic30f and dsPic33f devices

The timer module in dsPic30f series devices contains a total of 5 16-bit timers namely:

  • Timers 1 through 5.

Similarly a dspic33f series device contains up to 9 16-bit timers namely:

  • Timers 1 through 9.

Each of these timers are grouped into three types, Type A, Type B and Type C depending on their special characteristics.

Type - AType - BType - C

Can be operated from low power 32 Khz oscillator.

Can be concatenated with Type - C timer to form 32 - bit timer.**

Can be concatenated with Type - B timer to form 32 - bit timer.**

Can run in Asynchronous mode with external source.

-

Has the ability to trigger A/D conversion.

External clock source can be synchronized with internal clock

External clock source is always synchronized with internal clock.*

External clock source is always synchronized with internal clock.*

Timer Modes of Operation in dsPic30f and dsPic33f Devices

In addition to being grouped into Type A, B or C, each timer can be operated in 4 different modes:

  1. Timer Mode
  2. Gated Timer Mode
  3. Synchronous Counter Mode
  4. Asynchronous Counter Mode
Timer ModeGated Timer ModeSynchronous Counter ModeAsynchronous Counter Mode

Increments by one on every rising edge of the input clock

Increments by one on every rising edge of the input clock as long as the external gate signal at the TxCK pin is high

Increments by one on every rising edge of the input clock

Increments by one on every rising edge of the input clock

Internal clock is used

Internal clock is used

External clock is used on TxCK pin

External clock is used on TxCK pin

_

_

External and internal device clock is synchronized

External and internal device clock is not synchronized

Interrupt is generated on period match

Interrupt is generated on falling edge of the TxCK pin

Interrupt is generated on period match

Interrupt is generated on period match

Example Code to Initialize a Timer for dsPic30f and dsPic33f

void init_Timer( void )
{
    T1CONbits.TON = 1;    //Activate the timer module
    T1CONbits.TCKPS = 0;  //Select input clock prescaler as 1:1
    
    T1CONbits.TGATE = 0;  //Disable Gate Time Accumulation Mode
    T1CONbits.TCS = 0;    //Select internal clock as the timer clock source
    T1CONbits.TSYNC = 0;  //External clock source is left unsynchronized
    
    PR1 = 0xFFFF;
}

General Procedure to Initialize a Timer in dsPic30f and dsPic33f MicroController

The following general procedure can be followed when initializing a timer for any application:

  1. Decide which timer to use.
  2. Decide if a 16-bit timer is required or a 32-bit timer is required.
  3. Decide the timer mode of operation.
  4. Set the clock pre-scaler.
  5. Decide if a timer interrupt or any other special event trigger is required.

1) Which Timer to Use

Each of the timers can be enabled by the TON bit in the TxCON register, where 'x' being the number of timer that is to be enabled.

In our example code we have enabled Timer 1 by setting the TON bit in the T1CON register to 1.

2) 16-bit Timer or 32-bit Timer?

Type-B and Type-C timers can be combined to operate as a single 32-bit timer, when combined, configuration of Type-B timer will prevail over the Type-C timer.

  • In a dsPic30f device Timers 2 and 3 can be concatenated in one 32-bit timer.
  • dsPic33f devices have more then one 32-bit timer pairs where timers 2/3, 4/5, 6/7 and 8/9 can also form 32-bit timer pairs.

For this purpose the T32 bit in the TxCON register of a Type-B timer should be set to 1.

TxCON.T32*Timer Configuaration

1

Concatenated with its other timer pair.

0

Will operate as an independent 16-bit timer.

3) Timer Mode of Operation

Timer Mode of operation can be selected according to the following table:

Bit NameBit ValueMode Selected

TxCON.TCS

0

Timer Mode

TxCON.TGATE, TxCON.TCS

1, 0

Gated Timer Mode

TxCON.TCS, TxCON.TSYNC*

1, 1

Synchronous Counter Mode

TxCON.TSYNC

0

Asynchronous Counter Mode

4) Clock-Prescaler

A clock pre-scaler can be used to increase or decrease the frequency at which the clock source increments the time base value.

It can be selected with the help of the following table.

TxCON.TCKPS*Prescaler Value

3

1 : 256

2

1 : 64

1

1 : 8

0

1 : 1

5) Initialize the Timer Interrupt

Each timer can be programmed to trigger an interrupt on:

  1. Compare match between the value of Timer Counter Register (TMRx) and Period Register (PRx).
  2. Detecting a falling edge in Gated Time Accumulation Mode.

This interrupt can be initialized in dsPic microcontrollers with the help of the following registers and bits:

Bit NameRegister and Bit IdentificationValue

Interrupt Enable Control bit

IEC0/1.TxIE

1 = Enable 0 = Disable

Interrupt Flag Status bit

IFS0/1.TxIF

This bit must be reset in software after each interrupt trigger

Interrupt Priority Control bit

IPC0/1/5.TxIP

6 - 0 depending on the priority

This sample code can be used to initialize an interrupt service routine for timer 1. (Pick the timer initialization function from above and call the functions in main() as suitable.)

For a detailed procedure on interrupts, follow another tutorial on the topic: How to Use Interrupts

Example Code to Initialize Interrupt in dsPic30f and dsPic33f Controllers

void Interrupt_Init( void )
{
    IEC0bits.T1IE = 1;
    IPC0bits.T1IP = 6;
}
 
void __attribute__((interrupt, auto_psv)) _T1Interrupt( void )               
{
    //Your code here
    IFS0bits.T1IF = 0;
}

Complete Code Example to Initialize and Test a Timer and Timer Interrupt for dsPic30f and dsPic33f

[Tested by author on: 22/09/2018]

The following code can be used to initialize and test Timer 1 in the 'Timer Mode' of operation. It is made by incorporating the two code snippets given above.

This code will generate an interrupt when ever a compare match occurs between the value of PR1 register and TMR1 registers.

  • Interrupt has been programmed to flash an led for 10 milliseconds.
  • Value of PR1 register: 0x8FF4 has been set such that a compare match occurs every 20 milliseconds.

So the led should be on for 10 milliseconds (as long as the program counter stays in interrupt function) and off for another 10 milliseconds when program counter exits the interrupt. The off time is being controlled by Timer 1.

#define FCY 1842500
 
#include <xc.h>
#include <delay.h>
#include <libpic30.h>
#include <p30F4011.h>
 
_FOSC(CSW_FSCM_OFF & FRC);  // Fosc = 7.37 MHz, internal fast RC oscillator

void init_Timer( void )
{
    T1CONbits.TON = 1;    //Activate the timer module
    T1CONbits.TCKPS = 0;  //Select input clock prescaler as 1:1
    
    T1CONbits.TGATE = 0;  //Disable Gate Time Accumulation Mode
    T1CONbits.TCS = 0;    //Select internal clock as the timer clock source
    T1CONbits.TSYNC = 0;  //External clock source is left unsynchronized
    
    PR1 = 0x8FF4;
}

void Interrupt_Init( void )
{
    IEC0bits.T1IE = 1;
    IPC0bits.T1IP = 6;
}
 
void __attribute__((interrupt, auto_psv)) _T1Interrupt( void )               
{
    _LATD0 = 1;
    __delay_ms(10);
    _LATD0 = 0;
    IFS0bits.T1IF = 0;
}
      
void main( void ) 
{
    init_Timer();
    Interrupt_Init();
    
    while( 1 )
    {     
    } 
}
Logic analyzer trace showing interrupt being triggered every 20 ms and 10 ms second pulses through the interrupt function on RD0.

Logic analyzer trace showing interrupt being triggered every 20 ms and 10 ms second pulses through the interrupt function on RD0.

This article is accurate and true to the best of the author’s knowledge. Content is for informational or entertainment purposes only and does not substitute for personal counsel or professional advice in business, financial, legal, or technical matters.

© 2018 StormsHalted

Comments

StormsHalted (author) from Karachi, Pakistan on January 26, 2019:

I did intentionally omit this bit for the sake of simplicity in main article. Here is how you do it:

The oscillator frequency at my end is configured at 7.37 MHz and Fcy is defined as 4 / 7.37 MHz = 1842500.

This means that the timer will increment by 1 after every 1 / 1842500 = 0.5427 microseconds. (when it gets the trigger from internal clock source.)

To count up to 20 milliseconds the timer needs to count 20,000 us / 0.5427 us = 36,852 increments.

36,852 is equal to 0x8FF4 in hexadecimal.

Make sure you keep track of the conversion from milliseconds to microseconds.

Ali FARES on January 24, 2019:

Can explain me how did you find PR1 = 0X8FF4?

Thanks.

Related Articles