Mark Gottscho / HardwareTimersLib

Fork of HardwareTimersLib by Mark Gottscho

Committer:
mgottscho
Date:
Tue Mar 11 05:38:56 2014 +0000
Revision:
12:cb395e4be69e
Parent:
11:e0442c8b182b
Child:
13:3564122e9c10
Enabled a new mode for the timers. You can now do indefinite periodic callbacks, or a limited number using HardwareTimer::start(). Also got rid of C functions for PIT management.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mgottscho 1:7dde0e4d30da 1 /* Timer_LPTMR.cpp
mgottscho 1:7dde0e4d30da 2 * Tested with mbed board: FRDM-KL46Z
mgottscho 1:7dde0e4d30da 3 * Author: Mark Gottscho
mgottscho 1:7dde0e4d30da 4 * mgottscho@ucla.edu
mgottscho 1:7dde0e4d30da 5 */
mgottscho 1:7dde0e4d30da 6
mgottscho 1:7dde0e4d30da 7 #include "mbed.h"
mgottscho 1:7dde0e4d30da 8 #include "Timer_LPTMR.h"
mgottscho 1:7dde0e4d30da 9 #include "PreciseTime.h"
mgottscho 1:7dde0e4d30da 10
mgottscho 7:78f6ee57d324 11
mgottscho 7:78f6ee57d324 12 //Init Timer_LPTMR class variables
mgottscho 7:78f6ee57d324 13 bool Timer_LPTMR::__lptmr_used = false;
mgottscho 7:78f6ee57d324 14 Timer_LPTMR *Timer_LPTMR::__obj = NULL;
mgottscho 1:7dde0e4d30da 15
mgottscho 7:78f6ee57d324 16 Timer_LPTMR::Timer_LPTMR() :
mgottscho 7:78f6ee57d324 17 HardwareTimer(0xFFFF, 1, HardwareTimer::ms) //LPTMR has 16-bit counter. And at 1 KHz, each clock cycle is 1 ms
mgottscho 7:78f6ee57d324 18 {
mgottscho 7:78f6ee57d324 19 if (__lptmr_used)
mgottscho 7:78f6ee57d324 20 __valid = false;
mgottscho 7:78f6ee57d324 21 else {
mgottscho 7:78f6ee57d324 22 __valid = true;
mgottscho 7:78f6ee57d324 23 __lptmr_used = true;
mgottscho 7:78f6ee57d324 24 __obj = this;
mgottscho 7:78f6ee57d324 25 }
mgottscho 1:7dde0e4d30da 26 }
mgottscho 1:7dde0e4d30da 27
mgottscho 7:78f6ee57d324 28 Timer_LPTMR::~Timer_LPTMR() {
mgottscho 7:78f6ee57d324 29 if (__valid) {
mgottscho 7:78f6ee57d324 30 __lptmr_used = false; //free the hardware LPTMR resource
mgottscho 7:78f6ee57d324 31 __obj = NULL;
mgottscho 7:78f6ee57d324 32 }
mgottscho 1:7dde0e4d30da 33 }
mgottscho 1:7dde0e4d30da 34
mgottscho 1:7dde0e4d30da 35 uint32_t Timer_LPTMR::getTick() {
mgottscho 1:7dde0e4d30da 36 if (!__valid)
mgottscho 1:7dde0e4d30da 37 return 0;
mgottscho 9:dff7c891ec77 38
mgottscho 9:dff7c891ec77 39 uint16_t ticks;
mgottscho 9:dff7c891ec77 40 uint32_t count;
mgottscho 9:dff7c891ec77 41
mgottscho 11:e0442c8b182b 42 //__disable_irq(); //CRITICAL SECTION -- ALL INTERRUPTS MUST BE STOPPED!
mgottscho 1:7dde0e4d30da 43 LPTMR0->CNR = 0; //need to write to the register in order to read it due to buffering
mgottscho 9:dff7c891ec77 44 ticks = (uint16_t) LPTMR0->CNR;
mgottscho 11:e0442c8b182b 45
mgottscho 11:e0442c8b182b 46 //It is theoretically possible that the timer interrupt is invoked here, between these two lines.
mgottscho 11:e0442c8b182b 47 //However, the timer doesn't appear to work properly if I put these two in a critical section.
mgottscho 11:e0442c8b182b 48
mgottscho 9:dff7c891ec77 49 count = __count;
mgottscho 11:e0442c8b182b 50 //__enable_irq(); //END CRITICAL SECTION
mgottscho 1:7dde0e4d30da 51
mgottscho 1:7dde0e4d30da 52 //Convert to ticks
mgottscho 7:78f6ee57d324 53 return (uint32_t) count * __rolloverValue + ticks;
mgottscho 1:7dde0e4d30da 54 }
mgottscho 1:7dde0e4d30da 55
mgottscho 7:78f6ee57d324 56 void Timer_LPTMR::__init_timer() {
mgottscho 7:78f6ee57d324 57 //MCG clocks
mgottscho 7:78f6ee57d324 58 MCG->C2 &= ~MCG_C2_IRCS_MASK; //Set slow internal reference clk (32 KHz)
mgottscho 7:78f6ee57d324 59 MCG->C1 |= MCG_C1_IRCLKEN_MASK; //Enable internal reference clk (MCGIRCLK)
mgottscho 7:78f6ee57d324 60 // MCG->C1 |= MCG_C1_IREFSTEN_MASK; //Enable internal reference clk (MCGIRCLK) to work in stop mode
mgottscho 7:78f6ee57d324 61
mgottscho 7:78f6ee57d324 62 //Timer clock gating
mgottscho 7:78f6ee57d324 63 SIM->SCGC5 |= SIM_SCGC5_LPTMR_MASK; //Disable clock gating the timer
mgottscho 7:78f6ee57d324 64
mgottscho 7:78f6ee57d324 65 //Timer prescaling and clock selection
mgottscho 7:78f6ee57d324 66 LPTMR0->PSR = LPTMR_PSR_PCS(0); //Set LPTMR0 to use MCGIRCLK --> 32 KHz
mgottscho 7:78f6ee57d324 67 LPTMR0->PSR |= LPTMR_PSR_PRESCALE(4); // divide by 32 to get 1 KHz
mgottscho 7:78f6ee57d324 68
mgottscho 7:78f6ee57d324 69 //Status reset
mgottscho 7:78f6ee57d324 70 LPTMR0->CSR = 0; //Reset the timer control/status register
mgottscho 7:78f6ee57d324 71
mgottscho 7:78f6ee57d324 72 //Set interrupt handler
mgottscho 7:78f6ee57d324 73 NVIC_SetVector(LPTimer_IRQn, (uint32_t) __lptmr_isr_wrapper);
mgottscho 7:78f6ee57d324 74 NVIC_EnableIRQ(LPTimer_IRQn);
mgottscho 7:78f6ee57d324 75
mgottscho 7:78f6ee57d324 76 //Good to go!
mgottscho 7:78f6ee57d324 77 }
mgottscho 1:7dde0e4d30da 78
mgottscho 7:78f6ee57d324 79 void Timer_LPTMR::__start_timer() {
mgottscho 7:78f6ee57d324 80 LPTMR0->CSR = 0; //Reset the timer control/status register
mgottscho 7:78f6ee57d324 81 LPTMR0->CMR = __rolloverValue; //Set the compare register
mgottscho 7:78f6ee57d324 82 LPTMR0->CSR |= LPTMR_CSR_TIE_MASK; //Enable interrupt
mgottscho 7:78f6ee57d324 83 LPTMR0->CSR |= LPTMR_CSR_TEN_MASK; //Start the timer
mgottscho 7:78f6ee57d324 84 }
mgottscho 7:78f6ee57d324 85
mgottscho 7:78f6ee57d324 86 void Timer_LPTMR::__stop_timer() {
mgottscho 7:78f6ee57d324 87 LPTMR0->CSR = 0; //Reset the LPTMR timer control/status register
mgottscho 7:78f6ee57d324 88 }
mgottscho 7:78f6ee57d324 89
mgottscho 7:78f6ee57d324 90 void Timer_LPTMR::__timer_isr() {
mgottscho 1:7dde0e4d30da 91 LPTMR0->CSR |= LPTMR_CSR_TCF_MASK; //Write 1 to TCF to clear the LPT timer compare flag
mgottscho 12:cb395e4be69e 92 if ((__periodic || __num_callbacks > 0) && __user_fptr != NULL) { //user callback
mgottscho 7:78f6ee57d324 93 __user_fptr->call();
mgottscho 12:cb395e4be69e 94 if (!__periodic)
mgottscho 12:cb395e4be69e 95 __num_callbacks--;
mgottscho 7:78f6ee57d324 96 }
mgottscho 1:7dde0e4d30da 97 __count++;
mgottscho 1:7dde0e4d30da 98 }
mgottscho 1:7dde0e4d30da 99
mgottscho 7:78f6ee57d324 100 void Timer_LPTMR::__lptmr_isr_wrapper() {
mgottscho 7:78f6ee57d324 101 __obj->__timer_isr();
mgottscho 1:7dde0e4d30da 102 }