Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC Timing

Status
Not open for further replies.

baberjaved

New Member
I started programming 8051 and i calculated exact timing delays by using basic maths when i knew the crystal speed. For example when using a 11.059 crystal the time for a single instruction came out be 1.085x10exp-11. So i could generate exact delays by using this
How can i generate such exact timing delays in PIC (dsPIC) to be specific? What is the time for a single instruction in PIC? How can i generate these exact timing delays in C for pic's?
 
The datasheet will tell you the exact timings (I've never used dsPIC's), but for 16F series devices the timing is 1/4 of the clock speed. So a 16F running at 4MHz takes 1uS per instruction, apart from branch instructions, which takes 2 instruction cycles.
 
Just as an aside. No professional programmer worth his salt would ever use instruction cycles as a method of generating delays. It is fraught with perils too numerous to mention. If you want to distinguish yourself among your peers use the onboard timers for delays both short and long. In short don't program like a weenie.
 
Ontopic portion:

Usually for C source that require critical timing, this needs to be done in assembly. You can't really guarantee how many cycles the C compiler will use to design your function written in C. I've never used a PIC C compiler, but in gcc for the AVR there's the __asm__() directive which will let you hard code assembly into your C.

For these *really* timing sensitive applications you will need to use/tune assembly extensively, and it may be worth to get familiar with it. Be careful with the btfsc, btfss, decfsz, incfsz, etc. instructions as they may have unexpected timing numbers depending on situation. However I'm sure you're well aware of that after using the 8051.

Offtopic portion:

I actually beg to differ on programming jobs on devices with CPUs that never change. This was a bad assumption for personal computers that received speed bumps, and hence we got unplayable games when moving from an IBM XT to an IBM AT as well as broken emulators, but it may be appropriate for microcontrollers soldered into circuits that will never change/upgrade. Likely microcontroller software should be do once, never touch again. If you need to touch again, likely it's due to a bug that should have been fixed before completing the project. That being said, software timing loops can be really difficult to debug.

Back on topic:

If your microcontroller is much faster than your target application, and you have the timer resources to do it, you should go ahead and use the timers - there's no excuse not to. However, if you're out of resources, or the resolution of the timer will kill your performance (don't forget: timer interrupt latency dealing with context save and possibly multiplexed timer functions where the timer may be used for more than one thing) then software timers may not be a bad idea after all. Also note: during software timing you'll have to disable interrupts anyway, so I guess the timer resource availability issue is moot.

But if you are careful you can get pretty wicked software-timed applications. Just DON'T UPGRADE YOUR CPU (or firmware!) AFTER IT'S DONE! And do remember it's not your job to make people writing emulators for your code happy! (but if you want to be nice... then go ahead!)
 
boxer4 said:
Ontopic portion:

Usually for C source that require critical timing, this needs to be done in assembly. You can't really guarantee how many cycles the C compiler will use to design your function written in C. I've never used a PIC C compiler, but in gcc for the AVR there's the __asm__() directive which will let you hard code assembly into your C.

Even if you program in asm, it is full of problems.
The code becomes impractical to maintain if you try to do anything inside the code block. No one wants to recalculate the cycles a code block takes.
Interrupts must be disabled during this period, in many systems you can't do this for long.

But there are cases where it's fine. If you only need a specific delay, then a loop waiting 156 Nop instructions is fine and generally easy to maintain. If your delay requirement is actually only a minimum delay- like meeting timing of an external device- then interrupts increasing the execution time is just fine.
 
Papabravo said:
Just as an aside. No professional programmer worth his salt would ever use instruction cycles as a method of generating delays. It is fraught with perils too numerous to mention. If you want to distinguish yourself among your peers use the onboard timers for delays both short and long. In short don't program like a weenie.

Perhaps you would care to mention some of these 'perils', you appear to be talking complete rubbish?.

Software loop delays are commonplace, and are what HL compilers generate.
 
baberjaved said:
How can i generate such exact timing delays in PIC (dsPIC) to be specific? What is the time for a single instruction in PIC? How can i generate these exact timing delays in C for pic's?

I don't know about delays in C but there is an asm exact delay code generator provided by the piclist:


I suppose you could include some asm code within your C program to make the precise delay.
I have not used it with dsPIC chips so you may need to check if their instruction cycle timings are the same as the 16F series.

The timing for each instruction depends on the clock frequency and the type of instruction.
In the 16F and 18F series MOST instructions use 1 instruction cycle (which takes 1uS at a clock speed of 4Mhz - ie clock frequency/4)
Conditional instructions may take 1 or 2 cycles depending on the condition being false or true.
There are also more complex instructions in the 18F series that can take 3 instruction cycles - so check the manual for your dsPic chip to be sure.
 
Nigel Goodwin said:
Perhaps you would care to mention some of these 'perils', you appear to be talking complete rubbish?.

Software loop delays are commonplace, and are what HL compilers generate.
I can see his point, as soon as you want to port it to another processor it messes up your code because the instruction timing totally changes. However, if you are using a microcontroller, it's not very likely that you're ever going to port it to another platform.
 
Hero999 said:
I can see his point, as soon as you want to port it to another processor it messes up your code because the instruction timing totally changes.

Not really, if you port to another device the hardware timer code won't work either, and will most probably be far harder to change than a simple software loop.
 
I wonder if studying this example for 18F' devices might help? Other examples are available on PICLIST.

Longer periods, like HH:MM:SS Photo/Appliance Timers, Alarms, Stop Watch Functions, etc., are probably best handled with a Timer based interrupt routine.

Regards, Mike

Code:
        radix   dec
;******************************************************************
;                                                                 *
;  DelayMS() and DelayUS() Macros     Mike McLaren, K8LH, Jun'07  *
;                                                                 *
;  simple 'front end' macros for 24-bit DelayTcy() routines that  *
;  allow you to specify delays in 'usecs' and 'msecs'.            *
;                                                                 *
;  the delay parameter range is based on clock frequency          *
;                                                                 *
;    4 MHz,  1   cycle /usec, 21..16,777,215 us, 1..16,777 ms     *
;    6 MHz,  1.5 cycles/usec, 14..11,184,810 us, 1..11,184 ms (1) *
;    8 MHz,  2   cycles/usec, 11...8,388,607 us, 1...8,388 ms     *
;   10 MHz,  2.5 cycles/usec,  9...6,710,886 us, 1...6,710 ms (1) *
;   12 MHz,  3   cycles/usec,  7...5,592,405 us, 1...5,592 ms     *
;   16 MHz,  4   cycles/usec,  6...4,194,303 us, 1...4,194 ms     *
;   20 MHz,  5   cycles/usec,  5...3,355,443 us, 1...3,355 ms     *
;   24 MHz,  6   cycles/usec,  4...2,796,202 us, 1...2,796 ms     *
;   28 MHz,  7   cycles/usec,  3...2,396,745 us, 1...2,396 ms     *
;   32 MHz,  8   cycles/usec,  3...2,097,151 us, 1...2,097 ms     *
;   36 MHz,  9   cycles/usec,  3...1,864,135 us, 1...1,864 ms     *
;   40 MHz, 10   cycles/usec,  3...1,677,721 us, 1...1,677 ms     *
;   48 MHz, 12   cycles/usec,  2...1,398,101 us, 1...1,398 ms     *
;                                                                 *
;   (1) 6 and 10 MHz clocks produce inprecise timing              *
;                                                                 *
;  DelayMS() and DelayUS() macros require a 'clock' equate;       *
;                                                                 *
clock   equ   32                ; insert your clock freq (MHz)
;                                                                 *
;  DelayMS() and DelayUS() macros;                                *
;                                                                 *
DelayMS macro   msecs           ; delay range: see list above
        DelayUS(msecs*1000)
        endm
DelayUS macro   usecs           ; delay range: see list above
        DelayTcy(usecs*(10000/(4000/clock))/10)
        endm
;                                                                 *
;******************************************************************
;                                                                 *
;  DelayTcy(), 24-bit                 Mike McLaren, K8LH, Jun-07  *
;                                                                 *
;  simple macro for simulation testing;                           *
;                                                                 *
DelayTcy macro  delay           ; parameter 21..16777215
   if delay < 256
        movlw   delay           ; 2 instructions, 3 cycles
        rcall   DelayTcy.byte   ;
   else
     if delay < 65536
        movlw   ~(high(delay))  ; 4 instructions, 5 cycles
        movwf   TMRH            ;
        movlw   low delay       ;
        rcall   DelayTcy.16     ;
     else
        movlw   ~(upper(delay)) ; 6 instructions, 7 cycles
        movwf   TMRU            ;
        movlw   ~(high(delay))  ;
        movwf   TMRH            ;
        movlw   low delay       ;
        rcall   DelayTcy.24     ;
     endif
   endif
        endm
;                                                                 *
;  code for simulation testing;                                   *
;                                                                 *
SimTest DelayMS(2000)           ; DelayTcy(), DelayUS(), DelayMS()
        nop                     ; put simulator breakpoint here
;                                                                 *
;                                                                 *
;******************************************************************
;                                                                 *
;  DelayTcy() subroutine              Mike McLaren, K8LH, Jun-07  *
;                                                                 *
;  20 words, 2 RAM variables (16 bit core)                        *
;                             ^^^^^^^^^^^                         *
DelayTcy.byte
        clrf    TMRH            ;
        comf    TMRH,F          ; compliment TMRH
DelayTcy.16
        clrf    TMRU            ;
        comf    TMRU,F          ; compliment TMRU
DelayTcy.24
        addlw   -24             ; subtract "overhead" + 1 cycle
        bnc     DelayHi         ; borrow?  yes, branch, else
        addlw   1               ; replace unused 'borrow' cycle
DelayLo
        addlw   -3              ; subtract 3 cycle loop time
        bc      DelayLo         ;
DelayHi
        addlw   -3              ; subtract 3 cycle loop time
        incfsz  TMRH,F          ; TMRH done? yes, skip, else
        bra     DelayLo         ; loop again

        addlw   -3              ; subtract 3 cycle loop time
        incfsz  TMRU,F          ; TMRU done? yes, skip, else
        bra     DelayLo         ; loop again
;
;  account for delay%3 timing (3, 4, or 5 cycles before return)
;
        xorlw   0xF7            ;  F7 (1), F8 (1), F9 (1)
        bz      DelayXit        ;  F7 (2), F8 (1), F9 (1)
        xorlw   0xF9^0xF7       ;          F8 (1), F9 (1)
        bz      DelayXit        ;          F8 (1), F9 (2)
DelayXit                        ;  ----------------------
        return                  ;  F7=(3), F8=(4), F9=(5)
;                                                                 *
;******************************************************************
 
A couple problems with coded delay loops, they don't work with heavy interupt usage, they can also depend on the exact compiler options that are used to compile the code. Interupt timers are good but they can't do really fine timeing, only hard coded delay routines can do that. A mix of both is usually what's best. A hardware timer for course timeing to free the processor up to do things while it's waiting with some fudge room for other interupts, and then when you need to count out very precisly for one brief period the exact number of clock pulses from the event you disable interupts and run your delay code.
 
Last edited:
Status
Not open for further replies.

Latest threads

Back
Top