General-Purpose Timer (TIMER)¶
1. Introduction¶
- The TIMER is a 32‑bit decrementing counter with a configurable prescaler and multiple counting modes. When the counter reaches 0, a timer event is triggered. It is typically used to repeatedly trigger events at specific intervals, serving as a periodic interrupt generator or event counter.
- CI13XX supports four dedicated timers: TIMER0~TIMER3. Timer cascading is supported. PWM4 and PWM5 can also be used as AON timers.
2. Features¶
- Three counting modes configurable via
timer_init/timer_set_mode: one‑shot, auto‑reload, and free‑running. - One‑shot: counts a single period once.
- Auto‑reload: reinitializes the counter at the end of each period.
- Free‑running: rolls over from 0xFFFFFFFF to 0x00000000 continuously.
- Clock prescaler supports ÷½/4/16 via
timer_init. - 32‑bit decrementing counter with live value readable via
timer_get_count. - Cascade mode configurable via
timer_cascade_set. - Interrupt on count completion; see
timer_clear_irqfor clearing behavior.
3. API List¶
| Function Name | Description |
|---|---|
| timer_init | Initialize TIMER device |
| timer_start | Start TIMER device |
| timer_stop | Stop TIMER device |
| timer_set_mode | Set TIMER counting mode |
| timer_event_start | Start event counting |
| timer_set_count | Set TIMER period |
| timer_get_count | Get current counter value |
| timer_cascade_set | Configure cascade mode |
| timer_clear_irq | Clear TIMER interrupt |
4. TIMER Details¶
| TIMER Name | IRQ Name | ISR | Notes |
|---|---|---|---|
| TIMER0 | TIMER0_IRQn | TIMER0_IRQHandler | |
| TIMER1 | TIMER1_IRQn | TIMER1_IRQHandler | |
| TIMER2 | TIMER2_IRQn | TIMER2_IRQHandler | |
| TIMER3 | TIMER3_IRQn | TIMER3_IRQHandler | |
| AON_TIMER0 | AON_TIM_INT0_IRQn | AON_TIM_INT0_IRQHandler | HAL_PWM4_BASE can be used as AON_TIMER0 |
| AON_TIMER1 | AON_TIM_INT1_IRQn | AON_TIM_INT0_IRQHandler | HAL_PWM5_BASE can be used as AON_TIMER1 |
5. Examples¶
The TIMER interrupt service routines are wake‑type and can be defined anywhere:
#include "ci130x_timer.h"
#include "ci_log.h"
// TIMER0 interrupt service routine definition
void TIMER0_IRQHandler(void)
{
mprintf("timer0 irq\n");
timer_clear_irq(TIMER0);
}
// TIMER1 ISR similar to TIMER0
// TIMER2 ISR similar to TIMER0
// TIMER3 ISR similar to TIMER0
// AON_TIMER0 ISR similar to TIMER0
// AON_TIMER1 ISR similar to TIMER0
Note
When the interrupt width is configured as timer_iqr_width_f, if the interrupt is enabled, you must call timer_clear_irq to clear it. For other interrupt widths, hardware auto‑clears the interrupt.
The following configures and starts TIMER0. Passing 1 means a timer interrupt every 1 second:
#include "ci130x_time.h"
#include "ci130x_timer.h"
#include "ci130x_core_eclic.h"
void timer_s(uint32_t s)
{
/* TIMER0 controller clock configuration */
scu_set_device_gate(HAL_TIMER0_BASE,ENABLE);
/* Enable TIMER0 interrupt */
eclic_irq_enable(TIMER0_IRQn);
/* TIMER0 initialization */
timer_init_t init;
init.mode = timer_count_mode_auto; // Auto‑reload mode
init.div = timer_clk_div_0; // No prescaling
init.width = timer_iqr_width_f; // Requires timer_clear_irq to clear
init.count = get_apb_clk() * s; // Count for s seconds
timer_init(TIMER0,init);
/* Start TIMER0 */
timer_start(TIMER0);
}
The following configures and starts TIMER0. Passing 1 means an interrupt every 1 ms:
#include "ci130x_time.h"
#include "ci130x_timer.h"
#include "ci130x_core_eclic.h"
void timer_ms(uint32_t ms)
{
/* TIMER0 controller clock configuration */
scu_set_device_gate(HAL_TIMER0_BASE,ENABLE);
/* Enable TIMER0 interrupt */
eclic_irq_enable(TIMER0_IRQn);
/* TIMER0 initialization */
timer_init_t init;
init.mode = timer_count_mode_auto; // Auto‑reload mode
init.div = timer_clk_div_0; // No prescaling
init.width = timer_iqr_width_f; // Requires timer_clear_irq to clear
init.count = (get_apb_clk() / 1000) * ms; // Count for ms milliseconds
timer_init(TIMER0,init);
/* Start TIMER0 */
timer_start(TIMER0);
}
The following configures and starts TIMER0. Passing 1 means an interrupt every 1 µs:
#include "ci130x_time.h"
#include "ci130x_timer.h"
#include "ci130x_core_eclic.h"
void timer_us(uint32_t us)
{
/* TIMER0 controller clock configuration */
scu_set_device_gate(HAL_TIMER0_BASE,ENABLE);
/* Enable TIMER0 interrupt */
eclic_irq_enable(TIMER0_IRQn);
/* TIMER0 initialization */
timer_init_t init;
init.mode = timer_count_mode_auto; // Auto‑reload mode
init.div = timer_clk_div_0; // No prescaling
init.width = timer_iqr_width_f; // Requires timer_clear_irq to clear
init.count = (get_apb_clk() / 1000000) * us; // Count for us microseconds
timer_init(TIMER0,init);
/* Start TIMER0 */
timer_start(TIMER0);
}
Warning
CI13XX integrates 32‑bit counters with range 0x00000000 to 0xFFFFFFFF. For longer timing, use prescaling or cascade mode.
6. FAQs¶
- TIMER timing range (base clock CLK_S = 120000000 Hz)
Prescaler: DIV (valid values: 1, 2, 4, 16)
Counting clock: CLK = CLK_S / DIV (Hz)
Minimum period: MIN = 1 s / CLK (seconds)
Maximum period: MAX = 0xFFFFFFFF × MIN (seconds)
With the above, the maximum period is around 9 minutes. For longer periods, use timer cascade mode as described below:
TODO:
| Base Timer | Cascade Timer |
|---|---|
| TIMER0 | TIMER1\2\3 |
| TIMER1 | TIMER2\3 |
| TIMER2 | TIMER3 |
| AON_TIMER0 | AON_TIMER1 |
Example: Set TIMER0 as the base timer with prescaler = 16 (to maximize period). Configure TIMER½/3 in cascade with max counts (0xFFFFFFFF). Then each timer’s period is approximately:
| Timer | Period |
|---|---|
| TIMER0 | ~13 minutes |
| TIMER1 | 0xFFFFFFFF × ~13 minutes |
| TIMER2 | 0xFFFFFFFF × 0xFFFFFFFF × ~13 minutes |
| TIMER3 | 0xFFFFFFFF × 0xFFFFFFFF × 0xFFFFFFFF × ~13 minutes |
| AON_TIMER0 | ~13 minutes |
| AON_TIMER1 | 0xFFFFFFFF × ~13 minutes |