EmbeddedRelated.com
Forums

How do i create an accurate delay

Started by hybrid_snyper February 14, 2007
Hi all,

I am in the middle of coding a PIC16f876 and i require some time
sensitive delays. In the milli and micro domains. I am using C to
program the core functions but i was advised to use ASM to create a
delay as it is more accurate. i am clue less on how to go about this
and was wondering if anyone new any good resources i could use or if
there are any sample codes floating about that could help.

thanks

"hybrid_snyper" wrote:
>I am in the middle of coding a PIC16f876 and i require some time >sensitive delays. In the milli and micro domains. I am using C to >program the core functions but i was advised to use ASM to create a >delay as it is more accurate. i am clue less on how to go about this >and was wondering if anyone new any good resources i could use or if >there are any sample codes floating about that could help.
There are generic solutions, since I'm not familiar with that processor and you do not mention what compiler / OS (if any) / libraries etc. you are using. For delays in the millisecond range, many processors have high speed counters driven from the CPU clock (through a divider, or PLL, etc.) that can be read, configured to generate an interrupt when reaching zero (if counting down), or overflowing (if counting up), or reaching a predefined value (if compare functions are available), etc. Check what peripherals are available in your CPU, how to configure them, what type of time accuracy they provide, etc. For microsecond delays it is generally possible to write (in assembler) loops that execute a predefined number of instructions. If you know exactly how long each instruction takes, you can fine tune the loop to match the required delays. In some processors this is trivial, in others, advanced features like program/data caches, instruction pipelining, etc. may make very difficult to predict precise execution times. Roberto Waltman [ Please reply to the group, return address is invalid ]
"hybrid_snyper" <wayne_tams@hotmail.com> wrote in message 
news:1171457973.113550.250180@l53g2000cwa.googlegroups.com...
> Hi all, > > I am in the middle of coding a PIC16f876 and i require some time > sensitive delays. In the milli and micro domains. I am using C to > program the core functions but i was advised to use ASM to create a > delay as it is more accurate. i am clue less on how to go about this > and was wondering if anyone new any good resources i could use or if > there are any sample codes floating about that could help.
I used a PIC16F84 for my timings once and was pleased to find that all instructions take the same amount of time - 4 clock cycles - with the exception of things that modify the program counter, such as jumps, which take 8. With a 20MHz crystal then this means 5,000,000 instructions per second or 200ns per instruction. You can use the TMR0 interrupt which will trigger after an internal counter rolls over 255 instructions executed. You can prescale it by 256 (or it might be 128 max - check the manual) so that it rolls over after 256*256 instructions are executed. This means you get an interrupt every 13.1072ms (200ns * 256 * 256) which is milli domain. Reduce the prescale to get quicker interrupts. Alternatively, if interrupts worry you then you can write a fairly simple loop which, if you think about the number of instructions in it (and pad with NOPs if needed) will take a certain amount of time. For example movlw 0 ; 200ns Execution movwf COUNTER ; 200ns Exection loop: incf COUNTER ; 200ns execution btfss STATUS,Z; 400ns exection - detects 256 rollover of counter This will take 200+200+(256*(200+400)) = 154us to execute.
hybrid_snyper wrote:

> Hi all, > > I am in the middle of coding a PIC16f876 and i require some time > sensitive delays. In the milli and micro domains. I am using C to > program the core functions but i was advised to use ASM to create a > delay as it is more accurate. i am clue less on how to go about this > and was wondering if anyone new any good resources i could use or if > there are any sample codes floating about that could help. > > thanks >
there is a heap of basic routines that may help you at: http://www.dontronics.com/see.html Don... -- Don McKenzie E-Mail Contact Page: http://www.dontronics.com/e-mail.html Crystal clear, super bright OLED LCD (128x128) for your microcontroller. Simple serial RX/TX interface. Many memory sizes. http://www.dontronics-shop.com/product.php?productid=16460 No More Damn Spam: http://www.wizard-of-oz.com
Sorry i should of added a bit more info. The PIC is running on an
external crystal at 4MHz and i am using the PICC compiler from htsoft.
I am looking to use delays of 8us inside a loop, so when the loop runs
a delay of 8us occurs before the loop continues. The PIC is to
function as part of a larger multiplexed display,

"hybrid_snyper" <wayne_tams@hotmail.com> wrote in message 
news:1171553920.081031.281470@v45g2000cwv.googlegroups.com...
> Sorry i should of added a bit more info. The PIC is running on an > external crystal at 4MHz and i am using the PICC compiler from htsoft. > I am looking to use delays of 8us inside a loop, so when the loop runs > a delay of 8us occurs before the loop continues. The PIC is to > function as part of a larger multiplexed display,
4Mhz is 1,000,000 instructions per second or 1 per microsecond. you need 8us so your assembler is: NOP NOP NOP NOP NOP NOP NOP NOP Of course that is eight wasted cycles. Why not use that time to do something useful like a health check as long as it takes eight instructions?
Tom Lucas wrote:
> "hybrid_snyper" <wayne_tams@hotmail.com> wrote in message > news:1171553920.081031.281470@v45g2000cwv.googlegroups.com... >> Sorry i should of added a bit more info. The PIC is running on an >> external crystal at 4MHz and i am using the PICC compiler from htsoft. >> I am looking to use delays of 8us inside a loop, so when the loop runs >> a delay of 8us occurs before the loop continues. The PIC is to >> function as part of a larger multiplexed display, > > 4Mhz is 1,000,000 instructions per second or 1 per microsecond. you need > 8us so your assembler is: > NOP > NOP > NOP > NOP > NOP > NOP > NOP > NOP > > Of course that is eight wasted cycles. Why not use that time to do > something useful like a health check as long as it takes eight > instructions?
This sounds like a homework assignment. The first thing to do is to understand the assignment. Is the loop to repeat every 8us? Just what does "8us occurs before the loop continues" actually mean? 8us between what two events? Looking in from afar methinks this is not a job for C. That the entire loop needs to be coded in assembly. Last looked at C compilers for the 'F876 family 6 years ago and was not impressed. Never doubted the code would run, just that it was huge. When the compiler issues 10 or 20 instructions for a simple line of C you are not going to be able to hold to 8us timing.
On Feb 15, 4:57 pm, David Kelly <n...@Yahoo.com> wrote:
> Tom Lucas wrote: > > "hybrid_snyper" <wayne_t...@hotmail.com> wrote in message > >news:1171553920.081031.281470@v45g2000cwv.googlegroups.com... > >> Sorry i should of added a bit more info. The PIC is running on an > >> external crystal at 4MHz and i am using the PICC compiler from htsoft. > >> I am looking to use delays of 8us inside a loop, so when the loop runs > >> a delay of 8us occurs before the loop continues. The PIC is to > >> function as part of a larger multiplexed display, > > > 4Mhz is 1,000,000 instructions per second or 1 per microsecond. you need > > 8us so your assembler is: > > NOP > > NOP > > NOP > > NOP > > NOP > > NOP > > NOP > > NOP > > > Of course that is eight wasted cycles. Why not use that time to do > > something useful like a health check as long as it takes eight > > instructions? > > This sounds like a homework assignment. > > The first thing to do is to understand the assignment. > > Is the loop to repeat every 8us? Just what does "8us occurs before the > loop continues" actually mean? 8us between what two events? > > Looking in from afar methinks this is not a job for C. That the entire > loop needs to be coded in assembly. Last looked at C compilers for the > 'F876 family 6 years ago and was not impressed. Never doubted the code > would run, just that it was huge. When the compiler issues 10 or 20 > instructions for a simple line of C you are not going to be able to hold > to 8us timing.
the loop is a for loop where, the loop repeats it self dependant on an array size. Inside the loop i require RA0 to go high for 8us then low. then 7 bits on port B will change. RA0 is signaling a clock and with each clock the data on port b changes. The reason for the small time delays is to have some sort of control over the refresh rates. ASM is new to me so will have to work at it and see what i can come up with.
hybrid_snyper wrote:
> > Sorry i should of added a bit more info. The PIC is running on an > external crystal at 4MHz and i am using the PICC compiler from > htsoft. I am looking to use delays of 8us inside a loop, so when > the loop runs a delay of 8us occurs before the loop continues. > The PIC is to function as part of a larger multiplexed display,
Meaningless without proper quotations. See the link in my sig. Clue: executing a NOP takes a known time. Likewise such things as increment, decrement, test, conditional jump, etc. All in the absence of interrupts. -- If you want to post a followup via groups.google.com, ensure you quote enough for the article to make sense. Google is only an interface to Usenet; it's not Usenet itself. Don't assume your readers can, or ever will, see any previous articles. More details at: <http://cfaj.freeshell.org/google/>
hybrid_snyper wrote:
> On Feb 15, 4:57 pm, David Kelly <n...@Yahoo.com> wrote: >> >> The first thing to do is to understand the assignment. >> >> Is the loop to repeat every 8us? Just what does "8us occurs before the >> loop continues" actually mean? 8us between what two events? >> >> Looking in from afar methinks this is not a job for C. That the entire >> loop needs to be coded in assembly. Last looked at C compilers for the >> 'F876 family 6 years ago and was not impressed. Never doubted the code >> would run, just that it was huge. When the compiler issues 10 or 20 >> instructions for a simple line of C you are not going to be able to hold >> to 8us timing. > > the loop is a for loop where, the loop repeats it self dependant on an > array size. Inside the loop i require RA0 to go high for 8us then low. > then 7 bits on port B will change. RA0 is signaling a clock and with > each clock the data on port b changes. The reason for the small time > delays is to have some sort of control over the refresh rates.
So the loop doesn't have to repeat every 8us. That loosens things up to where C is still viable. If RA0 is an output strobe then I suggest you think some more about timing and how something else will be reading your 'F876. I think you ought to write the 7 bits on port B *then* strobe RA0 for 8us.
> ASM is new to me so will have to work at it and see what i can come up > with.
You should be able to slip the 8 NOP's right in the middle of your C code something like this: for(;;) { PORT_B = new_value; RA0 = 1; ASM("nop"); // 1 ASM("nop"); // 2 ASM("nop"); // 3 ASM("nop"); // 4 ASM("nop"); // 5 ASM("nop"); // 6 ASM("nop"); // 7 ASM("nop"); // 8 RA0 = 0; } Of course it varies with different compilers. Dig into your manuals for the exact syntax your compiler uses. And if you want to be picky, 8 NOPs may produce a 9us or longer delay depending on how the compiler does the RA0 assignments. Even in pure assembly 7 NOPs would be proper for the delay assuming the output bit sets at the same phase of the system clock as it clears. One of your delay clocks is in the set or the clear. IIRC the 'F876 has some sort of look ahead that might see a NOP and skip it in 0 clock cycles. Or maybe I'm thinking of a 0 clock cycle loop branch instruction?