How do i create an accurate delay

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

Reply to
hybrid_snyper
Loading thread data ...

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 ]
Reply to
Roberto Waltman

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.

Reply to
Tom Lucas

there is a heap of basic routines that may help you at:

formatting link

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
Reply to
Don McKenzie

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,

Reply to
hybrid_snyper

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?

Reply to
Tom Lucas

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.

Reply to
David Kelly

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.

Reply to
hybrid_snyper

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.

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?

Reply to
David Kelly

I've seen that written down somewhere in one of the books ive been looking through, will have a closer look, didn't realise what i was reading may be of some help.

thanks for that.

I will get back to you all and let you know how i get on.

Reply to
hybrid_snyper

For what it's worth, in the compiler I use, the C directive is:

delay_us(8);

to give an eight microsec delay in any PIC. The compiler handles all of the peculiarities of each PIC.

The proper compiler for the job can make it much easier. Cost, or course, is a factor.

Al

Reply to
Al

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.