X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=doc%2Fhtml%2Fuser-guide%2Fclocks-and-alarm-handlers.html;fp=doc%2Fhtml%2Fuser-guide%2Fclocks-and-alarm-handlers.html;h=9b346e08b8a47d20b6ee0bf6543bdded09dabffd;hb=2b5bec7716c03d42cfb16d8c98c9cea573bf6722;hp=0000000000000000000000000000000000000000;hpb=47412fc4bd1aefc0d5498bcb3860a9d727196f16;p=karo-tx-redboot.git diff --git a/doc/html/user-guide/clocks-and-alarm-handlers.html b/doc/html/user-guide/clocks-and-alarm-handlers.html new file mode 100644 index 00000000..9b346e08 --- /dev/null +++ b/doc/html/user-guide/clocks-and-alarm-handlers.html @@ -0,0 +1,467 @@ + + + + + + + + +
If a program wanted to execute a task at a given time, or +periodically, it could do it in an inefficient way by sitting in a +loop and checking the real-time clock to see if the proper amount of +time has elapsed. But operating systems usually provide system calls +which allow the program to be informed at the desired time.
eCos provides a rich timekeeping formalism, involving +counters, clocks, +alarms, and timers. The +precise definition, relationship, and motivation of these features is +beyond the scope of this tutorial, but these examples illustrate how +to set up basic periodic tasks.
Alarms are events that happen at +a given time, either once or periodically. A thread associates an +alarm handling function with the alarm, so that the function will +be invoked every time the alarm “goes off”.
simple-alarm.c (in +the examples directory) is a short program that creates a thread that +creates an alarm. The alarm is handled by the function +test_alarm_func(), which sets a global +variable. When the main thread of execution sees that the variable has +changed, it prints a message.
Example 14-1. A sample program that creates an alarm
/* this is a very simple program meant to demonstrate + a basic use of time, alarms and alarm-handling functions in eCos */ + +#include <cyg/kernel/kapi.h> + +#include <stdio.h> + +#define NTHREADS 1 +#define STACKSIZE 4096 + +static cyg_handle_t thread[NTHREADS]; + +static cyg_thread thread_obj[NTHREADS]; +static char stack[NTHREADS][STACKSIZE]; + +static void alarm_prog( cyg_addrword_t data ); + +/* we install our own startup routine which sets up + threads and starts the scheduler */ +void cyg_user_start(void) +{ + cyg_thread_create(4, alarm_prog, (cyg_addrword_t) 0, + "alarm_thread", (void *) stack[0], + STACKSIZE, &thread[0], &thread_obj[0]); + cyg_thread_resume(thread[0]); +} + +/* we need to declare the alarm handling function (which is + defined below), so that we can pass it to cyg_alarm_initialize() */ +cyg_alarm_t test_alarm_func; + +/* alarm_prog() is a thread which sets up an alarm which is then + handled by test_alarm_func() */ +static void alarm_prog(cyg_addrword_t data) +{ + cyg_handle_t test_counterH, system_clockH, test_alarmH; + cyg_tick_count_t ticks; + cyg_alarm test_alarm; + unsigned how_many_alarms = 0, prev_alarms = 0, tmp_how_many; + + system_clockH = cyg_real_time_clock(); + cyg_clock_to_counter(system_clockH, &test_counterH); + cyg_alarm_create(test_counterH, test_alarm_func, + (cyg_addrword_t) &how_many_alarms, + &test_alarmH, &test_alarm); + cyg_alarm_initialize(test_alarmH, cyg_current_time()+200, 200); + + /* get in a loop in which we read the current time and + print it out, just to have something scrolling by */ + for (;;) { + ticks = cyg_current_time(); + printf("Time is %llu\n", ticks); + /* note that we must lock access to how_many_alarms, since the + alarm handler might change it. this involves using the + annoying temporary variable tmp_how_many so that I can keep the + critical region short */ + cyg_scheduler_lock(); + tmp_how_many = how_many_alarms; + cyg_scheduler_unlock(); + if (prev_alarms != tmp_how_many) { + printf(" --- alarm calls so far: %u\n", tmp_how_many); + prev_alarms = tmp_how_many; + } + cyg_thread_delay(30); + } +} + +/* test_alarm_func() is invoked as an alarm handler, so + it should be quick and simple. in this case it increments + the data that is passed to it. */ +void test_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data) +{ + ++*((unsigned *) data); +} |
When you run this program (by typing continue at +the (gdb) prompt) the output should look like +this:
Starting program: BASE_DIR/examples/simple-alarm.exe +Time is 0 +Time is 30 +Time is 60 +Time is 90 +Time is 120 +Time is 150 +Time is 180 +Time is 210 + --- alarm calls so far: 1 +Time is 240 +Time is 270 +Time is 300 +Time is 330 +Time is 360 +Time is 390 +Time is 420 + --- alarm calls so far: 2 +Time is 450 +Time is 480 |
Note: When running in a simulator the delays +might be quite long. On a hardware board (where the clock speed is 100 +ticks/second) the delays should average to about 0.3 seconds (and 2 +seconds between alarms). In simulation, the delay will depend on the +speed of the host processor and will almost always be much slower than +the actual board. You might want to reduce the delay parameter when +running in simulation.
Here are a few things you might notice about this program:
It used the cyg_real_time_clock() function; +this always returns a handle to the default system real-time clock.
Clocks are based on counters, so the function cyg_alarm_create() +uses a counter handle. The program used the function +cyg_clock_to_counter() to strip the clock handle +to the underlying counter handle.
Once the alarm is created it is +initialized with cyg_alarm_initialize(), which +sets the time at which the alarm should go off, as well as the period +for repeating alarms. It is set to go off at the current time and +then to repeat every 200 ticks.
The alarm handler function +test_alarm_func() conforms to the guidelines for +writing alarm handlers and other delayed service routines: it does not invoke any +functions which might lock the scheduler. This is discussed in detail +in the eCos Reference Manual, in the chapter +The eCos Kernel.
There is a critical region in this program: +the variable how_many_alarms is accessed in the +main thread of control and is also modified in the alarm handler. To +prevent a possible (though unlikely) race condition on this variable, +access to how_many_alarms in the principal thread +is protected by calls to cyg_scheduler_lock() and +cyg_scheduler_unlock(). When the scheduler is +locked, the alarm handler will not be invoked, so the problem is +averted.