CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

dsPIC33F Timer Interrupt do not work for Prescaler 64 &

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
SpoonBilly



Joined: 25 May 2010
Posts: 16

View user's profile Send private message

dsPIC33F Timer Interrupt do not work for Prescaler 64 &
PostPosted: Tue Oct 05, 2010 9:29 pm     Reply with quote

I am just started on dsPIC33F, work on PIC18F mostly in the past.

I was intended to run the dsPIC33FJ128GP306 at 40MIPS, that is 80MHz. It works fine for timer prescaler 1 and 8, but cant get the timer interrupt working for prescaler 64 and 256.

My code:
Code:

#include  <33FJ128GP306.h>
#device   ICD = TRUE
#fuses    XT, NOWDT, PR_PLL, NOWDT, NOCOE, NODEBUG, NOWRTB, NOPUT, NOWRTSS, NOWRT, NOPROTECT, NORSS
#use      delay (clock = 80M, crystal = 10M) // 10MHz Oscillator

#int_TIMER1
void TIMER1_isr()
{
   set_timer1(53036) ;
   
   output_d (0b00000001) ; // Illuminate LED at RD0 (0b00000001 = 0x01)
   delay_us(500)          ; // Wait for 500us
   output_d (0b00000000) ; // Illuminate LED at RD0 (0b00000000 = 0x00)
}

void main()
{       
   setup_timer1(TMR_INTERNAL|TMR_DIV_BY_64) ; // Start timer 1, prescaler = 64
   enable_interrupts(INT_TIMER1)            ;
   enable_interrupts(INTR_GLOBAL)           ;

   while(TRUE) ;
 }


f_d = desired frequency
f_c = clock frequency
p = prescaler
t_s = value of which the timer needs to be set

t_s = 65536 - (1/f_d)*f_c/p/2
*dsPIC33F has 2 clock cycles per execution cycle, instead of 4.

In this case,
f_d = 50 Hz
f_c = 80000000
p = 64

Thus, t_s = 53036

Any idea? Thanks.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Wed Oct 06, 2010 12:53 am     Reply with quote

Why do you think, the timer interrupt doesn't work?

If you can afford a 500 us delay in the ISR, why don't you stay with slow PIC18. Smile
SpoonBilly



Joined: 25 May 2010
Posts: 16

View user's profile Send private message

PostPosted: Wed Oct 06, 2010 1:00 am     Reply with quote

FvM wrote:
Why do you think, the timer interrupt doesn't work?

If you can afford a 500 us delay in the ISR, why don't you stay with slow PIC18. Smile


I am new to dsPIC. Currently in the process of trying things out. The output high and low performed by the interrupt is to allow me justify the interrupt execution by using oscilloscope.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Wed Oct 06, 2010 6:03 am     Reply with quote

You are using a wrong method to setup timer1, I think.

You should set the timer period during initialization and not rewrite the timer in the ISR.
Code:
setup_timer1(TMR_INTERNAL|TMR_DIV_BY_64,12500);

I also noticed, that you are apparently using an old PCD version. If you still have problems with toimer operation, please tell your PCD version.
SpoonBilly



Joined: 25 May 2010
Posts: 16

View user's profile Send private message

PostPosted: Wed Oct 06, 2010 6:11 am     Reply with quote

FvM wrote:
You are using a wrong method to setup timer1, I think.

....


Thanks FvM.
The way I set the timer, it works fine for prescaler 1 and 8. Thanks for your advice. It is night over here, I will give it a try tomorrow and let you know.
.
.
.
.
.
I'm using PCD 4.093. Just tried it out. It works!!! Thank you very very much.


Last edited by SpoonBilly on Wed Oct 06, 2010 8:17 pm; edited 1 time in total
SpoonBilly



Joined: 25 May 2010
Posts: 16

View user's profile Send private message

PostPosted: Wed Oct 06, 2010 8:08 pm     Reply with quote

Even if the advice given by FvM works perfectly, but being able to set_timer inside the timer interrupt ISR is crucial if the interrupt execution rate is not always constant.

After some trials and errors, I came out with this:

Code:

#include  <33FJ128GP306.h>
#device   ICD = TRUE
#fuses    XT, NOWDT, PR_PLL, NOWDT, NOCOE, NODEBUG, NOWRTB, NOPUT, NOWRTSS, NOWRT, NOPROTECT, NORSS
#use      delay (clock = 80M, crystal = 10M) // 10MHz Oscillator

#int_TIMER1
void TIMER1_isr()
{
   //set_timer1(62411) ; // for some reasons, this doesn't work for prescaler 64 and 256
   
   // Timer1 is a 16 bit timer which means it overflows every 65536 counts
   // The Timer1 is triggled every time it overflows.
   // Let, f_d = desired frequency; f_c = clock frequency; p = prescaler
   //      t_s = value of which the timer needs to be set
   // t_s = 65536 - (1/f_d)*f_c/p/2   
   //
   // In this case, f_d = 50; f_c = 80000000; p = 256
   // Thus, t_s = 62411     

   /*
   for some unknown reasons, for prescaler 64 and 256, delay has to be introduced before set_timer
   delay_cycles(39)  ; // delay >= 39 instruction clocks. works for prescaler 64
   delay_cycles(231) ; // delay >= 231 instruction clocks. works for prescaler 256
                       // for dsPIC33F, 2 oscillator clock = 1 instruction clock.
                       // for clock = 80MHz, 39 instruction clocks = 1/80M*2*39 = 0.975us
                       // for clock = 80MHz, 231 instruction clocks = 1/80M*2*231 = 5.775us
   set_timer1(62411) ; // introducing delay comes with a price, the timer will no longer be accurate.

   Thus,
   for clock = 80MHz and prescaler 64, instead of delay_cycles(39), one can use delay_cycles(64)
   As such:
   // 64 instruction clocks = 1/80M*2*64 = 1.6us = 1 timer tick
   delay_cycles(64)  ;
   set_timer1(t_s+1) ;

   for clock = 80MHz and prescaler 256, instead of delay_cycles(231), one can use twice delay_cycles(128)
   As such:
   // 256 instruction clocks = 1/80M*2*256 = 6.4us = 1 timer tick
   delay_cycles(128) ;
   delay_cycles(128) ;
   set_timer1(t_s+1) ;

   Alternatively,
   if the timer interrupt is to be executed at a constant rate,
   instead of set_timer inside the timer interrupt, one can setup_timer in the main function.
   for example:
   setup_timer1(TMR_INTERNAL|TMR_DIV_BY_256,3125) ; // Start timer1, prescaler = 256, interrupt executed for every 3125 timer ticks
   */   

   delay_cycles(128) ;
   delay_cycles(128) ;
   set_timer1(62412) ; // 62411 + 1

   output_d (0b00000001) ; // Illuminate LED at RD0 (0b00000001 = 0x01)   
   delay_us(500)         ; // Wait for 500us   
   output_d (0b00000000) ; // Illuminate LED at RD0 (0b00000000 = 0x00)   
}

void main()
{       
   setup_oscillator(OSC_CRYSTAL)             ;
   setup_timer1(TMR_INTERNAL|TMR_DIV_BY_256) ; // Start timer1, prescaler = 256
   //setup_timer1(TMR_INTERNAL|TMR_DIV_BY_256,3125) ; // Start timer1, prescaler = 256, interrupt executed for every 3125 timer ticks
   enable_interrupts(INT_TIMER1)             ;
   enable_interrupts(INTR_GLOBAL)            ;

   while(TRUE) ;
}


Any comment is welcomed Smile
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Wed Oct 06, 2010 9:48 pm     Reply with quote

I also noticed, that rewriting the timer register doesn't work always as intended. I didn't check the documentation, but I guess, that the timer is reset to zero at the next divided clock after the interrupt, so if you manage to rewrite the timer before, the rewrite is possibly ignored. The behaviour is also reproduced by the MPLAB simulator, so I think it's basically well defined.

But, you didn't tell a motivation for rewriting the timer register. In most cases, even if a variable timer intervall is intended, one would write the preset register, because it's the only way to achieve a timer intervall that's exact to a clock tick.
SpoonBilly



Joined: 25 May 2010
Posts: 16

View user's profile Send private message

PostPosted: Wed Oct 06, 2010 10:09 pm     Reply with quote

FvM wrote:
...In most cases, even if a variable timer intervall is intended, one would write the preset register, because it's the only way to achieve a timer intervall that's exact to a clock tick.


I learnt the way I work with the timer interrupt from a book ("Embedded C Programming and the Microchip PIC" by Richard Barnett, Larry O'Cull, & Sarah Cox, ISBN: 1401837484, pg. 110).

Didn't quite get what you mean. Is there any example code?
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu Oct 07, 2010 10:39 am     Reply with quote

To understand the differences between writing PR1 and TMR1 register, you should consult the processor hardware manual. If you want an exact timer period, you have to use PR1. The timer generates an interrupt when the timer register equals PR1 and resets the timer register automatically. So the timer interval is independant of accidental variations. If you rewrite TMR1 (e.g. with set_timer() ), the actual timer period is increased by the interrupt latency and processing time until set_timer is executed. As far as I see, CCS C doesn't provide a function to write PR1, except setup_timer(), but you can always define the register yourself and assign a new value.
SpoonBilly



Joined: 25 May 2010
Posts: 16

View user's profile Send private message

PostPosted: Fri Oct 08, 2010 1:02 am     Reply with quote

FvM wrote:
... If you rewrite TMR1 (e.g. with set_timer() ), the actual timer period is increased by the interrupt latency and processing time until set_timer is executed...


hm... well, anyway, I have been using the timer interrupt on PIC18F for quite some time. It is not very accurate, but it serves my purpose. After all, I am not going to build an accurate clock.

FvM wrote:
...CCS C doesn't provide a function to write PR1, except setup_timer(), but you can always define the register yourself and assign a new value.


You are right about writing PR1, though in order to variate timer interrupt execution rate, I have no other idea but to write PR1 inside the timer interrupt ISR... this doesn't make it accurate either, I suppose~ But it works for prescaler 64 and 256, better than introducing a delay before set_timer as I suggested in the previous post.

Just to share the code of how to write PR1 with the rest of the CCS community:

Code:

#include  <33FJ128GP306.h>
#device   ICD = TRUE
#fuses    XT, NOWDT, PR_PLL, NOWDT, NOCOE, NODEBUG, NOWRTB, NOPUT, NOWRTSS, NOWRT, NOPROTECT, NORSS
#use      delay (clock = 80M, crystal = 10M) // 10MHz Oscillator

#word     PR1  = 0X0102 // Period Register 1

#int_TIMER1
void TIMER1_isr()
{
   PR1 = 3125 ; // changes PR1 register

   output_d (0b00000001) ; // Illuminate LED at RD0 (0b00000001 = 0x01)   
   delay_us(500)          ; // Wait for 500us
   output_d (0b00000000) ; // Illuminate LED at RD0 (0b00000000 = 0x00) 
}

void main()
{       
   setup_oscillator(OSC_CRYSTAL)             ;
   setup_timer1(TMR_INTERNAL|TMR_DIV_BY_256) ; // Start timer1, prescaler = 256
   enable_interrupts(INT_TIMER1)             ;
   enable_interrupts(INTR_GLOBAL)            ;

   while(TRUE) ;
}
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Fri Oct 08, 2010 2:41 am     Reply with quote

Your code sets PR1 to a constant value, this must be done only once. I don't see a reason, why this should be done inside the ISR, it's sufficient to set it with the initial setup_timer1(), as in my above example.

Varying PR1 during program execution would be a different thing, but you didn't mention this requirement yet.
SpoonBilly



Joined: 25 May 2010
Posts: 16

View user's profile Send private message

PostPosted: Fri Oct 08, 2010 7:18 am     Reply with quote

FvM wrote:
Your code sets PR1 to a constant value, this must be done only once. I don't see a reason, why this should be done inside the ISR, it's sufficient to set it with the initial setup_timer1(), as in my above example....


Yup~ the code is just to demonstrate that it is possible to do so. Indeed, if a constant value is desired, your example code is sufficient.
I haven't study the effect of writing PR1 in depth, I didn't know that varying PR1 during program execution would bring upon any side effect.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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