18
18
#include "PeripheralNames.h"
19
19
#include "clk_freqs.h"
20
20
21
- static void pit_init (void );
22
- static void lptmr_init (void );
21
+ #define PIT_TIMER PIT->CHANNEL[0]
22
+ #define PIT_TIMER_IRQ PIT0_IRQn
23
+ #define PIT_TICKER PIT->CHANNEL[1]
24
+ #define PIT_TICKER_IRQ PIT1_IRQn
25
+
26
+ static void timer_init (void );
27
+ static void ticker_init (void );
23
28
24
29
25
30
static int us_ticker_inited = 0 ;
26
- static uint32_t pit_ldval = 0 ;
31
+ static uint32_t clk_mhz ;
27
32
28
33
void us_ticker_init (void ) {
29
34
if (us_ticker_inited )
30
35
return ;
31
36
us_ticker_inited = 1 ;
37
+
38
+ SIM -> SCGC6 |= SIM_SCGC6_PIT_MASK ; // Clock PIT
39
+ PIT -> MCR = 0 ; // Enable PIT
40
+
41
+ clk_mhz = bus_frequency () / 1000000 ;
32
42
33
- pit_init ();
34
- lptmr_init ();
35
- }
36
-
37
- static volatile uint32_t pit_msb_counter = 0 ;
38
- static uint32_t pit_division ; //Division used to get LSB bits
39
-
40
- void pit0_isr (void ) {
41
- pit_msb_counter ++ ;
42
- PIT -> CHANNEL [0 ].LDVAL = pit_ldval ;
43
- PIT -> CHANNEL [0 ].TFLG = 1 ;
43
+ timer_init ();
44
+ ticker_init ();
44
45
}
45
46
46
47
/******************************************************************************
@@ -50,20 +51,24 @@ void pit0_isr(void) {
50
51
* to chain timers, which is why a software timer is required to get 32-bit
51
52
* word length.
52
53
******************************************************************************/
53
- static void pit_init ( void ) {
54
- SIM -> SCGC6 |= SIM_SCGC6_PIT_MASK ; // Clock PIT
55
- PIT -> MCR = 0 ; // Enable PIT
56
-
57
- pit_division = bus_frequency () / 1000000 ;
58
- //CLZ counts the leading zeros, returning number of bits not used by pit_division
59
- pit_ldval = pit_division << __CLZ ( pit_division );
54
+ static volatile uint32_t msb_counter = 0 ;
55
+ static uint32_t timer_ldval = 0 ;
56
+
57
+ static void timer_isr ( void ) {
58
+ msb_counter ++ ;
59
+ PIT_TIMER . TFLG = 1 ;
60
+ }
60
61
61
- PIT -> CHANNEL [ 0 ]. LDVAL = pit_ldval ; // 1us
62
- PIT -> CHANNEL [ 0 ]. TCTRL |= PIT_TCTRL_TIE_MASK ;
63
- PIT -> CHANNEL [ 0 ]. TCTRL |= PIT_TCTRL_TEN_MASK ; // Start timer 1
62
+ static void timer_init ( void ) {
63
+ //CLZ counts the leading zeros, returning number of bits not used by clk_mhz
64
+ timer_ldval = clk_mhz << __CLZ ( clk_mhz );
64
65
65
- NVIC_SetVector (PIT0_IRQn , (uint32_t )pit0_isr );
66
- NVIC_EnableIRQ (PIT0_IRQn );
66
+ PIT_TIMER .LDVAL = timer_ldval ; // 1us
67
+ PIT_TIMER .TCTRL |= PIT_TCTRL_TIE_MASK ;
68
+ PIT_TIMER .TCTRL |= PIT_TCTRL_TEN_MASK ; // Start timer 0
69
+
70
+ NVIC_SetVector (PIT_TIMER_IRQ , (uint32_t )timer_isr );
71
+ NVIC_EnableIRQ (PIT_TIMER_IRQ );
67
72
}
68
73
69
74
uint32_t us_ticker_read () {
@@ -72,14 +77,14 @@ uint32_t us_ticker_read() {
72
77
73
78
uint32_t retval ;
74
79
__disable_irq ();
75
- retval = (pit_ldval - PIT -> CHANNEL [ 0 ] .CVAL ) / pit_division ; //Hardware bits
76
- retval |= pit_msb_counter << __CLZ (pit_division ); //Software bits
80
+ retval = (timer_ldval - PIT_TIMER .CVAL ) / clk_mhz ; //Hardware bits
81
+ retval |= msb_counter << __CLZ (clk_mhz ); //Software bits
77
82
78
- if (PIT -> CHANNEL [ 0 ] .TFLG == 1 ) { //If overflow bit is set, force it to be handled
79
- pit0_isr (); //Handle IRQ, read again to make sure software/hardware bits are synced
80
- NVIC_ClearPendingIRQ (PIT0_IRQn );
83
+ if (PIT_TIMER .TFLG == 1 ) { //If overflow bit is set, force it to be handled
84
+ timer_isr (); //Handle IRQ, read again to make sure software/hardware bits are synced
85
+ NVIC_ClearPendingIRQ (PIT_TIMER_IRQ );
81
86
return us_ticker_read ();
82
- }
87
+ }
83
88
84
89
__enable_irq ();
85
90
return retval ;
@@ -89,98 +94,44 @@ uint32_t us_ticker_read() {
89
94
* Timer Event
90
95
*
91
96
* It schedules interrupts at given (32bit)us interval of time.
92
- * It is implemented used the 16bit Low Power Timer that remains powered in all
93
- * power modes .
97
+ * It is implemented using PIT channel 1, since no prescaler is available,
98
+ * some bits are implemented in software .
94
99
******************************************************************************/
95
- static void lptmr_isr (void );
96
-
97
- static void lptmr_init (void ) {
98
- /* Clock the timer */
99
- SIM -> SCGC5 |= SIM_SCGC5_LPTIMER_MASK ;
100
-
101
- /* Reset */
102
- LPTMR0 -> CSR = 0 ;
100
+ static void ticker_isr (void );
103
101
102
+ static void ticker_init (void ) {
104
103
/* Set interrupt handler */
105
- NVIC_SetVector (LPTimer_IRQn , (uint32_t )lptmr_isr );
106
- NVIC_EnableIRQ (LPTimer_IRQn );
107
-
108
- /* Clock at (1)MHz -> (1)tick/us */
109
- /* Check if the external oscillator can be divided to 1MHz */
110
- uint32_t extosc = extosc_frequency ();
111
-
112
- if (extosc != 0 ) { //If external oscillator found
113
- OSC0 -> CR |= OSC_CR_ERCLKEN_MASK ;
114
- if (extosc % 1000000u == 0 ) { //If it is a multiple if 1MHz
115
- extosc /= 1000000 ;
116
- if (extosc == 1 ) { //1MHz, set timerprescaler in bypass mode
117
- LPTMR0 -> PSR = LPTMR_PSR_PCS (3 ) | LPTMR_PSR_PBYP_MASK ;
118
- return ;
119
- } else { //See if we can divide it to 1MHz
120
- uint32_t divider = 0 ;
121
- extosc >>= 1 ;
122
- while (1 ) {
123
- if (extosc == 1 ) {
124
- LPTMR0 -> PSR = LPTMR_PSR_PCS (3 ) | LPTMR_PSR_PRESCALE (divider );
125
- return ;
126
- }
127
- if (extosc % 2 != 0 ) //If we can't divide by two anymore
128
- break ;
129
- divider ++ ;
130
- extosc >>= 1 ;
131
- }
132
- }
133
- }
134
- }
135
- //No suitable external oscillator clock -> Use fast internal oscillator (4MHz)
136
- MCG -> C1 |= MCG_C1_IRCLKEN_MASK ;
137
- MCG -> C2 |= MCG_C2_IRCS_MASK ;
138
- LPTMR0 -> PSR = LPTMR_PSR_PCS (0 ) | LPTMR_PSR_PRESCALE (1 );
104
+ NVIC_SetVector (PIT_TICKER_IRQ , (uint32_t )ticker_isr );
105
+ NVIC_EnableIRQ (PIT_TICKER_IRQ );
139
106
}
140
107
141
108
void us_ticker_disable_interrupt (void ) {
142
- LPTMR0 -> CSR &= ~LPTMR_CSR_TIE_MASK ;
109
+ PIT_TICKER . TCTRL &= ~PIT_TCTRL_TIE_MASK ;
143
110
}
144
111
145
112
void us_ticker_clear_interrupt (void ) {
146
113
// we already clear interrupt in lptmr_isr
147
114
}
148
115
149
116
static uint32_t us_ticker_int_counter = 0 ;
150
- static uint16_t us_ticker_int_remainder = 0 ;
151
-
152
- static void lptmr_set (unsigned short count ) {
153
- /* Reset */
154
- LPTMR0 -> CSR = 0 ;
155
-
156
- /* Set the compare register */
157
- LPTMR0 -> CMR = count ;
158
117
159
- /* Enable interrupt */
160
- LPTMR0 -> CSR |= LPTMR_CSR_TIE_MASK ;
161
-
162
- /* Start the timer */
163
- LPTMR0 -> CSR |= LPTMR_CSR_TEN_MASK ;
118
+ inline static void ticker_set (uint32_t count ) {
119
+ PIT_TICKER .TCTRL = 0 ;
120
+ PIT_TICKER .LDVAL = count ;
121
+ PIT_TICKER .TCTRL = PIT_TCTRL_TIE_MASK | PIT_TCTRL_TEN_MASK ;
164
122
}
165
123
166
- static void lptmr_isr (void ) {
167
- // write 1 to TCF to clear the LPT timer compare flag
168
- LPTMR0 -> CSR |= LPTMR_CSR_TCF_MASK ;
124
+ static void ticker_isr (void ) {
125
+ // Clear IRQ flag
126
+ PIT_TICKER . TFLG = 1 ;
169
127
170
128
if (us_ticker_int_counter > 0 ) {
171
- lptmr_set ( 0xFFFF );
129
+ ticker_set ( 0xFFFFFFFF );
172
130
us_ticker_int_counter -- ;
173
-
174
131
} else {
175
- if (us_ticker_int_remainder > 0 ) {
176
- lptmr_set (us_ticker_int_remainder );
177
- us_ticker_int_remainder = 0 ;
178
-
179
- } else {
180
- // This function is going to disable the interrupts if there are
181
- // no other events in the queue
182
- us_ticker_irq_handler ();
183
- }
132
+ // This function is going to disable the interrupts if there are
133
+ // no other events in the queue
134
+ us_ticker_irq_handler ();
184
135
}
185
136
}
186
137
@@ -192,13 +143,17 @@ void us_ticker_set_interrupt(unsigned int timestamp) {
192
143
return ;
193
144
}
194
145
195
- us_ticker_int_counter = (uint32_t )(delta >> 16 );
196
- us_ticker_int_remainder = (uint16_t )(0xFFFF & delta );
197
- if (us_ticker_int_counter > 0 ) {
198
- lptmr_set (0xFFFF );
146
+ //Calculate how much falls outside the 32-bit after multiplying with clk_mhz
147
+ //We shift twice 16-bit to keep everything within the 32-bit variable
148
+ us_ticker_int_counter = (uint32_t )(delta >> 16 );
149
+ us_ticker_int_counter *= clk_mhz ;
150
+ us_ticker_int_counter >>= 16 ;
151
+
152
+ uint32_t us_ticker_int_remainder = (uint32_t )delta * clk_mhz ;
153
+ if (us_ticker_int_remainder == 0 ) {
154
+ ticker_set (0xFFFFFFFF );
199
155
us_ticker_int_counter -- ;
200
156
} else {
201
- lptmr_set (us_ticker_int_remainder );
202
- us_ticker_int_remainder = 0 ;
157
+ ticker_set (us_ticker_int_remainder );
203
158
}
204
159
}
0 commit comments