mirror of https://github.com/ARMmbed/mbed-os.git
166 lines
4.8 KiB
C
166 lines
4.8 KiB
C
/* mbed Microcontroller Library
|
|
* Copyright (c) 2006-2015 ARM Limited
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#include <stddef.h>
|
|
#include "us_ticker_api.h"
|
|
#include "PeripheralNames.h"
|
|
#include "clk_freqs.h"
|
|
|
|
#define PIT_TIMER PIT->CHANNEL[0]
|
|
#define PIT_TIMER_IRQ PIT0_IRQn
|
|
#define PIT_TICKER PIT->CHANNEL[1]
|
|
#define PIT_TICKER_IRQ PIT1_IRQn
|
|
|
|
static void timer_init(void);
|
|
static void ticker_init(void);
|
|
|
|
|
|
static int us_ticker_inited = 0;
|
|
static uint32_t clk_mhz;
|
|
|
|
void us_ticker_init(void) {
|
|
if (us_ticker_inited)
|
|
return;
|
|
us_ticker_inited = 1;
|
|
|
|
SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT
|
|
PIT->MCR = 0; // Enable PIT
|
|
|
|
clk_mhz = bus_frequency() / 1000000;
|
|
|
|
timer_init();
|
|
ticker_init();
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Timer for us timing.
|
|
*
|
|
* The K20D5M does not have a prescaler on its PIT timer nor the option
|
|
* to chain timers, which is why a software timer is required to get 32-bit
|
|
* word length.
|
|
******************************************************************************/
|
|
static volatile uint32_t msb_counter = 0;
|
|
static uint32_t timer_ldval = 0;
|
|
|
|
static void timer_isr(void) {
|
|
if (PIT_TIMER.TFLG == 1) {
|
|
msb_counter++;
|
|
PIT_TIMER.TFLG = 1;
|
|
}
|
|
}
|
|
|
|
static void timer_init(void) {
|
|
//CLZ counts the leading zeros, returning number of bits not used by clk_mhz
|
|
timer_ldval = clk_mhz << __CLZ(clk_mhz);
|
|
|
|
PIT_TIMER.LDVAL = timer_ldval; // 1us
|
|
PIT_TIMER.TCTRL |= PIT_TCTRL_TIE_MASK;
|
|
PIT_TIMER.TCTRL |= PIT_TCTRL_TEN_MASK; // Start timer 0
|
|
|
|
NVIC_SetVector(PIT_TIMER_IRQ, (uint32_t)timer_isr);
|
|
NVIC_EnableIRQ(PIT_TIMER_IRQ);
|
|
}
|
|
|
|
uint32_t us_ticker_read() {
|
|
if (!us_ticker_inited)
|
|
us_ticker_init();
|
|
|
|
uint32_t retval;
|
|
__disable_irq();
|
|
retval = (timer_ldval - PIT_TIMER.CVAL) / clk_mhz; //Hardware bits
|
|
retval |= msb_counter << __CLZ(clk_mhz); //Software bits
|
|
|
|
if (PIT_TIMER.TFLG == 1) { //If overflow bit is set, force it to be handled
|
|
timer_isr(); //Handle IRQ, read again to make sure software/hardware bits are synced
|
|
NVIC_ClearPendingIRQ(PIT_TIMER_IRQ);
|
|
return us_ticker_read();
|
|
}
|
|
|
|
__enable_irq();
|
|
return retval;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Timer Event
|
|
*
|
|
* It schedules interrupts at given (32bit)us interval of time.
|
|
* It is implemented using PIT channel 1, since no prescaler is available,
|
|
* some bits are implemented in software.
|
|
******************************************************************************/
|
|
static void ticker_isr(void);
|
|
|
|
static void ticker_init(void) {
|
|
/* Set interrupt handler */
|
|
NVIC_SetVector(PIT_TICKER_IRQ, (uint32_t)ticker_isr);
|
|
NVIC_EnableIRQ(PIT_TICKER_IRQ);
|
|
}
|
|
|
|
void us_ticker_disable_interrupt(void) {
|
|
PIT_TICKER.TCTRL &= ~PIT_TCTRL_TIE_MASK;
|
|
}
|
|
|
|
void us_ticker_clear_interrupt(void) {
|
|
// we already clear interrupt in lptmr_isr
|
|
}
|
|
|
|
static uint32_t us_ticker_int_counter = 0;
|
|
|
|
inline static void ticker_set(uint32_t count) {
|
|
PIT_TICKER.TCTRL = 0;
|
|
PIT_TICKER.LDVAL = count;
|
|
PIT_TICKER.TCTRL = PIT_TCTRL_TIE_MASK | PIT_TCTRL_TEN_MASK;
|
|
}
|
|
|
|
static void ticker_isr(void) {
|
|
// Clear IRQ flag
|
|
PIT_TICKER.TFLG = 1;
|
|
|
|
if (us_ticker_int_counter > 0) {
|
|
ticker_set(0xFFFFFFFF);
|
|
us_ticker_int_counter--;
|
|
} else {
|
|
// This function is going to disable the interrupts if there are
|
|
// no other events in the queue
|
|
us_ticker_irq_handler();
|
|
}
|
|
}
|
|
|
|
void us_ticker_set_interrupt(timestamp_t timestamp) {
|
|
uint32_t delta = timestamp - us_ticker_read();
|
|
//Calculate how much falls outside the 32-bit after multiplying with clk_mhz
|
|
//We shift twice 16-bit to keep everything within the 32-bit variable
|
|
us_ticker_int_counter = (uint32_t)(delta >> 16);
|
|
us_ticker_int_counter *= clk_mhz;
|
|
us_ticker_int_counter >>= 16;
|
|
|
|
uint32_t us_ticker_int_remainder = (uint32_t)delta * clk_mhz;
|
|
if (us_ticker_int_remainder == 0) {
|
|
ticker_set(0xFFFFFFFF);
|
|
us_ticker_int_counter--;
|
|
} else {
|
|
ticker_set(us_ticker_int_remainder);
|
|
}
|
|
}
|
|
|
|
void us_ticker_fire_interrupt(void)
|
|
{
|
|
NVIC_SetPendingIRQ(PIT_TICKER_IRQ);
|
|
}
|
|
|
|
void us_ticker_free(void)
|
|
{
|
|
|
|
}
|