Author Topic: CLOCK, TIMER, DELAY  (Read 5687 times)

0 Members and 1 Guest are viewing this topic.

Offline MAD MACROTopic starter

  • Regular Contributor
  • *
  • Posts: 56
  • Country: eg
CLOCK, TIMER, DELAY
« on: June 04, 2016, 01:27:33 pm »
RANT START
PIC's clock system is too bloody confusing and inconsistent, and how come xc8 compiler doesn't have the correct definition of _delay() for my chip ?!
RANT END


So, it's been at least a week and i'm still trying to figure out what is the clock speed, I did two tests so far, the code is very clean, small and easy to read.
and is in the attached files.


First test: 16MHz external oscillator, using timer0 interrupt to get an interrupt every 1 second, but i'm getting led toggled every 4 seconds.
Second test: 16MHz external oscillator, trying to delay the led toggling by 1000 seconds, and I get exactly 6.4 seconds delay.[SOLVED]

no postscaling or prescaling for the input frequency used in either of the tests.

This is my delay function
Code: [Select]
#define delay_ms(x)             _delay((unsigned long)((x)*(_XTAL_FREQ/1000.0)))when I used the compiler's delay function, which is __delay_ms() , I get always get quarter that delay.

one small question, how much time does it take to do a NOP instruction in my chip ?

if you want me to do any extra tests, I will do them and post the results.


chip: pic18F2550
compiler: xc8
OS: linux
programmer: pickit2
« Last Edit: June 04, 2016, 02:52:27 pm by MAD MACRO »
 

Offline Ian.M

  • Super Contributor
  • ***
  • Posts: 14135
Re: CLOCK, TIMER, DELAY
« Reply #1 on: June 04, 2016, 02:00:39 pm »
One 8 bit PIC instruction cycles is four clock cycles. The internal clock to the timer prescalers is Fosc/4 not Fosc.

If the XC8 system delay macros don't produce the period expected, either your PIC is running at a different clock frequency to what you think it is, or you have an ISR taking up a significant proportion of the processing time stretching the delay, or you are using a very old compiler version that could silently fail to generate a delay, with no error or warning for delay parameters that were too large (though I think that bug was fixed before HiTech C became XC8).

Your timings are entirely consistent with the borked delay macro you are using and the fact that 100000 modulo 256 is 160.
 
The following users thanked this post: Kilrah, MAD MACRO

Offline JPortici

  • Super Contributor
  • ***
  • Posts: 3921
  • Country: it
Re: CLOCK, TIMER, DELAY
« Reply #2 on: June 04, 2016, 02:09:30 pm »
As i said in the other topic, i wouldn't use Timer 0 interrupt for a precise delay timer. Why? because if you want a specific time interval you have to reload TMR0 to a specific value inside the interrupt routine.

If you use, for example, TMR2.. TMR2 auto-resets and generate an interrupt when it matches the period register PR2, so by playing with the prescaler and PR2 value you will get a constant interval between two interrupts.

Back to the topic: clock structure.
The 18f2550 clock structure isn't really that complicated anyway... though it may appear confusing.

You can ignore the usb part for now.
You said you have a 16MHz oscillator. Almost all the parameters are set in the configuration words, for example by setting the CPUDIV bits you can divide the primary oscillator frequency by 1:1 to 1:4
Let's say you configure the divider to be 1:4

16 MHz in -> 4 MHz out. The cpu will be clocked at 4 MHz. Then, in PIC16/18 the instruction clock is 1/4 of the clock frequency, so 16 MHz divided by four (CLKDIV), divided by four (Inst clock), 1MIPS -> 1 Million instructions per second. 1us per instruction

In this example, let's try to get TMR2 to generate an interrupt every 1ms
Fig 13-1, page 138 of the datahseet you have TMR2 block diagram. TMR2 frequency is Fosc/4 (the instruction clock), divided by the prescaler.
if you divide the clock by 4  TMR2 clock will be 250kHz, if the timer is set to count 250 times between each interrupt the interrupt frequency will be 1kHz so one interrupt every 1ms so PR2 will be 249 (count from 0 to 249)

Code: [Select]
T2CON = 0;
T2CONbits.T2CKPS = 1;
PR2 = 249;
T2CONbits.TMR2ON = 1;
PIR1bits.T2IF = 0;
PIE1bits.T2IE = 1;

toggle an output in the interrupt routine, clear the flag. If you don't get the desired frequency it can only mean that the clock is NOT what you expect
« Last Edit: June 04, 2016, 02:11:58 pm by JPortici »
 

Offline MAD MACROTopic starter

  • Regular Contributor
  • *
  • Posts: 56
  • Country: eg
Re: CLOCK, TIMER, DELAY
« Reply #3 on: June 04, 2016, 02:25:56 pm »
One 8 bit PIC instruction cycles is four clock cycles. The internal clock to the timer prescalers is Fosc/4 not Fosc.
so, you're saying that a NOP instruction will take a period of 4/Fosc.

If the XC8 system delay macros don't produce the period expected, either your PIC is running at a different clock frequency to what you think it is, or you have an ISR taking up a significant proportion of the processing time stretching the delay, or you are using a very old compiler version that could silently fail to generate a delay, with no error or warning for delay parameters that were too large (though I think that bug was fixed before HiTech C became XC8).

What are you talking about ? Have you read the code ? they are two different tests, I didn't even have interrupts enabled in the second test where I was testing the delay.

stretching the delay ? really ? I went from 1000 seconds delay to only having 6.4 seconds delay.

I have 16MHz frequency oscillator crystal, it has 16 written on it, and my configuration are right there for you to point out any mistake if there is any.

I just downloaded the xc8 compiler very recently from the main microchip page.

Your timings are entirely consistent with the borked delay macro you are using and the fact that 100000 modulo 256 is 160.

my delay macro is bad ? well, can you please enlighten me with a suggested one ?
100000 modulo 256 is 160 , what does this have to do with anything ? ? ?
 

Offline MAD MACROTopic starter

  • Regular Contributor
  • *
  • Posts: 56
  • Country: eg
Re: CLOCK, TIMER, DELAY
« Reply #4 on: June 04, 2016, 02:42:15 pm »
Thanks alot for your reply, JPortici  :-+

As i said in the other topic, i wouldn't use Timer 0 interrupt for a precise delay timer. Why? because if you want a specific time interval you have to reload TMR0 to a specific value inside the interrupt routine.

it's alright I can live with the timer0 accuracy.

If you use, for example, TMR2.. TMR2 auto-resets and generate an interrupt when it matches the period register PR2, so by playing with the prescaler and PR2 value you will get a constant interval between two interrupts.

Back to the topic: clock structure.
The 18f2550 clock structure isn't really that complicated anyway... though it may appear confusing.

You can ignore the usb part for now.
You said you have a 16MHz oscillator. Almost all the parameters are set in the configuration words, for example by setting the CPUDIV bits you can divide the primary oscillator frequency by 1:1 to 1:4
Let's say you configure the divider to be 1:4

why ? I was using 1:1 postscaling using CPUDIV, why use 1:4 now ? you're going with your own testing....

16 MHz in -> 4 MHz out. The cpu will be clocked at 4 MHz. Then, in PIC16/18 the instruction clock is 1/4 of the clock frequency, so 16 MHz divided by four (CLKDIV), divided by four (Inst clock), 1MIPS -> 1 Million instructions per second. 1us per instruction

an instruction takes period of 4/FSOC , but that shouldn't affect the delay function, cuz the delay depends on the clock cycles and not the instruction period, right ?

In this example, let's try to get TMR2 to generate an interrupt every 1ms
Fig 13-1, page 138 of the datahseet you have TMR2 block diagram. TMR2 frequency is Fosc/4 (the instruction clock), divided by the prescaler.
if you divide the clock by 4  TMR2 clock will be 250kHz, if the timer is set to count 250 times between each interrupt the interrupt frequency will be 1kHz so one interrupt every 1ms so PR2 will be 249 (count from 0 to 249)

Code: [Select]
T2CON = 0;
T2CONbits.T2CKPS = 1;
PR2 = 249;
T2CONbits.TMR2ON = 1;
PIR1bits.T2IF = 0;
PIE1bits.T2IE = 1;

toggle an output in the interrupt routine, clear the flag. If you don't get the desired frequency it can only mean that the clock is NOT what you expect

I think I can read the datasheet and come up with an idea of how to deal with timer1 or timer2, and test them, but this is nothing close to the 2 tests in the OP.

i'm very thankful for your help, but you kinda just ditched my test code, timer0 is not that bad.




« Last Edit: June 04, 2016, 02:55:27 pm by MAD MACRO »
 

Offline Ian.M

  • Super Contributor
  • ***
  • Posts: 14135
Re: CLOCK, TIMER, DELAY
« Reply #5 on: June 04, 2016, 02:45:09 pm »
Your delay macro is borked because the builtin _delay() psudofunction's parameter is number of instruction cycles to delay, not Fosc clock cycles.   The definition  for the ms delay in XC8's htc.h is:
Code: [Select]
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))which uses the correct conversion factor of _XTAL_FREQ/4000.0 to get instruction cycles from ms.   You are using _XTAL_FREQ/1000.0 which will make all delays using your macro four times too long.

Code: [Select]
       delay_10ms(100000); // 1000 seconds delay
Code: [Select]
void delay_10ms(unsigned char n)
//              ^^^^^^^^^^^^^
So you don't see a problem with trying to stuff 100000 into a single byte?
   
 
 
The following users thanked this post: MAD MACRO

Offline MAD MACROTopic starter

  • Regular Contributor
  • *
  • Posts: 56
  • Country: eg
Re: CLOCK, TIMER, DELAY
« Reply #6 on: June 04, 2016, 02:51:42 pm »
Your delay macro is borked because the builtin _delay() psudofunction's parameter is number of instruction cycles to delay, not Fosc clock cycles.   The definition  for the ms delay in XC8's htc.h is:
Code: [Select]
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))which uses the correct conversion factor of _XTAL_FREQ/4000.0 to get instruction cycles from ms.   You are using _XTAL_FREQ/1000.0 which will make all delays using your macro four times too long.

Code: [Select]
       delay_10ms(100000); // 1000 seconds delay
Code: [Select]
void delay_10ms(unsigned char n)
//              ^^^^^^^^^^^^^
So you don't see a problem with trying to stuff 100000 into a single byte?
 


you're right, changed the argument to 255 and changed the macro definition to

Code: [Select]
#define delay_ms(x)             _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
giving me 2.5 seconds delay.

 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: CLOCK, TIMER, DELAY
« Reply #7 on: June 04, 2016, 07:40:39 pm »
Quote
First test: 16MHz external oscillator, using timer0 interrupt to get an interrupt every 1 second, but i'm getting led toggled every 4 seconds.

To be expected: 16Mhz EC / 1 -> 4Mhz F_CPU. TMR0 offset -62500 * 256 = 16M ticks so every 4 seconds TMR0 overflows.

================================
https://dannyelectronics.wordpress.com/
 

Offline MAD MACROTopic starter

  • Regular Contributor
  • *
  • Posts: 56
  • Country: eg
Re: CLOCK, TIMER, DELAY
« Reply #8 on: June 04, 2016, 07:42:43 pm »
Quote
First test: 16MHz external oscillator, using timer0 interrupt to get an interrupt every 1 second, but i'm getting led toggled every 4 seconds.

To be expected: 16Mhz EC / 1 -> 4Mhz F_CPU. TMR0 offset -62500 * 256 = 16M ticks so every 4 seconds TMR0 overflows.

ok, you seem to be having an explanation, can you please explain it a bit clearer and slower ?
 

Offline uncle_bob

  • Supporter
  • ****
  • Posts: 2441
  • Country: us
Re: CLOCK, TIMER, DELAY
« Reply #9 on: June 10, 2016, 06:25:40 pm »
Quote
First test: 16MHz external oscillator, using timer0 interrupt to get an interrupt every 1 second, but i'm getting led toggled every 4 seconds.

To be expected: 16Mhz EC / 1 -> 4Mhz F_CPU. TMR0 offset -62500 * 256 = 16M ticks so every 4 seconds TMR0 overflows.

ok, you seem to be having an explanation, can you please explain it a bit clearer and slower ?

Hi

Your external clock is 16 MHz. It is divided by one so the result is 16 MHz into the top of the clock tree.

With a 16 MHz signal into the top of the clock tree, the CPU  clock frequency will be one fourth of that frequency. This gives you 4 MHz for the CPU.

If you multiply your timer 0 offset of 62,500 * 256 you get 16,000,000.

If you divide 4 MHz by 16 MHz you get 4.

The interrupt happens each time the counter overflows.

The counter overflows every 4 seconds.

Bob
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

- - -
-->