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 CCS Technical Support

what is 18F4431 timer1's highest frequency?

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



Joined: 06 Jan 2009
Posts: 15

View user's profile Send private message

what is 18F4431 timer1's highest frequency?
PostPosted: Fri Jan 30, 2009 6:13 am     Reply with quote

I've been scratching my head for ages and hair's everywhere... What's the highest frequency for this damn timer?

for 18F4431, timer1 is a 16bit timer. The highest I've got is 22.5KHz... My 16F88 can do a lot better than that..., and the lowest I've got is 4.7Hz...

I've tried it at div_1 and the max freq is 22.5KHz, at set_timer1(65524)

at div_1 and set_timer1(65525), I'm getting a ~1% duty cycle square wave... So I'm suspecting that something is resetting it, but I don't know what it is. I thought it's CCP screwing things up, so I've deliberately turned them off.

22.5KHz is the max frequency for timer1??!! no way... Please help. thank you.

ompiler version = 4.038
PIC18F4431
20MHz osc



here's the problematic code.

Code:

#include <18f4431.h>
#device adc=10
#fuses hs,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOWRT
#use delay(clock=20000000)

//include files here..........
#include <stdio.h>
#include <stdlib.h>

//**************************************************************************************************************
//define global variables
//**************************************************************************************************************

int1 test_timer1=0;
unsigned int16 down_count_timer = 65524;

//**************************************************************************************************************
//**************************************************************************************************************
//set timer0 as the 1st priority
#priority INT_CCP1, INT_CCP2, INT_timer0, INT_RDA,INT_TBE


//**************************************************************************************************************
//  Timer1 ISR
//**************************************************************************************************************
#int_timer1
void Timer1_isr()
{
   set_timer1(down_count_timer);
   output_bit(PIN_C4,test_timer1);

   if(test_timer1==0)
      test_timer1 = 1;
   else
      test_timer1 = 0;
}

//**************************************************************************************************************
// MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN
//**************************************************************************************************************
void main ()
{

   
   setup_adc_ports(NO_ANALOGS); //= 0x06; //00000110   all digital to start
   
   //****************************************************************************************
   //setup CCP capture mode and timer1
   //****************************************************************************************
   setup_ccp1(CCP_OFF);    // Configure CCP1 to capture rise
   setup_ccp2(CCP_OFF);    // Configure CCP2 to capture rise
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);    // Start timer 1
   set_timer1(down_count_timer);           
   
   //****************************************************************************************
   //Setup interrupts
   //****************************************************************************************
   
   enable_interrupts(INT_timer1);
   enable_interrupts(GLOBAL);

   
   //Frequency = Fosc / (4 * (period+1) *postscale)   
   
//**************************************************************************************************************
// WHILE LOOP WHILE LOOP WHILE LOOP WHILE LOOP WHILE LOOP WHILE LOOP WHILE LOOP WHILE LOOP WHILE LOOP WHILE LOOP
//**************************************************************************************************************
   while (1)
   {       
               
   }
}


Last edited by Briany on Sun Feb 01, 2009 2:56 am; edited 7 times in total
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Jan 30, 2009 9:32 am     Reply with quote

Reduce the size of your test program, it is way too large. Remove every line in comment, remove the disabled interrupts, remove all unused variables and include files.
In the process of reducing the size it is very likely you will find the cause of your problem. If you didn't find the problem it will at least save us a lot of time checking your code and hence give you more and better answers. (yes, we are lazy too...)

The new sample program you post should not be more than 50 lines (and it can even be smaller without losing functionality).

Always post your compiler version number.

How do you measure the frequency?
Briany



Joined: 06 Jan 2009
Posts: 15

View user's profile Send private message

PostPosted: Sun Feb 01, 2009 2:44 am     Reply with quote

sorry, I didn't clear my test program enough for you guys. Being lazy is perfectly fine. Everyone should be lazy. :P

I've updated the program above, removed garbage etc.

anyway, I tested the timer1 interrupt frequency by having the timer1 interrupt routine toggle a pin high and low. divide the frequency I get on the CRO by 2 and I should get the frequency of the timer.

compiler version = 4.038
PIC18F4431
20MHz osc


here's what I've done with the setting
Code:

   down_count_timer = #value;
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);    // Start timer 1
   set_timer1(down_count_timer);       


where value can be anything.

here's the curious problem. If set_timer1 value increases, timer1 should interrupt faster and faster. But for me, it wasn't the case. It was increasing to a certain point, "set_timer1(65524)" frequency = 22.5KHz, then it dropped dramatically.

also, at "set_timer1(65525)", 1 value higher than the max frequency I obtained, the output was not a square wave, but a ~1% duty cycle square wave. afterwards, all settings are at 38.3Hz...

what's going on?
Ttelmah
Guest







PostPosted: Sun Feb 01, 2009 4:01 am     Reply with quote

It would, though your frequency seems a low. See at the bottom for why.

It takes _time_ to handle interrupts. Typically in excess of 70 instructions, to get into, and out of an interrupt handler. Your handler (assuming it is the one shown for timer1), then takes about another 18 instructions. You don't say whether you have left the the #priority line, but this as it currently stands, sets timer1, as the lowest priority interrupt (since it is not in the priority list), which adds another three instruction times for each interrupt 'above' it (15 instructions). On this basis, the 'best' loop time, will be about 100 instruction times, or about 50KHz. About twice what you are seeing.

Now, at a certain point in the loading, you will get to a count, where the timer then triggers again _before_ the code returns to the main routine. This is one limit, giving the 'fastest posible loop. The second though occurs when the interrupt triggers again, before it leaves the handler itself. This is happening at 65525, which triggers just 11 instructions later. There are more than 11 instructions from this point to the end of the routine, so the timer triggers while it is still inside the routine. The compiler automatically clears the interrupt flag, when you leave the routine, so you then interrupt at a total count of 65547 instruction times (65536, plus the eleven instructions).

Now, this tells me something. Your system _is not_ clocking at 20MHz. It is clocking at 10MHz. Check your crystal. The reason is that you are executing 65547 instruction counts, in 1/38.3 sec. This gives the processor running at 38.3*65547 instructions per second = 2510450. The crystal is then 4* this = 10MHz (allowing for a slight measurement error).....

So the reason you are not getting the speed you expect, is that your crystal is wrong. However you are also trying to do to much. If you want a fast pulse, then this is what the PWM outputs are for. The more interrupts you have, the more they will interfere wth each other, and the slower the total performance will be.

As a further comment, you can toggle the pins much faster with:
Code:

int1 test_timer1;

#int_timer1
void extra_isr() {
  set_timer1(down_count_timer);
  if(test_timer1) {
    output_low(PIN_C4);
    test_timer1=false;
  }
  else {
    output_high(PIN_C4);
    test_timer1=true;
  }
}

The 'output_bit' instruction, effectively has to contain a test to see if the bit is 1 or 0, and then two bit operations, one to set the bit, and one to clear it. It is more efficient to test just once, and both select the required output, and update the value, yourself. This save seven instruction times.

Best Wishes
Briany



Joined: 06 Jan 2009
Posts: 15

View user's profile Send private message

PostPosted: Sun Feb 01, 2009 6:52 am     Reply with quote

woah Ttelmah,

thanks a lot for the reply.

I think your calculation of the instruction cycle is correct but the crystal is fine. 38.3 Hz is the frequency of the complete square pulse that the timer1 generates, or it's 2 interrupt time. So, 2*10MHz is the crystal frequency. Smile


My ultimate objective with timer1 is to find out what the pausing time is for the CCP capture. Do you have a solution to test out whether timer1 is ticking at the right speed without using interrupt?

I'm pretty convinced that timer interrupts aren't gonna help me with high frequency data transmission... Or high occurance events for that matter.

Thanks a lot for reply, I know more about interrupts than before!
Ttelmah
Guest







PostPosted: Sun Feb 01, 2009 9:01 am     Reply with quote

OK. Complete cycle, makes sense.
The fastest way to 'tick' something, is to do it in a tight loop. For hardware timings, you can for example, 'poll' an interrupt flag, without having it enabled, and get response to an interrupt event that is only perhaps 4 or 5 machine cycles.
For timing something, then the best way is to read the timer, rather than interrupting with it. If (for instance), you wanted to time the interval between two events, just set a tmer to '0' in the first event, then read it in the second. Your resolution, is then the counting interval of the timer involved, so with your existing timer1, running of Fosc/4, you would have a resolution of 400nSec.
I'm not sure what you mean by the 'pausing time for CCP capture'. The CCP latches the timer value that was generated on the last T1 cycle. The latency is at worst, 4*Tcy. Far below anything you could measure with timer1.

Best Wishes
Briany



Joined: 06 Jan 2009
Posts: 15

View user's profile Send private message

PostPosted: Sun Feb 01, 2009 6:26 pm     Reply with quote

polling an interrupt flag without enabling it?

do you mean, I can poll it by creating a tight loop checking for the interrupt flag bit toggling? I've never thought of this method but it's definitely something I will try.

how many machine cycles does it take for the PIC to run the while loop?
or better, do you know where I can find all these machine cycles for commands in C language? I've learned assembly language before, but our platform was on 8051... (maybe I shouldn't even tell you what it was but whatever) I can see the machine cycle tables for commands like movl or add commands, but what about if/else, while/for, etc?

I'm trying to get an accurate timing (in uS) and I trust the CRO more than anything. If polling works, I'm gonna write a tight loop that does something like:


Code:

while(!interrupt_flag_address);
if (it's not logic high before)
    output_high(PIN_C4);
else
    output_low(PIN_C4);

Ttelmah
Guest







PostPosted: Mon Feb 02, 2009 4:05 am     Reply with quote

Yes. Not 'toggling', but going true.
Basically, if you make a #bit definition for an interrupt flag (call it 'INT_FLAG' say), setup the peripheral 'as normal', but don't enable the interrupt, then you can go:
Code:

   while (!INT_FLAG) ;
   //You will arrive here within a couple of machine instructions of the flag
   //going true
   INT_FLAG=FALSE; //clear the interrupt

   //Then code here

Written like this, the compiler uses the single 'BTFSS' instruction, and takes just two machine cycles for the loop. The lag to exiting, will depend 'when' in the loop the flag changes. However about 30 instructions quicker than calling an ISR....

Best Wishes
Briany



Joined: 06 Jan 2009
Posts: 15

View user's profile Send private message

PostPosted: Tue Feb 03, 2009 8:00 am     Reply with quote

thx a lot. I've got it working now!

I do have to increase my crystal frequency from 20MHz to 40MHz though. For some reason, my 40MHz isn't giving me 40MHz on the CRO, but rather, 13.6MHz. So I'm thinking it's a faulty one. I'm using 32.768MHz and it's working fine.

thanks!!
Ttelmah
Guest







PostPosted: Wed Feb 04, 2009 3:54 am     Reply with quote

Read the data sheet.
40MHz _for a crystal_, is above the maximum supported by the chip. To run the chip at 40MHz, you need either a 10MHz crystal, with the internal *4 PLL enabled, or a complete external oscillator. The internal oscillator, supports 25MHz _max_

Best Wishes
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