Fawwaz Nadzmy / mbed-STM

Fork of mbed-dev by mbed official

Committer:
bogdanm
Date:
Thu Oct 01 15:25:22 2015 +0300
Revision:
0:9b334a45a8ff
Child:
144:ef7eb2e8f9f7
Initial commit on mbed-dev

Replaces mbed-src (now inactive)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bogdanm 0:9b334a45a8ff 1 /* mbed Microcontroller Library
bogdanm 0:9b334a45a8ff 2 * Copyright (c) 2006-2013 ARM Limited
bogdanm 0:9b334a45a8ff 3 *
bogdanm 0:9b334a45a8ff 4 * Licensed under the Apache License, Version 2.0 (the "License");
bogdanm 0:9b334a45a8ff 5 * you may not use this file except in compliance with the License.
bogdanm 0:9b334a45a8ff 6 * You may obtain a copy of the License at
bogdanm 0:9b334a45a8ff 7 *
bogdanm 0:9b334a45a8ff 8 * http://www.apache.org/licenses/LICENSE-2.0
bogdanm 0:9b334a45a8ff 9 *
bogdanm 0:9b334a45a8ff 10 * Unless required by applicable law or agreed to in writing, software
bogdanm 0:9b334a45a8ff 11 * distributed under the License is distributed on an "AS IS" BASIS,
bogdanm 0:9b334a45a8ff 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
bogdanm 0:9b334a45a8ff 13 * See the License for the specific language governing permissions and
bogdanm 0:9b334a45a8ff 14 * limitations under the License.
bogdanm 0:9b334a45a8ff 15 */
bogdanm 0:9b334a45a8ff 16 #include <stddef.h>
bogdanm 0:9b334a45a8ff 17 #include "us_ticker_api.h"
bogdanm 0:9b334a45a8ff 18 #include "PeripheralNames.h"
bogdanm 0:9b334a45a8ff 19 #include "clk_freqs.h"
bogdanm 0:9b334a45a8ff 20
bogdanm 0:9b334a45a8ff 21 static void pit_init(void);
bogdanm 0:9b334a45a8ff 22 static void lptmr_init(void);
bogdanm 0:9b334a45a8ff 23
bogdanm 0:9b334a45a8ff 24 static int us_ticker_inited = 0;
bogdanm 0:9b334a45a8ff 25
bogdanm 0:9b334a45a8ff 26 void us_ticker_init(void) {
bogdanm 0:9b334a45a8ff 27 if (us_ticker_inited) return;
bogdanm 0:9b334a45a8ff 28 us_ticker_inited = 1;
bogdanm 0:9b334a45a8ff 29
bogdanm 0:9b334a45a8ff 30 pit_init();
bogdanm 0:9b334a45a8ff 31 lptmr_init();
bogdanm 0:9b334a45a8ff 32 }
bogdanm 0:9b334a45a8ff 33
bogdanm 0:9b334a45a8ff 34 /******************************************************************************
bogdanm 0:9b334a45a8ff 35 * Timer for us timing.
bogdanm 0:9b334a45a8ff 36 ******************************************************************************/
bogdanm 0:9b334a45a8ff 37 static void pit_init(void) {
bogdanm 0:9b334a45a8ff 38 SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT
bogdanm 0:9b334a45a8ff 39 PIT->MCR = 0; // Enable PIT
bogdanm 0:9b334a45a8ff 40
bogdanm 0:9b334a45a8ff 41 // Channel 1
bogdanm 0:9b334a45a8ff 42 PIT->CHANNEL[1].LDVAL = 0xFFFFFFFF;
bogdanm 0:9b334a45a8ff 43 PIT->CHANNEL[1].TCTRL = PIT_TCTRL_CHN_MASK; // Chain to timer 0, disable Interrupts
bogdanm 0:9b334a45a8ff 44 PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TEN_MASK; // Start timer 1
bogdanm 0:9b334a45a8ff 45
bogdanm 0:9b334a45a8ff 46 // Use channel 0 as a prescaler for channel 1
bogdanm 0:9b334a45a8ff 47 PIT->CHANNEL[0].LDVAL = (bus_frequency() + 500000) / 1000000 - 1;
bogdanm 0:9b334a45a8ff 48 PIT->CHANNEL[0].TCTRL = PIT_TCTRL_TEN_MASK; // Start timer 0, disable interrupts
bogdanm 0:9b334a45a8ff 49 }
bogdanm 0:9b334a45a8ff 50
bogdanm 0:9b334a45a8ff 51 uint32_t us_ticker_read() {
bogdanm 0:9b334a45a8ff 52 if (!us_ticker_inited)
bogdanm 0:9b334a45a8ff 53 us_ticker_init();
bogdanm 0:9b334a45a8ff 54
bogdanm 0:9b334a45a8ff 55 // The PIT is a countdown timer
bogdanm 0:9b334a45a8ff 56 return ~(PIT->CHANNEL[1].CVAL);
bogdanm 0:9b334a45a8ff 57 }
bogdanm 0:9b334a45a8ff 58
bogdanm 0:9b334a45a8ff 59 /******************************************************************************
bogdanm 0:9b334a45a8ff 60 * Timer Event
bogdanm 0:9b334a45a8ff 61 *
bogdanm 0:9b334a45a8ff 62 * It schedules interrupts at given (32bit)us interval of time.
bogdanm 0:9b334a45a8ff 63 * It is implemented used the 16bit Low Power Timer that remains powered in all
bogdanm 0:9b334a45a8ff 64 * power modes.
bogdanm 0:9b334a45a8ff 65 ******************************************************************************/
bogdanm 0:9b334a45a8ff 66 static void lptmr_isr(void);
bogdanm 0:9b334a45a8ff 67
bogdanm 0:9b334a45a8ff 68 static void lptmr_init(void) {
bogdanm 0:9b334a45a8ff 69 uint32_t extosc;
bogdanm 0:9b334a45a8ff 70
bogdanm 0:9b334a45a8ff 71 /* Clock the timer */
bogdanm 0:9b334a45a8ff 72 SIM->SCGC5 |= SIM_SCGC5_LPTMR_MASK;
bogdanm 0:9b334a45a8ff 73
bogdanm 0:9b334a45a8ff 74 /* Reset */
bogdanm 0:9b334a45a8ff 75 LPTMR0->CSR = 0;
bogdanm 0:9b334a45a8ff 76
bogdanm 0:9b334a45a8ff 77 #if defined(TARGET_KL43Z)
bogdanm 0:9b334a45a8ff 78 /* Set interrupt handler */
bogdanm 0:9b334a45a8ff 79 NVIC_SetVector(LPTMR0_IRQn, (uint32_t)lptmr_isr);
bogdanm 0:9b334a45a8ff 80 NVIC_EnableIRQ(LPTMR0_IRQn);
bogdanm 0:9b334a45a8ff 81
bogdanm 0:9b334a45a8ff 82
bogdanm 0:9b334a45a8ff 83 MCG->C1 |= MCG_C1_IRCLKEN_MASK;
bogdanm 0:9b334a45a8ff 84 extosc = mcgirc_frequency();
bogdanm 0:9b334a45a8ff 85 #else
bogdanm 0:9b334a45a8ff 86 /* Set interrupt handler */
bogdanm 0:9b334a45a8ff 87 NVIC_SetVector(LPTimer_IRQn, (uint32_t)lptmr_isr);
bogdanm 0:9b334a45a8ff 88 NVIC_EnableIRQ(LPTimer_IRQn);
bogdanm 0:9b334a45a8ff 89
bogdanm 0:9b334a45a8ff 90 /* Clock at (1)MHz -> (1)tick/us */
bogdanm 0:9b334a45a8ff 91 /* Check if the external oscillator can be divided to 1MHz */
bogdanm 0:9b334a45a8ff 92 extosc = extosc_frequency();
bogdanm 0:9b334a45a8ff 93 #endif
bogdanm 0:9b334a45a8ff 94 if (extosc != 0) { //If external oscillator found
bogdanm 0:9b334a45a8ff 95 if (extosc % 1000000u == 0) { //If it is a multiple if 1MHz
bogdanm 0:9b334a45a8ff 96 extosc /= 1000000;
bogdanm 0:9b334a45a8ff 97 if (extosc == 1) { //1MHz, set timerprescaler in bypass mode
bogdanm 0:9b334a45a8ff 98 LPTMR0->PSR = LPTMR_PSR_PCS(3) | LPTMR_PSR_PBYP_MASK;
bogdanm 0:9b334a45a8ff 99 return;
bogdanm 0:9b334a45a8ff 100 } else { //See if we can divide it to 1MHz
bogdanm 0:9b334a45a8ff 101 uint32_t divider = 0;
bogdanm 0:9b334a45a8ff 102 extosc >>= 1;
bogdanm 0:9b334a45a8ff 103 while (1) {
bogdanm 0:9b334a45a8ff 104 if (extosc == 1) {
bogdanm 0:9b334a45a8ff 105 LPTMR0->PSR = LPTMR_PSR_PCS(3) | LPTMR_PSR_PRESCALE(divider);
bogdanm 0:9b334a45a8ff 106 return;
bogdanm 0:9b334a45a8ff 107 }
bogdanm 0:9b334a45a8ff 108 if (extosc % 2 != 0) //If we can't divide by two anymore
bogdanm 0:9b334a45a8ff 109 break;
bogdanm 0:9b334a45a8ff 110 divider++;
bogdanm 0:9b334a45a8ff 111 extosc >>= 1;
bogdanm 0:9b334a45a8ff 112 }
bogdanm 0:9b334a45a8ff 113 }
bogdanm 0:9b334a45a8ff 114 }
bogdanm 0:9b334a45a8ff 115 }
bogdanm 0:9b334a45a8ff 116 #if defined(TARGET_KL43Z)
bogdanm 0:9b334a45a8ff 117 //No suitable actual IRC oscillator clock -> Set it to (8MHz / divider)
bogdanm 0:9b334a45a8ff 118 MCG->SC &= ~MCG_SC_FCRDIV_MASK;
bogdanm 0:9b334a45a8ff 119 MCG->MC &= ~MCG->MC & MCG_MC_LIRC_DIV2_MASK;
bogdanm 0:9b334a45a8ff 120 LPTMR0->PSR = LPTMR_PSR_PCS(0) | LPTMR_PSR_PRESCALE(2);
bogdanm 0:9b334a45a8ff 121 #else
bogdanm 0:9b334a45a8ff 122 //No suitable external oscillator clock -> Use fast internal oscillator (4MHz / divider)
bogdanm 0:9b334a45a8ff 123 MCG->C1 |= MCG_C1_IRCLKEN_MASK;
bogdanm 0:9b334a45a8ff 124 MCG->C2 |= MCG_C2_IRCS_MASK;
bogdanm 0:9b334a45a8ff 125 LPTMR0->PSR = LPTMR_PSR_PCS(0);
bogdanm 0:9b334a45a8ff 126 switch (MCG->SC & MCG_SC_FCRDIV_MASK) {
bogdanm 0:9b334a45a8ff 127 case MCG_SC_FCRDIV(0): //4MHz
bogdanm 0:9b334a45a8ff 128 LPTMR0->PSR |= LPTMR_PSR_PRESCALE(1);
bogdanm 0:9b334a45a8ff 129 break;
bogdanm 0:9b334a45a8ff 130 case MCG_SC_FCRDIV(1): //2MHz
bogdanm 0:9b334a45a8ff 131 LPTMR0->PSR |= LPTMR_PSR_PRESCALE(0);
bogdanm 0:9b334a45a8ff 132 break;
bogdanm 0:9b334a45a8ff 133 default: //1MHz or anything else, in which case we put it on 1MHz
bogdanm 0:9b334a45a8ff 134 MCG->SC &= ~MCG_SC_FCRDIV_MASK;
bogdanm 0:9b334a45a8ff 135 MCG->SC |= MCG_SC_FCRDIV(2);
bogdanm 0:9b334a45a8ff 136 LPTMR0->PSR |= LPTMR_PSR_PBYP_MASK;
bogdanm 0:9b334a45a8ff 137 }
bogdanm 0:9b334a45a8ff 138 #endif
bogdanm 0:9b334a45a8ff 139 }
bogdanm 0:9b334a45a8ff 140
bogdanm 0:9b334a45a8ff 141 void us_ticker_disable_interrupt(void) {
bogdanm 0:9b334a45a8ff 142 LPTMR0->CSR &= ~LPTMR_CSR_TIE_MASK;
bogdanm 0:9b334a45a8ff 143 }
bogdanm 0:9b334a45a8ff 144
bogdanm 0:9b334a45a8ff 145 void us_ticker_clear_interrupt(void) {
bogdanm 0:9b334a45a8ff 146 // we already clear interrupt in lptmr_isr
bogdanm 0:9b334a45a8ff 147 }
bogdanm 0:9b334a45a8ff 148
bogdanm 0:9b334a45a8ff 149 static uint32_t us_ticker_int_counter = 0;
bogdanm 0:9b334a45a8ff 150 static uint16_t us_ticker_int_remainder = 0;
bogdanm 0:9b334a45a8ff 151
bogdanm 0:9b334a45a8ff 152 static void lptmr_set(unsigned short count) {
bogdanm 0:9b334a45a8ff 153 /* Reset */
bogdanm 0:9b334a45a8ff 154 LPTMR0->CSR = 0;
bogdanm 0:9b334a45a8ff 155
bogdanm 0:9b334a45a8ff 156 /* Set the compare register */
bogdanm 0:9b334a45a8ff 157 LPTMR0->CMR = count;
bogdanm 0:9b334a45a8ff 158
bogdanm 0:9b334a45a8ff 159 /* Enable interrupt */
bogdanm 0:9b334a45a8ff 160 LPTMR0->CSR |= LPTMR_CSR_TIE_MASK;
bogdanm 0:9b334a45a8ff 161
bogdanm 0:9b334a45a8ff 162 /* Start the timer */
bogdanm 0:9b334a45a8ff 163 LPTMR0->CSR |= LPTMR_CSR_TEN_MASK;
bogdanm 0:9b334a45a8ff 164 }
bogdanm 0:9b334a45a8ff 165
bogdanm 0:9b334a45a8ff 166 static void lptmr_isr(void) {
bogdanm 0:9b334a45a8ff 167 // write 1 to TCF to clear the LPT timer compare flag
bogdanm 0:9b334a45a8ff 168 LPTMR0->CSR |= LPTMR_CSR_TCF_MASK;
bogdanm 0:9b334a45a8ff 169
bogdanm 0:9b334a45a8ff 170 if (us_ticker_int_counter > 0) {
bogdanm 0:9b334a45a8ff 171 lptmr_set(0xFFFF);
bogdanm 0:9b334a45a8ff 172 us_ticker_int_counter--;
bogdanm 0:9b334a45a8ff 173
bogdanm 0:9b334a45a8ff 174 } else {
bogdanm 0:9b334a45a8ff 175 if (us_ticker_int_remainder > 0) {
bogdanm 0:9b334a45a8ff 176 lptmr_set(us_ticker_int_remainder);
bogdanm 0:9b334a45a8ff 177 us_ticker_int_remainder = 0;
bogdanm 0:9b334a45a8ff 178
bogdanm 0:9b334a45a8ff 179 } else {
bogdanm 0:9b334a45a8ff 180 // This function is going to disable the interrupts if there are
bogdanm 0:9b334a45a8ff 181 // no other events in the queue
bogdanm 0:9b334a45a8ff 182 us_ticker_irq_handler();
bogdanm 0:9b334a45a8ff 183 }
bogdanm 0:9b334a45a8ff 184 }
bogdanm 0:9b334a45a8ff 185 }
bogdanm 0:9b334a45a8ff 186
bogdanm 0:9b334a45a8ff 187 void us_ticker_set_interrupt(timestamp_t timestamp) {
bogdanm 0:9b334a45a8ff 188 int delta = (int)((uint32_t)timestamp - us_ticker_read());
bogdanm 0:9b334a45a8ff 189 if (delta <= 0) {
bogdanm 0:9b334a45a8ff 190 // This event was in the past:
bogdanm 0:9b334a45a8ff 191 us_ticker_irq_handler();
bogdanm 0:9b334a45a8ff 192 return;
bogdanm 0:9b334a45a8ff 193 }
bogdanm 0:9b334a45a8ff 194
bogdanm 0:9b334a45a8ff 195 us_ticker_int_counter = (uint32_t)(delta >> 16);
bogdanm 0:9b334a45a8ff 196 us_ticker_int_remainder = (uint16_t)(0xFFFF & delta);
bogdanm 0:9b334a45a8ff 197 if (us_ticker_int_counter > 0) {
bogdanm 0:9b334a45a8ff 198 lptmr_set(0xFFFF);
bogdanm 0:9b334a45a8ff 199 us_ticker_int_counter--;
bogdanm 0:9b334a45a8ff 200 } else {
bogdanm 0:9b334a45a8ff 201 lptmr_set(us_ticker_int_remainder);
bogdanm 0:9b334a45a8ff 202 us_ticker_int_remainder = 0;
bogdanm 0:9b334a45a8ff 203 }
bogdanm 0:9b334a45a8ff 204 }