mbed-os/targets/TARGET_ONSEMI/TARGET_NCS36510/ncs36510_us_ticker_api.c

211 lines
6.5 KiB
C

/**
******************************************************************************
* @file us_ticker_api.h
* @brief Implementation of a Timer driver
* @internal
* @author ON Semiconductor
* $Rev: $
* $Date: 2015-11-15 $
******************************************************************************
* Copyright 2016 Semiconductor Components Industries LLC (d/b/a “ON Semiconductor”).
* All rights reserved. This software and/or documentation is licensed by ON Semiconductor
* under limited terms and conditions. The terms and conditions pertaining to the software
* and/or documentation are available at http://www.onsemi.com/site/pdf/ONSEMI_T&C.pdf
* (“ON Semiconductor Standard Terms and Conditions of Sale, Section 8 Software”) and
* if applicable the software license agreement. Do not use this software and/or
* documentation unless you have carefully read and you agree to the limited terms and
* conditions. By using this software and/or documentation, you agree to the limited
* terms and conditions.
*
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* ON SEMICONDUCTOR SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
* @endinternal
*
* @ingroup timer
*/
#include <stddef.h>
#include "timer_ncs36510.h"
#define US_TIMER TIMER0
#define US_TICKER TIMER1
static int us_ticker_inited = 0;
static void us_timer_init(void);
static uint32_t us_ticker_target = 0;
static volatile uint16_t msb_counter = 0;
void us_ticker_init(void)
{
if (!us_ticker_inited) {
us_timer_init();
}
}
/*******************************************************************************
* Timer for us timing reference
*
* Uptime counter for scheduling reference. It uses TIMER0.
* The NCS36510 does not have a 32 bit timer nor the option to chain timers,
* which is why a software timer is required to get 32-bit word length.
******************************************************************************/
/* TODO - Need some sort of load value/prescale calculation for non-32MHz clock */
/* TODO - How is overflow handled? */
/* Timer 0 for free running time */
extern void us_timer_isr(void)
{
TIM0REG->CLEAR = 0;
msb_counter++;
}
/* Initializing TIMER 0(TImer) and TIMER 1(Ticker) */
static void us_timer_init(void)
{
/* Enable the timer0 periphery clock */
CLOCK_ENABLE(CLOCK_TIMER0);
/* Enable the timer0 periphery clock */
CLOCK_ENABLE(CLOCK_TIMER1);
/* Timer init */
/* load timer value */
TIM0REG->LOAD = 0xFFFF;
/* set timer prescale 32 (1 us), mode & enable */
TIM0REG->CONTROL.WORD = ((CLK_DIVIDER_32 << TIMER_PRESCALE_BIT_POS) |
(TIME_MODE_PERIODIC << TIMER_MODE_BIT_POS) |
(TIMER_ENABLE_BIT << TIMER_ENABLE_BIT_POS));
/* Ticker init */
/* load timer value */
TIM1REG->LOAD = 0xFFFF;
/* set timer prescale 32 (1 us), mode & enable */
TIM1REG->CONTROL.WORD = ((CLK_DIVIDER_32 << TIMER_PRESCALE_BIT_POS) |
(TIME_MODE_PERIODIC << TIMER_MODE_BIT_POS));
/* Register & enable interrupt associated with the timer */
NVIC_SetVector(Tim0_IRQn,(uint32_t)us_timer_isr);
NVIC_SetVector(Tim1_IRQn,(uint32_t)us_ticker_isr);
/* Clear pending irqs */
NVIC_ClearPendingIRQ(Tim0_IRQn);
NVIC_ClearPendingIRQ(Tim1_IRQn);
/* Setup NVIC for timer */
NVIC_EnableIRQ(Tim0_IRQn);
NVIC_EnableIRQ(Tim1_IRQn);
us_ticker_inited = 1;
}
/* Reads 32 bit timer's current value (16 bit s/w timer | 16 bit h/w timer) */
uint32_t us_ticker_read()
{
if (!us_ticker_inited) {
us_timer_init();
}
NVIC_DisableIRQ(Tim0_IRQn);
uint32_t retval, tim0cval;
/* Get the current tick from the hw and sw timers */
tim0cval = TIM0REG->VALUE; /* read current time */
retval = (0xFFFF - tim0cval); /* subtract down count */
if (TIM0REG->CONTROL.BITS.INT) {
us_timer_isr(); /* handle ISR again */
NVIC_ClearPendingIRQ(Tim0_IRQn);
retval = (0xFFFF - TIM0REG->VALUE);
}
retval |= msb_counter << 16; /* add software bits */
NVIC_EnableIRQ(Tim0_IRQn);
return retval;
}
void us_ticker_fire_interrupt(void)
{
us_ticker_target = 0;
NVIC_SetPendingIRQ(Tim1_IRQn);
}
/*******************************************************************************
* Event Timer
*
* Schedules interrupts at given (32bit)us interval of time. It uses TIMER1.
* The NCS36510 does not have a 32 bit timer nor the option to chain timers,
* which is why a software timer is required to get 32-bit word length.
*******************************************************************************/
/* TODO - Need some sort of load value/prescale calculation for non-32MHz clock */
/* TImer 1 disbale interrupt */
void us_ticker_disable_interrupt(void)
{
/* Disable the TIMER1 interrupt */
TIM1REG->CONTROL.BITS.ENABLE = 0x0;
}
/* TImer 1 clear interrupt */
void us_ticker_clear_interrupt(void)
{
/* Clear the Ticker (TIMER1) interrupt */
TIM1REG->CLEAR = 0;
}
/* Setting TImer 1 (ticker) */
inline static void ticker_set(uint32_t count)
{
/* Disable TIMER1, load the new value, and re-enable */
TIM1REG->CONTROL.BITS.ENABLE = 0;
TIM1REG->LOAD = count;
TIM1REG->CONTROL.BITS.ENABLE = 1;
}
/* TImer 1 - ticker ISR */
extern void us_ticker_isr(void)
{
/* Clear IRQ flag */
TIM1REG->CLEAR = 0;
if (us_ticker_target > 0) {
--us_ticker_target;
ticker_set(0xFFFF);
} else {
us_ticker_irq_handler();
}
}
/* Set timer 1 ticker interrupt */
void us_ticker_set_interrupt(timestamp_t timestamp)
{
int32_t delta = timestamp - us_ticker_read();
// we got 16 bit timer, use upper 16bit as a simple counter how many times
// we need to schedule full range ticker count
us_ticker_target = (uint32_t)delta >> 16;
if (delta <= 0) {
/* This event was in the past */
//us_ticker_irq_handler();
// This event was in the past.
// Set the interrupt as pending, but don't process it here.
// This prevents a recurive loop under heavy load
// which can lead to a stack overflow.
NVIC_SetPendingIRQ(Tim1_IRQn);
return;
}
// we set the full reminder of 16 bit, the next ISR will do the upper part
ticker_set(delta & 0xFFFF);
}
void us_ticker_free(void)
{
}