Wake-up timer library to wake from deepsleep/power-down

Dependencies:   LPC1114_WakeInterruptIn

Fork of WakeUp by Erik -

Device/WakeUp_Freescale.cpp

Committer:
Sissors
Date:
2014-09-14
Revision:
16:f3adba7cf7c4
Parent:
Device/WakeUp_KLxxZ.cpp@ 7:bb411115f814
Child:
18:13aed323e040

File content as of revision 16:f3adba7cf7c4:

#if defined(TARGET_Freescale)

#include "WakeUp.h"
#include "us_ticker_api.h"

FunctionPointer WakeUp::callback;
float WakeUp::cycles_per_ms = 1.0;

static uint16_t remainder_count;
static uint32_t oldvector;
static uint8_t oldPSR;

void restore(void);

void WakeUp::set_ms(uint32_t ms)
{
    /* Clock the timer */
    SIM->SCGC5 |= 0x1u;
    
    //Check if it is running, in that case, store current values
    remainder_count = 0;
    if (NVIC_GetVector(LPTimer_IRQn) != (uint32_t)WakeUp::irq_handler) {
        oldvector = NVIC_GetVector(LPTimer_IRQn);
        oldPSR = LPTMR0->PSR;
        
        if (LPTMR0->CSR & LPTMR_CSR_TIE_MASK) {
            //Write first to sync value
            LPTMR0->CNR = 0;
            uint16_t countval = LPTMR0->CNR;
            if (countval < LPTMR0->CMR)
                remainder_count = countval - LPTMR0->CMR;
        }
    }
    
    LPTMR0->CSR = 0;

    if (ms != 0) {
        //Clock from the 1kHz LPO
        LPTMR0->PSR = LPTMR_PSR_PCS(1);

        /* Set interrupt handler */
        NVIC_SetVector(LPTimer_IRQn, (uint32_t)WakeUp::irq_handler);
        NVIC_EnableIRQ(LPTimer_IRQn);
        
        uint32_t counts = (uint32_t)((float)ms * cycles_per_ms);

        //If no prescaler is needed
        if (counts <= 0xFFFF) 
            LPTMR0->PSR |= LPTMR_PSR_PBYP_MASK;
        else {        //Otherwise increase prescaler until it fits
            counts >>= 1;
            uint32_t prescaler = 0;
            while (counts > 0xFFFF) {
                counts >>= 1;
                prescaler++;
            }
            LPTMR0->PSR |= LPTMR_PSR_PRESCALE(prescaler);
        }
        LPTMR0->CMR = counts;        

        LPTMR0->CSR = LPTMR_CSR_TIE_MASK;
        LPTMR0->CSR |= LPTMR_CSR_TEN_MASK;
    } else {
        restore();
    }

}


void WakeUp::irq_handler(void)
{
    // write 1 to TCF to clear the LPT timer compare flag
    LPTMR0->CSR |= LPTMR_CSR_TCF_MASK;
    restore();
    callback.call();
}

void WakeUp::calibrate(void)
{
    wait_us(1);     //Otherwise next wait might overwrite our settings
    cycles_per_ms = 1.0;
    set_ms(1100);
    wait_ms(100);

    //Write first to sync value
    LPTMR0->CNR = 0;
    uint32_t ticks = LPTMR0->CNR;
    cycles_per_ms = ticks / 100.0;
    set_ms(0);
}

void restore(void){
    /* Reset */
    LPTMR0->CSR = 0;
    
    /* Set interrupt handler */
    NVIC_SetVector(LPTimer_IRQn, oldvector);
    NVIC_EnableIRQ(LPTimer_IRQn);
    
    /* Clock at (1)MHz -> (1)tick/us */
    LPTMR0->PSR = oldPSR;

    if (remainder_count) {  
        /* Set the compare register */
        LPTMR0->CMR = remainder_count;
        
        /* Enable interrupt */
        LPTMR0->CSR |= LPTMR_CSR_TIE_MASK;
        
        /* Start the timer */
        LPTMR0->CSR |= LPTMR_CSR_TEN_MASK;
    }
}

#endif