This is the code used on my video series "Hybrid Supercapacitor Car Battery" for my own hardware monitoring system. THe videos can be found on madelectronengineering.com
Dependencies: BurstSPI Fonts INA219 mbed LPC1114_WakeInterruptIn
Fork of SharpMemoryLCD by
Device/WakeUp_Freescale.cpp@2:0c49a8f32f6e, 2017-12-26 (annotated)
- Committer:
- madelectroneng
- Date:
- Tue Dec 26 21:30:09 2017 +0000
- Revision:
- 2:0c49a8f32f6e
Inital setup
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
madelectroneng | 2:0c49a8f32f6e | 1 | #if defined(TARGET_Freescale) |
madelectroneng | 2:0c49a8f32f6e | 2 | |
madelectroneng | 2:0c49a8f32f6e | 3 | #include "WakeUp.h" |
madelectroneng | 2:0c49a8f32f6e | 4 | #include "us_ticker_api.h" |
madelectroneng | 2:0c49a8f32f6e | 5 | |
madelectroneng | 2:0c49a8f32f6e | 6 | Callback<void()> WakeUp::callback; |
madelectroneng | 2:0c49a8f32f6e | 7 | float WakeUp::cycles_per_ms = 1.0; |
madelectroneng | 2:0c49a8f32f6e | 8 | |
madelectroneng | 2:0c49a8f32f6e | 9 | static uint16_t remainder_count; |
madelectroneng | 2:0c49a8f32f6e | 10 | static uint32_t oldvector; |
madelectroneng | 2:0c49a8f32f6e | 11 | static uint8_t oldPSR; |
madelectroneng | 2:0c49a8f32f6e | 12 | |
madelectroneng | 2:0c49a8f32f6e | 13 | //See if we have a 32kHz crystal on the clock input |
madelectroneng | 2:0c49a8f32f6e | 14 | //Check if the DMX32 bit is set, not perfect, but most cases will work |
madelectroneng | 2:0c49a8f32f6e | 15 | static inline bool is32kXtal(void) { |
madelectroneng | 2:0c49a8f32f6e | 16 | return (MCG->C4 & MCG_C4_DMX32_MASK); |
madelectroneng | 2:0c49a8f32f6e | 17 | } |
madelectroneng | 2:0c49a8f32f6e | 18 | |
madelectroneng | 2:0c49a8f32f6e | 19 | void restore(void); |
madelectroneng | 2:0c49a8f32f6e | 20 | |
madelectroneng | 2:0c49a8f32f6e | 21 | void WakeUp::set_ms(uint32_t ms) |
madelectroneng | 2:0c49a8f32f6e | 22 | { |
madelectroneng | 2:0c49a8f32f6e | 23 | /* Clock the timer */ |
madelectroneng | 2:0c49a8f32f6e | 24 | SIM->SCGC5 |= 0x1u; |
madelectroneng | 2:0c49a8f32f6e | 25 | |
madelectroneng | 2:0c49a8f32f6e | 26 | //Check if it is running, in that case, store current values |
madelectroneng | 2:0c49a8f32f6e | 27 | remainder_count = 0; |
madelectroneng | 2:0c49a8f32f6e | 28 | if (NVIC_GetVector(LPTimer_IRQn) != (uint32_t)WakeUp::irq_handler) { |
madelectroneng | 2:0c49a8f32f6e | 29 | oldvector = NVIC_GetVector(LPTimer_IRQn); |
madelectroneng | 2:0c49a8f32f6e | 30 | oldPSR = LPTMR0->PSR; |
madelectroneng | 2:0c49a8f32f6e | 31 | |
madelectroneng | 2:0c49a8f32f6e | 32 | if (LPTMR0->CSR & LPTMR_CSR_TIE_MASK) { |
madelectroneng | 2:0c49a8f32f6e | 33 | //Write first to sync value |
madelectroneng | 2:0c49a8f32f6e | 34 | LPTMR0->CNR = 0; |
madelectroneng | 2:0c49a8f32f6e | 35 | uint16_t countval = LPTMR0->CNR; |
madelectroneng | 2:0c49a8f32f6e | 36 | if (countval < LPTMR0->CMR) |
madelectroneng | 2:0c49a8f32f6e | 37 | remainder_count = countval - LPTMR0->CMR; |
madelectroneng | 2:0c49a8f32f6e | 38 | } |
madelectroneng | 2:0c49a8f32f6e | 39 | } |
madelectroneng | 2:0c49a8f32f6e | 40 | |
madelectroneng | 2:0c49a8f32f6e | 41 | LPTMR0->CSR = 0; |
madelectroneng | 2:0c49a8f32f6e | 42 | |
madelectroneng | 2:0c49a8f32f6e | 43 | if (ms != 0) { |
madelectroneng | 2:0c49a8f32f6e | 44 | /* Set interrupt handler */ |
madelectroneng | 2:0c49a8f32f6e | 45 | NVIC_SetVector(LPTimer_IRQn, (uint32_t)WakeUp::irq_handler); |
madelectroneng | 2:0c49a8f32f6e | 46 | NVIC_EnableIRQ(LPTimer_IRQn); |
madelectroneng | 2:0c49a8f32f6e | 47 | |
madelectroneng | 2:0c49a8f32f6e | 48 | uint32_t counts; |
madelectroneng | 2:0c49a8f32f6e | 49 | //Set clock |
madelectroneng | 2:0c49a8f32f6e | 50 | if (is32kXtal()) { |
madelectroneng | 2:0c49a8f32f6e | 51 | SIM->SOPT1 &= ~SIM_SOPT1_OSC32KSEL_MASK; //Put RTC/LPTMR on 32kHz external. |
madelectroneng | 2:0c49a8f32f6e | 52 | #ifdef OSC0 |
madelectroneng | 2:0c49a8f32f6e | 53 | OSC0->CR |= OSC_CR_EREFSTEN_MASK; |
madelectroneng | 2:0c49a8f32f6e | 54 | #else |
madelectroneng | 2:0c49a8f32f6e | 55 | OSC->CR |= OSC_CR_EREFSTEN_MASK; |
madelectroneng | 2:0c49a8f32f6e | 56 | #endif |
madelectroneng | 2:0c49a8f32f6e | 57 | LPTMR0->PSR = LPTMR_PSR_PCS(2); |
madelectroneng | 2:0c49a8f32f6e | 58 | counts = (uint32_t)((float)ms * 32.768f); |
madelectroneng | 2:0c49a8f32f6e | 59 | } else { |
madelectroneng | 2:0c49a8f32f6e | 60 | //Clock from the 1kHz LPO |
madelectroneng | 2:0c49a8f32f6e | 61 | LPTMR0->PSR = LPTMR_PSR_PCS(1); |
madelectroneng | 2:0c49a8f32f6e | 62 | counts = (uint32_t)((float)ms * cycles_per_ms); |
madelectroneng | 2:0c49a8f32f6e | 63 | } |
madelectroneng | 2:0c49a8f32f6e | 64 | |
madelectroneng | 2:0c49a8f32f6e | 65 | //If no prescaler is needed |
madelectroneng | 2:0c49a8f32f6e | 66 | if (counts <= 0xFFFF) |
madelectroneng | 2:0c49a8f32f6e | 67 | LPTMR0->PSR |= LPTMR_PSR_PBYP_MASK; |
madelectroneng | 2:0c49a8f32f6e | 68 | else { //Otherwise increase prescaler until it fits |
madelectroneng | 2:0c49a8f32f6e | 69 | counts >>= 1; |
madelectroneng | 2:0c49a8f32f6e | 70 | uint32_t prescaler = 0; |
madelectroneng | 2:0c49a8f32f6e | 71 | while (counts > 0xFFFF) { |
madelectroneng | 2:0c49a8f32f6e | 72 | counts >>= 1; |
madelectroneng | 2:0c49a8f32f6e | 73 | prescaler++; |
madelectroneng | 2:0c49a8f32f6e | 74 | } |
madelectroneng | 2:0c49a8f32f6e | 75 | LPTMR0->PSR |= LPTMR_PSR_PRESCALE(prescaler); |
madelectroneng | 2:0c49a8f32f6e | 76 | } |
madelectroneng | 2:0c49a8f32f6e | 77 | LPTMR0->CMR = counts; |
madelectroneng | 2:0c49a8f32f6e | 78 | |
madelectroneng | 2:0c49a8f32f6e | 79 | LPTMR0->CSR = LPTMR_CSR_TIE_MASK; |
madelectroneng | 2:0c49a8f32f6e | 80 | LPTMR0->CSR |= LPTMR_CSR_TEN_MASK; |
madelectroneng | 2:0c49a8f32f6e | 81 | } else { |
madelectroneng | 2:0c49a8f32f6e | 82 | restore(); |
madelectroneng | 2:0c49a8f32f6e | 83 | } |
madelectroneng | 2:0c49a8f32f6e | 84 | |
madelectroneng | 2:0c49a8f32f6e | 85 | } |
madelectroneng | 2:0c49a8f32f6e | 86 | |
madelectroneng | 2:0c49a8f32f6e | 87 | |
madelectroneng | 2:0c49a8f32f6e | 88 | void WakeUp::irq_handler(void) |
madelectroneng | 2:0c49a8f32f6e | 89 | { |
madelectroneng | 2:0c49a8f32f6e | 90 | // write 1 to TCF to clear the LPT timer compare flag |
madelectroneng | 2:0c49a8f32f6e | 91 | LPTMR0->CSR |= LPTMR_CSR_TCF_MASK; |
madelectroneng | 2:0c49a8f32f6e | 92 | restore(); |
madelectroneng | 2:0c49a8f32f6e | 93 | callback.call(); |
madelectroneng | 2:0c49a8f32f6e | 94 | } |
madelectroneng | 2:0c49a8f32f6e | 95 | |
madelectroneng | 2:0c49a8f32f6e | 96 | void WakeUp::calibrate(void) |
madelectroneng | 2:0c49a8f32f6e | 97 | { |
madelectroneng | 2:0c49a8f32f6e | 98 | if (!is32kXtal()) { |
madelectroneng | 2:0c49a8f32f6e | 99 | wait_us(1); //Otherwise next wait might overwrite our settings |
madelectroneng | 2:0c49a8f32f6e | 100 | cycles_per_ms = 1.0; |
madelectroneng | 2:0c49a8f32f6e | 101 | set_ms(1100); |
madelectroneng | 2:0c49a8f32f6e | 102 | wait_ms(100); |
madelectroneng | 2:0c49a8f32f6e | 103 | |
madelectroneng | 2:0c49a8f32f6e | 104 | //Write first to sync value |
madelectroneng | 2:0c49a8f32f6e | 105 | LPTMR0->CNR = 0; |
madelectroneng | 2:0c49a8f32f6e | 106 | uint32_t ticks = LPTMR0->CNR; |
madelectroneng | 2:0c49a8f32f6e | 107 | cycles_per_ms = ticks / 100.0; |
madelectroneng | 2:0c49a8f32f6e | 108 | set_ms(0); |
madelectroneng | 2:0c49a8f32f6e | 109 | } |
madelectroneng | 2:0c49a8f32f6e | 110 | } |
madelectroneng | 2:0c49a8f32f6e | 111 | |
madelectroneng | 2:0c49a8f32f6e | 112 | void restore(void){ |
madelectroneng | 2:0c49a8f32f6e | 113 | /* Reset */ |
madelectroneng | 2:0c49a8f32f6e | 114 | LPTMR0->CSR = 0; |
madelectroneng | 2:0c49a8f32f6e | 115 | |
madelectroneng | 2:0c49a8f32f6e | 116 | /* Set interrupt handler */ |
madelectroneng | 2:0c49a8f32f6e | 117 | NVIC_SetVector(LPTimer_IRQn, oldvector); |
madelectroneng | 2:0c49a8f32f6e | 118 | NVIC_EnableIRQ(LPTimer_IRQn); |
madelectroneng | 2:0c49a8f32f6e | 119 | |
madelectroneng | 2:0c49a8f32f6e | 120 | /* Clock at (1)MHz -> (1)tick/us */ |
madelectroneng | 2:0c49a8f32f6e | 121 | LPTMR0->PSR = oldPSR; |
madelectroneng | 2:0c49a8f32f6e | 122 | |
madelectroneng | 2:0c49a8f32f6e | 123 | if (remainder_count) { |
madelectroneng | 2:0c49a8f32f6e | 124 | /* Set the compare register */ |
madelectroneng | 2:0c49a8f32f6e | 125 | LPTMR0->CMR = remainder_count; |
madelectroneng | 2:0c49a8f32f6e | 126 | |
madelectroneng | 2:0c49a8f32f6e | 127 | /* Enable interrupt */ |
madelectroneng | 2:0c49a8f32f6e | 128 | LPTMR0->CSR |= LPTMR_CSR_TIE_MASK; |
madelectroneng | 2:0c49a8f32f6e | 129 | |
madelectroneng | 2:0c49a8f32f6e | 130 | /* Start the timer */ |
madelectroneng | 2:0c49a8f32f6e | 131 | LPTMR0->CSR |= LPTMR_CSR_TEN_MASK; |
madelectroneng | 2:0c49a8f32f6e | 132 | } |
madelectroneng | 2:0c49a8f32f6e | 133 | } |
madelectroneng | 2:0c49a8f32f6e | 134 | |
madelectroneng | 2:0c49a8f32f6e | 135 | #endif |