|
|
View previous topic :: View next topic |
Author |
Message |
Damaso
Joined: 07 Nov 2012 Posts: 11
|
Problem with PIC24FJ timers |
Posted: Tue Jan 15, 2013 4:16 am |
|
|
I'm using a PIC24FJ128GB106 with USB support and a external 20MHz crystal. I used these fuses and the USB works flawlessly:
Code: |
#FUSES NOWDT //No Watch Dog Timer
#FUSES ICSP2 //ICD uses PGC2/PGD2 pins
#FUSES NOJTAG //JTAG disabled
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOIOL1WAY //Allows multiple reconfigurations of peripheral pins
#FUSES NOCKSFSM //Clock Switching is disabled, fail Safe clock monitor is disabled
#FUSES PR_PLL //Primary Oscillator with PLL
#FUSES PLL5 //Divide By 5(20MHz oscillator input)
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES DISUVREG
#use delay(clock=20MHz)
|
I'm planning on using timers in my project, so I made the usual simple program for blinking a led. But, no matter which value I put in set_timer1(), the result is always the same, the interrupt happens every 1 second. Here is my code:
Code: |
#include <24FJ128GB106.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES ICSP2 //ICD uses PGC2/PGD2 pins
#FUSES NOJTAG //JTAG disabled
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOIOL1WAY //Allows multiple reconfigurations of peripheral pins
#FUSES NOCKSFSM //Clock Switching is disabled, fail Safe clock monitor is disabled
#FUSES PR_PLL //Primary Oscillator with PLL
#FUSES PLL5 //Divide By 5(20MHz oscillator input)
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES DISUVREG
#use delay (clock=20MHz)
#include <usb_cdc.h>
#int_TIMER1
void TIMER1_isr(void)
{
set_timer1 (50000);
output_toggle(PIN_G8);
}
void main()
{
setup_spi( FALSE );
setup_spi2( FALSE );
setup_timer2(TMR_DISABLED |TMR_DIV_BY_1 ,0);
setup_timer4(TMR_DISABLED |TMR_DIV_BY_1 ,0);
setup_timer3(TMR_DISABLED |TMR_DIV_BY_1 ,0);
setup_timer5(TMR_DISABLED |TMR_DIV_BY_1 ,0);
usb_cdc_init();
usb_init();
setup_timer1(TMR_INTERNAL | TMR_DIV_BY_256);
set_timer1 (50000);
enable_interrupts(INT_TIMER1);
enable_interrupts(INTR_GLOBAL);
output_low (PIN_G8);
while (TRUE);
}
|
With set_timer1(50000), the interrupt should happen every 0.4s. How can this be even possible?
And yes, I also tried it without loading the usb part and the result is the same. |
|
|
Damaso
Joined: 07 Nov 2012 Posts: 11
|
|
Posted: Tue Jan 15, 2013 5:01 am |
|
|
I changed the #use delay to:
Code: | #use delay(clock=20MHz, xtal=20MHz) |
and the blinking period changed to 1.6s. That is the exact period for when the timer goes from 0x0000 to 0xFFFF with the 256 divider. The problem seems to be that the PIC ignores the set_timer1() instruction.
If I change the setup_timer1(TMR_INTERNAL | TMR_DIV_BY_256); to
Code: | setup_timer1(TMR_INTERNAL | TMR_DIV_BY_256, xxx); |
it works correctly for every xxx value that I enter.
This is my first project with a PIC24, I'm used to PIC18. Does the set_timer1() works differently? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19535
|
|
Posted: Tue Jan 15, 2013 5:29 am |
|
|
Timers in the PIC24, are completely different from those on the older PIC's.
Instead of counting up to 0xFFFF, and then resetting, they count to the value specified in the period register. This is the second number in the setup_timer command.
Hence you never need to set the timer 'to' a value to get a time interval, the hardware does all of this for you.
Now if you are setting a value in the period, that is below the value you set in the timer interrupt, it'll have no effect (since you are past the count already....).
Second thing is that the timers are clocked off oscillator/2, not oscillator/4, so calculations change.
If you want 0.4 seconds, then all you need is:
10000000*0.4 = 4000000
4000000/256 = 15625
Remember it counts from 0 to the period value, so:
Code: |
setup_timer1(TMR_INTERNAL | TMR_DIV_BY_256, 15624);
|
Then get rid of all the set_timer lines.
Problem is that you are setting the count value 'past' the programmed reset point, so it gets ignored.
This merrily gives 0.4second interrupts with your chip/clock.
Best Wishes |
|
|
Damaso
Joined: 07 Nov 2012 Posts: 11
|
|
Posted: Tue Jan 15, 2013 9:02 am |
|
|
So, by default, the setup_timer1() sets a 0xFF period and that's why the interrupts happens every 1.6s, isn't it?
In my application I need to change the interrupt frequency during execution, and that's why I used set_timer1() inside the isr. That worked with PIC18s, but it seems that I need to find another way to do it with this new pic. The solutions that occurs to me is to directly change the "Period Register 1" inside the isr whenever I need it.
Code: | #word PR1 = 0X0102
...
#int_TIMER1
void TIMER1_isr(void)
{
PR1 = period ; //changed elsewhere during execution
output_toggle(PIN_G8);
}
... |
But I have one more question. Does the interrupt happens when the timer equals the PR1 value and then goes back to zero? Or does the interrupt happens when the timer equals 0xFF and then goes back to (0xFF-PR1)? I suppose it's the first one, but I would like some clarification if you don't mind |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19535
|
|
Posted: Tue Jan 15, 2013 9:48 am |
|
|
The first.
The data sheet tells all.
However the period register, is a _16bit_ register, not an 8bit register. None of the PIC24 timers are 8bit. 0xFFFF period by default, not 0xFF.
Use the compilers ability to find registers for you - safer:
Code: |
#word PR1=getenv("SFR:PR1")
|
Best Wishes |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|