2013-09-24 14:36:04 +00:00
|
|
|
/* mbed Microcontroller Library
|
2015-01-15 19:11:40 +00:00
|
|
|
* Copyright (c) 2006-2015 ARM Limited
|
2013-09-24 14:36:04 +00:00
|
|
|
*
|
|
|
|
* 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"
|
2014-01-14 16:51:09 +00:00
|
|
|
#include "clk_freqs.h"
|
2013-09-24 14:36:04 +00:00
|
|
|
|
2014-04-17 20:36:03 +00:00
|
|
|
#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);
|
2013-09-24 14:36:04 +00:00
|
|
|
|
2014-01-14 16:51:09 +00:00
|
|
|
|
2013-09-24 14:36:04 +00:00
|
|
|
static int us_ticker_inited = 0;
|
2014-04-17 20:36:03 +00:00
|
|
|
static uint32_t clk_mhz;
|
2013-09-24 14:36:04 +00:00
|
|
|
|
|
|
|
void us_ticker_init(void) {
|
2013-12-23 18:57:10 +00:00
|
|
|
if (us_ticker_inited)
|
|
|
|
return;
|
2013-09-24 14:36:04 +00:00
|
|
|
us_ticker_inited = 1;
|
2014-04-17 20:36:03 +00:00
|
|
|
|
|
|
|
SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT
|
|
|
|
PIT->MCR = 0; // Enable PIT
|
|
|
|
|
|
|
|
clk_mhz = bus_frequency() / 1000000;
|
2013-12-23 18:57:10 +00:00
|
|
|
|
2014-04-17 20:36:03 +00:00
|
|
|
timer_init();
|
|
|
|
ticker_init();
|
2013-11-19 19:06:26 +00:00
|
|
|
}
|
|
|
|
|
2013-09-24 14:36:04 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* Timer for us timing.
|
2014-04-17 16:04:36 +00:00
|
|
|
*
|
|
|
|
* 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.
|
2013-09-24 14:36:04 +00:00
|
|
|
******************************************************************************/
|
2014-04-17 20:36:03 +00:00
|
|
|
static volatile uint32_t msb_counter = 0;
|
|
|
|
static uint32_t timer_ldval = 0;
|
|
|
|
|
|
|
|
static void timer_isr(void) {
|
2015-10-24 19:54:36 +00:00
|
|
|
if (PIT_TIMER.TFLG == 1) {
|
|
|
|
msb_counter++;
|
|
|
|
PIT_TIMER.TFLG = 1;
|
|
|
|
}
|
2014-04-17 20:36:03 +00:00
|
|
|
}
|
2014-01-14 16:51:09 +00:00
|
|
|
|
2014-04-17 20:36:03 +00:00
|
|
|
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);
|
2013-11-19 19:06:26 +00:00
|
|
|
|
2014-04-17 20:36:03 +00:00
|
|
|
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);
|
2013-09-24 14:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t us_ticker_read() {
|
|
|
|
if (!us_ticker_inited)
|
|
|
|
us_ticker_init();
|
2014-04-17 16:04:36 +00:00
|
|
|
|
|
|
|
uint32_t retval;
|
|
|
|
__disable_irq();
|
2014-04-17 20:36:03 +00:00
|
|
|
retval = (timer_ldval - PIT_TIMER.CVAL) / clk_mhz; //Hardware bits
|
|
|
|
retval |= msb_counter << __CLZ(clk_mhz); //Software bits
|
2014-04-17 16:04:36 +00:00
|
|
|
|
2014-04-17 20:36:03 +00:00
|
|
|
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);
|
2014-04-17 16:04:36 +00:00
|
|
|
return us_ticker_read();
|
2014-04-17 20:36:03 +00:00
|
|
|
}
|
2014-04-17 16:04:36 +00:00
|
|
|
|
|
|
|
__enable_irq();
|
|
|
|
return retval;
|
2013-09-24 14:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* Timer Event
|
2013-12-23 18:57:10 +00:00
|
|
|
*
|
2013-09-24 14:36:04 +00:00
|
|
|
* It schedules interrupts at given (32bit)us interval of time.
|
2014-04-17 20:36:03 +00:00
|
|
|
* It is implemented using PIT channel 1, since no prescaler is available,
|
|
|
|
* some bits are implemented in software.
|
2013-09-24 14:36:04 +00:00
|
|
|
******************************************************************************/
|
2014-04-17 20:36:03 +00:00
|
|
|
static void ticker_isr(void);
|
2013-12-23 18:57:10 +00:00
|
|
|
|
2014-04-17 20:36:03 +00:00
|
|
|
static void ticker_init(void) {
|
2013-09-24 14:36:04 +00:00
|
|
|
/* Set interrupt handler */
|
2014-04-17 20:36:03 +00:00
|
|
|
NVIC_SetVector(PIT_TICKER_IRQ, (uint32_t)ticker_isr);
|
|
|
|
NVIC_EnableIRQ(PIT_TICKER_IRQ);
|
2013-09-24 14:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void us_ticker_disable_interrupt(void) {
|
2014-04-17 20:36:03 +00:00
|
|
|
PIT_TICKER.TCTRL &= ~PIT_TCTRL_TIE_MASK;
|
2013-09-24 14:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void us_ticker_clear_interrupt(void) {
|
|
|
|
// we already clear interrupt in lptmr_isr
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t us_ticker_int_counter = 0;
|
2013-12-23 18:57:10 +00:00
|
|
|
|
2014-04-17 20:36:03 +00:00
|
|
|
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;
|
2013-09-24 14:36:04 +00:00
|
|
|
}
|
|
|
|
|
2014-04-17 20:36:03 +00:00
|
|
|
static void ticker_isr(void) {
|
|
|
|
// Clear IRQ flag
|
|
|
|
PIT_TICKER.TFLG = 1;
|
2013-12-23 18:57:10 +00:00
|
|
|
|
2013-09-24 14:36:04 +00:00
|
|
|
if (us_ticker_int_counter > 0) {
|
2014-04-17 20:36:03 +00:00
|
|
|
ticker_set(0xFFFFFFFF);
|
2013-09-24 14:36:04 +00:00
|
|
|
us_ticker_int_counter--;
|
|
|
|
} else {
|
2014-04-17 20:36:03 +00:00
|
|
|
// This function is going to disable the interrupts if there are
|
|
|
|
// no other events in the queue
|
|
|
|
us_ticker_irq_handler();
|
2013-09-24 14:36:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-21 10:48:02 +00:00
|
|
|
void us_ticker_set_interrupt(timestamp_t timestamp) {
|
Ticker: add fire interrupt now function
fire_interrupt function should be used for events in the past. As we have now
64bit timestamp, we can figure out what is in the past, and ask a target to invoke
an interrupt immediately. The previous attemps in the target HAL tickers were not ideal, as it can wrap around easily (16 or 32 bit counters). This new
functionality should solve this problem.
set_interrupt for tickers in HAL code should not handle anything but the next match interrupt. If it was in the past is handled by the upper layer.
It is possible that we are setting next event to the close future, so once it is set it is already in the past. Therefore we add a check after set interrupt to verify it is in future.
If it is not, we fire interrupt immediately. This results in
two events - first one immediate, correct one. The second one might be scheduled in far future (almost entire ticker range),
that should be discarded.
The specification for the fire_interrupts are:
- should set pending bit for the ticker interrupt (as soon as possible),
the event we are scheduling is already in the past, and we do not want to skip
any events
- no arguments are provided, neither return value, not needed
- ticker should be initialized prior calling this function (no need to check if it is already initialized)
All our targets provide this new functionality, removing old misleading if (timestamp is in the past) checks.
2017-06-27 11:18:59 +00:00
|
|
|
uint32_t delta = timestamp - us_ticker_read();
|
2014-04-17 20:36:03 +00:00
|
|
|
//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);
|
2013-09-24 14:36:04 +00:00
|
|
|
us_ticker_int_counter--;
|
|
|
|
} else {
|
2014-04-17 20:36:03 +00:00
|
|
|
ticker_set(us_ticker_int_remainder);
|
2013-09-24 14:36:04 +00:00
|
|
|
}
|
|
|
|
}
|
Ticker: add fire interrupt now function
fire_interrupt function should be used for events in the past. As we have now
64bit timestamp, we can figure out what is in the past, and ask a target to invoke
an interrupt immediately. The previous attemps in the target HAL tickers were not ideal, as it can wrap around easily (16 or 32 bit counters). This new
functionality should solve this problem.
set_interrupt for tickers in HAL code should not handle anything but the next match interrupt. If it was in the past is handled by the upper layer.
It is possible that we are setting next event to the close future, so once it is set it is already in the past. Therefore we add a check after set interrupt to verify it is in future.
If it is not, we fire interrupt immediately. This results in
two events - first one immediate, correct one. The second one might be scheduled in far future (almost entire ticker range),
that should be discarded.
The specification for the fire_interrupts are:
- should set pending bit for the ticker interrupt (as soon as possible),
the event we are scheduling is already in the past, and we do not want to skip
any events
- no arguments are provided, neither return value, not needed
- ticker should be initialized prior calling this function (no need to check if it is already initialized)
All our targets provide this new functionality, removing old misleading if (timestamp is in the past) checks.
2017-06-27 11:18:59 +00:00
|
|
|
|
|
|
|
void us_ticker_fire_interrupt(void)
|
|
|
|
{
|
|
|
|
NVIC_SetPendingIRQ(PIT_TICKER_IRQ);
|
|
|
|
}
|
2018-07-25 06:40:30 +00:00
|
|
|
|
|
|
|
void us_ticker_free(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|