Real-Time Embedded Multithreading--Using ThreadX & ARM-INTERNAL SYSTEM CLOCK AND APPLICATION TIMERS

If you want to get the book of Real-Time Embedded Multithreading–Using ThreadX please click the below link, https://download.csdn.net/download/u014100559/11583651

Internal System Clock Services

ThreadX sets the internal system clock to zero during application initialization, and each
timer-tick increases the clock by one. The internal system clock is intended for the sole
use of the developer; ThreadX does not use it for any purpose, including implementing
application timers. Applications can perform exactly two actions on the internal system
clock: either read the current clock value, or set its value.
The tx_time_get service retrieves the current time from the internal system clock.
Code snap 1 get current time from the internal system clock.

ULONG current_time;
/* Retrieve the current system time, in timer-ticks. */
current_time = tx_time_get();
/* Variable current_time now contains the current system time */

After invoking this service, the variable current_time contains a copy of the internal
system clock. This service can be used to measure elapsed time and perform other
time-related calculations.
The tx_time_set service sets the current time of the internal system clock to some
specified value. Code snap 2 illustrates how this service can be used.

Code snap 2 set current time of the internal system clock.
/* Set the internal system time to 0x1234. */
tx_time_set(0x1234);
/* Current time now contains 0x1234 until the next
timer interrupt. */

After invoking this service, the current time of the internal system clock contains the
value 0x1234. The time will remain at this value until the next timer-tick, when it will be
incremented by one.

Application Timer Control Block

The characteristics of each application timer are found in its Application Timer Control
Block. It contains useful information such as the ID, application timer name, the number
of remaining timer-ticks, the re-initialization value, the pointer to the timeout function,
the parameter for the timeout function, and various pointers. As with the other Control
Blocks, ThreadX prohibits an application from explicitly modifying the Application
Timer Control Block.
Application Timer Control Blocks can be located anywhere in memory, but it is most
common to make the Control Block a global structure by defining it outside the scope of
any function. Table 3 contains many of the fields that comprise this Control Block.
在这里插入图片描述
An Application Timer Control Block is created when an application timer is declared
with the TX_TIMER data type. For example, we declare my_timer as follows:
TX_TIMER my_timer;
The declaration of application timers normally appears in the declaration and definition
section of the application program.

Summary of Application Timer Services

Appendix J contains detailed information about application timer services. This appendix
contains information about each service, such as the prototype, a brief description of
the service, required parameters, return values, notes and warnings, allowable invocation,
and an example showing how the service can be used. Table 4 contains a listing
of all available application timer services. We will investigate each of these services in the
subsequent sections of this chapter.
We will first consider the tx_timer_pool_create service because it needs to be
invoked before any of the other services.
Table 4 Services of the application timer.
在这里插入图片描述

Creating an Application Timer

An application timer is declared with the TX_TIMER data type and is defined with the
tx_timer_create service. When defining an application timer, you must specify its
Control Block, the name of the application timer, the expiration function to call when
the timer expires, the input value to pass to the expiration function, the initial number of
timer-ticks before timer expiration, the number of timer-ticks for all timer expirations
after the first, and the option that determines when the timer is activated. The valid
range of values for the initial number of timer-ticks is from 1 to 0xFFFFFFFF (inclusive).
For subsequent time timer-ticks, the valid range of values is from 0 to 0xFFFFFFFF
(inclusive), where the value of 0 means this is a one-shot timer, and all other values in
that range are for periodic timers. Table 5 contains a list of these attributes.
在这里插入图片描述
We will illustrate the application timer creation service with an example. We will give
our application timer the name “my_timer” and cause it to activate immediately. The
timer will expire after 100 timer-ticks, call the expiration function called “my_timer_
function,” and will continue to do so every 25 timer-ticks thereafter. Code snap 6 contains
an example of application timer creation.
Code snap 6 Creating an application timer.

TX_TIMER my_timer;
UINT status;
/* Create an application timer that executes
"my_timer_function" after 100 timer-ticks initially and then
after every 25 timer-ticks. This timer is specified to start
immediately. */
status = tx_timer_create(&my_timer,"my_timer_name",
my_timer_function, 0x1234, 100, 25,
TX_AUTO_ACTIVATE);
/* If status equals TX_SUCCESS, my_timer_function will
be called 100 timer-ticks later and then called every
25 timer-ticks. Note that the value 0x1234 is passed to
my_timer_function every time it is called. */

If variable status contains the return value TX_SUCCESS, we have successfully created
the application timer. We must place a prototype for the expiration function in the
declaration and definition section of our program as follows:
void my_timer_function (ULONG);
The expiration function definition appears in the final section of the program, where
the thread entry functions are defined. Following is a skeleton of that function definition.

void my_timer_function (ULONG invalue)
{
:
}
`

Activating an Application Timer

When an application timer is created with the TX_NO_ACTIVATE option, it remains
inactive until the tx_timer_activate service is called. Similarly, if an application timer
is deactivated with the tx_timer_deactive service, it remains inactive until the tx_
timer_activate service is called. If two or more application timers expire at the same
time, the corresponding expiration functions are executed in the order in which they
were activated. Code snap 7 contains an example of application timer activation.
Code snap 7 Activation of an application timer.

TX_TIMER my_timer;
UINT status;
...
/* Activate an application timer. Assume that the
application timer has already been created. */
status = tx_timer_activate(&my_timer);
/* If status equals TX_SUCCESS, the application timer is
now active. */

If variable status contains the return value TX_SUCCESS, we have successfully activated
the application timer.

Changing an Application Timer

When you create an application timer, you must specify the initial number of timer-ticks
before timer expiration, as well as the number of timer-ticks for all timer expirations
after the first. Invoking the tx_timer_change service can change these values. You must
deactivate the application timer before calling this service, and call tx_timer_activate
after this service to restart the timer. Code snap 8 illustrates how this service can be called.
Code snap 8 Change characteristics of an application timer.

TX_TIMER my_timer;
UINT status;
...
/* Change a previously created and now deactivated timer
to expire every 50 timer-ticks, including the initial
expiration. */
status = tx_timer_change(&my_timer,50, 50);
/* If status equals TX_SUCCESS, the specified timer is
changed to expire every 50 timer-ticks. */
/* Activate the specified timer to get it started again. */
status = tx_timer_activate(&my_timer);

If variable status contains the return value TX_SUCCESS, we have successfully
changed the number of timer-ticks for initial and subsequent expiration to 50.

Deactivating an Application Timer

Before modifying the timing characteristics of an application timer, that timer must first
be deactivated. This is the sole purpose of the tx_timer_deactivate service. Code snap 9
shows how to use this service.
Code snap 9 Deactivate an application timer.

TX_TIMER my_timer;
UINT status;
...
/* Deactivate an application timer. Assume that the
application timer has already been created. */
status = tx_timer_deactivate(&my_timer);
/* If status equals TX_SUCCESS, the application timer
is now deactivated. */

If variable status contains the value TX_SUCCESS, the application timer is now deactivated.
This timer remains in an inactive state until it is activated with the tx_timer_activate service.

Deleting an Application Timer

The tx_timer_delete service deletes an application timer. Code snap 10 shows how to
delete an application timer.
Code snap 10 Deleting an application timer.

TX_TIMER my_timer;
UINT status;
...
/* Delete application timer. Assume that the
application timer has already been created. */
status = tx_timer_delete(&my_timer);
/* If status equals TX_SUCCESS, the application
timer is deleted. */

If variable status contains the return value TX_SUCCESS, we have successfully
deleted the application timer. Make certain that you do not inadvertently use a deleted
timer.

Retrieving Application Timer Information

The tx_timer_info_get service retrieves a variety of information about an application
timer. The information that is retrieved includes the application timer name, its active/
inactive state, the number of timer-ticks before the timer expires, the number of subsequent
timer-ticks for timer expiration after the first expiration, and a pointer to the next
created application timer. Code snap 11 shows how this service can be used to obtain
information about an application timer.
Code snap 11 Retrieve information about an application timer.

TX_TIMER my_timer;
CHAR *my_timer_name;
UINT active;
ULONG remaining_ticks;
ULONG reschedule_ticks;
TX_TIMER *next_timer;
UINT status;
...
/* Retrieve information about the previously created
application timer called "my_timer." */
status = tx_timer_info_get(&my_timer, &my_timer_name,
&active,&remaining_ticks,
&reschedule_ticks,
&next_timer);
/* If status equals TX_SUCCESS, the information
requested is valid. */

If variable status contains the return value TX_SUCCESS, we have retrieved valid
information about the timer.

Sample System Using Timers to Measure Thread Performance

In Chapter 7, we created a sample system that produced output beginning as follows:
Current Time: 34 Speedy_Thread finished cycle…
Current Time: 40 Slow_Thread finished cycle…
Current Time: 56 Speedy_Thread finished cycle…
The timing data in this output was captured with the use of the internal system clock.
Following are the statements near the end of the Speedy_Thread entry function that generate
information about the performance of Speedy_Thread.
current_time = tx_time_get();
printf(“Current Time: %5lu Speedy_Thread finished cycle…\n”,
current_time);
We used the tx_time_get service to retrieve the current time from the internal system
clock. Each time the Speedy_Thread finished its cycle it displayed the preceding timing
information.
For this sample system, we will eliminate the display of information at the end of
each thread cycle. However, we will continue to use the internal system clock to determine
the time duration of a thread cycle, but we will display a summary of information
at designated intervals, say every 500 timer-ticks. We will use an application timer to
trigger this periodic display. Following is a portion of the sample output we would like
to have displayed on a periodic basis:
**** Timing Info Summary
Current Time: 500
Speedy_Thread counter: 22
Speedy_Thread avg time: 22
Slow_Thread counter: 11
Slow_Thread avg time: 42
We need to compute the average cycle time for both the Speedy_Thread and the
Slow_Thread. To accomplish this, we need two variables for each of the two threads:
one to store the total time spent in the cycle, and one to count the total number of cycles
completed. Figure 9.12 contains these variable declarations and the other additions to
the declarations and definitions section of the program.
Figure 9.12 Additions to the declarations and definitions section.
/* Declare the application timer /
TX_TIMER stats_timer;
/
Declare the counters and accumulators /
ULONG Speedy_Thread_counter = 0,
total_speedy_time = 0;
ULONG Slow_Thread_counter = 0,
total_slow_time = 0;
/
Define prototype for expiration function /
void print_stats(ULONG);
We need to add the timer creation service to the tx_application_define function,
as indicated by Figure 9.13.
Figure 9.13 Additions to the application definitions section.
/
Create and activate the timer /
tx_timer_create (&stats_timer, “stats_timer”, print_stats,
0x1234, 500, 500, TX_AUTO_ACTIVATE);
We need to modify the entry functions for the Speedy_Thread and the Slow_Thread.
Delete the following statements at the end of the Speedy_Thread entry function:
current_time = tx_time_get();
printf(“Current Time: %lu Speedy_Thread finished cycle…\n”,
current_time);
We will use the internal system clock to compute the time to complete each cycle. We
also need to compute the total cycle time as follows:
Figure 9.14 contains the necessary additions for the Speedy_Thread.
Figure 9.14 Additions to the Speedy_Thread entry function.
/
Insert at the beginning of Speedy_Thread entry function /
ULONG start_time, cycle_time;
/
Get the starting time for this cycle /
start_time = tx_time_get();

/
Insert at the end of Speedy_Thread entry function /
/
Increment thread counter, compute cycle time & total time /
Speedy_Thread_counter++;
current_time = tx_time_get();
cycle_time = current_time - start_time;
total_speedy_time = total_speedy_time + cycle_time;
The entry function for Slow_Thread requires similar additions, but we leave that as
an exercise for the reader. These computations store the total number of cycles that have
been completed, and the total amount of time spent in those cycles. The expiration function
called print_stats will use these values to compute average cycle time for both
threads and will display summary information.
Every 500 timer-ticks, the application timer called stats_timer expires and invokes
the expiration function print_stats. After determining that both thread counters are
greater than zero, that function computes the average cycle times for Speedy_Thread
and Slow_Thread, as follows:
and
Function print_stats then displays the current time, the average cycle times, and
the number of cycles completed by each of the threads. Figure 9.15 contains a listing of
the print_stats expiration function.
Figure 9.15 Expiration function to display summary information.
/
Display statistics at periodic intervals /
void print_stats (ULONG invalue)
{
ULONG current_time, avg_slow_time, avg_speedy_time;
if ((Speedy_Thread_counter>0) && (Slow_Thread_counter>0))
{
current_time = tx_time_get();
avg_slow_time = total_slow_time / Slow_Thread_counter;
avg_speedy_time = total_speedy_time / Speedy_Thread_counter;
printf("\n
*** Timing Info Summary\n\n");
printf(“Current Time: %lu\n”, current_time);
printf(" Speedy_Thread counter: %lu\n", Speedy_Thread_counter);
printf(" Speedy_Thread avg time: %lu\n", avg_speedy_time);
printf(" Slow_Thread counter: %lu\n", Slow_Thread_counter);
printf(" Slow_Thread avg time: %lu\n\n", avg_slow_time);
}
else printf(“Bypassing print_stats, Time: %lu\n”, tx_time_get());
This program can be modified easily to display other timing information; the timer
can be changed to expire at different time intervals as well. The complete program listing
called 09_sample_system.c is located in the next section of this chapter and on the
attached CD.

Listing for 09_sample_system.c

The sample system named 09_sample_system.c is located on the attached CD. The complete
listing appears below; line numbers have been added for easy reference.

 /* 09_sample_system.c

 Create two threads, and one mutex.
 Use arrays for the thread stacks.
 The mutex protects the critical sections.
 Use an application timer to display thread timings. */

 /****************************************************/
 /* Declarations, Definitions, and Prototypes */
 /****************************************************/

 #include "tx_api.h"
 #include <stdio.h>

 #define STACK_SIZE 1024

 CHAR stack_speedy[STACK_SIZE];
 CHAR stack_slow[STACK_SIZE];


 /* Define the ThreadX object control blocks... */

 TX_THREAD Speedy_Thread;
 TX_THREAD Slow_Thread;

 TX_MUTEX my_mutex;

 /* Declare the application timer */
 TX_TIMER stats_timer;

 /* Declare the counters and accumulators */
 ULONG Speedy_Thread_counter = 0,
 Total_speedy_time = 0;
 ULONG Slow_Thread_counter = 0,
 Total_slow_time = 0;

 /* Define prototype for expiration function */
 void print_stats(ULONG);

 /* Define thread prototypes. */

 void Speedy_Thread_entry(ULONG thread_input);
 void Slow_Thread_entry(ULONG thread_input);


 /****************************************************/
 /* Main Entry Point */
 /****************************************************/

 /* Define main entry point. */

 int main()
 {

 /* Enter the ThreadX kernel. */
 tx_kernel_enter();
 }


 /****************************************************/
 /* Application Definitions */
 /****************************************************/

 /* Define what the initial system looks like. */

 void tx_application_define(void *first_unused_memory)
 {


 /* Put system definitions here,
 e.g., thread and mutex creates */

 /* Create the Speedy_Thread. */
 tx_thread_create(&Speedy_Thread, "Speedy_Thread",
 Speedy_Thread_entry, 0,
 stack_speedy, STACK_SIZE,
 5, 5, TX_NO_TIME_SLICE, TX_AUTO_START);

 /* Create the Slow_Thread */
 tx_thread_create(&Slow_Thread, "Slow_Thread",
 Slow_Thread_entry, 1,
 stack_slow, STACK_SIZE,
 15, 15, TX_NO_TIME_SLICE, TX_AUTO_START);

 /* Create the mutex used by both threads */
 tx_mutex_create(&my_mutex, "my_mutex", TX_NO_INHERIT);

 /* Create and activate the timer */
 tx_timer_create (&stats_timer, "stats_timer", print_stats,
 0x1234, 500, 500, TX_AUTO_ACTIVATE);

 }


 /****************************************************/
 /* Function Definitions */
 /****************************************************/

 /* Define the activities for the Speedy_Thread */

 void Speedy_Thread_entry(ULONG thread_input)
 {
 UINT status;
 ULONG current_time;
 ULONG start_time, cycle_time;

 while(1)
 {

 /* Get the starting time for this cycle */
 start_time = tx_time_get();

 /* Activity 1: 2 timer-ticks. */
 tx_thread_sleep(2);

 /* Activity 2: 5 timer-ticks *** critical section ***
 Get the mutex with suspension. */

 status = tx_mutex_get(&my_mutex, TX_WAIT_FOREVER);
 if (status != TX_SUCCESS) break; /* Check status */

 tx_thread_sleep(5);

 /* Release the mutex. */
 status = tx_mutex_put(&my_mutex);
 if (status != TX_SUCCESS) break; /* Check status */

 /* Activity 3: 4 timer-ticks. */
 tx_thread_sleep(4);

 /* Activity 4: 3 timer-ticks *** critical section ***
 Get the mutex with suspension. */

 status = tx_mutex_get(&my_mutex, TX_WAIT_FOREVER);
 if (status != TX_SUCCESS) break; /* Check status */

 tx_thread_sleep(3);

 /* Release the mutex. */
 status = tx_mutex_put(&my_mutex);
 if (status != TX_SUCCESS) break; /* Check status */

 /* Increment thread counter, compute cycle time & total time */
 Speedy_Thread_counter++;
 current_time = tx_time_get();
 cycle_time = current_time - start_time;
 total_speedy_time = total_speedy_time + cycle_time;

 }
 }

 /****************************************************/

 /* Define the activities for the Slow_Thread */

 void Slow_Thread_entry(ULONG thread_input)
 {
 UINT status;
 ULONG current_time;
 ULONG start_time, cycle_time;

 while(1)
 {

 /* Get the starting time for this cycle */
 start_time = tx_time_get();

 /* Activity 5: 12 timer-ticks *** critical section ***
 Get the mutex with suspension. */

 status = tx_mutex_get(&my_mutex, TX_WAIT_FOREVER);
 if (status != TX_SUCCESS) break; /* Check status */

 tx_thread_sleep(12);

 /* Release the mutex. */
 status = tx_mutex_put(&my_mutex);
 if (status != TX_SUCCESS) break; /* Check status */

 /* Activity 6: 8 timer-ticks. */
 tx_thread_sleep(8);

 /* Activity 7: 11 timer-ticks *** critical section ***
 Get the mutex with suspension. */

 status = tx_mutex_get(&my_mutex, TX_WAIT_FOREVER);
 if (status != TX_SUCCESS) break; /* Check status */

 tx_thread_sleep(11);

 /* Release the mutex. */
 status = tx_mutex_put(&my_mutex);
 if (status != TX_SUCCESS) break; /* Check status */

 /* Activity 8: 9 timer-ticks. */
 tx_thread_sleep(9);

 /* Increment thread counter, compute cycle time & total time */
 Slow_Thread_counter++;
 current_time = tx_time_get();
 cycle_time = current_time - start_time;
 total_slow_time = total_slow_time + cycle_time;

 }
 }

 /****************************************************/

 /* Display statistics at periodic intervals */
 void print_stats (ULONG invalue)
 {
 ULONG current_time, avg_slow_time, avg_speedy_time;

 if ((Speedy_Thread_counter>0) && (Slow_Thread_counter>0))
215 {
 current_time = tx_time_get();
 avg_slow_time = total_slow_time / Slow_Thread_counter;
 avg_speedy_time = total_speedy_time / Speedy_Thread_counter;

 printf("\n**** Timing Info Summary\n\n");
 printf("Current Time: %lu\n", current_time);
 printf(" Speedy_Thread counter: %lu\n", Speedy_Thread_counter);
 printf(" Speedy_Thread avg time: %lu\n", avg_speedy_time);
 printf(" Slow_Thread counter: %lu\n", Slow_Thread_counter);
 printf(" Slow_Thread avg time: %lu\n\n", avg_slow_time);
 }
 else printf("Bypassing print_stats, Time: %lu\n", tx_time_get());
 }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值