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

Erratic Timer0? (shoud be easy answer)
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Guest








Erratic Timer0? (shoud be easy answer)
PostPosted: Fri Aug 27, 2004 9:31 pm     Reply with quote

First off, I want to mention that I read almost every rtcc topic the search had, but I couldnt find anything that was exactly what I needed,

I'm trying to use the timer0/rtcc to make an interupt every 20us. I thought what I had was right by the data that comes back looks slightly erratic, like my time is not 20us but maybe somthing a little higher ?

Code:

#int_RTCC
void isr() {
... do stuff...
}

void main()
{                      //// 256-(.000020/(4/20000000))
set_rtcc(156);                     //Interupt every 20us ?
setup_timer_0(RTCC_INTERNAL);
...
}
alexbilo



Joined: 01 Jun 2004
Posts: 39
Location: Trois-Rivières

View user's profile Send private message

PostPosted: Fri Aug 27, 2004 10:04 pm     Reply with quote

Hi,

From what I can see, your thinking is correct, except that the rtcc timer defaults to 16 bits, which means that it'll overflow every 65 536 counts... What I do to avoid these kind of errors is to initialize timers to -[#counts].

In your application, that could translate to :

Code:

set_rtcc(-100) // 100 counts = 20µs


Good luck! Laughing
_________________
Alex
iso9000
Guest







PostPosted: Fri Aug 27, 2004 10:49 pm     Reply with quote

I forgot to mention that I'm using a 16F part... I think thats still 8bit no ?

Also, I see there is no option to setup_counters() to a prescaler of 1 (I read that unless somthing with the WDT)...

Does setup_timer_0(RTCC_INTERNAL); set a PS of 1 ? Cause that could be screwing me up for sure...
Felix Althaus



Joined: 09 Sep 2003
Posts: 67
Location: Winterthur, Switzerland

View user's profile Send private message

PostPosted: Sat Aug 28, 2004 4:39 am     Reply with quote

Hi

Quote:
I forgot to mention that I'm using a 16F part... I think thats still 8bit no ?

Yes, thats true, TMR0 (or the RTCC) is 8Bits.

Look at your list file to see what setup_timer_0(RTCC_INTERNAL) writes into the option register.

What do you mean with "somthing a little higher"? Is it much to long or only a few us?
Have alos a look at the TMR0 section in the datasheet. Somewhere it sais, that after a write to the TMR0 register, it waits two cycles before continuing counting (or something similar).

Felix
Ttelmah
Guest







Re: Erratic Timer0? (shoud be easy answer)
PostPosted: Sat Aug 28, 2004 10:54 am     Reply with quote

Anonymous wrote:
First off, I want to mention that I read almost every rtcc topic the search had, but I couldnt find anything that was exactly what I needed,

I'm trying to use the timer0/rtcc to make an interupt every 20us. I thought what I had was right by the data that comes back looks slightly erratic, like my time is not 20us but maybe somthing a little higher ?

Code:

#int_RTCC
void isr() {
... do stuff...
}

void main()
{                      //// 256-(.000020/(4/20000000))
set_rtcc(156);                     //Interupt every 20us ?
setup_timer_0(RTCC_INTERNAL);
...
}

I'm afraid you are not going to get what you want.
The first time you setup the interrupt, it'll occur about 20uSec after you set the counter (plus a couple of uSec for the actual data transfer), but then it'll change 'down' to occurring every 51.2usec as normal (the 'offset' is not maintained). Even if you try to set the timer forward in the interrupt routine, because of the latency involved in arriving in the routine, the results will be unreliable. Finally, the actual overhead, for the interrupt handler, makes this sort of rate very hard to maintain (look at the interrupt handler having an overhead of perhaps 60-80 clock cycles - about 25 to save the registers, 10 to decide where to branch, and actually branch, and another 25 to restore the registers. Plus the call/return. A 20uSec interrupt, is 'pushing', having the processor permanently inside the interrupt handler...
Realistically, the 51.2uSec interrupt frequency (at 20MHz), that the normal 'drop through' of timer0, corresponds to, is about as short as you want to go, to leave time to do anything else.

Best Wishes
ckielstra



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

View user's profile Send private message

PostPosted: Sat Aug 28, 2004 11:19 am     Reply with quote

You are calling set_rtc() only once, but you have to call this function after every timer overflow again.

The easiest solution is to use a PIC controller which has a timer2 device, because this timer has a compare register which has to be set only once. In the call to setup_timer_2() you can specify the required period time.

Without a timer2 device you can use one of the other timers and then in your interrupt handler call set_timer0() for every timer overflow. Beware however that it takes the CCS interrupt dispatcher code about 20 instructions on a PIC16 (40 on a PIC18) to enter your interrupt function and you will have to make a correction for this. One way to make the correction is:
Code:
#int_RTCC
void isr()
{
  signed int PeriodTime = -100;  // 100 counts = 20µs
  set_timer0(PeriodTime + get_timer0());
}
iso9001+
Guest







PostPosted: Sat Aug 28, 2004 3:18 pm     Reply with quote

Well.... Hmm..

I did switch to timer2. I found that way easier to understand. I'm using the command:

Code:

    setup_timer_2(T2_DIV_BY_1, 99, 1);


To interupt every 20us... And I 'seem' to be getting sort of accurate results when there is no ops other then the interupt stuff... However, every 8 ints, I store the data collected into an array to use later, when that happends, I do notice an erratic behavior in my code... It does look like I'm running out of time.

I dont understand it though. I found a commercial chip doing way more then what I'm doing and they're using a 12C chip running at some freakin 3.85Mhz! For the same type of signals, Its the Elm VPW/1850 chip. Plus they're doing alot of conversions AND transmitting, geez.

Hmm... All I want to do is start recording signals when the chip is on, a short pulse of 60 us and a long of 120us, highs and lows. I tried using interupts to record the time of the pulse but that didnt work at all...

Since now all I'm doing is sampling at a constant rate, maybe I can set timer2 and ignore the interupts ? Just keep checking the value of timer2, when I see its about to rollover I just call my function, instead of having an interupt do it ?

This should take less overhead no ?
dyeatman



Joined: 06 Sep 2003
Posts: 1933
Location: Norman, OK

View user's profile Send private message

Timer1 10ms Timing routine I use
PostPosted: Sat Aug 28, 2004 5:47 pm     Reply with quote

Heres what I do using timer 1 on the 16F876/877 running at 18.432MHZ and it gives me a stable ~10ms interrupt I then count to get 1 second. If you are going to create an RTC I would do something entirely different

I set up a debug pin that I toggled in the interrupt routine and monitored with a scope to fine tune the 10ms timing by changing TIMER1START.

Code:

#PRIORITY TIMER1, other interrupts
#DEFINE TIMER1START 21000  // ctr start value for 10ms timer
int  _10mscntr = 100;
int seconds=0;

//************ Begin Interrupt Area ******************
#INT_TIMER1
Timer1_int()
{
    set_timer1(TIMER1START); 
//
    // toggle the debug pin here if needed
    output_toggle(put pin# here);
//
// *****
    // count the 10ms intervals
    if (--_10mscntr < 1)
        {
        _10mscntr = 100;  // reset for one second

        // increment the seconds counter
           if  (seconds++ > 59)
                     seconds =0;

        }  // if --10mscntr < 1
  }

// *****
// Part of Init section

    setup_timer_1(T1_INTERNAL || T1_DIV_BY_8);
    set_timer1(TIMER1START); 
    //
    enable_interrupts(INT_TIMER1);
    enable_interrupts(global);
//
// start of main ()


FWIW


Last edited by dyeatman on Sat Aug 28, 2004 9:21 pm; edited 1 time in total
ckielstra



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

View user's profile Send private message

PostPosted: Sat Aug 28, 2004 6:24 pm     Reply with quote

Iso9001,

Quote:
To interupt every 20us... And I 'seem' to be getting sort of accurate results when there is no ops other then the interupt stuff... However, every 8 ints, I store the data collected into an array to use later, when that happends, I do notice an erratic behavior in my code... It does look like I'm running out of time.

As Ttelmah already pointed out, interrupts have some extra overhead for saving and restoring registers, on a PIC16 this totals to about 45 instructions. Running at 20MHz and an interrupt every 20us you have time for only 100 instructions of which 45 are taken by the interrupt handler.... This leaves very little time for your code as you have found out....

As always on any forum, be very careful in describing your problem. We will try to give you an answer to your question, but asking the wrong questions won't give you the answers you are looking for. Also provide as much info as possible about your environment, for example you didn't mention your type of PIC processor and later you only mentioned it to be a pic16 without giving the exact number.
Now you mention an 'Elm VPW/1850 chip' and you expect us to know what you are talking about? Just by chance I found out you are talking about a module from ELM Electronics for interpreting OBD (On Board Diagnostics) signals in vehicles which are encoded as either J1850 PWM 41,6kHz or J1850 VPW 10.4kHz signals. Which of these two do you want to decode?

A couple of days ago in this thread you were experimenting with the CCP unit. If you want to measure pulse widths I still think CCP is the way to go. Why didn't you continue using the CCP? What happened to your experiments?

One problem in recording the measured times you already have found out: it takes a lot of time to store the data in EEPROM. One possible optimization is that you are not really interrested in the actual times, because this is a decoding of a digital signal with '0's and '1's, so you can reduce the data throughput by a factor 8 by storing 8 'bits' in a byte. EEPROM will still be too slow, so use a faster component like FRAM or even easier, output the data over rs232 to your PC.

Another remark: Please log in to this forum! Or at least stick to the same name. In this same thread you have been posting as 'guest', 'iso9001' and 'iso9001+'.
iso9001



Joined: 02 Dec 2003
Posts: 262

View user's profile Send private message

PostPosted: Sun Aug 29, 2004 12:10 pm     Reply with quote

Ok... a lot to cover.

I'm using a 16F876A and 20Mhz Xstal

I've narrowed it down to the 45 instructions I have not being enough (however if I count them I only have 20 some commands, most are if and variable assainment, those should be fast I figured... some of the varaible are an 8 place array, maybe that takes more time?)

What happened to the ccp ? Well.... after messing with it for a week and not getting even one correct result, I switched to checking the pin state every 20us, which the first time worked great except for the fact that the fastest way to do it was to store each high and low in a byte of an array, however this leaves me with 80 symbols which is not even a full transmission. So that brings me to where I am now, I take 8 symbols I've collected and make them into 1 8bit byte, so If I see 7C in the rom, then I know it was high for 120us and then went low for 40us

I'm working around another problem. I'm not counting 1's and 0's really. I'm checking for 4 condictions. I have a short high, short low, long high, long low. My goal is to have an almost oscelliscope graph of a transmission (with no scope available to me)... That way I can see how the messege is actually composed (with a start symbol, header, data, crc, end symbols)

I foget that not everyone is me and somtimes mention things like an Elm VPW/1850 chip not realising there may be people who don't know what that is. I do it all the time, I'm probably self absorbed or somthing. I'm working with VPW signals that are almost exactly J1850 (but without the name i think)

I'de would not be against using CCP if it worked for me, but none of the numbers I get are even close to where they should be, plus... doesnt CCP take some time too ?

I my computer doesnt like to log on or stay logged on to anything. I have the worlds worst phone line system (disconnected twice while writing this) and I cant get anything but dialup here (500ft from the last dsl point). I'll try and stay logged it though,
ckielstra



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

View user's profile Send private message

PostPosted: Sun Aug 29, 2004 1:41 pm     Reply with quote

I'm not really sure how the 'log in' for this forum works, but I'm having a computer both at home and at work and I have logged in with both computers only once and never after. The computers are being switched of on a regular basis, so for loggin in to the forum it doesn't seem important for your computers to be connected to the internet all the time.

Instead of storing the data in internal memory (RAM or flash), what do you think of transmitting the data to your PC directly? Your PIC already has an hardware UART, then choosing some ridiculous high baudrate like 230kbaud you can even transmit the measured 8-bit value without the need for flow control (although your pc might have a diffent opinion in this).
Ttelmah
Guest







PostPosted: Sun Aug 29, 2004 2:36 pm     Reply with quote

iso9001 wrote:
Ok... a lot to cover.

I'm using a 16F876A and 20Mhz Xstal

I've narrowed it down to the 45 instructions I have not being enough (however if I count them I only have 20 some commands, most are if and variable assainment, those should be fast I figured... some of the varaible are an 8 place array, maybe that takes more time?)

What happened to the ccp ? Well.... after messing with it for a week and not getting even one correct result, I switched to checking the pin state every 20us, which the first time worked great except for the fact that the fastest way to do it was to store each high and low in a byte of an array, however this leaves me with 80 symbols which is not even a full transmission. So that brings me to where I am now, I take 8 symbols I've collected and make them into 1 8bit byte, so If I see 7C in the rom, then I know it was high for 120us and then went low for 40us

I'm working around another problem. I'm not counting 1's and 0's really. I'm checking for 4 condictions. I have a short high, short low, long high, long low. My goal is to have an almost oscelliscope graph of a transmission (with no scope available to me)... That way I can see how the messege is actually composed (with a start symbol, header, data, crc, end symbols)

I foget that not everyone is me and somtimes mention things like an Elm VPW/1850 chip not realising there may be people who don't know what that is. I do it all the time, I'm probably self absorbed or somthing. I'm working with VPW signals that are almost exactly J1850 (but without the name i think)

I'de would not be against using CCP if it worked for me, but none of the numbers I get are even close to where they should be, plus... doesnt CCP take some time too ?

I my computer doesnt like to log on or stay logged on to anything. I have the worlds worst phone line system (disconnected twice while writing this) and I cant get anything but dialup here (500ft from the last dsl point). I'll try and stay logged it though,

Transferring one byte to a fixed address, 'costs' one instruction. With an int16, this doubles. With an array, if using a variable, the time 'leaps up'. To access a byte in an array, the compiler has to take the index, multiply it by the size of the elements, add this to the address of the start of the array, transfer this result to the indirect addressing registers, and then transfer the byte to the addressed register. You can reckon on a single byte transfer, taking perhaps 8 instructions, if dealing with an 8 bit value, while with a 16bit value, this goes up to perhaps 14 instructions.
You really are trying to do too much in a 20uSec interval. One of the key things when dealin with fast interrupts, is to work out how to minimise the work in the interrupt...

Best Wishes
iso9001



Joined: 02 Dec 2003
Posts: 262

View user's profile Send private message

PostPosted: Sun Aug 29, 2004 3:46 pm     Reply with quote

This computer doesnt handle cookies well and even if I have the option to log on automatically, it wont do it. Every time I click post In eed to log on and then find that post again, click post a 2nd time then I can write, unless I disconnect which I get to do it all over again. Its roughly a 5min ordeal just to post a relpy.

Cant transmit to PC :( No laptop around, and have no access to one. It would be a little hard to bring one out in the field. I'm actually not upset about the long eeprom times, I am suprised about how long an array takes though! I wish I knew how to use pointers

I have my processing code outside the interupt, but your right I was trying to do too much in 20us.

I'm going to look into ccp again, I'm about to test and I'll post how it goes... I am curious as to this line of CCP's ccpmp example:

Code:

     printf("\r%lu us      ", pulse_width/5 );


Why are they dividing the perfectly good pulse_width by 5 ????

Also, how much time passes from when setup_ccp1(CCP_CAPTURE_RE); detects a rising edge to the time when CCP_1 is actually assigned the time? I'm guessing it should be rather fast and that using the ccp I shouldn't need to worry about the interupt overhead.
iso9001



Joined: 02 Dec 2003
Posts: 262

View user's profile Send private message

PostPosted: Sun Aug 29, 2004 6:02 pm     Reply with quote

Ok... I tried out the CCP and got poor results... Maybe someone can explain what it is I'm doing wrong !?

Here is my code:

Code:

#include <16F876.h>
#fuses HS,LVP,NOWDT,NOPROTECT, PUT, NOBROWNOUT
#use delay(clock=20000000)
#Define black_saab_rules 1

int i=0, ct=0;
int storage[76];
long fall=0, rise=0, prise=0;  //prise == previous rise


#int_ccp1
void isr1()  //Rising Edge - Counts Low Width
 {
  if (rise!=0) {  //skip the first high
   prise=rise;
   rise = CCP_1;

   storage[i]=(rise-fall)/2;  //Div 2 incase pulse>255
   i++;
  }
  else {
   rise=CCP_1;
  }
 }

#int_ccp2
void isr2()
 {
  fall = CCP_2;
  storage[i]=(fall-prise)/2;
  i++;
}

void saveState() {
 disable_interrupts(INT_CCP1);
 disable_interrupts(INT_CCP2);
 disable_interrupts(GLOBAL);

 for (ct=0; ct<=75; ct++)
  write_eeprom(ct, storage[ct]);

 while(1) {       //Inf Loop
  output_high(PIN_A2); //Led On
  delay_ms(250);
  output_float(PIN_A2); //Led Off
  delay_ms(250);
 }
}

void main()
{
   output_high(PIN_A2);

   setup_ccp1(CCP_CAPTURE_RE);
   setup_ccp2(CCP_CAPTURE_FE);
   setup_timer_1(T1_INTERNAL);
   enable_interrupts(INT_CCP1);
   enable_interrupts(INT_CCP2);
   enable_interrupts(GLOBAL);

   delay_ms(2000);
   output_low(PIN_A2);

while(black_saab_rules) {
  if (i >= 75)
   saveState();
 }
}


And this is the data I got back.... The pulses are of ~60us and ~120us...

0000: 29 95 2D 96 C7 3E 70 3D )•-–Ç>p=
0008: 18 95 70 3D 18 95 C8 95 .•p=.•È•
0010: C7 96 70 95 70 95 70 94 Ç–p•p•p”
0018: 70 95 70 96 70 95 6F 95 p•p–p•o•
0020: 70 95 C8 3D 70 95 C8 95 p•È=p•È•
0028: C8 3D 18 3D 70 3D 70 95 È=.=p=p•
0030: C8 22 13 95 2E 96 C7 96 È".•.–Ç–
0038: C8 95 70 95 70 95 70 95 È•p•p•p•
0040: 6F 95 70 95 70 96 70 95 o•p•p–p•

But my numbers dont suggest this at all... with the Div 2 in there I should have somthing like this:

0000: 30 60 60 60 30 30 60 30 (shown in decimal)

I dont get it! Sad Sad Sad

(btw: i REALLY appreciate all the help from everyone, this would be impossible for me without your help)[/code]
ckielstra



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

View user's profile Send private message

PostPosted: Mon Aug 30, 2004 1:42 am     Reply with quote

Quote:
But my numbers dont suggest this at all... with the Div 2 in there I should have somthing like this:

0000: 30 60 60 60 30 30 60 30 (shown in decimal)

From this I conclude you assume your timer1 is running at 1 tick per microsecond. Well, it isn't.
Code:
setup_timer_1(T1_INTERNAL);

Your timer1 is running at 20Mhz/4 = 0,2 us tick rate.
... A div2 isn't enough, better try a div 10 (or a much faster div 16 which is basically a shift operation).

Second problem are several weak points in your algorithm for calculating the time differences. The largest error is this one:
Code:
storage[i]=(fall-prise)/2;

Here you calculate the time difference over 1.5 cycles instead of 1 cycle.

In one of your previous threads you were pointed to a Microchip application note with tips and tricks for the CCP. Why don't you stick to the given method in the example there? It uses only one CCP unit and doesn't have the startup problems your code has.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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