MEVIHUB

Blinking LEDs with Timer Interrupts on the dsPIC33FJ64GS606

Introduction

Microcontrollers have revolutionized the world of embedded systems by providing a versatile platform for building intelligent devices. In this blog post, we will explore the powerful dsPIC33FJ64GS606 microcontroller and learn how to create an engaging LED blinking project using a 10-millisecond timer interrupt. With a deep dive into the intricacies of timer configuration, we’ll leverage the prescaler value of 8 and a system frequency (Fcy) of 40MHz to achieve precise timing. By the end of this tutorial, you’ll have a solid understanding of using timer interrupts and be ready to illuminate your own creative projects.

Required components

S.NoCOMPONENTSQUANTITY 
1DSPIC33FJ64GS6061Amazon
2PICkit4 Programmer1Amazon
3Led1Amazon
3Oscilloscope1Amazon
4Logic Analyser1Amazon
5connection wires1Amazon

Specification

ParameterValue
Core TypedsPIC33F
CPU Speed40 MIPS (10 MHz)
Flash Memory64 KB
SRAM8 KB
Operating Voltage2.5V – 3.6V
Number of Pins64
Timers5 Timers
Analog-to-Digital Converter (ADC)10-bit, up to 16 channels
Digital-to-Analog Converter (DAC)2x 10-bit DACs
Pulse Width Modulation (PWM)Up to 12 channels
Serial Communication InterfacesUART, SPI, I2C
Inter-Integrated Circuit (I2C)Up to 2 channels
Universal Asynchronous Receiver/Transmitter (UART)Up to 2 channels
Serial Peripheral Interface (SPI)Up to 2 channels
USBUSB 2.0 Full-Speed Host/Device
Operating Temperature Range-40°C to +125°C

Understanding Timer Interrupts

Timer interrupts are an essential microcontroller feature that enables precise timing and real-time event handling. By setting up a timer interrupt, we can trigger a specific action, such as toggling an LED, at regular intervals. The dsPIC33FJ64GS606 microcontroller offers a range of timers with diverse configurations, making it a perfect choice for this project.

explanation of the timer setting registers typically found in microcontrollers like the dsPIC33FJ64GS606. These registers control various aspects of the timer module’s behaviour, such as clock source selection, Prescaler configuration, and interrupt enable/disable settings. Here are the commonly used timer-setting registers and their functionalities:

TMRx (Timer Register)

PRx (Period Register)

TCONx (Control Register)

TCKPSx (Prescaler Select Bits)

TCSx (Clock Source Select Bit)

TIE, TIF (Interrupt Enable and Interrupt Flag)

Explanation Of The Timer Setting

The TCKPS bits in the T1CON register control the prescaler settings for Timer1 in the dsPIC33FJ64GS606 microcontroller. The Prescaler value determines the division factor for the input clock frequency, allowing you to adjust the timer’s resolution and interrupt frequency.

Prescaler Division Factor Calculation:

With TCKPS = 0b01 (binary 01) and a prescaler value of 8, the prescaler division factor is determined by the prescaler bits as follows: Prescaler Division Factor = 8

Timer Frequency Calculation

The timer frequency (Ftimer) can be calculated using the following formula: Ftimer = Fcy / (Prescaler * (PR1 + 1))

Given:

Assuming a desired interrupt period of 10 milliseconds (10 ms), we can calculate the value for PR1:

PR1 = (Fcy / (Prescaler * Ftimer)) – 1
= (40,000,000 / (8 * 0.01)) – 1
= 50000 – 1
= 49999

Therefore, to achieve a timer interrupt frequency of approximately 100 Hz (10 ms period) with a prescaler of 8 and Fcy of 40 MHz, you should set the TCKPS bits to 0b01 and the PR1 register to 49999.

Source Code

/*
 * File:   main.c
 * Author: Admin
 *
 * 
 */

#include "xc.h"
#include <p33FJ64GS606.h>
#include "stdio.h"
#include "stdlib.h"
#include <string.h>
#include <math.h>
#include <dsp.h>

#include "libpic30.h"
#define HEARTBEAT_LED           LATGbits.LATG3      // Heart Beat LED

_FOSCSEL(FNOSC_FRC & IESO_OFF);                     // Internal FRC start-up without PLL,// no Two Speed Start-up
_FOSC(FCKSM_CSECMD & OSCIOFNC_ON & POSCMD_NONE);    // POSCMD_XT);// Clock switch enabled,// Primarly Oscillator XT
_FWDT(FWDTEN_OFF);                                  // Watchdog Timer disabled
_FICD(JTAGEN_OFF);                                  // & ICS_PGD3);// Disable JTAG
_FPOR(FPWRT_PWR128);                                // Power up timer enabled by 128 mS



void initOscFreq(void);
void initInputCapture (void);                       // Initialization of Input capture for Hall sensor sensing
void initTimer ();

unsigned int uiTmrCnt = 0;
int main(void) {
    PTCONbits.PTEN = 0;                              /* Enable the PWM Module */
    //------------------- Start ------------------------//

    // -------------- Output's ------------- //
    TRISGbits.TRISG3 = 0;                           // Led_1
    TRISGbits.TRISG2 = 0;                           // Led_2
    TRISDbits.TRISD2 = 0;                           // Led

    initOscFreq();                                  // Oscillator Initialization
    initInputCapture();                             // Input Capture Init
    initTimer();                                    // Timer One Initialization


    while(1)
    {

    }
}

void initTimer ()
{
    // Prescaler=8, Fcy=40MHz, T = 1/Fcy = 25nS 
    // Ex: For 10ms, 10mS/(25nS*8)
    //TimerInterruptCount = 0; // Clear Interrupt counter flag
    T1CONbits.TCKPS = 1;    //Pre scale = 8
    PR1 = 0XC350;           //5mS = 0X61A8; 2.5mS = 0x30d4;  10mS = 0xC350
    IPC0bits.T1IP = 4;      // Set Interrupt Priority lower then ADC
    IEC0bits.T1IE = 1;      // Enable Timer1 interrupt
    T1CONbits.TON = 1;      // Enable Timer1 module
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

void __attribute__((__interrupt__, no_auto_psv)) _T1Interrupt()
        {   
    IFS0bits.T1IF = 0;              // Clear Interrupt Flag

    uiTmrCnt = uiTmrCnt + 1;
    if(uiTmrCnt >= 100)             //for 1Sec 
    {
        uiTmrCnt = 0;
        HEARTBEAT_LED^=1;

    }   



        }

//***************Function Definitions starts from here************************************
void initOscFreq(void)
{
    // Configure PLL prescaler, PLL postscaler, PLL divisor for FOsc=80Mhz and Fcy=40Mhz
    PLLFBD = 63;            // M = 65
    CLKDIVbits.PLLPOST=0;   // N2 = 2
    CLKDIVbits.PLLPRE=1;    // N1 = 3

    // Initiate Clock Switch to Internal FRC with PLL (NOSC = 0b001)
    __builtin_write_OSCCONH(0x01);
    __builtin_write_OSCCONL(OSCCON | 0x01); //Clock witch Enable

    //OSCTUNbits.TUN = 0b111111;        //FRC tuning to 7.345Mhz    

    while (OSCCONbits.COSC != 0b001);   // Wait for Clock switch to occur
    while (OSCCONbits.LOCK != 1);       //wait till PLL is locked

    /* Now setup the ADC and PWM clock for 120MHz
     ** ((FRC * 16) / APSTSCLR ) = (7.37 * 16) / 1 = ~ 120MHz
     */
    ACLKCONbits.FRCSEL = 1;         // FRC provides input for Auxiliary PLL (x16)
    ACLKCONbits.SELACLK = 1;        // Auxiliary Ocillator provides clock source for PWM & ADC
    ACLKCONbits.APSTSCLR = 7;       // Divide Auxiliary clock by 1 
    ACLKCONbits.ENAPLL = 1;         // Enable Auxiliary PLL 

    while(ACLKCONbits.APLLCK != 1); // Wait for Aux. PLL to Lock  {{for Testing}}

}

void initInputCapture()
{
    IC1CONbits.ICSIDL = 0;
    IC1CONbits.ICM = 1;

}

Exit mobile version