CLOCK, TIMER, DELAY  - Page 1
Forum section: electronics / general

author: MAD MACRO
author_rank: Regular Contributor
timestamp: June 04, 2016, 01:27:33 pm
content: RANT STARTPIC'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 ENDSo, 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.no postscaling or prescaling for the input frequency used in either of the tests.This is my delay functionCode:#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: pic18F2550compiler: xc8OS: linuxprogrammer: pickit2

author: Ian.M
author_rank: Super Contributor
timestamp: June 04, 2016, 02:00:39 pm
content: 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.

author: JPortici
author_rank: Super Contributor
timestamp: June 04, 2016, 02:09:30 pm
content: 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:4Let's say you configure the divider to be 1:416 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 instructionIn this example, let's try to get TMR2 to generate an interrupt every 1msFig 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: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

author: MAD MACRO
author_rank: Regular Contributor
timestamp: June 04, 2016, 02:25:56 pm
content: Quote from: Ian.M on June 04, 2016, 02:00:39 pmso, you're saying that a NOP instruction will take a period of 4/Fosc.Quote from: Ian.M on June 04, 2016, 02:00:39 pmWhat 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.Quote from: Ian.M on June 04, 2016, 02:00:39 pmmy 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 ? ? ?

author: MAD MACRO
author_rank: Regular Contributor
timestamp: June 04, 2016, 02:42:15 pm
content: Thanks alot for your reply, JPorticiQuote from: JPortici on June 04, 2016, 02:09:30 pmit's alright I can live with the timer0 accuracy.Quote from: JPortici on June 04, 2016, 02:09:30 pmwhy ? I was using 1:1 postscaling using CPUDIV, why use 1:4 now ? you're going with your own testing....Quote from: JPortici on June 04, 2016, 02:09:30 pman 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 ?Quote from: JPortici on June 04, 2016, 02:09:30 pmI 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.

author: Ian.M
author_rank: Super Contributor
timestamp: June 04, 2016, 02:45:09 pm
content: 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:#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:delay_10ms(100000); // 1000 seconds delayCode:void delay_10ms(unsigned char n)// ^^^^^^^^^^^^^So you don't see a problem with trying to stuff 100000 into a single byte?

author: MAD MACRO
author_rank: Regular Contributor
timestamp: June 04, 2016, 02:51:42 pm
content: Quote from: Ian.M on June 04, 2016, 02:45:09 pmyou're right, changed the argument to 255 and changed the macro definition toCode:#define delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))giving me 2.5 seconds delay.

author: dannyf
author_rank: Super Contributor
timestamp: June 04, 2016, 07:40:39 pm
content: QuoteTo be expected: 16Mhz EC / 1 -> 4Mhz F_CPU. TMR0 offset -62500 * 256 = 16M ticks so every 4 seconds TMR0 overflows.

author: MAD MACRO
author_rank: Regular Contributor
timestamp: June 04, 2016, 07:42:43 pm
content: Quote from: dannyf on June 04, 2016, 07:40:39 pmok, you seem to be having an explanation, can you please explain it a bit clearer and slower ?

author: uncle_bob
author_rank: Unknown
timestamp: June 10, 2016, 06:25:40 pm
content: Quote from: MAD MACRO on June 04, 2016, 07:42:43 pmHiYour 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