In traditional embedded programming, we will give a delay function like so:
for(i=0;i<255;i++)
for(j=0;j<255;j++);
In the microprocessor's view, is this how the sleep() function works?
Is there an alternative for the sleep() function in C?
In traditional embedded programming, we will give a delay function like so:
for(i=0;i<255;i++)
for(j=0;j<255;j++);
In the microprocessor's view, is this how the sleep() function works?
Is there an alternative for the sleep() function in C?
The kind of loop you describe is called a "busy wait". In real operating systems, sleeping does not cause a busy wait; it tells the operating system to not schedule the process in until the sleep period is over.
You talk about "embedded programming" in the OP. If you're doing embedded work and need something like sleep(), there are often hardware counters/timers available. This will vary from architecture to architecture, so have a look at the datasheet.
If you're not doing embedded work, I apologize :)
If you're using for-loops, you'd better know what they compile to and how long those instructions take at your given clock speed, and ensure the CPU runs your instructions and nothing else (this can be done in embedded systems but it's tricky since it disallows interrupts).
Otherwise, you won't be able to tell how long it's really going to take.
Early PC games had this problem - they were built for a 4.7MHz PC and, when the faster computers came along, they were unplayable.
The best way a 'sleep' can work is for the CPU to know what time it is at any given point. Not necessarily the actual time (7:15 am) but at least the relative time (8612 seconds since some point in time).
That way it can apply a delta to the current time and wait in a loop until the current+delta is reached.
Anything that relies on number CPU cycles is inherently unreliable as the CPU may go off to another task and leave your loop hanging.
Let's say you have a memory-mapped 16-bit I/O port which the CPU increments once a second. Let's also assume it's at memory location 0x33 in your embedded system, where ints are also 16 bits. A function called sleep then becomes something like:
void sleep (unsigned int delay) {
unsigned int target = peek(0x33) + delay;
while (peek(0x33) != target);
}
You'll have to ensure that peek() returns the memory contents every time (so optimizing compilers don't muck up the logic) and that your while statement runs more than once per second so you don't miss the target, but these are operational issues that don't affect the concept I'm presenting.
Alternatives depend in what you are trying to do and what OS you are on.
If you just want to waste time, then these might help:
On most unix-type systems you'll find a 'usleep' function, which is more or less like sleep with greater resolution. Be careful with that one because it usually can not sleep for just one microsecond.
On some unix-type systems, the select system call can be used with all file descriptor sets zero in order to get a fairly accurate sub-second wait.
On windows systems, you have Sleep, which is pretty much the same, but taking a number of milliseconds.
In a multi-tasking operating system, a sleep function can sometimes be given 0 as a parameter. This generally causes the function to give up it's timeslice, but be re-scheduled immediately if no other task is ready to run.
One common mechanism is to use a select()
that is guaranteed to time out and specify the sleep time as the timeout:
// Sleep for 1.5 sec
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 500000;
select(0, NULL, NULL, NULL, &tv);
The select()
is typically used to check a set of file descriptors and wait until at least one is ready to perform I/O. If none is ready (or, in this case, if no fds are specified), it will time out.
The advantage of select()
over a busy loop is that it consumes very little resources while sleeping, while a busy loop monopolizes the processor as much as permitted by its priority level.
In a unix-derivative OS, you would probably schedule a signal() call, and your code would simply block the code until the signal is raised. Signals are intended for the purpose, and they are very simple and efficient.
Busy-waiting is for amateurs even in an embedded system, use a real time source.
There's more information on how sleep() works here
By the way, busy waiting is not necessarily for amateurs--although it does burn processor that you may want to use for some other purpose. If you are using a time source, you are limited to the granularity of that source. E.G. if you have a 1 ms timer, and want to way 500 uS, you have a problem. If your embedded system can handle the fact that you'll be buzzing in a loop for 500 uSec, that might be acceptable. And even if you have a timer with your desired granularity, you also need to get an interrupt off that timer at the right time...then dispatch ot the interrupt handler...then get to your code. Sometimes a busy loop is the most expedient solution. Sometimes.
sleep actually interfaces with operating system, where sleeping processes are placed outside of scheduling queue. I usually use:
poll(0, 0, milliseconds);
for POSIX compliant systems. select
also works for windows (they must have a native API (probably called Sleep
) for that.)
any decent C compiler would, without extra work, remove your code entirely and the delay would vanish
You would not use the code you published to sleep on an embedded system. A decent compiler would entirely remove it, and even if your compiler does not remove it is suboptimal, since running the processor in a tight loop will burn power, which is an issue for embedded system. Even systems not running on battery care about power usage, since lower power usage means cheaper power supplies and cooling.
The way you normally do this is your CPU will implement some sort of IDLE or SLEEP instructions, that will cause it to temporarily stop processing commands. An external interrupt line connected to a timer circuit will wake the processor back up at regular intervals, and which point the CPU checks to see if it has been asleep for long enough, and if not it goes back to sleep.
//Pseudo code
int start = getTime();
int end = start + sleepTime;
while (getTime() < end) {
asm("SLEEP");
}
The exact details vary from processor to processor. If you are running as a process on an OS the sleep call generally just tells the scheduler to suspend your process, and then the kernel decides whether to schedule another process or to sleep the CPU. Also, the above code will not be adequete for real time systems, which want deadline guarantees, etc. In those cases you will need to get the time in the loop, know the duration of the time interrupt so ou know if you can resleep without blowing the deadline, and potentially reprogram the timer hardware or busy wait.