Author Topic: How do you code your delays and waits  (Read 10239 times)

0 Members and 1 Guest are viewing this topic.

Offline jancumpsTopic starter

  • Supporter
  • ****
  • Posts: 1273
  • Country: be
  • New Low
How do you code your delays and waits
« on: March 23, 2014, 11:25:04 am »
I'm curious about the options to wait/delay that you use (for instance, if the spec of a device says to wait 10msec after a command before it is ready to receive the next command).
Do you use a loop, a timer/counter, an interrupt, something else?

 

Offline han

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: 00
Re: How do you code your delays and waits
« Reply #1 on: March 23, 2014, 11:39:56 am »
loop delay in low end 8 bit micro controller because it's simple
interrupt/timer for complex device since loop delay is bad when using complex device (e.g computer)
 

Offline jancumpsTopic starter

  • Supporter
  • ****
  • Posts: 1273
  • Country: be
  • New Low
Re: How do you code your delays and waits
« Reply #2 on: March 23, 2014, 11:46:51 am »
Really depends entirely on the rest of the code you have and how it all fits together etc. Their are different ways to do such a thing.
That's what I'm interested in. These different ways you are mentioning.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: How do you code your delays and waits
« Reply #3 on: March 23, 2014, 11:48:30 am »
It depends on the actual application. I use both. For start-ups, I tend to initialize the slow devices first and then do software delays (looping around).

Once the code is running, I typically use a flag to maintain timing - this allows the mcu to take care of other tasks while the slow process is running.
================================
https://dannyelectronics.wordpress.com/
 

Offline madires

  • Super Contributor
  • ***
  • Posts: 8398
  • Country: de
  • A qualified hobbyist ;)
Re: How do you code your delays and waits
« Reply #4 on: March 23, 2014, 12:08:50 pm »
I use whatever works best in a given situation. Another method is to create a stacked or cascaded wait with calls and nops in assembler.
« Last Edit: March 23, 2014, 12:21:29 pm by madires »
 

Offline 8086

  • Super Contributor
  • ***
  • Posts: 1085
  • Country: gb
    • Circuitology - Electronics Assembly
Re: How do you code your delays and waits
« Reply #5 on: March 23, 2014, 12:10:50 pm »
Depends on:

Type of micro
Clock frequency
Language used
Length of delay
 

Offline han

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: 00
Re: How do you code your delays and waits
« Reply #6 on: March 23, 2014, 12:29:30 pm »
loop delay:
   pro:- simple easy to use
         -  not much things to wrong
   con:- 100% cpu time when not optimized
          - cpu cannot do anything else (except its threaded operation)
          - waste on computing power
   typical uses : -simple program
                         -your program didn't have anything else to do
                         -if you lazy to learn how to use interrupt properly


interrupt/timer/counter:
   pro: - cpu can do someting else
           - power save mode can be done
           - most precise timing
   con: - more complex programming
           - too much interrupt can ruin your day





 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 10433
  • Country: nz
Re: How do you code your delays and waits
« Reply #7 on: March 23, 2014, 12:48:22 pm »
I usually dedicate one hardware timer to delays. I enable its overflow interrupt and write code to increment many variables inside the interrupt handler. These variables are reset to zero when they reach a set point which stops the incrementing.
So my clk_100Hz variable might count 50 interrupt events then reset where as my clk_200Hz variable might count 100 etc.. then reset to zero

Inside the main program loop i then check these 'flag variables' for a zero condition and run any code that i want repeating at that rate. (Then i set it back to 1 so it starts counting again).

Although you can divide any clock down to as slow as you want you should configure the timer so the overflow interrupt happens as slow as you can get away with so it doesn't take up CPU time needlessly. This can be done with a combination of changing the timers clock setting and updating the timers count register to a value which will overflow sooner. The timers clock settings give you course control and the counter register gives you fine control to get the interrupt running at the right speed so your delay numbers make sense, eg, 10 count = 1 ms 

I wrote a page in the wiki with an example a while back Here
« Last Edit: March 23, 2014, 01:03:11 pm by Psi »
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: How do you code your delays and waits
« Reply #8 on: March 23, 2014, 01:13:13 pm »
Quote
loop delay:
         -  not much things to wrong

Try to write one with awareness of cpu speed and works under all optimization levels.
================================
https://dannyelectronics.wordpress.com/
 

Offline han

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: 00
Re: How do you code your delays and waits
« Reply #9 on: March 23, 2014, 01:41:02 pm »
Quote
loop delay:
         -  not much things to wrong

Try to write one with awareness of cpu speed and works under all optimization levels.


the only problem i ever get is only wrong delay period (e.g longer / shorter delay)

using interrupt blindly can cause greater headache
 

Offline jaxbird

  • Frequent Contributor
  • **
  • Posts: 778
  • Country: 00
Re: How do you code your delays and waits
« Reply #10 on: March 23, 2014, 01:43:04 pm »
Highly depends on the situation and what you are programming in.

Some suggestions (some already mentioned)

  • a simple NOP loop if you got nothing better to do.
  • Put the mcu to sleep for the duration if you are on battery power.
  • One or more timer interrupt based counters.
  • If you go full assembly, write your main loop with a constant cycle count independent of the code path to keep track of timings.

Etc, ect, lots of room for creativity here if you need to squeeze more cycles out of your mcu or save a few bytes of memory.


Analog Discovery Projects: http://www.thestuffmade.com
Youtube random project videos: https://www.youtube.com/user/TheStuffMade
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: How do you code your delays and waits
« Reply #11 on: March 23, 2014, 01:53:13 pm »
Quote
using interrupt blindly can cause greater headache

Using anything blindly can cause greater headache.

Quote
Highly depends on the situation and what you are programming in.

Yeah. creating delays() is one of those simple yet highly challenging things due to the large number of approaches that can be deployed.
================================
https://dannyelectronics.wordpress.com/
 

Offline jaxbird

  • Frequent Contributor
  • **
  • Posts: 778
  • Country: 00
Re: How do you code your delays and waits
« Reply #12 on: March 23, 2014, 02:30:35 pm »
Quote
Highly depends on the situation and what you are programming in.

Yeah. creating delays() is one of those simple yet highly challenging things due to the large number of approaches that can be deployed.

Agree, it really depends on the accuracy, frequency and environment required plus what else needs to be taken care of at the same time. Priority etc, no best practice to recommended without very specific details.

Analog Discovery Projects: http://www.thestuffmade.com
Youtube random project videos: https://www.youtube.com/user/TheStuffMade
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: How do you code your delays and waits
« Reply #13 on: March 23, 2014, 05:35:53 pm »
It's not difficult at all to implement a systick-styled timer. The issues are resource and cycle drain.

a low end mcu may have 2-3 timers and dedicating one to time keeping can be expensive.

not to mention that you likely need to keep time over a few seconds at a minimum so a 32-bit type is needed. That means isr and reading and writing 32-bit types frequently in a 8-bitter.

so it is doable, but not wise to do, in my view.
================================
https://dannyelectronics.wordpress.com/
 

Offline Rick Law

  • Super Contributor
  • ***
  • Posts: 3506
  • Country: us
Re: How do you code your delays and waits
« Reply #14 on: March 24, 2014, 03:19:51 am »
With MCU's, I am only familiar with the ATMega using the Arduino boot loader.

Everything that must be done or are done in the start(), I would use delay().  Stuff done in the loop(), I use an elapse timer unless it is in the single-digit millisecond range.
 

Offline SL4P

  • Super Contributor
  • ***
  • Posts: 2318
  • Country: au
  • There's more value if you figure it out yourself!
Re: How do you code your delays and waits
« Reply #15 on: March 24, 2014, 06:55:33 am »
What I usually do is setup a timer interrupt at the highest tick rate I'm going to need (e.g. 100mS), and simply increment a global variable with each tick.  Use an unsigned int or long as the counter, and reset those counters for each time domain as needed* - e.g. user interface events are cleared when a button is released so that new events will time-up from that.

In main() code, I test when the tick count reaches my next desired trigger point, an execute the required code.
You can test several times for different tasks, or maintain 'separate' tickers at divisors of the main tick count.
Remember to put as little as you can within the interrupt routinbe to keep the time-critical takk on-time, and called when 'you' want them.

You can also perform relative timing - e.g. button down + 1500mS represents a long-press event.
Remember to arrange your timed 'ifs' in order that the most important calls are made first !!

The possibilities are endless.  Or as others have mentioned - simple while() loops are OK in single-task code... as long as there is no chance of getting stuck in the loop!.  WDT are made to protect you from this (* e.g. above)!
Don't ask a question if you aren't willing to listen to the answer.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: How do you code your delays and waits
« Reply #16 on: March 24, 2014, 11:11:11 am »
-reset those counters for each time domain as needed* -

I wouldn't reset it - just keep it running. Local timing events will keep their timing info locally. With this approach, multiple timing events can be kept concurrently and independently.

an almost true systick implementation.
================================
https://dannyelectronics.wordpress.com/
 

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 6611
  • Country: nl
Re: How do you code your delays and waits
« Reply #17 on: March 24, 2014, 11:33:50 am »
It's not difficult at all to implement a systick-styled timer. The issues are resource and cycle drain.
a low end mcu may have 2-3 timers and dedicating one to time keeping can be expensive.
not to mention that you likely need to keep time over a few seconds at a minimum so a 32-bit type is needed. That means isr and reading and writing 32-bit types frequently in a 8-bitter.
so it is doable, but not wise to do, in my view.
I generally use one HW timer to generate an universal 1ms tick. Not only for timekeeping but also for other tasks that have to wait for an event for instance (not extremely timecritical stuff).
That 1ms tick I can subscribe 8 or 16 bit timers. Indeed I never use 32 bit timers on 8 bit uC, instead I sub-subscribe a second timer on a primary timer, for instance one 16bit 60000 count (for one second) on the 1ms and then another 16 bits on the 1s . So I cascade timers.
 

Offline SL4P

  • Super Contributor
  • ***
  • Posts: 2318
  • Country: au
  • There's more value if you figure it out yourself!
Re: How do you code your delays and waits
« Reply #18 on: March 25, 2014, 01:22:45 am »
-reset those counters for each time domain as needed* -

I wouldn't reset it - just keep it running. Local timing events will keep their timing info locally. With this approach, multiple timing events can be kept concurrently and independently.

If your tick timing is critical, or can have problems with interrupts too close together - then reset the counter(s) on and to - a known value !  Allowing the counter to wrap around is OK, but not predictable if you are  using a preset value other than zero as a counter calibration start point.

e.g. if you reset the tick-counter arbitrarily, then then next interrupt event may occur 'too soon' r 'too late' if you are using it as a constant (e.g. time-of-day), or your LED blinky may randomly give a double-blink, and you wonder why !

Don't ask a question if you aren't willing to listen to the answer.
 

Offline ve7xen

  • Super Contributor
  • ***
  • Posts: 1196
  • Country: ca
    • VE7XEN Blog
Re: How do you code your delays and waits
« Reply #19 on: March 25, 2014, 05:19:53 am »
I often do 1ms ticks, the ISR simply incrementing the current time. In main, I then have a scheduler queue (simple) which contains the target time and either a function pointer or index for a switch block to do the work, sorted by target time. Each loop pass just needs to check if the target time of the queue head is reached or not, and pop/execute it if so. For delays shorter than 1ms like satisfying setup times, busy wait is usually fine.

Timing precision isn't guaranteed (worst case is probably if your 1ms turns into 0ms, I think), but execution order is, it's pretty easy to extend (e.g. add priority) and manage, and you're not blocking interrupts for very long. Likewise, I usually try to have my ISRs just collect data or set pre-processed outputs/settings and submit an event to the queue for processing if necessary.
« Last Edit: March 25, 2014, 05:23:09 am by ve7xen »
73 de VE7XEN
He/Him
 

Online zapta

  • Super Contributor
  • ***
  • Posts: 6316
  • Country: 00
Re: How do you code your delays and waits
« Reply #20 on: March 25, 2014, 01:05:17 pm »
In my last project I used a 16 bit counter with 4usec ticks. For short critical ticks (e.g. half a start bit with serial bit banging) I busy loop that polls the timer.  For longer time period I extend it in the main loop() to a global uint32 time in millis, no interrupts needed.  Then I used multiple instances of a simple class that tracks time in millis based on the global uin32 time in millis  https://github.com/zapta/linbus/blob/master/prototype/arduino/passive_timer.h
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: How do you code your delays and waits
« Reply #21 on: March 25, 2014, 01:06:05 pm »
Quote
That 1ms tick I can subscribe 8 or 16 bit timers. Indeed I never use 32 bit timers on 8 bit uC,

You can still get sub 1ms timing resolution (for example, down to 1us on a 1Mhz mcu) even if your timer overflows every 1ms. It just increases the overhead when you read that value, and / or you are willing to live with non-atomicity.

================================
https://dannyelectronics.wordpress.com/
 

jucole

  • Guest
Re: How do you code your delays and waits
« Reply #22 on: March 25, 2014, 11:51:25 pm »
For PIC projects with very small delays I setup some #DEFS to some NOPs;  for longer non-critical I sometimes do loops on NOP's;  but if I need longer still then instead of loops on loops of NOPs I use the internal timers;   a while back I created a simple c# application to create the code for delays using timers on PICs.

ISR "Tickers", as mentioned are very handy to ensure you widget does everything it needs to at the right time.

 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 10433
  • Country: nz
Re: How do you code your delays and waits
« Reply #23 on: March 26, 2014, 12:02:58 am »
On the subject of timing. If anyone else decides to use a raw 2-4khz piezo beeper with a <20mhz mcu make sure you put it on a timer output pin and don't try to pulse it in software. 

I had a mistake on one of my PCBs where the beeper ended up on an input compare pin instead of an output compare pin so i couldn't drive it in hardware. I had to resort to interrupt driven software toggling the pin at 4khz.
It was quite hard to get a 'pure' sound out of it. All other active interrupts randomly delayed execution of the beeper interrupt and caused a 'dirty tone'
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline Rerouter

  • Super Contributor
  • ***
  • Posts: 4706
  • Country: au
  • Question Everything... Except This Statement
Re: How do you code your delays and waits
« Reply #24 on: March 26, 2014, 01:26:41 am »
As my recent project have been lower power, i put the processor into sleep and have a watchdog wake it up close to the required delay (I'm not doing mission critical stuff, e.g. waiting greater than 400ms for a sensor to wake up)

other than that, it comes down to why your waiting, if its just wait 500ms to prevent registering a button press twice, then use a time stamp compare and remove the delay altogether,

my other normal way is doing a time compare and return system, and it can work well even for large code, though i will admit it makes it a little less maintainable,
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 10433
  • Country: nz
Re: How do you code your delays and waits
« Reply #25 on: March 26, 2014, 01:37:29 am »
Does anyone have tips/tricks for dealing with wrap-around on global tick variables?
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline mazurov

  • Frequent Contributor
  • **
  • Posts: 524
  • Country: us
Re: How do you code your delays and waits
« Reply #26 on: March 26, 2014, 01:40:28 am »
Some time ago I wrote a code to drive HD44780-compatible display. The application for which it was written is very sensitive to blocking so loop/nop delays are not possible. I have a queue to feed the display consumed by a timer interrupt. Depending on the data, the interrupt reloads its own (timer's) period register - there are two commands requiring longer delays. Here's the link -> https://www.circuitsathome.com/mcu/driving-a-character-lcd-using-pic24-enhanced-parallel-master-port
With sufficient thrust, pigs fly just fine - RFC1925
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: How do you code your delays and waits
« Reply #27 on: March 26, 2014, 02:23:18 am »
Does anyone have tips/tricks for dealing with wrap-around on global tick variables?

I usually ignore them because what matters is deltas, so when doing the math on unsigned values it should wrap around naturally and the deltas would be preserved

so for unsigned shorts:

2 - 33 = 65505
 0x0002
 0x0021
 0xFFE1

Code: [Select]
    unsigned short val1, val2, val3;
    val1 = 2;
    val2 = 33;
    val3 = val1 - val2;

So as long as you don't wrap around more than once per measurement you'll be fine.

Edit: to explain a bit better

2 - 33 = 65505 is the same as (65536)+2-33, where the 65536 is all the values that a 16 bit unsigned integer can hold (including 0).

So the rule of thumb will be (2^x)+val1-val2 = delta if val1 is less than val2, where x is the bit count for your unsigned register. And the 2^x is implied and doesn't need to be coded because your are using deltas.




« Last Edit: March 26, 2014, 02:34:55 am by miguelvp »
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: How do you code your delays and waits
« Reply #28 on: March 26, 2014, 02:44:56 am »
I should have used better names for my variables so replying again

Code: [Select]
    unsigned short beginTime, endTime, deltaTime;

    beginTime = 33;
    endTime = 2; // after warp-around
    deltaTime = endTime - beginTime;
 

Offline ecat

  • Frequent Contributor
  • **
  • Posts: 296
  • Country: gb
Re: How do you code your delays and waits
« Reply #29 on: March 26, 2014, 02:46:30 am »
Does anyone have tips/tricks for dealing with wrap-around on global tick variables?

What are you trying to achieve? What are you trying to avoid? Why is wrap-around a problem?
What CPU are you using? What size is its native integer? How does the compiler handle addition when using larger than native integer types?

tl;dr
It depends ;)
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 10433
  • Country: nz
Re: How do you code your delays and waits
« Reply #30 on: March 26, 2014, 03:01:12 am »
I thought it was pretty obvious.

You have a variable that ticks (incremented from interrupt/hardware timer).
Eventually it's going to wrap-around and start from zero again.
If you try and use that for timestamping things then you have to deal with the situation of the wrap occuring during two timestamps.

You can detect the wrap around and remove it but then you have to consider that the wrap may occur multiple times etc..

Are there any coding tips/tricks to handle this in a simple way.
« Last Edit: March 26, 2014, 03:03:27 am by Psi »
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: How do you code your delays and waits
« Reply #31 on: March 26, 2014, 03:19:36 am »
I thought it was pretty obvious.

You have a variable that ticks (incremented from interrupt/hardware timer).
Eventually it's going to wrap-around and start from zero again.
If you try and use that for timestamping things then you have to deal with the situation of the wrap occuring during two timestamps.

You can detect the wrap around and remove it but then you have to consider that the wrap may occur multiple times etc..

Are there any coding tips/tricks to handle this in a simple way.

Not sure if you saw my answer.

If you use deltas then there is no problem with unsigned computer math, doesn't get simpler than that.

If you want to keep a time stamp, use the deltas to update a bigger number (like an unsigned 64bit counter) provided you call the update within twice the wrap around time.

If using an interrupt then you can update the bigger number there making it available to the system.

If hardware counter (usually at least 32bits) or 4294967296, you have that many ticks per check So you might get in trouble if you don't update it once a second on a 4.29 GHz processor.

Edit: actually if you don't update it once in 2 seconds on a 4.29 GHz processor because it won't wrap around twice until then
« Last Edit: March 26, 2014, 03:30:59 am by miguelvp »
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 10433
  • Country: nz
Re: How do you code your delays and waits
« Reply #32 on: March 26, 2014, 03:44:10 am »
Edit: to explain a bit better

2 - 33 = 65505 is the same as (65536)+2-33, where the 65536 is all the values that a 16 bit unsigned integer can hold (including 0).

So the rule of thumb will be (2^x)+val1-val2 = delta if val1 is less than val2, where x is the bit count for your unsigned register. And the 2^x is implied and doesn't need to be coded because your are using deltas.

thanks, that makes sense :)
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline ecat

  • Frequent Contributor
  • **
  • Posts: 296
  • Country: gb
Re: How do you code your delays and waits
« Reply #33 on: March 26, 2014, 03:45:52 am »
I thought it was pretty obvious.

You have a variable that ticks (incremented from interrupt/hardware timer).
Eventually it's going to wrap-around and start from zero again.
If you try and use that for timestamping things then you have to deal with the situation of the wrap occuring during two timestamps.

You can detect the wrap around and remove it but then you have to consider that the wrap may occur multiple times etc..

Are there any coding tips/tricks to handle this in a simple way.

The simple answer is 'use a bigger integer'.
You can count the wrap arounds in the interrupt routine, maybe you can count them in you main loop - both methods are effectively making a bigger integer.

If you are constrained by code size, data size, execution time or the need to ensure your interrupt routine always executes in a fixed number of cycles then you may need something a little more imaginative than changing a uint16 to either a unit32 or something involving a couple of 'if' statements. Obviously ;)
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: How do you code your delays and waits
« Reply #34 on: March 26, 2014, 03:56:47 am »

thanks, that makes sense :)

Just make sure you use unsigned types if possible. Signed types will work as well but it's harder to wrap your head around it (pun intended).

But the problem with signed types is that it doesn't allow you to wait for two times the wrapping since some values will result on negative numbers, so stick to unsigned types.

Edit: And you have to measure within the wrap around not twice like I mentioned before I just tried it and it will only allow you up to 2^x-1 delta, but on a 32bit counter that is once a second in a 4.29GHz system.

i.e. maximum delta time possible is (2^x)-1 or 4294967295 on a 32 bit unsigned counter
« Last Edit: March 26, 2014, 04:15:32 am by miguelvp »
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: How do you code your delays and waits
« Reply #35 on: March 26, 2014, 10:58:38 am »
Quote
then you have to consider that the wrap may occur multiple times etc..

There is no cure for that (within the confines of the polling construct that we are discussing here) other than using a sufficiently large data type so it doesn't happen.
================================
https://dannyelectronics.wordpress.com/
 

Offline jancumpsTopic starter

  • Supporter
  • ****
  • Posts: 1273
  • Country: be
  • New Low
Re: How do you code your delays and waits
« Reply #36 on: March 30, 2014, 07:39:47 pm »
Some time ago I wrote a code to drive HD44780-compatible display. The application for which it was written is very sensitive to blocking so loop/nop delays are not possible. I have a queue to feed the display consumed by a timer interrupt. Depending on the data, the interrupt reloads its own (timer's) period register - there are two commands requiring longer delays. Here's the link -> https://www.circuitsathome.com/mcu/driving-a-character-lcd-using-pic24-enhanced-parallel-master-port
I'm going to check your library and see if I can make it work on the TI TMS570 ARM Cortex that I have running here.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf