Merge branch 'feature/docs_update_timer_api' into 'master'

Timer API docs update, refactored example

See merge request !1316
This commit is contained in:
Angus Gratton
2017-10-27 13:31:18 +08:00
5 changed files with 270 additions and 186 deletions

View File

@@ -1,3 +1,33 @@
# Example: timer_group
This example uses the timer group driver to generate timer interrupts at two specified alarm intervals.
## Functionality Overview
* Two timers are configured
* Each timer is set with some sample alarm interval
* On reaching the interval value each timer will generate an alarm
* One of the timers is configured to automatically reload it's counter value on the alarm
* The other timer is configured to keep incrementing and is reloaded by the application each time the alarm happens
* Alarms trigger subsequent interrupts, that is tracked with messages printed on the terminal:
```
Example timer with auto reload
Group[0], timer[1] alarm event
------- EVENT TIME --------
Counter: 0x000000000000000a
Time : 0.00000200 s
-------- TASK TIME --------
Counter: 0x00000000000107ff
Time : 0.01351660 s
Example timer without reload
Group[0], timer[0] alarm event
------- EVENT TIME --------
Counter: 0x00000000092ae316
Time : 30.76111800 s
-------- TASK TIME --------
Counter: 0x00000000092bd535
Time : 30.77351460 s
```

View File

@@ -16,186 +16,159 @@
#include "driver/periph_ctrl.h"
#include "driver/timer.h"
#define TIMER_INTR_SEL TIMER_INTR_LEVEL /*!< Timer level interrupt */
#define TIMER_GROUP TIMER_GROUP_0 /*!< Test on timer group 0 */
#define TIMER_DIVIDER 16 /*!< Hardware timer clock divider */
#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) /*!< used to calculate counter value */
#define TIMER_FINE_ADJ (1.4*(TIMER_BASE_CLK / TIMER_DIVIDER)/1000000) /*!< used to compensate alarm value */
#define TIMER_INTERVAL0_SEC (3.4179) /*!< test interval for timer 0 */
#define TIMER_INTERVAL1_SEC (5.78) /*!< test interval for timer 1 */
#define TEST_WITHOUT_RELOAD 0 /*!< example of auto-reload mode */
#define TEST_WITH_RELOAD 1 /*!< example without auto-reload mode */
#define TIMER_DIVIDER 16 // Hardware timer clock divider
#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) // convert counter value to seconds
#define TIMER_INTERVAL0_SEC (3.4179) // sample test interval for the first timer
#define TIMER_INTERVAL1_SEC (5.78) // sample test interval for the second timer
#define TEST_WITHOUT_RELOAD 0 // testing will be done without auto reload
#define TEST_WITH_RELOAD 1 // testing will be done with auto reload
/*
* A sample structure to pass events
* from the timer interrupt handler to the main program.
*/
typedef struct {
int type; /*!< event type */
int group; /*!< timer group */
int idx; /*!< timer number */
uint64_t counter_val; /*!< timer counter value */
int type; // the type of timer's event
int timer_group;
int timer_idx;
uint64_t timer_counter_value;
} timer_event_t;
xQueueHandle timer_queue;
/*
* @brief Print a uint64_t value
* A simple helper function to print the raw timer counter value
* and the counter value converted to seconds
*/
static void inline print_u64(uint64_t val)
static void inline print_timer_counter(uint64_t counter_value)
{
printf("0x%08x%08x\n", (uint32_t) (val >> 32), (uint32_t) (val));
}
static void timer_example_evt_task(void *arg)
{
while(1) {
timer_event_t evt;
xQueueReceive(timer_queue, &evt, portMAX_DELAY);
if(evt.type == TEST_WITHOUT_RELOAD) {
printf("\n\n example of count-up-timer \n");
} else if(evt.type == TEST_WITH_RELOAD) {
printf("\n\n example of reload-timer \n");
}
/*Show timer event from interrupt*/
printf("-------INTR TIME EVT--------\n");
printf("TG[%d] timer[%d] alarm evt\n", evt.group, evt.idx);
printf("reg: ");
print_u64(evt.counter_val);
double time = (double) evt.counter_val / (TIMER_BASE_CLK / TIMERG0.hw_timer[evt.idx].config.divider);
printf("time: %.8f S\n", time);
/*Read timer value from task*/
printf("======TASK TIME======\n");
uint64_t timer_val;
timer_get_counter_value(evt.group, evt.idx, &timer_val);
timer_get_counter_time_sec(evt.group, evt.idx, &time);
printf("TG[%d] timer[%d] alarm evt\n", evt.group, evt.idx);
printf("reg: ");
print_u64(timer_val);
printf("time: %.8f S\n", time);
}
printf("Counter: 0x%08x%08x\n", (uint32_t) (counter_value >> 32),
(uint32_t) (counter_value));
printf("Time : %.8f s\n", (double) counter_value / TIMER_SCALE);
}
/*
* @brief timer group0 ISR handler
* Timer group0 ISR handler
*
* Note:
* We don't call the timer API here because they are not declared with IRAM_ATTR.
* If we're okay with the timer irq not being serviced while SPI flash cache is disabled,
* we can allocate this interrupt without the ESP_INTR_FLAG_IRAM flag and use the normal API.
*/
void IRAM_ATTR timer_group0_isr(void *para)
{
int timer_idx = (int) para;
/* Retrieve the interrupt status and the counter value
from the timer that reported the interrupt */
uint32_t intr_status = TIMERG0.int_st_timers.val;
TIMERG0.hw_timer[timer_idx].update = 1;
uint64_t timer_counter_value =
((uint64_t) TIMERG0.hw_timer[timer_idx].cnt_high) << 32
| TIMERG0.hw_timer[timer_idx].cnt_low;
/* Prepare basic event data
that will be then sent back to the main program task */
timer_event_t evt;
if((intr_status & BIT(timer_idx)) && timer_idx == TIMER_0) {
/*Timer0 is an example that doesn't reload counter value*/
TIMERG0.hw_timer[timer_idx].update = 1;
evt.timer_group = 0;
evt.timer_idx = timer_idx;
evt.timer_counter_value = timer_counter_value;
/* We don't call a API here because they are not declared with IRAM_ATTR.
If we're okay with the timer irq not being serviced while SPI flash cache is disabled,
we can alloc this interrupt without the ESP_INTR_FLAG_IRAM flag and use the normal API. */
TIMERG0.int_clr_timers.t0 = 1;
uint64_t timer_val = ((uint64_t) TIMERG0.hw_timer[timer_idx].cnt_high) << 32
| TIMERG0.hw_timer[timer_idx].cnt_low;
/*Post an event to out example task*/
/* Clear the interrupt
and update the alarm time for the timer with without reload */
if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_0) {
evt.type = TEST_WITHOUT_RELOAD;
evt.group = 0;
evt.idx = timer_idx;
evt.counter_val = timer_val;
xQueueSendFromISR(timer_queue, &evt, NULL);
/*For a timer that will not reload, we need to set the next alarm value each time. */
timer_val +=
(uint64_t) (TIMER_INTERVAL0_SEC * (TIMER_BASE_CLK / TIMERG0.hw_timer[timer_idx].config.divider));
/*Fine adjust*/
timer_val -= TIMER_FINE_ADJ;
TIMERG0.hw_timer[timer_idx].alarm_high = (uint32_t) (timer_val >> 32);
TIMERG0.hw_timer[timer_idx].alarm_low = (uint32_t) timer_val;
/*After set alarm, we set alarm_en bit if we want to enable alarm again.*/
TIMERG0.hw_timer[timer_idx].config.alarm_en = 1;
} else if((intr_status & BIT(timer_idx)) && timer_idx == TIMER_1) {
/*Timer1 is an example that will reload counter value*/
TIMERG0.hw_timer[timer_idx].update = 1;
/*We don't call a API here because they are not declared with IRAM_ATTR*/
TIMERG0.int_clr_timers.t1 = 1;
uint64_t timer_val = ((uint64_t) TIMERG0.hw_timer[timer_idx].cnt_high) << 32
| TIMERG0.hw_timer[timer_idx].cnt_low;
/*Post an event to out example task*/
TIMERG0.int_clr_timers.t0 = 1;
timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE);
TIMERG0.hw_timer[timer_idx].alarm_high = (uint32_t) (timer_counter_value >> 32);
TIMERG0.hw_timer[timer_idx].alarm_low = (uint32_t) timer_counter_value;
} else if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_1) {
evt.type = TEST_WITH_RELOAD;
evt.group = 0;
evt.idx = timer_idx;
evt.counter_val = timer_val;
xQueueSendFromISR(timer_queue, &evt, NULL);
/*For a auto-reload timer, we still need to set alarm_en bit if we want to enable alarm again.*/
TIMERG0.hw_timer[timer_idx].config.alarm_en = 1;
TIMERG0.int_clr_timers.t1 = 1;
} else {
evt.type = -1; // not supported even type
}
/* After the alarm has been triggered
we need enable it again, so it is triggered the next time */
TIMERG0.hw_timer[timer_idx].config.alarm_en = TIMER_ALARM_EN;
/* Now just send the event data back to the main program task */
xQueueSendFromISR(timer_queue, &evt, NULL);
}
/*
* Initialize selected timer of the timer group 0
*
* timer_idx - the timer number to initialize
* auto_reload - should the timer auto reload on alarm?
* timer_interval_sec - the interval of alarm to set
*/
static void example_tg0_timer_init(int timer_idx,
bool auto_reload, double timer_interval_sec)
{
/* Select and initialize basic parameters of the timer */
timer_config_t config;
config.divider = TIMER_DIVIDER;
config.counter_dir = TIMER_COUNT_UP;
config.counter_en = TIMER_PAUSE;
config.alarm_en = TIMER_ALARM_EN;
config.intr_type = TIMER_INTR_LEVEL;
config.auto_reload = auto_reload;
timer_init(TIMER_GROUP_0, timer_idx, &config);
/* Timer's counter will initially start from value below.
Also, if auto_reload is set, this value will be automatically reload on alarm */
timer_set_counter_value(TIMER_GROUP_0, timer_idx, 0x00000000ULL);
/* Configure the alarm value and the interrupt on alarm. */
timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE);
timer_enable_intr(TIMER_GROUP_0, timer_idx);
timer_isr_register(TIMER_GROUP_0, timer_idx, timer_group0_isr,
(void *) timer_idx, ESP_INTR_FLAG_IRAM, NULL);
timer_start(TIMER_GROUP_0, timer_idx);
}
/*
* The main task of this example program
*/
static void timer_example_evt_task(void *arg)
{
while (1) {
timer_event_t evt;
xQueueReceive(timer_queue, &evt, portMAX_DELAY);
/* Print information that the timer reported an event */
if (evt.type == TEST_WITHOUT_RELOAD) {
printf("\n Example timer without reload\n");
} else if (evt.type == TEST_WITH_RELOAD) {
printf("\n Example timer with auto reload\n");
} else {
printf("\n UNKNOWN EVENT TYPE\n");
}
printf("Group[%d], timer[%d] alarm event\n", evt.timer_group, evt.timer_idx);
/* Print the timer values passed by event */
printf("------- EVENT TIME --------\n");
print_timer_counter(evt.timer_counter_value);
/* Print the timer values as visible by this task */
printf("-------- TASK TIME --------\n");
uint64_t task_counter_value;
timer_get_counter_value(evt.timer_group, evt.timer_idx, &task_counter_value);
print_timer_counter(task_counter_value);
}
}
/*
* @brief timer group0 hardware timer0 init
*/
static void example_tg0_timer0_init()
{
int timer_group = TIMER_GROUP_0;
int timer_idx = TIMER_0;
timer_config_t config;
config.alarm_en = 1;
config.auto_reload = 0;
config.counter_dir = TIMER_COUNT_UP;
config.divider = TIMER_DIVIDER;
config.intr_type = TIMER_INTR_SEL;
config.counter_en = TIMER_PAUSE;
/*Configure timer*/
timer_init(timer_group, timer_idx, &config);
/*Stop timer counter*/
timer_pause(timer_group, timer_idx);
/*Load counter value */
timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL);
/*Set alarm value*/
timer_set_alarm_value(timer_group, timer_idx, TIMER_INTERVAL0_SEC * TIMER_SCALE - TIMER_FINE_ADJ);
/*Enable timer interrupt*/
timer_enable_intr(timer_group, timer_idx);
/*Set ISR handler*/
timer_isr_register(timer_group, timer_idx, timer_group0_isr, (void*) timer_idx, ESP_INTR_FLAG_IRAM, NULL);
/*Start timer counter*/
timer_start(timer_group, timer_idx);
}
/*
* @brief timer group0 hardware timer1 init
*/
static void example_tg0_timer1_init()
{
int timer_group = TIMER_GROUP_0;
int timer_idx = TIMER_1;
timer_config_t config;
config.alarm_en = 1;
config.auto_reload = 1;
config.counter_dir = TIMER_COUNT_UP;
config.divider = TIMER_DIVIDER;
config.intr_type = TIMER_INTR_SEL;
config.counter_en = TIMER_PAUSE;
/*Configure timer*/
timer_init(timer_group, timer_idx, &config);
/*Stop timer counter*/
timer_pause(timer_group, timer_idx);
/*Load counter value */
timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL);
/*Set alarm value*/
timer_set_alarm_value(timer_group, timer_idx, TIMER_INTERVAL1_SEC * TIMER_SCALE);
/*Enable timer interrupt*/
timer_enable_intr(timer_group, timer_idx);
/*Set ISR handler*/
timer_isr_register(timer_group, timer_idx, timer_group0_isr, (void*) timer_idx, ESP_INTR_FLAG_IRAM, NULL);
/*Start timer counter*/
timer_start(timer_group, timer_idx);
}
/**
* @brief In this test, we will test hardware timer0 and timer1 of timer group0.
* In this example, we will test hardware timer0 and timer1 of timer group0.
*/
void app_main()
{
timer_queue = xQueueCreate(10, sizeof(timer_event_t));
example_tg0_timer0_init();
example_tg0_timer1_init();
example_tg0_timer_init(TIMER_0, TEST_WITHOUT_RELOAD, TIMER_INTERVAL0_SEC);
example_tg0_timer_init(TIMER_1, TEST_WITH_RELOAD, TIMER_INTERVAL1_SEC);
xTaskCreate(timer_example_evt_task, "timer_evt_task", 2048, NULL, 5, NULL);
}