2
\$\begingroup\$

I know how to write accurate delay routines in assembly to run on a PIC microcontroller. The problem I have is creating delays of a arbitrary length.

What I want to do is accept some data which tells me how long to delay for, and then the PIC will write a port high or low for that period of time. So if I have a 1uS delay and a 1mS delay, I can break up the data and find out how many times I need to call each function. for example:

0.123567 Seconds means I would call Delay_1uS 567 times, then Delay_1mS 123 times.

The problem is that all these calls create delays of their own which means that there will be an error is the total delay time.

To combat this I can calculate the incurred delay of the calls and subtract this from the the total delay time. However now the total number of calls is less and thus the incurred delay is less... This seems like some sort or recursive optimization problem that I do not know how to solve. Is there a "best practice" way of doing this?

\$\endgroup\$
4
  • \$\begingroup\$ The number of clock cycles wasted by call and return is constant and can be easily subtracted. \$\endgroup\$
    – venny
    Sep 19, 2014 at 19:23
  • \$\begingroup\$ Yes, but if that value is subtracted from the total delay time, the number of calls and returns changes meaning that the total delay time will still be wrong. \$\endgroup\$
    – Tim M
    Sep 19, 2014 at 19:26
  • \$\begingroup\$ I would say nesting delay functions is unnecesary. But even when it is used, you can adjust the inner functions to be spot on including call,return and loop iteration. Then the number of calls will not affect anything. \$\endgroup\$
    – venny
    Sep 19, 2014 at 19:31
  • \$\begingroup\$ Rather than calling Delay_1mS 123 times, you want to call a Delay_mS routine with a parameter set to 123, so you don't incur the call/return overhead 123 times. This also saves the need to have a loop around the Delay_1mS routine. Same for the Delay_1µs routine. \$\endgroup\$
    – tcrosley
    Sep 19, 2014 at 22:07

2 Answers 2

3
\$\begingroup\$

Delay loops are nasty, and you shouldn't be using them very often.

Alternatives include timers, periodic interrupts and such like.

That said, they're occasionally useful. Be sure to take care of the WDT somewhere during the looping or you could have some nasty problems.

There's an assembly language code generator here that generates cycle perfect assembly delay routines (delay time fixed at assembly, not variable).

There's no reason why you couldn't make a cycle-perfect programmable delay generator in asm but I think it would be a bit complex. Interrupts would cause inaccuracy, but often you only need to guarantee a minimum time and if it runs (say) 11ms rather than 10ms it's not a big deal.

\$\endgroup\$
5
  • \$\begingroup\$ Thank you for the advice, and the site (I have used it before, its amazing!). In my application I do need to guarantee an exact time, but I'm starting to think that a PIC is not going to be the best solution. \$\endgroup\$
    – Tim M
    Sep 19, 2014 at 20:06
  • \$\begingroup\$ Perhaps a PIC is not the best solution, but the same issues will arise with any processor. If you need nanosecond precision, FPGAs can be a good solution if no uC peripherals exist that do the job. \$\endgroup\$ Sep 19, 2014 at 20:10
  • \$\begingroup\$ Okay, more simply CPLDs such as Xilinx Coolrunner series, which may be easier to get into (though the software is still a bit intimidating). They're good if you just need fast logic block that isn't too complex. \$\endgroup\$ Sep 19, 2014 at 20:53
  • \$\begingroup\$ I assume this is the timer/ interrupt alt. But why not send a "good" 1MHz clock into a counter. Send out a "zero" pulse at the first clock edge after the "start" trigger. and a stop after the counter gets to 123456... or whatever. There's always asynchronous error's that you have to think about. \$\endgroup\$ Sep 20, 2014 at 0:06
  • \$\begingroup\$ @GeorgeHerold The OP had a very specific request- if the point was to generate something like a 100.000 Hz square wave, or a very precise 1.00 millisecond pulse, that can be done almost autonomously by using a counter-timer module in compare mode to directly toggle a port pin. The micro would just have to service an interrupt every n milliseconds (where n depends on the clock frequency), leaving most of the processor bandwidth available for other tasks. \$\endgroup\$ Sep 20, 2014 at 3:35
0
\$\begingroup\$

Actually in my opinion the best practise would be using a timer which generates in a defined cycle an interrupt and using this interrupt for your delay functions. So using the timer as systick timer

If you have to do a very accurate delay just use the timer with a adequate prescaler and match value.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.