|
1 | 1 | /* mbed Microcontroller Library
|
2 |
| - * Copyright (c) 2006-2013 ARM Limited |
| 2 | + * Copyright (c) 2006-2018 ARM Limited |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
17 | 17 | #include "us_ticker_api.h"
|
18 | 18 | #include "PeripheralNames.h"
|
19 | 19 | #include "fsl_pit.h"
|
20 |
| -#include "fsl_lptmr.h" |
| 20 | +#include "fsl_tpm.h" |
21 | 21 | #include "fsl_clock_config.h"
|
22 | 22 |
|
23 |
| -static int us_ticker_inited = 0; |
24 |
| - |
25 |
| -static void lptmr_isr(void) |
| 23 | +const ticker_info_t* us_ticker_get_info() |
26 | 24 | {
|
27 |
| - LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag); |
28 |
| - LPTMR_StopTimer(LPTMR0); |
| 25 | + static const ticker_info_t info = { |
| 26 | + 3000000, |
| 27 | + 32 |
| 28 | + }; |
| 29 | + return &info; |
| 30 | +} |
| 31 | + |
| 32 | +static bool us_ticker_inited = false; |
29 | 33 |
|
30 |
| - us_ticker_irq_handler(); |
| 34 | +static uint32_t us_ticker_int_counter = 0; |
| 35 | +static uint16_t us_ticker_int_remainder = 0; |
| 36 | + |
| 37 | +static void tpm_isr(void) |
| 38 | +{ |
| 39 | + // Clear the TPM timer overflow flag |
| 40 | + TPM_ClearStatusFlags(TPM2, kTPM_TimeOverflowFlag); |
| 41 | + TPM_StopTimer(TPM2); |
| 42 | + |
| 43 | + if (us_ticker_int_counter > 0) { |
| 44 | + TPM2->MOD = 0xFFFF; |
| 45 | + TPM_StartTimer(TPM2, kTPM_SystemClock); |
| 46 | + us_ticker_int_counter--; |
| 47 | + } else { |
| 48 | + if (us_ticker_int_remainder > 0) { |
| 49 | + TPM2->MOD = us_ticker_int_remainder; |
| 50 | + TPM_StartTimer(TPM2, kTPM_SystemClock); |
| 51 | + us_ticker_int_remainder = 0; |
| 52 | + } else { |
| 53 | + // This function is going to disable the interrupts if there are |
| 54 | + // no other events in the queue |
| 55 | + us_ticker_irq_handler(); |
| 56 | + } |
| 57 | + } |
31 | 58 | }
|
32 | 59 |
|
33 | 60 | void us_ticker_init(void)
|
34 | 61 | {
|
| 62 | + /* Common for ticker/timer. */ |
| 63 | + uint32_t busClock; |
| 64 | + /* Structure to initialize PIT. */ |
| 65 | + pit_config_t pitConfig; |
| 66 | + |
35 | 67 | if (us_ticker_inited) {
|
| 68 | + /* calling init again should cancel current interrupt */ |
| 69 | + TPM_DisableInterrupts(TPM2, kTPM_TimeOverflowInterruptEnable); |
36 | 70 | return;
|
37 | 71 | }
|
38 |
| - us_ticker_inited = 1; |
39 |
| - |
40 |
| - //Timer uses PIT |
41 |
| - //Common for ticker/timer |
42 |
| - uint32_t busClock; |
43 |
| - |
44 |
| - // Structure to initialize PIT |
45 |
| - pit_config_t pitConfig; |
46 | 72 |
|
47 | 73 | PIT_GetDefaultConfig(&pitConfig);
|
48 | 74 | PIT_Init(PIT, &pitConfig);
|
49 | 75 |
|
50 | 76 | busClock = CLOCK_GetFreq(kCLOCK_BusClk);
|
51 | 77 |
|
52 |
| - PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, busClock / 1000000 - 1); |
| 78 | + PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, (busClock / 3000000) - 1); |
53 | 79 | PIT_SetTimerPeriod(PIT, kPIT_Chnl_1, 0xFFFFFFFF);
|
54 | 80 | PIT_SetTimerChainMode(PIT, kPIT_Chnl_1, true);
|
55 | 81 | PIT_StartTimer(PIT, kPIT_Chnl_0);
|
56 | 82 | PIT_StartTimer(PIT, kPIT_Chnl_1);
|
57 | 83 |
|
58 |
| - //Ticker uses LPTMR |
59 |
| - lptmr_config_t lptmrConfig; |
60 |
| - LPTMR_GetDefaultConfig(&lptmrConfig); |
61 |
| - lptmrConfig.prescalerClockSource = kLPTMR_PrescalerClock_0; |
62 |
| - LPTMR_Init(LPTMR0, &lptmrConfig); |
63 |
| - |
64 |
| - busClock = CLOCK_GetFreq(kCLOCK_McgInternalRefClk); |
65 |
| - LPTMR_SetTimerPeriod(LPTMR0, busClock / 1000000 - 1); |
66 |
| - /* Set interrupt handler */ |
67 |
| - NVIC_SetVector(LPTMR0_IRQn, (uint32_t)lptmr_isr); |
68 |
| - NVIC_EnableIRQ(LPTMR0_IRQn); |
| 84 | + /* Configure interrupt generation counters and disable ticker interrupts. */ |
| 85 | + tpm_config_t tpmConfig; |
| 86 | + |
| 87 | + TPM_GetDefaultConfig(&tpmConfig); |
| 88 | + /* Set to Div 16 to get 3MHz clock source for TPM */ |
| 89 | + tpmConfig.prescale = kTPM_Prescale_Divide_16; |
| 90 | + TPM_Init(TPM2, &tpmConfig); |
| 91 | + NVIC_SetVector(TPM2_IRQn, (uint32_t)tpm_isr); |
| 92 | + NVIC_EnableIRQ(TPM2_IRQn); |
| 93 | + |
| 94 | + us_ticker_inited = true; |
69 | 95 | }
|
70 | 96 |
|
71 | 97 |
|
72 | 98 | uint32_t us_ticker_read()
|
73 | 99 | {
|
74 |
| - if (!us_ticker_inited) { |
75 |
| - us_ticker_init(); |
76 |
| - } |
77 |
| - |
78 | 100 | return ~(PIT_GetCurrentTimerCount(PIT, kPIT_Chnl_1));
|
79 | 101 | }
|
80 | 102 |
|
81 | 103 | void us_ticker_disable_interrupt(void)
|
82 | 104 | {
|
83 |
| - LPTMR_DisableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable); |
| 105 | + TPM_DisableInterrupts(TPM2, kTPM_TimeOverflowInterruptEnable); |
84 | 106 | }
|
85 | 107 |
|
86 | 108 | void us_ticker_clear_interrupt(void)
|
87 | 109 | {
|
88 |
| - LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag); |
| 110 | + TPM_ClearStatusFlags(TPM2, kTPM_TimeOverflowFlag); |
89 | 111 | }
|
90 | 112 |
|
91 | 113 | void us_ticker_set_interrupt(timestamp_t timestamp)
|
92 | 114 | {
|
93 |
| - uint32_t now_us, delta_us; |
| 115 | + /* We get here absolute interrupt time which takes into account counter overflow. |
| 116 | + * Since we use additional count-down timer to generate interrupt we need to calculate |
| 117 | + * load value based on time-stamp. |
| 118 | + */ |
| 119 | + const uint32_t now_ticks = us_ticker_read(); |
| 120 | + uint32_t delta_ticks = |
| 121 | + timestamp >= now_ticks ? timestamp - now_ticks : (uint32_t)((uint64_t) timestamp + 0xFFFFFFFF - now_ticks); |
| 122 | + |
| 123 | + if (delta_ticks == 0) { |
| 124 | + /* The requested delay is less than the minimum resolution of this counter. */ |
| 125 | + delta_ticks = 1; |
| 126 | + } |
| 127 | + |
| 128 | + us_ticker_int_counter = (uint32_t)(delta_ticks >> 16); |
| 129 | + us_ticker_int_remainder = (uint16_t)(0xFFFF & delta_ticks); |
94 | 130 |
|
95 |
| - now_us = us_ticker_read(); |
96 |
| - delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us); |
| 131 | + TPM_StopTimer(TPM2); |
| 132 | + TPM2->CNT = 0; |
97 | 133 |
|
98 |
| - LPTMR_StopTimer(LPTMR0); |
99 |
| - LPTMR_SetTimerPeriod(LPTMR0, (uint32_t)delta_us); |
100 |
| - LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable); |
101 |
| - LPTMR_StartTimer(LPTMR0); |
| 134 | + if (us_ticker_int_counter > 0) { |
| 135 | + TPM2->MOD = 0xFFFF; |
| 136 | + us_ticker_int_counter--; |
| 137 | + } else { |
| 138 | + TPM2->MOD = us_ticker_int_remainder; |
| 139 | + us_ticker_int_remainder = 0; |
| 140 | + } |
| 141 | + |
| 142 | + /* Clear the count and set match value */ |
| 143 | + TPM_ClearStatusFlags(TPM2, kTPM_TimeOverflowFlag); |
| 144 | + TPM_EnableInterrupts(TPM2, kTPM_TimeOverflowInterruptEnable); |
| 145 | + TPM_StartTimer(TPM2, kTPM_SystemClock); |
102 | 146 | }
|
103 | 147 |
|
104 | 148 | void us_ticker_fire_interrupt(void)
|
105 | 149 | {
|
106 |
| - NVIC_SetPendingIRQ(LPTMR0_IRQn); |
| 150 | + us_ticker_int_counter = 0; |
| 151 | + us_ticker_int_remainder = 0; |
| 152 | + |
| 153 | + NVIC_SetPendingIRQ(TPM2_IRQn); |
107 | 154 | }
|
0 commit comments