Mark Gottscho / HardwareTimersLib

Fork of HardwareTimersLib by Mark Gottscho

Committer:
mgottscho
Date:
Tue Mar 11 05:49:26 2014 +0000
Revision:
13:3564122e9c10
Parent:
12:cb395e4be69e
Updated start() to allow repeated calls without stopping the timer. This allows the user to re-start callbacks at runtime without breaking the timer.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mgottscho 1:7dde0e4d30da 1 /* Timer_TPM.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 "HardwareTimer.h"
mgottscho 1:7dde0e4d30da 9 #include "Timer_TPM.h"
mgottscho 1:7dde0e4d30da 10
mgottscho 7:78f6ee57d324 11 //Init Timer_TPM class variables
mgottscho 7:78f6ee57d324 12 bool Timer_TPM::__tpm_used = false;
mgottscho 7:78f6ee57d324 13 Timer_TPM *Timer_TPM::__obj = NULL;
mgottscho 1:7dde0e4d30da 14
mgottscho 7:78f6ee57d324 15 Timer_TPM::Timer_TPM() :
mgottscho 7:78f6ee57d324 16 HardwareTimer(0xFFFF, 20.833333333, HardwareTimer::ns) //TPM has 16-bit counter. And at 48MHz, each clock cycle is 20.8333333 ns
mgottscho 1:7dde0e4d30da 17 {
mgottscho 7:78f6ee57d324 18 if (__tpm_used)
mgottscho 7:78f6ee57d324 19 __valid = false;
mgottscho 7:78f6ee57d324 20 else {
mgottscho 7:78f6ee57d324 21 __valid = true;
mgottscho 7:78f6ee57d324 22 __tpm_used = true;
mgottscho 7:78f6ee57d324 23 __obj = this;
mgottscho 7:78f6ee57d324 24 }
mgottscho 1:7dde0e4d30da 25 }
mgottscho 1:7dde0e4d30da 26
mgottscho 7:78f6ee57d324 27 Timer_TPM::~Timer_TPM() {
mgottscho 7:78f6ee57d324 28 if (__valid) {
mgottscho 7:78f6ee57d324 29 __tpm_used = false; //free the hardware TPM resource
mgottscho 7:78f6ee57d324 30 __obj = NULL;
mgottscho 7:78f6ee57d324 31 }
mgottscho 1:7dde0e4d30da 32 }
mgottscho 1:7dde0e4d30da 33
mgottscho 1:7dde0e4d30da 34 uint32_t Timer_TPM::getTick() {
mgottscho 7:78f6ee57d324 35 if (!__valid)
mgottscho 7:78f6ee57d324 36 return 0;
mgottscho 1:7dde0e4d30da 37
mgottscho 9:dff7c891ec77 38 uint16_t tick;
mgottscho 9:dff7c891ec77 39 uint32_t count;
mgottscho 9:dff7c891ec77 40
mgottscho 10:12c1c5cef918 41 //__disable_irq(); //CRITICAL SECTION -- ALL INTERRUPTS MUST BE STOPPED!
mgottscho 10:12c1c5cef918 42 TPM0->CNT = 0; //Need to write to the TPM CNT register in order to latch current value.
mgottscho 11:e0442c8b182b 43 tick = (uint16_t) TPM0->CNT; //Value was previously latched, just read it
mgottscho 11:e0442c8b182b 44
mgottscho 10:12c1c5cef918 45 //It is theoretically possible that the timer interrupt is invoked here, between these two lines.
mgottscho 10:12c1c5cef918 46 //However, the timer doesn't appear to work properly if I put these two in a critical section.
mgottscho 10:12c1c5cef918 47
mgottscho 10:12c1c5cef918 48 count = __count; //Latch current count value.
mgottscho 10:12c1c5cef918 49 //__enable_irq(); //END CRITICAL SECTION
mgottscho 10:12c1c5cef918 50
mgottscho 1:7dde0e4d30da 51 //Convert to ticks
mgottscho 9:dff7c891ec77 52 return count * __rolloverValue + (uint32_t) tick;
mgottscho 1:7dde0e4d30da 53 }
mgottscho 1:7dde0e4d30da 54
mgottscho 7:78f6ee57d324 55 void Timer_TPM::__init_timer() {
mgottscho 7:78f6ee57d324 56 //Set TPM clocks
mgottscho 7:78f6ee57d324 57 SIM->SOPT2 |= SIM_SOPT2_TPMSRC(1); //Set TPM global clock source: MCGFLLCLK
mgottscho 7:78f6ee57d324 58 SIM->SCGC6 |= SIM_SCGC6_TPM0_MASK; //Enable TPM block (clock gating)
mgottscho 7:78f6ee57d324 59
mgottscho 7:78f6ee57d324 60 TPM0->SC = 0; //Reset TPM
mgottscho 7:78f6ee57d324 61
mgottscho 7:78f6ee57d324 62 //Configure TPM prescaler
mgottscho 7:78f6ee57d324 63 TPM0->SC = TPM_SC_PS(0); //Prescaler set to 1
mgottscho 7:78f6ee57d324 64
mgottscho 13:3564122e9c10 65 TPM0->CNT = 0; //Set the count register
mgottscho 13:3564122e9c10 66
mgottscho 7:78f6ee57d324 67 //Set interrupt handler
mgottscho 7:78f6ee57d324 68 NVIC_SetVector(TPM0_IRQn, (uint32_t) __tpm_isr_wrapper);
mgottscho 7:78f6ee57d324 69 NVIC_EnableIRQ(TPM0_IRQn);
mgottscho 7:78f6ee57d324 70 }
mgottscho 7:78f6ee57d324 71
mgottscho 7:78f6ee57d324 72 void Timer_TPM::__start_timer() {
mgottscho 7:78f6ee57d324 73 TPM0->MOD = (uint16_t) __rolloverValue; //Set the modulo register
mgottscho 1:7dde0e4d30da 74 TPM0->SC |= TPM_SC_TOIE_MASK; //Enable interrupt
mgottscho 1:7dde0e4d30da 75 TPM0->SC |= TPM_SC_CMOD(1); //Start the timer. Timer will increment on the TPM clock edges, not an external clock
mgottscho 1:7dde0e4d30da 76 }
mgottscho 1:7dde0e4d30da 77
mgottscho 7:78f6ee57d324 78 void Timer_TPM::__stop_timer() {
mgottscho 7:78f6ee57d324 79 TPM0->SC = 0; //Reset TPM
mgottscho 7:78f6ee57d324 80 }
mgottscho 7:78f6ee57d324 81
mgottscho 7:78f6ee57d324 82 void Timer_TPM::__timer_isr() {
mgottscho 1:7dde0e4d30da 83 TPM0->SC |= TPM_SC_TOF_MASK;
mgottscho 7:78f6ee57d324 84 TPM0->MOD = (uint16_t) __rolloverValue; //Set the modulo register
mgottscho 12:cb395e4be69e 85 if ((__periodic || __num_callbacks > 0) && __user_fptr != NULL) { //user callback
mgottscho 7:78f6ee57d324 86 __user_fptr->call();
mgottscho 12:cb395e4be69e 87 if (!__periodic)
mgottscho 12:cb395e4be69e 88 __num_callbacks--;
mgottscho 7:78f6ee57d324 89 }
mgottscho 1:7dde0e4d30da 90 __count++;
mgottscho 7:78f6ee57d324 91 }
mgottscho 7:78f6ee57d324 92
mgottscho 7:78f6ee57d324 93 void Timer_TPM::__tpm_isr_wrapper() {
mgottscho 7:78f6ee57d324 94 __obj->__timer_isr();
mgottscho 1:7dde0e4d30da 95 }