added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Committer:
<>
Date:
Fri Sep 02 15:07:44 2016 +0100
Revision:
144:ef7eb2e8f9f7
This updates the lib to the mbed lib v125

Who changed what in which revision?

UserRevisionLine numberNew contents of line
<> 144:ef7eb2e8f9f7 1 /* mbed Microcontroller Library
<> 144:ef7eb2e8f9f7 2 * Copyright (c) 2015-2016 Nuvoton
<> 144:ef7eb2e8f9f7 3 *
<> 144:ef7eb2e8f9f7 4 * Licensed under the Apache License, Version 2.0 (the "License");
<> 144:ef7eb2e8f9f7 5 * you may not use this file except in compliance with the License.
<> 144:ef7eb2e8f9f7 6 * You may obtain a copy of the License at
<> 144:ef7eb2e8f9f7 7 *
<> 144:ef7eb2e8f9f7 8 * http://www.apache.org/licenses/LICENSE-2.0
<> 144:ef7eb2e8f9f7 9 *
<> 144:ef7eb2e8f9f7 10 * Unless required by applicable law or agreed to in writing, software
<> 144:ef7eb2e8f9f7 11 * distributed under the License is distributed on an "AS IS" BASIS,
<> 144:ef7eb2e8f9f7 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<> 144:ef7eb2e8f9f7 13 * See the License for the specific language governing permissions and
<> 144:ef7eb2e8f9f7 14 * limitations under the License.
<> 144:ef7eb2e8f9f7 15 */
<> 144:ef7eb2e8f9f7 16
<> 144:ef7eb2e8f9f7 17 #include "lp_ticker_api.h"
<> 144:ef7eb2e8f9f7 18
<> 144:ef7eb2e8f9f7 19 #if DEVICE_LOWPOWERTIMER
<> 144:ef7eb2e8f9f7 20
<> 144:ef7eb2e8f9f7 21 #include "sleep_api.h"
<> 144:ef7eb2e8f9f7 22 #include "nu_modutil.h"
<> 144:ef7eb2e8f9f7 23 #include "nu_miscutil.h"
<> 144:ef7eb2e8f9f7 24 #include "critical.h"
<> 144:ef7eb2e8f9f7 25
<> 144:ef7eb2e8f9f7 26 // lp_ticker tick = us = timestamp
<> 144:ef7eb2e8f9f7 27 // clock of timer peripheral = ms
<> 144:ef7eb2e8f9f7 28 #define US_PER_TICK (1)
<> 144:ef7eb2e8f9f7 29
<> 144:ef7eb2e8f9f7 30 #define MS_PER_TMR2_INT (1000 * 10)
<> 144:ef7eb2e8f9f7 31 #define TMR2_FIRE_FREQ (1000 / MS_PER_TMR2_INT)
<> 144:ef7eb2e8f9f7 32 #define MS_PER_TMR2_CLK 1
<> 144:ef7eb2e8f9f7 33 #define TMR2_CLK_FREQ (1000 / MS_PER_TMR2_CLK)
<> 144:ef7eb2e8f9f7 34
<> 144:ef7eb2e8f9f7 35 #define MS_PER_TMR3_CLK 1
<> 144:ef7eb2e8f9f7 36 #define TMR3_CLK_FREQ (1000 / MS_PER_TMR3_CLK)
<> 144:ef7eb2e8f9f7 37
<> 144:ef7eb2e8f9f7 38 static void tmr2_vec(void);
<> 144:ef7eb2e8f9f7 39 static void tmr3_vec(void);
<> 144:ef7eb2e8f9f7 40 static void lp_ticker_arm_cd(void);
<> 144:ef7eb2e8f9f7 41
<> 144:ef7eb2e8f9f7 42 static int lp_ticker_inited = 0;
<> 144:ef7eb2e8f9f7 43 static volatile uint32_t counter_major = 0;
<> 144:ef7eb2e8f9f7 44 static volatile int cd_major_minor_ms = 0;
<> 144:ef7eb2e8f9f7 45 static volatile int cd_minor_ms = 0;
<> 144:ef7eb2e8f9f7 46 static volatile uint32_t wakeup_tick = (uint32_t) -1;
<> 144:ef7eb2e8f9f7 47
<> 144:ef7eb2e8f9f7 48 // NOTE: To wake the system from power down mode, timer clock source must be ether LXT or LIRC.
<> 144:ef7eb2e8f9f7 49 // NOTE: TIMER_2 for normal counting and TIMER_3 for scheduled wakeup
<> 144:ef7eb2e8f9f7 50 static const struct nu_modinit_s timer2_modinit = {TIMER_2, TMR2_MODULE, CLK_CLKSEL1_TMR2SEL_LXT, 0, TMR2_RST, TMR2_IRQn, (void *) tmr2_vec};
<> 144:ef7eb2e8f9f7 51 static const struct nu_modinit_s timer3_modinit = {TIMER_3, TMR3_MODULE, CLK_CLKSEL1_TMR3SEL_LXT, 0, TMR3_RST, TMR3_IRQn, (void *) tmr3_vec};
<> 144:ef7eb2e8f9f7 52
<> 144:ef7eb2e8f9f7 53 #define TMR_CMP_MIN 2
<> 144:ef7eb2e8f9f7 54 #define TMR_CMP_MAX 0xFFFFFFu
<> 144:ef7eb2e8f9f7 55
<> 144:ef7eb2e8f9f7 56 void lp_ticker_init(void)
<> 144:ef7eb2e8f9f7 57 {
<> 144:ef7eb2e8f9f7 58 if (lp_ticker_inited) {
<> 144:ef7eb2e8f9f7 59 return;
<> 144:ef7eb2e8f9f7 60 }
<> 144:ef7eb2e8f9f7 61 lp_ticker_inited = 1;
<> 144:ef7eb2e8f9f7 62
<> 144:ef7eb2e8f9f7 63 counter_major = 0;
<> 144:ef7eb2e8f9f7 64 cd_major_minor_ms = 0;
<> 144:ef7eb2e8f9f7 65 cd_minor_ms = 0;
<> 144:ef7eb2e8f9f7 66 wakeup_tick = (uint32_t) -1;
<> 144:ef7eb2e8f9f7 67
<> 144:ef7eb2e8f9f7 68 // Reset module
<> 144:ef7eb2e8f9f7 69 SYS_ResetModule(timer2_modinit.rsetidx);
<> 144:ef7eb2e8f9f7 70 SYS_ResetModule(timer3_modinit.rsetidx);
<> 144:ef7eb2e8f9f7 71
<> 144:ef7eb2e8f9f7 72 // Select IP clock source
<> 144:ef7eb2e8f9f7 73 CLK_SetModuleClock(timer2_modinit.clkidx, timer2_modinit.clksrc, timer2_modinit.clkdiv);
<> 144:ef7eb2e8f9f7 74 CLK_SetModuleClock(timer3_modinit.clkidx, timer3_modinit.clksrc, timer3_modinit.clkdiv);
<> 144:ef7eb2e8f9f7 75 // Enable IP clock
<> 144:ef7eb2e8f9f7 76 CLK_EnableModuleClock(timer2_modinit.clkidx);
<> 144:ef7eb2e8f9f7 77 CLK_EnableModuleClock(timer3_modinit.clkidx);
<> 144:ef7eb2e8f9f7 78
<> 144:ef7eb2e8f9f7 79 // Configure clock
<> 144:ef7eb2e8f9f7 80 uint32_t clk_timer2 = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
<> 144:ef7eb2e8f9f7 81 uint32_t prescale_timer2 = clk_timer2 / TMR2_CLK_FREQ - 1;
<> 144:ef7eb2e8f9f7 82 MBED_ASSERT((prescale_timer2 != (uint32_t) -1) && prescale_timer2 <= 127);
<> 144:ef7eb2e8f9f7 83 uint32_t cmp_timer2 = MS_PER_TMR2_INT / MS_PER_TMR2_CLK;
<> 144:ef7eb2e8f9f7 84 MBED_ASSERT(cmp_timer2 >= TMR_CMP_MIN && cmp_timer2 <= TMR_CMP_MAX);
<> 144:ef7eb2e8f9f7 85 // Continuous mode
<> 144:ef7eb2e8f9f7 86 ((TIMER_T *) NU_MODBASE(timer2_modinit.modname))->CTL = TIMER_PERIODIC_MODE | prescale_timer2 | TIMER_CTL_CNTDATEN_Msk;
<> 144:ef7eb2e8f9f7 87 ((TIMER_T *) NU_MODBASE(timer2_modinit.modname))->CMP = cmp_timer2;
<> 144:ef7eb2e8f9f7 88
<> 144:ef7eb2e8f9f7 89 // Set vector
<> 144:ef7eb2e8f9f7 90 NVIC_SetVector(timer2_modinit.irq_n, (uint32_t) timer2_modinit.var);
<> 144:ef7eb2e8f9f7 91 NVIC_SetVector(timer3_modinit.irq_n, (uint32_t) timer3_modinit.var);
<> 144:ef7eb2e8f9f7 92
<> 144:ef7eb2e8f9f7 93 NVIC_EnableIRQ(timer2_modinit.irq_n);
<> 144:ef7eb2e8f9f7 94 NVIC_EnableIRQ(timer3_modinit.irq_n);
<> 144:ef7eb2e8f9f7 95
<> 144:ef7eb2e8f9f7 96 TIMER_EnableInt((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
<> 144:ef7eb2e8f9f7 97 TIMER_EnableWakeup((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
<> 144:ef7eb2e8f9f7 98
<> 144:ef7eb2e8f9f7 99 // Schedule wakeup to match semantics of lp_ticker_get_compare_match()
<> 144:ef7eb2e8f9f7 100 lp_ticker_set_interrupt(wakeup_tick);
<> 144:ef7eb2e8f9f7 101
<> 144:ef7eb2e8f9f7 102 // Start timer
<> 144:ef7eb2e8f9f7 103 TIMER_Start((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
<> 144:ef7eb2e8f9f7 104 }
<> 144:ef7eb2e8f9f7 105
<> 144:ef7eb2e8f9f7 106 timestamp_t lp_ticker_read()
<> 144:ef7eb2e8f9f7 107 {
<> 144:ef7eb2e8f9f7 108 if (! lp_ticker_inited) {
<> 144:ef7eb2e8f9f7 109 lp_ticker_init();
<> 144:ef7eb2e8f9f7 110 }
<> 144:ef7eb2e8f9f7 111
<> 144:ef7eb2e8f9f7 112 TIMER_T * timer2_base = (TIMER_T *) NU_MODBASE(timer2_modinit.modname);
<> 144:ef7eb2e8f9f7 113
<> 144:ef7eb2e8f9f7 114 do {
<> 144:ef7eb2e8f9f7 115 uint64_t major_minor_ms;
<> 144:ef7eb2e8f9f7 116 uint32_t minor_ms;
<> 144:ef7eb2e8f9f7 117
<> 144:ef7eb2e8f9f7 118 // NOTE: As TIMER_CNT = TIMER_CMP and counter_major has increased by one, TIMER_CNT doesn't change to 0 for one tick time.
<> 144:ef7eb2e8f9f7 119 // NOTE: As TIMER_CNT = TIMER_CMP or TIMER_CNT = 0, counter_major (ISR) may not sync with TIMER_CNT. So skip and fetch stable one at the cost of 1 clock delay on this read.
<> 144:ef7eb2e8f9f7 120 do {
<> 144:ef7eb2e8f9f7 121 core_util_critical_section_enter();
<> 144:ef7eb2e8f9f7 122
<> 144:ef7eb2e8f9f7 123 // NOTE: Order of reading minor_us/carry here is significant.
<> 144:ef7eb2e8f9f7 124 minor_ms = TIMER_GetCounter(timer2_base) * MS_PER_TMR2_CLK;
<> 144:ef7eb2e8f9f7 125 uint32_t carry = (timer2_base->INTSTS & TIMER_INTSTS_TIF_Msk) ? 1 : 0;
<> 144:ef7eb2e8f9f7 126 // When TIMER_CNT approaches TIMER_CMP and will wrap soon, we may get carry but TIMER_CNT not wrapped. Hanlde carefully carry == 1 && TIMER_CNT is near TIMER_CMP.
<> 144:ef7eb2e8f9f7 127 if (carry && minor_ms > (MS_PER_TMR2_INT / 2)) {
<> 144:ef7eb2e8f9f7 128 major_minor_ms = (counter_major + 1) * MS_PER_TMR2_INT;
<> 144:ef7eb2e8f9f7 129 }
<> 144:ef7eb2e8f9f7 130 else {
<> 144:ef7eb2e8f9f7 131 major_minor_ms = (counter_major + carry) * MS_PER_TMR2_INT + minor_ms;
<> 144:ef7eb2e8f9f7 132 }
<> 144:ef7eb2e8f9f7 133
<> 144:ef7eb2e8f9f7 134 core_util_critical_section_exit();
<> 144:ef7eb2e8f9f7 135 }
<> 144:ef7eb2e8f9f7 136 while (minor_ms == 0 || minor_ms == MS_PER_TMR2_INT);
<> 144:ef7eb2e8f9f7 137
<> 144:ef7eb2e8f9f7 138 // Add power-down compensation
<> 144:ef7eb2e8f9f7 139 return (major_minor_ms * 1000 / US_PER_TICK);
<> 144:ef7eb2e8f9f7 140 }
<> 144:ef7eb2e8f9f7 141 while (0);
<> 144:ef7eb2e8f9f7 142 }
<> 144:ef7eb2e8f9f7 143
<> 144:ef7eb2e8f9f7 144 void lp_ticker_set_interrupt(timestamp_t timestamp)
<> 144:ef7eb2e8f9f7 145 {
<> 144:ef7eb2e8f9f7 146 uint32_t now = lp_ticker_read();
<> 144:ef7eb2e8f9f7 147 wakeup_tick = timestamp;
<> 144:ef7eb2e8f9f7 148
<> 144:ef7eb2e8f9f7 149 TIMER_Stop((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
<> 144:ef7eb2e8f9f7 150
<> 144:ef7eb2e8f9f7 151 int delta = (timestamp > now) ? (timestamp - now) : (uint32_t) ((uint64_t) timestamp + 0xFFFFFFFFu - now);
<> 144:ef7eb2e8f9f7 152 // NOTE: If this event was in the past, arm an interrupt to be triggered immediately.
<> 144:ef7eb2e8f9f7 153 cd_major_minor_ms = delta * US_PER_TICK / 1000;
<> 144:ef7eb2e8f9f7 154
<> 144:ef7eb2e8f9f7 155 lp_ticker_arm_cd();
<> 144:ef7eb2e8f9f7 156 }
<> 144:ef7eb2e8f9f7 157
<> 144:ef7eb2e8f9f7 158 void lp_ticker_disable_interrupt(void)
<> 144:ef7eb2e8f9f7 159 {
<> 144:ef7eb2e8f9f7 160 TIMER_DisableInt((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
<> 144:ef7eb2e8f9f7 161 }
<> 144:ef7eb2e8f9f7 162
<> 144:ef7eb2e8f9f7 163 void lp_ticker_clear_interrupt(void)
<> 144:ef7eb2e8f9f7 164 {
<> 144:ef7eb2e8f9f7 165 TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
<> 144:ef7eb2e8f9f7 166 }
<> 144:ef7eb2e8f9f7 167
<> 144:ef7eb2e8f9f7 168 static void tmr2_vec(void)
<> 144:ef7eb2e8f9f7 169 {
<> 144:ef7eb2e8f9f7 170 TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
<> 144:ef7eb2e8f9f7 171 TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(timer2_modinit.modname));
<> 144:ef7eb2e8f9f7 172 counter_major ++;
<> 144:ef7eb2e8f9f7 173 }
<> 144:ef7eb2e8f9f7 174
<> 144:ef7eb2e8f9f7 175 static void tmr3_vec(void)
<> 144:ef7eb2e8f9f7 176 {
<> 144:ef7eb2e8f9f7 177 TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
<> 144:ef7eb2e8f9f7 178 TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
<> 144:ef7eb2e8f9f7 179 cd_major_minor_ms -= cd_minor_ms;
<> 144:ef7eb2e8f9f7 180 if (cd_major_minor_ms > 0) {
<> 144:ef7eb2e8f9f7 181 lp_ticker_arm_cd();
<> 144:ef7eb2e8f9f7 182 }
<> 144:ef7eb2e8f9f7 183 }
<> 144:ef7eb2e8f9f7 184
<> 144:ef7eb2e8f9f7 185 static void lp_ticker_arm_cd(void)
<> 144:ef7eb2e8f9f7 186 {
<> 144:ef7eb2e8f9f7 187 TIMER_T * timer3_base = (TIMER_T *) NU_MODBASE(timer3_modinit.modname);
<> 144:ef7eb2e8f9f7 188
<> 144:ef7eb2e8f9f7 189 // Reset 8-bit PSC counter, 24-bit up counter value and CNTEN bit
<> 144:ef7eb2e8f9f7 190 timer3_base->CTL |= TIMER_CTL_RSTCNT_Msk;
<> 144:ef7eb2e8f9f7 191 // One-shot mode, Clock = 1 KHz
<> 144:ef7eb2e8f9f7 192 uint32_t clk_timer3 = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
<> 144:ef7eb2e8f9f7 193 uint32_t prescale_timer3 = clk_timer3 / TMR3_CLK_FREQ - 1;
<> 144:ef7eb2e8f9f7 194 MBED_ASSERT((prescale_timer3 != (uint32_t) -1) && prescale_timer3 <= 127);
<> 144:ef7eb2e8f9f7 195 timer3_base->CTL &= ~(TIMER_CTL_OPMODE_Msk | TIMER_CTL_PSC_Msk | TIMER_CTL_CNTDATEN_Msk);
<> 144:ef7eb2e8f9f7 196 timer3_base->CTL |= TIMER_ONESHOT_MODE | prescale_timer3 | TIMER_CTL_CNTDATEN_Msk;
<> 144:ef7eb2e8f9f7 197
<> 144:ef7eb2e8f9f7 198 cd_minor_ms = cd_major_minor_ms;
<> 144:ef7eb2e8f9f7 199 cd_minor_ms = NU_CLAMP(cd_minor_ms, TMR_CMP_MIN * MS_PER_TMR3_CLK, TMR_CMP_MAX * MS_PER_TMR3_CLK);
<> 144:ef7eb2e8f9f7 200 timer3_base->CMP = cd_minor_ms / MS_PER_TMR3_CLK;
<> 144:ef7eb2e8f9f7 201
<> 144:ef7eb2e8f9f7 202 TIMER_EnableInt(timer3_base);
<> 144:ef7eb2e8f9f7 203 TIMER_EnableWakeup((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
<> 144:ef7eb2e8f9f7 204 TIMER_Start(timer3_base);
<> 144:ef7eb2e8f9f7 205 }
<> 144:ef7eb2e8f9f7 206 #endif