mbed library sources

Dependents:   FRDM-KL46Z_LCD_Test FRDM-KL46Z_LCD_Test FRDM-KL46Z_Plantilla FRDM-KL46Z_Plantilla ... more

Committer:
ebrus
Date:
Thu Jul 28 15:56:34 2016 +0000
Revision:
0:6bc4ac881c8e
1;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ebrus 0:6bc4ac881c8e 1 /* mbed Microcontroller Library
ebrus 0:6bc4ac881c8e 2 * Copyright (c) 2006-2013 ARM Limited
ebrus 0:6bc4ac881c8e 3 *
ebrus 0:6bc4ac881c8e 4 * Licensed under the Apache License, Version 2.0 (the "License");
ebrus 0:6bc4ac881c8e 5 * you may not use this file except in compliance with the License.
ebrus 0:6bc4ac881c8e 6 * You may obtain a copy of the License at
ebrus 0:6bc4ac881c8e 7 *
ebrus 0:6bc4ac881c8e 8 * http://www.apache.org/licenses/LICENSE-2.0
ebrus 0:6bc4ac881c8e 9 *
ebrus 0:6bc4ac881c8e 10 * Unless required by applicable law or agreed to in writing, software
ebrus 0:6bc4ac881c8e 11 * distributed under the License is distributed on an "AS IS" BASIS,
ebrus 0:6bc4ac881c8e 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ebrus 0:6bc4ac881c8e 13 * See the License for the specific language governing permissions and
ebrus 0:6bc4ac881c8e 14 * limitations under the License.
ebrus 0:6bc4ac881c8e 15 */
ebrus 0:6bc4ac881c8e 16 #include <stddef.h>
ebrus 0:6bc4ac881c8e 17 #include "us_ticker_api.h"
ebrus 0:6bc4ac881c8e 18 #include "PeripheralNames.h"
ebrus 0:6bc4ac881c8e 19 #include "clk_freqs.h"
ebrus 0:6bc4ac881c8e 20
ebrus 0:6bc4ac881c8e 21 #define PIT_TIMER PIT->CHANNEL[0]
ebrus 0:6bc4ac881c8e 22 #define PIT_TIMER_IRQ PIT0_IRQn
ebrus 0:6bc4ac881c8e 23 #define PIT_TICKER PIT->CHANNEL[1]
ebrus 0:6bc4ac881c8e 24 #define PIT_TICKER_IRQ PIT1_IRQn
ebrus 0:6bc4ac881c8e 25
ebrus 0:6bc4ac881c8e 26 static void timer_init(void);
ebrus 0:6bc4ac881c8e 27 static void ticker_init(void);
ebrus 0:6bc4ac881c8e 28
ebrus 0:6bc4ac881c8e 29
ebrus 0:6bc4ac881c8e 30 static int us_ticker_inited = 0;
ebrus 0:6bc4ac881c8e 31 static uint32_t clk_mhz;
ebrus 0:6bc4ac881c8e 32
ebrus 0:6bc4ac881c8e 33 void us_ticker_init(void) {
ebrus 0:6bc4ac881c8e 34 if (us_ticker_inited)
ebrus 0:6bc4ac881c8e 35 return;
ebrus 0:6bc4ac881c8e 36 us_ticker_inited = 1;
ebrus 0:6bc4ac881c8e 37
ebrus 0:6bc4ac881c8e 38 SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT
ebrus 0:6bc4ac881c8e 39 PIT->MCR = 0; // Enable PIT
ebrus 0:6bc4ac881c8e 40
ebrus 0:6bc4ac881c8e 41 clk_mhz = bus_frequency() / 1000000;
ebrus 0:6bc4ac881c8e 42
ebrus 0:6bc4ac881c8e 43 timer_init();
ebrus 0:6bc4ac881c8e 44 ticker_init();
ebrus 0:6bc4ac881c8e 45 }
ebrus 0:6bc4ac881c8e 46
ebrus 0:6bc4ac881c8e 47 /******************************************************************************
ebrus 0:6bc4ac881c8e 48 * Timer for us timing.
ebrus 0:6bc4ac881c8e 49 *
ebrus 0:6bc4ac881c8e 50 * The K20D5M does not have a prescaler on its PIT timer nor the option
ebrus 0:6bc4ac881c8e 51 * to chain timers, which is why a software timer is required to get 32-bit
ebrus 0:6bc4ac881c8e 52 * word length.
ebrus 0:6bc4ac881c8e 53 ******************************************************************************/
ebrus 0:6bc4ac881c8e 54 static volatile uint32_t msb_counter = 0;
ebrus 0:6bc4ac881c8e 55 static uint32_t timer_ldval = 0;
ebrus 0:6bc4ac881c8e 56
ebrus 0:6bc4ac881c8e 57 static void timer_isr(void) {
ebrus 0:6bc4ac881c8e 58 msb_counter++;
ebrus 0:6bc4ac881c8e 59 PIT_TIMER.TFLG = 1;
ebrus 0:6bc4ac881c8e 60 }
ebrus 0:6bc4ac881c8e 61
ebrus 0:6bc4ac881c8e 62 static void timer_init(void) {
ebrus 0:6bc4ac881c8e 63 //CLZ counts the leading zeros, returning number of bits not used by clk_mhz
ebrus 0:6bc4ac881c8e 64 timer_ldval = clk_mhz << __CLZ(clk_mhz);
ebrus 0:6bc4ac881c8e 65
ebrus 0:6bc4ac881c8e 66 PIT_TIMER.LDVAL = timer_ldval; // 1us
ebrus 0:6bc4ac881c8e 67 PIT_TIMER.TCTRL |= PIT_TCTRL_TIE_MASK;
ebrus 0:6bc4ac881c8e 68 PIT_TIMER.TCTRL |= PIT_TCTRL_TEN_MASK; // Start timer 0
ebrus 0:6bc4ac881c8e 69
ebrus 0:6bc4ac881c8e 70 NVIC_SetVector(PIT_TIMER_IRQ, (uint32_t)timer_isr);
ebrus 0:6bc4ac881c8e 71 NVIC_EnableIRQ(PIT_TIMER_IRQ);
ebrus 0:6bc4ac881c8e 72 }
ebrus 0:6bc4ac881c8e 73
ebrus 0:6bc4ac881c8e 74 uint32_t us_ticker_read() {
ebrus 0:6bc4ac881c8e 75 if (!us_ticker_inited)
ebrus 0:6bc4ac881c8e 76 us_ticker_init();
ebrus 0:6bc4ac881c8e 77
ebrus 0:6bc4ac881c8e 78 uint32_t retval;
ebrus 0:6bc4ac881c8e 79 __disable_irq();
ebrus 0:6bc4ac881c8e 80 retval = (timer_ldval - PIT_TIMER.CVAL) / clk_mhz; //Hardware bits
ebrus 0:6bc4ac881c8e 81 retval |= msb_counter << __CLZ(clk_mhz); //Software bits
ebrus 0:6bc4ac881c8e 82
ebrus 0:6bc4ac881c8e 83 if (PIT_TIMER.TFLG == 1) { //If overflow bit is set, force it to be handled
ebrus 0:6bc4ac881c8e 84 timer_isr(); //Handle IRQ, read again to make sure software/hardware bits are synced
ebrus 0:6bc4ac881c8e 85 NVIC_ClearPendingIRQ(PIT_TIMER_IRQ);
ebrus 0:6bc4ac881c8e 86 return us_ticker_read();
ebrus 0:6bc4ac881c8e 87 }
ebrus 0:6bc4ac881c8e 88
ebrus 0:6bc4ac881c8e 89 __enable_irq();
ebrus 0:6bc4ac881c8e 90 return retval;
ebrus 0:6bc4ac881c8e 91 }
ebrus 0:6bc4ac881c8e 92
ebrus 0:6bc4ac881c8e 93 /******************************************************************************
ebrus 0:6bc4ac881c8e 94 * Timer Event
ebrus 0:6bc4ac881c8e 95 *
ebrus 0:6bc4ac881c8e 96 * It schedules interrupts at given (32bit)us interval of time.
ebrus 0:6bc4ac881c8e 97 * It is implemented using PIT channel 1, since no prescaler is available,
ebrus 0:6bc4ac881c8e 98 * some bits are implemented in software.
ebrus 0:6bc4ac881c8e 99 ******************************************************************************/
ebrus 0:6bc4ac881c8e 100 static void ticker_isr(void);
ebrus 0:6bc4ac881c8e 101
ebrus 0:6bc4ac881c8e 102 static void ticker_init(void) {
ebrus 0:6bc4ac881c8e 103 /* Set interrupt handler */
ebrus 0:6bc4ac881c8e 104 NVIC_SetVector(PIT_TICKER_IRQ, (uint32_t)ticker_isr);
ebrus 0:6bc4ac881c8e 105 NVIC_EnableIRQ(PIT_TICKER_IRQ);
ebrus 0:6bc4ac881c8e 106 }
ebrus 0:6bc4ac881c8e 107
ebrus 0:6bc4ac881c8e 108 void us_ticker_disable_interrupt(void) {
ebrus 0:6bc4ac881c8e 109 PIT_TICKER.TCTRL &= ~PIT_TCTRL_TIE_MASK;
ebrus 0:6bc4ac881c8e 110 }
ebrus 0:6bc4ac881c8e 111
ebrus 0:6bc4ac881c8e 112 void us_ticker_clear_interrupt(void) {
ebrus 0:6bc4ac881c8e 113 // we already clear interrupt in lptmr_isr
ebrus 0:6bc4ac881c8e 114 }
ebrus 0:6bc4ac881c8e 115
ebrus 0:6bc4ac881c8e 116 static uint32_t us_ticker_int_counter = 0;
ebrus 0:6bc4ac881c8e 117
ebrus 0:6bc4ac881c8e 118 inline static void ticker_set(uint32_t count) {
ebrus 0:6bc4ac881c8e 119 PIT_TICKER.TCTRL = 0;
ebrus 0:6bc4ac881c8e 120 PIT_TICKER.LDVAL = count;
ebrus 0:6bc4ac881c8e 121 PIT_TICKER.TCTRL = PIT_TCTRL_TIE_MASK | PIT_TCTRL_TEN_MASK;
ebrus 0:6bc4ac881c8e 122 }
ebrus 0:6bc4ac881c8e 123
ebrus 0:6bc4ac881c8e 124 static void ticker_isr(void) {
ebrus 0:6bc4ac881c8e 125 // Clear IRQ flag
ebrus 0:6bc4ac881c8e 126 PIT_TICKER.TFLG = 1;
ebrus 0:6bc4ac881c8e 127
ebrus 0:6bc4ac881c8e 128 if (us_ticker_int_counter > 0) {
ebrus 0:6bc4ac881c8e 129 ticker_set(0xFFFFFFFF);
ebrus 0:6bc4ac881c8e 130 us_ticker_int_counter--;
ebrus 0:6bc4ac881c8e 131 } else {
ebrus 0:6bc4ac881c8e 132 // This function is going to disable the interrupts if there are
ebrus 0:6bc4ac881c8e 133 // no other events in the queue
ebrus 0:6bc4ac881c8e 134 us_ticker_irq_handler();
ebrus 0:6bc4ac881c8e 135 }
ebrus 0:6bc4ac881c8e 136 }
ebrus 0:6bc4ac881c8e 137
ebrus 0:6bc4ac881c8e 138 void us_ticker_set_interrupt(timestamp_t timestamp) {
ebrus 0:6bc4ac881c8e 139 int delta = (int)((uint32_t)timestamp - us_ticker_read());
ebrus 0:6bc4ac881c8e 140 if (delta <= 0) {
ebrus 0:6bc4ac881c8e 141 // This event was in the past:
ebrus 0:6bc4ac881c8e 142 us_ticker_irq_handler();
ebrus 0:6bc4ac881c8e 143 return;
ebrus 0:6bc4ac881c8e 144 }
ebrus 0:6bc4ac881c8e 145
ebrus 0:6bc4ac881c8e 146 //Calculate how much falls outside the 32-bit after multiplying with clk_mhz
ebrus 0:6bc4ac881c8e 147 //We shift twice 16-bit to keep everything within the 32-bit variable
ebrus 0:6bc4ac881c8e 148 us_ticker_int_counter = (uint32_t)(delta >> 16);
ebrus 0:6bc4ac881c8e 149 us_ticker_int_counter *= clk_mhz;
ebrus 0:6bc4ac881c8e 150 us_ticker_int_counter >>= 16;
ebrus 0:6bc4ac881c8e 151
ebrus 0:6bc4ac881c8e 152 uint32_t us_ticker_int_remainder = (uint32_t)delta * clk_mhz;
ebrus 0:6bc4ac881c8e 153 if (us_ticker_int_remainder == 0) {
ebrus 0:6bc4ac881c8e 154 ticker_set(0xFFFFFFFF);
ebrus 0:6bc4ac881c8e 155 us_ticker_int_counter--;
ebrus 0:6bc4ac881c8e 156 } else {
ebrus 0:6bc4ac881c8e 157 ticker_set(us_ticker_int_remainder);
ebrus 0:6bc4ac881c8e 158 }
ebrus 0:6bc4ac881c8e 159 }