mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-02-06 09:02:20 +08:00
[clock_time] Add comprehensive examples and test code
- Created clock_time_example.c with 7 different usage examples - Added examples for info display, boottime, conversion, delays, timers - Included performance benchmark example - Added comprehensive examples README with troubleshooting guide Co-authored-by: BernardXiong <1241087+BernardXiong@users.noreply.github.com>
This commit is contained in:
241
examples/clock_time/README.md
Normal file
241
examples/clock_time/README.md
Normal file
@@ -0,0 +1,241 @@
|
||||
# Clock Time Examples
|
||||
|
||||
This directory contains examples demonstrating the use of the unified `clock_time` subsystem.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Enable `RT_USING_CLOCK_TIME` in your configuration:
|
||||
```
|
||||
CONFIG_RT_USING_CLOCK_TIME=y
|
||||
```
|
||||
|
||||
## Available Examples
|
||||
|
||||
### 1. Clock Time Information (`clock_time_info_example`)
|
||||
Displays basic information about the clock_time device:
|
||||
- Clock frequency
|
||||
- Clock resolution
|
||||
- Current counter value
|
||||
- Device capabilities
|
||||
|
||||
**Usage:**
|
||||
```
|
||||
msh> clock_time_info_example
|
||||
```
|
||||
|
||||
### 2. Boottime Tracking (`clock_boottime_example`)
|
||||
Shows system uptime in different formats:
|
||||
- Nanosecond precision
|
||||
- Microsecond precision
|
||||
- Second precision
|
||||
|
||||
**Usage:**
|
||||
```
|
||||
msh> clock_boottime_example
|
||||
```
|
||||
|
||||
### 3. Time Conversion (`clock_conversion_example`)
|
||||
Demonstrates conversion between counter ticks and time units (ms, us, ns).
|
||||
|
||||
**Usage:**
|
||||
```
|
||||
msh> clock_conversion_example
|
||||
```
|
||||
|
||||
### 4. High-Precision Delay (`clock_delay_example`)
|
||||
Tests high-precision delay functions and measures actual delays:
|
||||
- Microsecond delays (`rt_clock_udelay`)
|
||||
- Millisecond delays (`rt_clock_mdelay`)
|
||||
|
||||
**Usage:**
|
||||
```
|
||||
msh> clock_delay_example
|
||||
```
|
||||
|
||||
### 5. One-Shot Timer (`clock_hrtimer_oneshot_example`)
|
||||
Demonstrates using a high-resolution timer for one-shot timeouts.
|
||||
|
||||
**Usage:**
|
||||
```
|
||||
msh> clock_hrtimer_oneshot_example
|
||||
```
|
||||
|
||||
**Expected Output:**
|
||||
```
|
||||
=== High-Resolution Timer (One-Shot) Example ===
|
||||
Starting timer for 500ms...
|
||||
Timer started successfully
|
||||
High-resolution timer fired! Parameter: One-shot timer
|
||||
Timer example complete
|
||||
```
|
||||
|
||||
### 6. Periodic Timer (`clock_hrtimer_periodic_example`)
|
||||
Demonstrates using a high-resolution timer for periodic callbacks.
|
||||
|
||||
**Usage:**
|
||||
```
|
||||
msh> clock_hrtimer_periodic_example
|
||||
```
|
||||
|
||||
**Expected Output:**
|
||||
```
|
||||
=== High-Resolution Timer (Periodic) Example ===
|
||||
Starting periodic timer (200ms period)...
|
||||
Timer started successfully
|
||||
Periodic timer tick #1
|
||||
Periodic timer tick #2
|
||||
Periodic timer tick #3
|
||||
Periodic timer tick #4
|
||||
Periodic timer tick #5
|
||||
Timer stopped. Total ticks: 5
|
||||
```
|
||||
|
||||
### 7. Performance Benchmark (`clock_benchmark_example`)
|
||||
Measures the overhead of clock_time operations:
|
||||
- `get_counter()` call overhead
|
||||
- Time conversion overhead
|
||||
|
||||
**Usage:**
|
||||
```
|
||||
msh> clock_benchmark_example
|
||||
```
|
||||
|
||||
### Run All Examples (`clock_time_examples_all`)
|
||||
Runs all examples in sequence.
|
||||
|
||||
**Usage:**
|
||||
```
|
||||
msh> clock_time_examples_all
|
||||
```
|
||||
|
||||
## Building the Examples
|
||||
|
||||
### Method 1: Include in BSP
|
||||
|
||||
Add to your BSP's `applications/SConscript`:
|
||||
```python
|
||||
src += Glob('../../examples/clock_time/*.c')
|
||||
```
|
||||
|
||||
### Method 2: Manual Compilation
|
||||
|
||||
Copy `clock_time_example.c` to your BSP's `applications` directory and rebuild.
|
||||
|
||||
### Method 3: menuconfig
|
||||
|
||||
Some BSPs may include examples in menuconfig. Look for:
|
||||
```
|
||||
RT-Thread online packages --->
|
||||
miscellaneous packages --->
|
||||
[*] Enable clock_time examples
|
||||
```
|
||||
|
||||
## Interpreting Results
|
||||
|
||||
### Delay Accuracy
|
||||
The delay examples measure actual vs. target delays. Typical results:
|
||||
- **Good**: Actual delay within 1-5% of target
|
||||
- **Acceptable**: Actual delay within 10% of target
|
||||
- **Poor**: Actual delay > 10% off target (may indicate timer issues)
|
||||
|
||||
Factors affecting accuracy:
|
||||
- Timer resolution
|
||||
- Interrupt latency
|
||||
- System load
|
||||
- Compiler optimizations
|
||||
|
||||
### Performance Benchmarks
|
||||
Typical overhead values (depending on platform):
|
||||
- `get_counter()`: 10-100 ns per call
|
||||
- `cnt_to_us()`: 50-500 ns per call
|
||||
|
||||
Lower values are better. Very high values may indicate:
|
||||
- Slow hardware timer access
|
||||
- Cache misses
|
||||
- Inefficient implementation
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "RT_USING_CLOCK_TIME is not enabled"
|
||||
Enable the clock_time subsystem in Kconfig:
|
||||
```
|
||||
Device Drivers --->
|
||||
[*] Using unified clock_time subsystem
|
||||
```
|
||||
|
||||
### "No clock_time device found"
|
||||
No clock_time device has been registered. Options:
|
||||
1. Enable an adapter (e.g., ARM Generic Timer, SysTick)
|
||||
2. Implement a custom adapter for your hardware
|
||||
3. The tick-based fallback should be available
|
||||
|
||||
### Timer callbacks not firing
|
||||
If one-shot or periodic timers don't fire:
|
||||
1. Check that your clock_time device supports `RT_CLOCK_TIME_CAP_CLOCKEVENT`
|
||||
2. Verify the timer ISR calls `rt_clock_hrtimer_process()`
|
||||
3. Check interrupt configuration and priority
|
||||
4. Ensure timer interrupts are enabled
|
||||
|
||||
### Inaccurate delays
|
||||
If delays are consistently off:
|
||||
1. Verify timer frequency with `clock_time_info_example`
|
||||
2. Check for interrupt latency issues
|
||||
3. Ensure timer counter is actually counting
|
||||
4. Consider using a higher frequency timer
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Custom Timer Callbacks
|
||||
|
||||
```c
|
||||
static void my_callback(void *parameter)
|
||||
{
|
||||
int *count = (int *)parameter;
|
||||
(*count)++;
|
||||
rt_kprintf("Callback executed %d times\n", *count);
|
||||
}
|
||||
|
||||
void custom_timer_example(void)
|
||||
{
|
||||
struct rt_clock_hrtimer timer;
|
||||
int count = 0;
|
||||
|
||||
rt_clock_hrtimer_init(&timer, "custom",
|
||||
RT_TIMER_FLAG_PERIODIC,
|
||||
my_callback,
|
||||
&count);
|
||||
|
||||
unsigned long period = (unsigned long)rt_clock_time_ms_to_cnt(100);
|
||||
rt_clock_hrtimer_start(&timer, period);
|
||||
|
||||
/* Let it run... */
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
rt_clock_hrtimer_stop(&timer);
|
||||
rt_clock_hrtimer_detach(&timer);
|
||||
}
|
||||
```
|
||||
|
||||
### Precision Timing
|
||||
|
||||
```c
|
||||
void measure_function_time(void)
|
||||
{
|
||||
unsigned long start = (unsigned long)rt_clock_time_getcnt();
|
||||
|
||||
/* Function to measure */
|
||||
my_function();
|
||||
|
||||
unsigned long end = (unsigned long)rt_clock_time_getcnt();
|
||||
unsigned long delta = end - start;
|
||||
|
||||
rt_kprintf("Function took %u us\n",
|
||||
(rt_uint32_t)rt_clock_time_cnt_to_us(delta));
|
||||
}
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- [Clock Time Documentation](../../documentation/6.components/device-driver/clock_time.md)
|
||||
- [Clock Time README](../../components/drivers/clock_time/README.md)
|
||||
- [Adapter Examples](../../components/drivers/clock_time/adapters/)
|
||||
303
examples/clock_time/clock_time_example.c
Normal file
303
examples/clock_time/clock_time_example.c
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-12-04 RT-Thread clock_time usage examples
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file clock_time_example.c
|
||||
* @brief Examples demonstrating the unified clock_time subsystem
|
||||
*
|
||||
* This file contains various examples showing how to use the clock_time
|
||||
* subsystem for different time-related tasks.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#ifdef RT_USING_CLOCK_TIME
|
||||
|
||||
/**
|
||||
* @brief Example 1: Basic time information
|
||||
*
|
||||
* Demonstrates how to get clock frequency, resolution, and current counter.
|
||||
*/
|
||||
static void clock_time_info_example(void)
|
||||
{
|
||||
rt_kprintf("\n=== Clock Time Info Example ===\n");
|
||||
|
||||
/* Get clock frequency */
|
||||
rt_uint64_t freq = rt_clock_time_getfreq();
|
||||
rt_kprintf("Clock frequency: %u Hz\n", (rt_uint32_t)freq);
|
||||
|
||||
/* Get clock resolution (in nanoseconds * RT_CLOCK_TIME_RESMUL) */
|
||||
rt_uint64_t res = rt_clock_time_getres();
|
||||
rt_kprintf("Clock resolution: %u ns (scaled)\n",
|
||||
(rt_uint32_t)(res / RT_CLOCK_TIME_RESMUL));
|
||||
|
||||
/* Get current counter value */
|
||||
rt_uint64_t cnt = rt_clock_time_getcnt();
|
||||
rt_kprintf("Current counter: %u\n", (rt_uint32_t)cnt);
|
||||
|
||||
/* Get device info */
|
||||
struct rt_clock_time_device *dev = rt_clock_time_get_default();
|
||||
if (dev)
|
||||
{
|
||||
rt_kprintf("Device name: %s\n", dev->parent.parent.name);
|
||||
rt_kprintf("Capabilities: ");
|
||||
if (dev->caps & RT_CLOCK_TIME_CAP_CLOCKSOURCE)
|
||||
rt_kprintf("CLOCKSOURCE ");
|
||||
if (dev->caps & RT_CLOCK_TIME_CAP_CLOCKEVENT)
|
||||
rt_kprintf("CLOCKEVENT ");
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
MSH_CMD_EXPORT(clock_time_info_example, Show clock time information);
|
||||
|
||||
/**
|
||||
* @brief Example 2: Boottime tracking
|
||||
*
|
||||
* Demonstrates how to get system uptime in different formats.
|
||||
*/
|
||||
static void clock_boottime_example(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
struct timeval tv;
|
||||
time_t t;
|
||||
|
||||
rt_kprintf("\n=== Boottime Example ===\n");
|
||||
|
||||
/* Get boottime in nanoseconds */
|
||||
rt_clock_time_boottime_ns(&ts);
|
||||
rt_kprintf("Boottime (ns): %d.%09d seconds\n",
|
||||
(rt_uint32_t)ts.tv_sec, (rt_uint32_t)ts.tv_nsec);
|
||||
|
||||
/* Get boottime in microseconds */
|
||||
rt_clock_time_boottime_us(&tv);
|
||||
rt_kprintf("Boottime (us): %d.%06d seconds\n",
|
||||
(rt_uint32_t)tv.tv_sec, (rt_uint32_t)tv.tv_usec);
|
||||
|
||||
/* Get boottime in seconds */
|
||||
rt_clock_time_boottime_s(&t);
|
||||
rt_kprintf("Boottime (s): %d seconds\n", (rt_uint32_t)t);
|
||||
}
|
||||
MSH_CMD_EXPORT(clock_boottime_example, Show system boottime);
|
||||
|
||||
/**
|
||||
* @brief Example 3: Time conversion
|
||||
*
|
||||
* Demonstrates conversion between counter ticks and time units.
|
||||
*/
|
||||
static void clock_conversion_example(void)
|
||||
{
|
||||
rt_kprintf("\n=== Time Conversion Example ===\n");
|
||||
|
||||
/* Convert 1 second to counter ticks */
|
||||
unsigned long cnt_1s = (unsigned long)rt_clock_time_ms_to_cnt(1000);
|
||||
rt_kprintf("1 second = %u counter ticks\n", cnt_1s);
|
||||
|
||||
/* Convert back to time units */
|
||||
rt_uint64_t ms = rt_clock_time_cnt_to_ms(cnt_1s);
|
||||
rt_uint64_t us = rt_clock_time_cnt_to_us(cnt_1s);
|
||||
rt_uint64_t ns = rt_clock_time_cnt_to_ns(cnt_1s);
|
||||
|
||||
rt_kprintf(" = %u ms\n", (rt_uint32_t)ms);
|
||||
rt_kprintf(" = %u us\n", (rt_uint32_t)us);
|
||||
rt_kprintf(" = %u ns\n", (rt_uint32_t)ns);
|
||||
}
|
||||
MSH_CMD_EXPORT(clock_conversion_example, Show time conversion);
|
||||
|
||||
/**
|
||||
* @brief Example 4: High-precision delay
|
||||
*
|
||||
* Demonstrates using high-precision delay functions.
|
||||
*/
|
||||
static void clock_delay_example(void)
|
||||
{
|
||||
rt_kprintf("\n=== High-Precision Delay Example ===\n");
|
||||
|
||||
/* Measure delay accuracy */
|
||||
unsigned long start_cnt = (unsigned long)rt_clock_time_getcnt();
|
||||
|
||||
rt_kprintf("Delaying 100 microseconds...\n");
|
||||
rt_clock_udelay(100);
|
||||
|
||||
unsigned long end_cnt = (unsigned long)rt_clock_time_getcnt();
|
||||
unsigned long delta_cnt = end_cnt - start_cnt;
|
||||
|
||||
rt_uint64_t actual_us = rt_clock_time_cnt_to_us(delta_cnt);
|
||||
rt_kprintf("Actual delay: %u us (target: 100 us)\n", (rt_uint32_t)actual_us);
|
||||
|
||||
/* Millisecond delay */
|
||||
start_cnt = (unsigned long)rt_clock_time_getcnt();
|
||||
rt_kprintf("Delaying 10 milliseconds...\n");
|
||||
rt_clock_mdelay(10);
|
||||
end_cnt = (unsigned long)rt_clock_time_getcnt();
|
||||
delta_cnt = end_cnt - start_cnt;
|
||||
|
||||
rt_uint64_t actual_ms = rt_clock_time_cnt_to_ms(delta_cnt);
|
||||
rt_kprintf("Actual delay: %u ms (target: 10 ms)\n", (rt_uint32_t)actual_ms);
|
||||
}
|
||||
MSH_CMD_EXPORT(clock_delay_example, Demonstrate high-precision delays);
|
||||
|
||||
/**
|
||||
* @brief Example 5: High-resolution timer (one-shot)
|
||||
*
|
||||
* Demonstrates using high-resolution timer for one-shot timeout.
|
||||
*/
|
||||
static void hrtimer_callback(void *parameter)
|
||||
{
|
||||
rt_kprintf("High-resolution timer fired! Parameter: %s\n",
|
||||
(char *)parameter);
|
||||
}
|
||||
|
||||
static void clock_hrtimer_oneshot_example(void)
|
||||
{
|
||||
struct rt_clock_hrtimer timer;
|
||||
|
||||
rt_kprintf("\n=== High-Resolution Timer (One-Shot) Example ===\n");
|
||||
|
||||
/* Initialize one-shot timer */
|
||||
rt_clock_hrtimer_init(&timer, "oneshot_timer",
|
||||
RT_TIMER_FLAG_ONE_SHOT,
|
||||
hrtimer_callback,
|
||||
(void *)"One-shot timer");
|
||||
|
||||
/* Start with 500ms delay */
|
||||
unsigned long delay_cnt = (unsigned long)rt_clock_time_ms_to_cnt(500);
|
||||
rt_kprintf("Starting timer for 500ms...\n");
|
||||
|
||||
rt_err_t result = rt_clock_hrtimer_start(&timer, delay_cnt);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
rt_kprintf("Timer started successfully\n");
|
||||
}
|
||||
|
||||
/* Let timer fire, then cleanup */
|
||||
rt_thread_mdelay(600);
|
||||
rt_clock_hrtimer_detach(&timer);
|
||||
|
||||
rt_kprintf("Timer example complete\n");
|
||||
}
|
||||
MSH_CMD_EXPORT(clock_hrtimer_oneshot_example, Demonstrate one-shot hrtimer);
|
||||
|
||||
/**
|
||||
* @brief Example 6: High-resolution timer (periodic)
|
||||
*
|
||||
* Demonstrates using high-resolution timer for periodic callbacks.
|
||||
*/
|
||||
static volatile int periodic_count = 0;
|
||||
|
||||
static void periodic_callback(void *parameter)
|
||||
{
|
||||
periodic_count++;
|
||||
rt_kprintf("Periodic timer tick #%d\n", periodic_count);
|
||||
}
|
||||
|
||||
static void clock_hrtimer_periodic_example(void)
|
||||
{
|
||||
struct rt_clock_hrtimer timer;
|
||||
|
||||
rt_kprintf("\n=== High-Resolution Timer (Periodic) Example ===\n");
|
||||
|
||||
/* Initialize periodic timer */
|
||||
rt_clock_hrtimer_init(&timer, "periodic_timer",
|
||||
RT_TIMER_FLAG_PERIODIC,
|
||||
periodic_callback,
|
||||
RT_NULL);
|
||||
|
||||
/* Start with 200ms period */
|
||||
unsigned long period_cnt = (unsigned long)rt_clock_time_ms_to_cnt(200);
|
||||
rt_kprintf("Starting periodic timer (200ms period)...\n");
|
||||
|
||||
periodic_count = 0;
|
||||
rt_err_t result = rt_clock_hrtimer_start(&timer, period_cnt);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
rt_kprintf("Timer started successfully\n");
|
||||
}
|
||||
|
||||
/* Let it tick 5 times */
|
||||
rt_thread_mdelay(1100);
|
||||
|
||||
/* Stop and cleanup */
|
||||
rt_clock_hrtimer_stop(&timer);
|
||||
rt_clock_hrtimer_detach(&timer);
|
||||
|
||||
rt_kprintf("Timer stopped. Total ticks: %d\n", periodic_count);
|
||||
}
|
||||
MSH_CMD_EXPORT(clock_hrtimer_periodic_example, Demonstrate periodic hrtimer);
|
||||
|
||||
/**
|
||||
* @brief Example 7: Benchmark overhead
|
||||
*
|
||||
* Measures the overhead of various clock_time operations.
|
||||
*/
|
||||
static void clock_benchmark_example(void)
|
||||
{
|
||||
const int iterations = 1000;
|
||||
unsigned long start, end;
|
||||
int i;
|
||||
|
||||
rt_kprintf("\n=== Clock Time Benchmark ===\n");
|
||||
|
||||
/* Benchmark get_counter() */
|
||||
start = (unsigned long)rt_clock_time_getcnt();
|
||||
for (i = 0; i < iterations; i++)
|
||||
{
|
||||
volatile unsigned long cnt = (unsigned long)rt_clock_time_getcnt();
|
||||
(void)cnt;
|
||||
}
|
||||
end = (unsigned long)rt_clock_time_getcnt();
|
||||
rt_kprintf("get_counter() x%d: %u ns per call\n",
|
||||
iterations,
|
||||
(rt_uint32_t)(rt_clock_time_cnt_to_ns(end - start) / iterations));
|
||||
|
||||
/* Benchmark time conversion */
|
||||
start = (unsigned long)rt_clock_time_getcnt();
|
||||
for (i = 0; i < iterations; i++)
|
||||
{
|
||||
volatile rt_uint64_t us = rt_clock_time_cnt_to_us(1000);
|
||||
(void)us;
|
||||
}
|
||||
end = (unsigned long)rt_clock_time_getcnt();
|
||||
rt_kprintf("cnt_to_us() x%d: %u ns per call\n",
|
||||
iterations,
|
||||
(rt_uint32_t)(rt_clock_time_cnt_to_ns(end - start) / iterations));
|
||||
}
|
||||
MSH_CMD_EXPORT(clock_benchmark_example, Benchmark clock_time operations);
|
||||
|
||||
/**
|
||||
* @brief Run all examples
|
||||
*/
|
||||
static void clock_time_examples_all(void)
|
||||
{
|
||||
clock_time_info_example();
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
clock_boottime_example();
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
clock_conversion_example();
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
clock_delay_example();
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
clock_hrtimer_oneshot_example();
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
clock_hrtimer_periodic_example();
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
clock_benchmark_example();
|
||||
}
|
||||
MSH_CMD_EXPORT(clock_time_examples_all, Run all clock_time examples);
|
||||
|
||||
#else
|
||||
#warning "RT_USING_CLOCK_TIME is not enabled. Examples will not be compiled."
|
||||
#endif /* RT_USING_CLOCK_TIME */
|
||||
Reference in New Issue
Block a user