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

WDT is affecting Timer0 clock

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







WDT is affecting Timer0 clock
PostPosted: Tue Oct 23, 2007 2:09 pm     Reply with quote

Im using a 16f688, and compiler version 4.058. I am using both the WDT and timer0, with no prescaler. Im simply counting interrupts to get up to my desired increment. Using timer0 by itself, with WDT disabled, I get the expected results. But adding the WDT makes timer0's clock run about 1.5 times slower.

No WDT:
Clock = 125khz
Prescaler = 1
timer0 counts 244 ticks per interrupt
128 interrupts take approximately 1 second

WDT in use:
Clock = 125kHz
Prescaler = 1
WDT set to 18ms, and WDT_TIMES_128 to achieve 2304ms
timer0 counts 161 ticks per interrupt
128 interrupts take approximately 1 second

im using the following line to set up timer0 and WDT:
setup_counters(RTCC_INTERNAL | RTCC_DIV_1, WDT_18MS | WDT_TIMES_128);

Can anyone think of why the addition of a watchdog timer would change the interrupt frequency?

Im happy to post code, but Im not sure what will be helpful, and it is rather long.

Thanks in advance.
ckielstra



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

View user's profile Send private message

PostPosted: Tue Oct 23, 2007 4:39 pm     Reply with quote

Quote:
Can anyone think of why the addition of a watchdog timer would change the interrupt frequency?
Check chapter 5.4 of the PIC16F688 data sheet and you will see the watchdog uses a combination of two prescalers, one shared with Timer0. It is configurable to assign the second prescaler to either the watchdog or timer0.

From the manual on setup_counters():
Quote:
This function is provided for compatibility with older versions. setup_timer_0 and
setup_WDT are the recommended replacements when possible.


I tested setup_counters in v4.057 and the resulting code doesn't look good (compiler bug). The newer functions are around for at least 4 years now and when tried the generated assembly looks good. Replace your line with the code below:
Code:
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_1);
setup_wdt(WDT_ON | WDT_TIMES_128);
wetodd
Guest







PostPosted: Wed Oct 24, 2007 7:59 am     Reply with quote

I changed the setup functions to the ones listed above, and saw no change. Timer0 still interrupts every 1/128th of a second with only 161 cycles/interrupt, instead of the calculated 244

128 ints/sec * 244 cycles/int * 4 clocks/cycle = 124928 cycles/sec

Im still able to achieve the desired results with the workaround of using 95 (256-161) as my reload value instead of 12 (256-244), but it makes me uneasy that the addition of the WDT has that effect.
ckielstra



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

View user's profile Send private message

PostPosted: Wed Oct 24, 2007 8:05 am     Reply with quote

The above configuration should not have the watchdog interfering with timer0, there must be an error in your program or in the compiler.

Please post a short program demonstrating your problem. Ensure the program is complete so we can copy/paste it into our compilers, include the #fuse statements, #device lines, etc.
Make the program as short as possible, max. about 30 lines.
Guest








PostPosted: Wed Oct 24, 2007 12:45 pm     Reply with quote

Code:


#include <16F688.h>
#define TICKS_PER_SECOND   128
#define TIMER0_RELOAD      12
#define LED PIN_C5
#fuses INTRC_IO, WDT, PUT, MCLR, BROWNOUT_NOSL, NOPROTECT, NOCPD, NOIESO, NOFCMEN
#use delay(clock = 125000, restart_wdt)

unsigned int8 tick_count;

#int_timer0
void timer0_isr()
{
  set_timer0(TIMER0_RELOAD);   // reload counter
  tick_count++;
  if(tick_count == 32)
  {
    output_low(LED);
  }
  if(tick_count == TICKS_PER_SECOND)  //every second
  {
    tick_count = 0;  //reset tick_count
    output_high(LED);
  }
 
 
}
#zero_ram
void main()

   setup_oscillator(OSC_125KHZ);
   setup_timer_0(RTCC_INTERNAL | RTCC_DIV_1);
   setup_wdt(WDT_ON | WDT_TIMES_128);
   set_timer0(TIMER0_RELOAD);   // reload counter
   enable_interrupts(INT_TIMER0);
   enable_interrupts(GLOBAL);
   while(1)
   {
     restart_wdt();
   }
}



Previously, I had the set_timer0(TIMER0_RELOAD); at the end of the isr. Moving it to the first statement seemed to speed things up a little bit, but Im still slower than the calculated speed. I know it was at the end of the isr when I had the WDT off before, and the timing matched the calculations, though. I do have several if statements and flag settings in my full isr, but no delays or while loops.
evsource



Joined: 21 Nov 2006
Posts: 129

View user's profile Send private message

PostPosted: Thu May 01, 2008 12:05 pm     Reply with quote

ckielstra wrote:
The above configuration should not have the watchdog interfering with timer0, there must be an error in your program or in the compiler.

Please post a short program demonstrating your problem. Ensure the program is complete so we can copy/paste it into our compilers, include the #fuse statements, #device lines, etc.
Make the program as short as possible, max. about 30 lines.


I've been able to confirm this bug. When I use the suggested lines you provided on a 16F88, the WDT is always set at 18ms, seemingly no matter what I do (I figured out that it was actually set at 18ms by putting in delays of 15ms and 20ms in between restart_wdt() calls - chip reboots with 20ms delays, and doesn't with 15ms delays) :

Code:

setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256);
setup_wdt(WDT_ON | WDT_TIMES_128);


The timer works perfectly though.

I can't get both timer0 and the WDT to work correctly using setup_counters either.

Here's my test program:

Code:

/*
PIN_A2 is the green LED pin
PIN_A3 is the red LED pin
*/

#include <16f88.h>
#DEVICE ADC=10
#device *=16
#fuses WDT,NOPROTECT,NOMCLR,NOLVP,HS
#use delay(clock=20000000)

#define INTS_PER_4SECONDS 306
//#define INTS_PER_2SECONDS 154
//#define INTS_PER_SECOND 77     // (20000000/(4*256*256))

int1 led_on;
int16 comm_timeout_counter;

#int_rtcc
void clock_isr() {
     if(--comm_timeout_counter==0) {
          comm_timeout_counter=INTS_PER_4SECONDS;
          if(led_on) {
               output_high(PIN_A2);
               led_on = FALSE;
          }
          else {
               output_low(PIN_A2);
               led_on = TRUE;
          }
     }
}

main() {
     // to see reboot condition
     output_low(PIN_A3);
     delay_ms(500);
     output_high(PIN_A3);
     delay_ms(500);
     output_low(PIN_A3);
     delay_ms(500);
     output_high(PIN_A3);
     delay_ms(500);
     
     led_on = FALSE;
     
     comm_timeout_counter=INTS_PER_4SECONDS;
    // setup_counters(RTCC_INTERNAL | RTCC_DIV_256, WDT_18MS | WDT_TIMES_128);
     
     setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256);
     setup_wdt(WDT_ON | WDT_TIMES_128);
     
     set_timer0(0);
     
     enable_interrupts(INT_RTCC);
     enable_interrupts(GLOBAL);
     
     while(TRUE) {
          restart_wdt();
          delay_ms(15);
     }
}


Basically, the program starts by blinking a red LED a couple times. The timer should turn the green LED on every 4 seconds, then back off in 4 seconds. By adjusting the delay_ms function in the while(TRUE) loop, you can see what the WDT is set to. The code, as it is, shows that the WDT is set at 18ms. I would expect that it should be about 2.3s, 18ms * 128 = 2.304 seconds.

Any hints, tips, corrections, or tricks would be appreciated!
evsource



Joined: 21 Nov 2006
Posts: 129

View user's profile Send private message

PostPosted: Thu May 01, 2008 12:48 pm     Reply with quote

Okay, figured it out, but not using the CCS functions.

As a previous post (different thread) suggested, you have to manipulate the WDTCON register directly.

I modified my test program to show the change. Keep in mind, I'm using compiler version 4.032, so it's possible this problem has been fixed in newer versions.

Code:

/*
PIN_A2 is the green LED pin
PIN_A3 is the red LED pin
*/

#include <16f88.h>
#DEVICE ADC=10
#device *=16
#fuses NOWDT,NOPROTECT,NOMCLR,NOLVP,HS
#use delay(clock=20000000)

#define INTS_PER_4SECONDS 306
//#define INTS_PER_2SECONDS 154
//#define INTS_PER_SECOND 77     // (20000000/(4*256*256))

int1 led_on;
int16 comm_timeout_counter;

#int_rtcc
void clock_isr() {
     if(--comm_timeout_counter==0) {
          comm_timeout_counter=INTS_PER_4SECONDS;
          if(led_on) {
               output_high(PIN_A2);
               led_on = FALSE;
          }
          else {
               output_low(PIN_A2);
               led_on = TRUE;
          }
     }
}

#byte WDTCON= 0x105

main() {
     // to see reboot condition
     output_low(PIN_A3);
     delay_ms(500);
     output_high(PIN_A3);
     delay_ms(500);
     output_low(PIN_A3);
     delay_ms(500);
     output_high(PIN_A3);
     delay_ms(500);
     
     led_on = FALSE;
     
     comm_timeout_counter=INTS_PER_4SECONDS;
     
     setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256);
   
     WDTCON = 0x17; // 0x16 turns WDT off, set for approximately 2.1s WDT
     
     set_timer0(0);
     
     enable_interrupts(INT_RTCC);
     enable_interrupts(GLOBAL);
     
     while(TRUE) {
          restart_wdt();
          delay_ms(2000);
     }
}


I got the values for the timeouts straight from the 16F88 datasheet. The last bit is used to turn the WDT on or off, but I think that only works if you have the fuse set to NOWDT. Otherwise, it is always turned on.

Hopefully this helps someone else out that was running into the same problem I was.
ckielstra



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

View user's profile Send private message

PostPosted: Thu May 01, 2008 7:38 pm     Reply with quote

Quote:
I'm using compiler version 4.032, so it's possible this problem has been fixed in newer versions.
I tried reproducing your problem but the oldest v4 version I have is v4.038 and the workaround I posted creates assembly code that looks correct. Note that v4.032 was one of the first v4.0xx releases that started to work more or less. Everything before v4.030 was crap.

ckielstra wrote:
Replace your line with the code below:
Code:
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_1);
setup_wdt(WDT_ON | WDT_TIMES_128);
I've made an error here... Documentation on the use of the setup_wdt function is poor, but it turns out WDT_ON and WDT_TIMES_128 are not supposed to be combined. If you look at the values defined in the header file there are two tables given and we are only allowed to combine one value of each table. I used two values from the second table... It compiles to correct code but is not written according to the specifications.

Here are some more test results performed in v4.057:
Code:
 setup_wdt(WDT_ON | WDT_TIMES_128);   // OK: timing is correct but uses an invalid combination of parameters.
                                      // Only the prescaler is used, postscaler is available for Timer0.

 setup_wdt(WDT_TIMES_128);            // OK: Timing correct and postscaler is available for Timer0.

 setup_wdt(WDT_2304MS);               // OK: Correct timing but too bad it also uses the postscaler while it
                                      // can be done with just the prescaler.

 setup_wdt(WDT_2304MS | WDT_OFF);     // Bug: WDT_OFF does nothing (WDT is enabled).

 setup_wdt(WDT_ON);                   // Bug: I expected this command to leave settings untouched, instead it
                                      // sets the prescaler to 1ms (WDT_DIV_16). This is differs from the
                                      // default 18ms (WDT_TIMES_1) as mentioned in the header file.

 setup_wdt(WDT_2304MS | WDT_ON);      // Bug: Sets smallest WDT prescaler (1ms) and postscaler at 128 = 131ms.

 setup_wdt(WDT_OFF);                  // Wrong? : Disables the WDT but also destroys the setup.

 setup_wdt(WDT_18MS | WDT_TIMES_128); // Wrong?: Correct timing (maximum prescaler and postscaler at 0)
                                      // Why using the postscaler? Now not available for Timer0.
ckielstra



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

View user's profile Send private message

PostPosted: Mon May 05, 2008 2:34 pm     Reply with quote

Regarding the above failed test examples I got a response from CCS that "The problem you reported has been fixed and will be in the next compiler release". Current version is v4.072, so next release will most likely be 4.073.

Too bad they didn't mention which of the 5 issues they have fixed...
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