2
\$\begingroup\$

Experimenting with blinking LEDs, I learned about creating delays with either a software loop or a timeout from a timer. I know that for a simple blinking LED program, where the processes aren't that complicated and timing isn't crucial, using either wouldn't matter. But in more of a time-crucial multitasking context what are the benefits and/or disadvantages of both?

Thanks heaps, here's how I set them up:

Software delay:

void softwaredelay()
{
    int i;
    for(i=0; i<1000; i++)
    {/*Timer Stuff*/}
}

Hardware delay (specific for PIC16 mcu's):

void timerdelay()
{
    OPTION_REGbits.PSA = 0;
    OPTION_REGbits.PS.  = 0b111;
    OPTION_REGbits.T0CS =  0;

    INTCONbits.T0IF = 0;
    TMR0 = 0b11111000;
    INTCONbits.T0IE = 1;

    while(INTCONbits.T0IF==0)
    {/*Timer Stuff*/}
}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ I guess in professional projects no one even thinks about implementing software interrupts so I would suggest you getting used to handle timers :). \$\endgroup\$
    – Al Bundy
    Commented Sep 29, 2015 at 9:33
  • \$\begingroup\$ There's a third option, which is to create a global 'tick' variable that gets updated inside a periodic timer interrupt handler (i usually have it update once every millisecond). You can use that global time for managing periodic tasks in your main loop without blocking, and without having to dedicate a timer peripheral to each task \$\endgroup\$
    – Ocanath
    Commented Apr 20, 2020 at 21:37

3 Answers 3

11
\$\begingroup\$

You need to go to the bank (which is just around the corner) and do your laundry. Going to laundry requires you to wait for the washer to finish, and then wait for the the dryer to finish.

How would you go about performing these tasks?

On a lazy day, you could just do the laundry and then go to the bank. It's not that important. Who cares.

But on a busy day, where you have other things to do, like catching a movie, or studying or whatever task, the efficient thing to do is you load the first part of the laundry, then go to the bank, then load the second part of the laundry. Now you are free to do other things. That is maximizing your time so you can do other tasks.

Now for a microcontroller or any embedded system, the same is true. If you don't care about power, time, or anything, then go with a software-driven delay. It's easier to implement, and you can scale it as high as you want with great ease.

If you care about power, time, or efficiency, then a hardware timer is the way to go. While you wait you can either go to sleep or perform another task. It's a bit more complicated to setup, and if multiple tasks require delays, you may run out of hardware timers and then have to resort to a more complicated system of managing time and delays.

If you care about anything other than ease of use: Hardware Timer

If you care only about ease of use: Software

\$\endgroup\$
2
\$\begingroup\$

It largely depends on what you want to achieve.

For a software blocking delay like you have set up, you will not be able to service interrupts and maintain a constant interval. If you add more code into the loop the delay will change, potentially unpredictably or inconsistently if you have variable control flow blocks. I suspect that none of this matters much for a simple blinky program, but you asked about time critical applications

\$\endgroup\$
2
\$\begingroup\$

The "software delay" is a naive solution. You should never use such code in any microcontroller program because there is never a reason to do so: you will always have hardware timers. "Software delays" is unprofessional, since it has the following problems:

  • Blocks the CPU from doing anything useful.
  • Timing is very inaccurate and depends on how the C code gets translated to machine code. Writing reliable "software delays" requires you to disassemble the C code and check CPU ticks per assembler instruction. Quite tedious and has to be done over and over, as soon as the code or compiler options are changed.
  • Interrupts will also make the timing inaccurate.
  • The delay depends on the system clock. If the clock is changed, the delay will change too.
  • The optimizer might remove the whole "software delay" code if it finds out that it does nothing. You might need various clever tricks to prevent this from happening.
  • Keeps CPU current consumption at 100%.

If blocking the CPU is not an issue, that is if your program has nothing useful to do while waiting, then you should setup a hardware timer and poll that timer flag as in your second example.

For harder real-time requirements, you will have to use timer interrupts.

If current consumption is an issue and the MCU supports sleep/wake-up, you can usually configure the MCU to go into sleep mode until the timer has elapsed.

\$\endgroup\$
12
  • 1
    \$\begingroup\$ Largely agree, but "never" is a very strong term. There certainly are cases where a software delay is perfectly acceptable and may be the right answer. If you're resource-starved for peripheral clocks because you're on legacy hardware or just trying to save money on the BOM, for example, or if the delay is obscenely long with respect to the timer width and you don't want to add the parts for a slow RTC. There are certainly numerous advantages to using timers for delays that might make one choose that path, but nothing beats an understanding of when its OK to break the rules. \$\endgroup\$ Commented Sep 29, 2015 at 12:43
  • \$\begingroup\$ @ScottSeidman Of all the embedded code I've read, I don't remember ever seeing such delays used because the MCU had no hardware timers left. So far, in all the code I have ever read, the only reason why such delays were used was incompetence, period. And since you need to be somewhat competent to get such a delay accurate, the same people almost always fail to implement them with sufficient accuracy. Which in turn gives all manner of obscure bugs, such as communication protocols failing randomly, LCD:s misbehaving and showing garbage etc etc. \$\endgroup\$
    – Lundin
    Commented Sep 29, 2015 at 14:00
  • \$\begingroup\$ @ScottSeidman In fact, "running low on hardware timers" is not a valid argument, as you should reserve at least one timer for general/purpose timer tasks. You can wrap this single hardware timer inside a driver which allows multiple software timers to be created. The overhead code will create a slight timer inaccuracy, why you use such a general-purpose timer for low priority tasks, such as delays. This is everyday embedded programming; even a beginner should be able to write such a driver and make it somewhat useful. \$\endgroup\$
    – Lundin
    Commented Sep 29, 2015 at 14:02
  • 1
    \$\begingroup\$ I'll stand by it. "Never" is an engineering absurdity. "Accuracy" is a spec you put on this issue, not the OP. It is one factor that might point you to using a timer. A "not very expensive" oscillator might force an expensive redesign of a board, it might result in noise if the original design was not stacked properly, it might require expensive FCC retesting, or those few cents on the BOM might have large impact on the bottom line on a commodity item. There are plenty of situations where blocking delays are acceptable and accuracy is not called for. \$\endgroup\$ Commented Sep 29, 2015 at 14:23
  • 1
    \$\begingroup\$ If I'm initializing an SPI ADC, and I couldn't care less if breaks between commands were 30ms or 3000ms, and there are no interrupts enabled, is a simple loop delay still wrong? If I needed accuracy, and didn't care about blocking, and I wrote my handful of lines in assembly to account for every clock tick on a non-pipelined microcontroller, is it wrong? I'm not saying a timer is wrong, I'm saying "never" is silly. Even if timers were your religion, I can't imagine an embedded programmer calling for the redesign of a board in your oscillator example when a simple delay loop is good enough. \$\endgroup\$ Commented Sep 29, 2015 at 14:39

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.