Skip to content

Commit ccdfed5

Browse files
committed
Moved ticker timer to a PIT channel + adjusted namings
The timer which creates interrupts is now also done using one of the PIT channels. Since also here no chaining is possible we still need to do some bits in software, but 32-bit without prescaling is still better than 16-bit with. Also some code was moved around and naming conventions changes, since no lptmr is used anymore, and calling both pit-timer would get confusing
1 parent ee658aa commit ccdfed5

File tree

1 file changed

+65
-110
lines changed
  • libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M

1 file changed

+65
-110
lines changed

libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c

Lines changed: 65 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,30 @@
1818
#include "PeripheralNames.h"
1919
#include "clk_freqs.h"
2020

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);
2328

2429

2530
static int us_ticker_inited = 0;
26-
static uint32_t pit_ldval = 0;
31+
static uint32_t clk_mhz;
2732

2833
void us_ticker_init(void) {
2934
if (us_ticker_inited)
3035
return;
3136
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;
3242

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();
4445
}
4546

4647
/******************************************************************************
@@ -50,20 +51,24 @@ void pit0_isr(void) {
5051
* to chain timers, which is why a software timer is required to get 32-bit
5152
* word length.
5253
******************************************************************************/
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+
}
6061

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);
6465

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);
6772
}
6873

6974
uint32_t us_ticker_read() {
@@ -72,14 +77,14 @@ uint32_t us_ticker_read() {
7277

7378
uint32_t retval;
7479
__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
7782

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);
8186
return us_ticker_read();
82-
}
87+
}
8388

8489
__enable_irq();
8590
return retval;
@@ -89,98 +94,44 @@ uint32_t us_ticker_read() {
8994
* Timer Event
9095
*
9196
* 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.
9499
******************************************************************************/
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);
103101

102+
static void ticker_init(void) {
104103
/* 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);
139106
}
140107

141108
void us_ticker_disable_interrupt(void) {
142-
LPTMR0->CSR &= ~LPTMR_CSR_TIE_MASK;
109+
PIT_TICKER.TCTRL &= ~PIT_TCTRL_TIE_MASK;
143110
}
144111

145112
void us_ticker_clear_interrupt(void) {
146113
// we already clear interrupt in lptmr_isr
147114
}
148115

149116
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;
158117

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;
164122
}
165123

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;
169127

170128
if (us_ticker_int_counter > 0) {
171-
lptmr_set(0xFFFF);
129+
ticker_set(0xFFFFFFFF);
172130
us_ticker_int_counter--;
173-
174131
} 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();
184135
}
185136
}
186137

@@ -192,13 +143,17 @@ void us_ticker_set_interrupt(unsigned int timestamp) {
192143
return;
193144
}
194145

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);
199155
us_ticker_int_counter--;
200156
} else {
201-
lptmr_set(us_ticker_int_remainder);
202-
us_ticker_int_remainder = 0;
157+
ticker_set(us_ticker_int_remainder);
203158
}
204159
}

0 commit comments

Comments
 (0)