Table of Contents
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.No | COMPONENTS | QUANTITY | |
1 | DSPIC33FJ64GS606 | 1 | Amazon |
2 | PICkit4 Programmer | 1 | Amazon |
3 | Led | 1 | Amazon |
3 | Oscilloscope | 1 | Amazon |
4 | Logic Analyser | 1 | Amazon |
5 | connection wires | 1 | Amazon |
Specification
Parameter | Value |
Core Type | dsPIC33F |
CPU Speed | 40 MIPS (10 MHz) |
Flash Memory | 64 KB |
SRAM | 8 KB |
Operating Voltage | 2.5V – 3.6V |
Number of Pins | 64 |
Timers | 5 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 Interfaces | UART, 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 |
USB | USB 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)
- The TMRx register holds the current value of the timer counter.
- It increments or decrements on each clock cycle depending on the timer configuration.
PRx (Period Register)
- The PRx register determines the timer period or the value at which the timer counter should reset.
- When the timer counter matches the value in PRx, an interrupt can be generated, or a specific action can be taken.
TCONx (Control Register)
- The TCONx register contains control bits for configuring the timer module.
- It typically includes bits for enabling/disabling the timer, selecting the clock source, setting the prescaler, and configuring other specific options.
TCKPSx (Prescaler Select Bits)
- The TCKPSx bits determine the prescaler value for dividing the input clock frequency.
- The Prescaler value determines the timer’s resolution and affects the timer’s interrupt frequency.
TCSx (Clock Source Select Bit)
- The TCSx bit selects the clock source for the timer.
- It allows you to choose between using an internal clock or an external clock input.
TIE, TIF (Interrupt Enable and Interrupt Flag)
- The TIE bit enables or disables the timer interrupt.
- The TIF bit indicates whether a timer interrupt has occurred.
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:
- Fcy: System frequency (40 MHz)
- Prescaler: Prescaler division factor (8)
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;
}