1 /* General timer management.
3 * The tic55x has multiple 64-bit timers, we'll use timer0 and timer1.
5 * Since a timer can either be set to fire or continue to count,
6 * but not both, we'll need two timers:
8 * - timer0 counts until the next time-based interrupt
9 * - timer1 counts the time since the system started
11 * The reason for assigning the timers like this? timer0 has a higher
12 * interrupt level than, say, uart. That helps to get more accuracy
13 * from a realtime system.
15 * The tic55x timers are 64-bit, and can be split in two halves.
17 * The first half (CNT4:CNT3 and PRD4:PRD3) is used as a prescale-counter,
18 * to reduce the crystal clock frequency to a 1 ms pace. This is chained
19 * to the second half (CNT2:CNT1), which then forms the actual timer used
20 * by the 0cpm firmerware.
22 * The actual 2:1 timer1 is a 32-bit counter that counts round and round
23 * in circles, without ever causing an interrupt. The actual 2:1 timer0
24 * is set to the next interrupt time, and causes an interrupt when it is
25 * reached. This setting is based on the requested interrupt time and
26 * the value in timer1 at the time of the request.
28 * The top half takes care of setting up timer queues to implement a more
29 * general timing discipline, processing interrupts at such timeouts.
32 * From: Rick van Rein <rick@openfortress.nl>
44 #include <0cpm/timer.h>
47 /* Global variables */
49 static timing_t current_timer = 0;
52 /* Read the current time from timer1's top part. Be careful about
53 * timer increments between the two word reads.
55 * The tic55x copies timer registers to shadow registers to ensure
56 * that all values are in sync; the code need not verify that.
58 timing_t bottom_time (void) {
59 uint16_t cnt1 = GPTCNT1_1;
60 uint16_t cnt2 = GPTCNT2_1;
61 return (((timing_t) cnt2) << 16) | ((timing_t) cnt1);
65 /* Setup a new timing for the following timer interrupt. If one is
66 * currently underway, disable it so it will not spark new interrupts
67 * after this function returns.
69 timing_t bottom_timer_set (timing_t tim) {
70 timing_t intval, previous;
71 /* First of all, reset timer0 so it can be configured */
72 GPTGCTL1_0 &= ~ ( REGVAL_GCTL_TIM12RS | REGVAL_GCTL_TIM34RS );
73 IFR0 = (1 << REGBIT_IER0_TINT0);
74 previous = current_timer;
76 /* Poll the running timer1 */
77 // tim = bottom_time () + TIME_MSEC(1500);
78 intval = tim - bottom_time ();
79 // intval = intval & 0x0000ffff;
80 if ((intval == 0) || (intval >> 31)) {
81 /* Cause interrupt right now, do not run the timer */
82 top_timer_expiration (tim);
84 bottom_led_set (0, 1);
85 { uint32_t ctr = 6500000; while (ctr > 0) ctr--; }
86 bottom_led_set (0, 0);
87 { uint32_t ctr = 6500000; while (ctr > 0) ctr--; }
90 /* Setup counter value and period */
91 GPTCNT3_0 = GPTCNT3_1; /* also copies GPTCNT4_1 to shadow register */
92 GPTCNT4_0 = GPTCNT4_1; /* retrieve shadow register for GPTCNT4_1 */
95 GPTPRD2_0 = (uint16_t) (intval >> 16 );
96 GPTPRD1_0 = (uint16_t) intval ; //(intval & 0xffff);
97 /* Finally, enable timer1 so it can cause interrupts */
98 GPTGCTL1_0 |= REGVAL_GCTL_TIM12RS | REGVAL_GCTL_TIM34RS;
99 bottom_led_set (0, 1);
100 { uint32_t ctr = 650000; while (ctr > 0) ctr--; }
101 bottom_led_set (0, 0);
102 { uint32_t ctr = 650000; while (ctr > 0) ctr--; }
107 /* Timer interrupt handler for timer0 expiration */
108 interrupt void tic55x_tint0_isr (void) {
110 extern bool tic55x_top_has_been_interrupted;
111 timing_t now = bottom_time ();
113 top_timer_expiration (now);
114 tic55x_top_has_been_interrupted = true;
119 /* Setup timers and the corresponding interrupts for timer0/timer1
121 void tic55x_setup_timers (void) {
122 /* Be sure that the timers are reset, so they can be configured */
125 /* Let the lower half of timer0/timer1 count once per ms */
127 GPTPRD4_1 = (uint16_t) ((SYSCLK1_TO_MS_DIVIDER-1) >> 16);
129 GPTPRD3_1 = (uint16_t) ((SYSCLK1_TO_MS_DIVIDER-1) & 0xffff);
130 /* Let the upper half of timer1 count with a 2^32 period */
133 /* Let timer1 run entirely free; let timer0 lower half run free */
134 GPTCTL1_0 = REGVAL_CTL12_ENAMODE_ONETIME;
135 GPTCTL1_1 = REGVAL_CTL12_ENAMODE_CONTINUOUS;
136 GPTGCTL1_0 = REGVAL_GCTL_TIMMODE_DUAL32CHAINED;
137 GPTGCTL1_1 = REGVAL_GCTL_TIMMODE_DUAL32CHAINED | REGVAL_GCTL_TIM12RS | REGVAL_GCTL_TIM34RS;
138 /* Clear, then permit interrupts from timer0 */
139 IFR0 = (1 << REGBIT_IER0_TINT0);