[KL25Z] Fix us_ticker_api implementation and improve documentation

pull/1/head
Emilio Monti 2013-03-05 18:16:46 +00:00
parent c906468071
commit 5f09c37d0f
1 changed files with 110 additions and 81 deletions

View File

@ -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();
}