mirror of https://github.com/ARMmbed/mbed-os.git
[KL25Z] Fix us_ticker_api implementation and improve documentation
parent
c906468071
commit
5f09c37d0f
|
@ -17,50 +17,17 @@
|
|||
#include "us_ticker_api.h"
|
||||
#include "PeripheralNames.h"
|
||||
|
||||
static void (*us_ticker_interrupt_handler)(void) = NULL;
|
||||
|
||||
static uint16_t us_ticker_int_counter = 0;
|
||||
static uint16_t us_ticker_int_remainder = 0;
|
||||
|
||||
void lptmr_isr(void) {
|
||||
// write 1 to TCF to clear the LPT timer compare flag
|
||||
LPTMR0->CSR |= LPTMR_CSR_TCF_MASK;
|
||||
|
||||
if (us_ticker_int_counter > 0) {
|
||||
us_ticker_int_counter--;
|
||||
|
||||
} else {
|
||||
if (us_ticker_int_remainder > 0) {
|
||||
us_ticker_int_remainder = 0;
|
||||
LPTMR0->CMR = us_ticker_int_remainder;
|
||||
|
||||
} else {
|
||||
if (us_ticker_interrupt_handler != NULL) {
|
||||
us_ticker_interrupt_handler();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int lptmr_inited = 0;
|
||||
void lptmr_init(void) {
|
||||
lptmr_inited = 1;
|
||||
|
||||
/* Clock the timer */
|
||||
SIM->SCGC5 |= SIM_SCGC5_LPTMR_MASK;
|
||||
|
||||
/* Reset */
|
||||
LPTMR0->CSR = 0;
|
||||
|
||||
/* Set interrupt handler */
|
||||
NVIC_SetVector(LPTimer_IRQn, (uint32_t)lptmr_isr);
|
||||
NVIC_EnableIRQ(LPTimer_IRQn);
|
||||
|
||||
/* Clock at (1)MHz -> (1)tick/us */
|
||||
LPTMR0->PSR = LPTMR_PSR_PCS(3); // OSCERCLK -> 8MHz
|
||||
LPTMR0->PSR |= LPTMR_PSR_PRESCALE(2); // divide by 8
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Timer for us timing.
|
||||
*
|
||||
* Need to have 32bit resolution, we are using the PIT (2x32bit timers) for
|
||||
* that. All the other timers have only 16bit resolution.
|
||||
* Unfortunately, the PIT does not have a prescaler, therefore it ticks at the
|
||||
* bus clock of (24)MHz.
|
||||
* To keep 32bit resolution we are chaining the 2 32bit timers together dividing
|
||||
* the final result by 24.
|
||||
* NOTE: The PIT is a countdown timer.
|
||||
******************************************************************************/
|
||||
static int us_ticker_running = 0;
|
||||
|
||||
static void us_ticker_init(void) {
|
||||
|
@ -96,56 +63,99 @@ uint32_t us_ticker_read() {
|
|||
return (uint32_t)(0xFFFFFFFF & ticks);
|
||||
}
|
||||
|
||||
static void us_ticker_set_interrupt(unsigned int timestamp) {
|
||||
if (!lptmr_inited)
|
||||
lptmr_init();
|
||||
|
||||
int delta = (int)(timestamp - us_ticker_read());
|
||||
if (delta < 0) {
|
||||
if (us_ticker_interrupt_handler != NULL) {
|
||||
us_ticker_interrupt_handler();
|
||||
}
|
||||
return;
|
||||
}
|
||||
us_ticker_int_counter = (uint16_t)(delta >> 16);
|
||||
us_ticker_int_remainder = (uint16_t)(0xFFFF & delta);
|
||||
if (us_ticker_int_counter > 0) {
|
||||
LPTMR0->CMR = 0xFFFF;
|
||||
} else {
|
||||
LPTMR0->CMR = us_ticker_int_remainder;
|
||||
}
|
||||
/******************************************************************************
|
||||
* Timer Event
|
||||
*
|
||||
* It schedules interrupts at given (32bit)us interval of time.
|
||||
* It is implemented used the 16bit Low Power Timer that remains powered in all
|
||||
* power modes.
|
||||
******************************************************************************/
|
||||
static void lptmr_isr(void);
|
||||
static void lptmr_irq_handler(void);
|
||||
static void us_ticker_set_interrupt(unsigned int timestamp);
|
||||
|
||||
static ticker_event_handler event_handler = NULL;
|
||||
void us_ticker_set_handler(ticker_event_handler handler) {
|
||||
event_handler = handler;
|
||||
}
|
||||
|
||||
static uint32_t us_ticker_int_counter = 0;
|
||||
static uint16_t us_ticker_int_remainder = 0;
|
||||
|
||||
static int lptmr_inited = 0;
|
||||
void lptmr_init(void) {
|
||||
lptmr_inited = 1;
|
||||
|
||||
/* Clock the timer */
|
||||
SIM->SCGC5 |= SIM_SCGC5_LPTMR_MASK;
|
||||
|
||||
/* Reset */
|
||||
LPTMR0->CSR = 0;
|
||||
|
||||
/* Set interrupt handler */
|
||||
NVIC_SetVector(LPTimer_IRQn, (uint32_t)lptmr_isr);
|
||||
NVIC_EnableIRQ(LPTimer_IRQn);
|
||||
|
||||
/* Clock at (1)MHz -> (1)tick/us */
|
||||
LPTMR0->PSR = LPTMR_PSR_PCS(3); // OSCERCLK -> 8MHz
|
||||
LPTMR0->PSR |= LPTMR_PSR_PRESCALE(2); // divide by 8
|
||||
}
|
||||
|
||||
static void lptmr_set(unsigned short count) {
|
||||
/* Reset */
|
||||
LPTMR0->CSR = 0;
|
||||
|
||||
/* Set the compare register */
|
||||
LPTMR0->CMR = count;
|
||||
|
||||
/* Enable interrupt */
|
||||
LPTMR0->CSR |= LPTMR_CSR_TIE_MASK;
|
||||
|
||||
|
||||
/* Start the timer */
|
||||
LPTMR0->CSR |= LPTMR_CSR_TEN_MASK;
|
||||
}
|
||||
|
||||
static void us_ticker_disable_interrupt(void) {
|
||||
LPTMR0->CSR &= ~LPTMR_CSR_TIE_MASK;
|
||||
static void lptmr_isr(void) {
|
||||
// write 1 to TCF to clear the LPT timer compare flag
|
||||
LPTMR0->CSR |= LPTMR_CSR_TCF_MASK;
|
||||
|
||||
if (us_ticker_int_counter > 0) {
|
||||
lptmr_set(0xFFFF);
|
||||
us_ticker_int_counter--;
|
||||
|
||||
} else {
|
||||
if (us_ticker_int_remainder > 0) {
|
||||
lptmr_set(us_ticker_int_remainder);
|
||||
us_ticker_int_remainder = 0;
|
||||
|
||||
} else {
|
||||
// This function is going to disable the interrupts if there are
|
||||
// no other events in the queue
|
||||
lptmr_irq_handler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ticker_event_handler event_handler;
|
||||
static ticker_event_t *head = NULL;
|
||||
|
||||
void irq_handler(void) {
|
||||
static void lptmr_irq_handler(void) {
|
||||
/* Go through all the pending TimerEvents */
|
||||
while (1) {
|
||||
if (head == NULL) {
|
||||
// There are no more TimerEvents left, so disable matches.
|
||||
us_ticker_disable_interrupt();
|
||||
LPTMR0->CSR &= ~LPTMR_CSR_TIE_MASK;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ((int)(head->timestamp - us_ticker_read()) <= 0) {
|
||||
// This event was in the past:
|
||||
// point to the following one and execute its handler
|
||||
ticker_event_t *p = head;
|
||||
head = head->next;
|
||||
|
||||
event_handler(p->id); // NOTE: the handler can set new events
|
||||
|
||||
if (event_handler != NULL) {
|
||||
event_handler(p->id); // NOTE: the handler can set new events
|
||||
}
|
||||
} else {
|
||||
// This event and the following ones in the list are in the future:
|
||||
// set it as next interrupt and return
|
||||
|
@ -155,19 +165,36 @@ void irq_handler(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void us_ticker_set_handler(ticker_event_handler handler) {
|
||||
event_handler = handler;
|
||||
us_ticker_interrupt_handler = irq_handler;
|
||||
static void us_ticker_set_interrupt(unsigned int timestamp) {
|
||||
if (!lptmr_inited)
|
||||
lptmr_init();
|
||||
|
||||
int delta = (int)(timestamp - us_ticker_read());
|
||||
if (delta <= 0) {
|
||||
// This event was in the past:
|
||||
lptmr_irq_handler();
|
||||
return;
|
||||
}
|
||||
|
||||
us_ticker_int_counter = (uint32_t)(delta >> 16);
|
||||
us_ticker_int_remainder = (uint16_t)(0xFFFF & delta);
|
||||
if (us_ticker_int_counter > 0) {
|
||||
lptmr_set(0xFFFF);
|
||||
us_ticker_int_counter--;
|
||||
} else {
|
||||
lptmr_set(us_ticker_int_remainder);
|
||||
us_ticker_int_remainder = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void us_ticker_insert_event(ticker_event_t *obj, unsigned int timestamp, uint32_t id) {
|
||||
/* disable interrupts for the duration of the function */
|
||||
__disable_irq();
|
||||
|
||||
|
||||
// initialise our data
|
||||
obj->timestamp = timestamp;
|
||||
obj->id = id;
|
||||
|
||||
|
||||
/* Go through the list until we either reach the end, or find
|
||||
an element this should come before (which is possibly the
|
||||
head). */
|
||||
|
@ -190,20 +217,22 @@ void us_ticker_insert_event(ticker_event_t *obj, unsigned int timestamp, uint32_
|
|||
}
|
||||
/* if we're at the end p will be NULL, which is correct */
|
||||
obj->next = p;
|
||||
|
||||
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
void us_ticker_remove_event(ticker_event_t *obj) {
|
||||
__disable_irq();
|
||||
|
||||
|
||||
// remove this object from the list
|
||||
if (head == obj) { // first in the list, so just drop me
|
||||
if (head == obj) {
|
||||
// first in the list, so just drop me
|
||||
head = obj->next;
|
||||
if (obj->next != NULL) {
|
||||
us_ticker_set_interrupt(head->timestamp);
|
||||
}
|
||||
} else { // find the object before me, then drop me
|
||||
} else {
|
||||
// find the object before me, then drop me
|
||||
ticker_event_t* p = head;
|
||||
while (p != NULL) {
|
||||
if (p->next == obj) {
|
||||
|
@ -213,6 +242,6 @@ void us_ticker_remove_event(ticker_event_t *obj) {
|
|||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__enable_irq();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue