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