Mark Gottscho / HardwareTimersLib

Fork of HardwareTimersLib by Mark Gottscho

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Timer_TPM.cpp Source File

Timer_TPM.cpp

00001 /* Timer_TPM.cpp
00002  * Tested with mbed board: FRDM-KL46Z
00003  * Author: Mark Gottscho
00004  * mgottscho@ucla.edu
00005  */
00006 
00007 #include "mbed.h"
00008 #include "HardwareTimer.h"
00009 #include "Timer_TPM.h"
00010 
00011 //Init Timer_TPM class variables
00012 bool Timer_TPM::__tpm_used = false;
00013 Timer_TPM *Timer_TPM::__obj = NULL;
00014 
00015 Timer_TPM::Timer_TPM() :
00016         HardwareTimer(0xFFFF, 20.833333333, HardwareTimer::ns) //TPM has 16-bit counter. And at 48MHz, each clock cycle is 20.8333333 ns
00017         {   
00018     if (__tpm_used)
00019         __valid = false;
00020     else {
00021         __valid = true;
00022         __tpm_used = true;
00023         __obj = this;
00024     }
00025 }
00026 
00027 Timer_TPM::~Timer_TPM() {
00028     if (__valid) {
00029         __tpm_used = false; //free the hardware TPM resource
00030         __obj = NULL;
00031     }
00032 }
00033 
00034 uint32_t Timer_TPM::getTick () {
00035     if (!__valid)
00036         return 0;
00037         
00038     uint16_t tick;
00039     uint32_t count;
00040     
00041     //__disable_irq(); //CRITICAL SECTION -- ALL INTERRUPTS MUST BE STOPPED!
00042     TPM0->CNT = 0; //Need to write to the TPM CNT register in order to latch current value.
00043     tick = (uint16_t) TPM0->CNT; //Value was previously latched, just read it
00044 
00045     //It is theoretically possible that the timer interrupt is invoked here, between these two lines.
00046     //However, the timer doesn't appear to work properly if I put these two in a critical section.
00047     
00048     count = __count; //Latch current count value.
00049     //__enable_irq(); //END CRITICAL SECTION
00050     
00051     //Convert to ticks
00052     return count * __rolloverValue + (uint32_t) tick;
00053 }
00054 
00055 void Timer_TPM::__init_timer() {    
00056     //Set TPM clocks
00057     SIM->SOPT2 |= SIM_SOPT2_TPMSRC(1); //Set TPM global clock source: MCGFLLCLK
00058     SIM->SCGC6 |= SIM_SCGC6_TPM0_MASK; //Enable TPM block (clock gating)
00059 
00060     TPM0->SC = 0; //Reset TPM
00061     
00062     //Configure TPM prescaler
00063     TPM0->SC = TPM_SC_PS(0); //Prescaler set to 1
00064     
00065     TPM0->CNT = 0; //Set the count register
00066     
00067     //Set interrupt handler
00068     NVIC_SetVector(TPM0_IRQn, (uint32_t) __tpm_isr_wrapper);
00069     NVIC_EnableIRQ(TPM0_IRQn);
00070 }
00071 
00072 void Timer_TPM::__start_timer() {
00073     TPM0->MOD = (uint16_t) __rolloverValue; //Set the modulo register
00074     TPM0->SC |= TPM_SC_TOIE_MASK; //Enable interrupt
00075     TPM0->SC |= TPM_SC_CMOD(1); //Start the timer. Timer will increment on the TPM clock edges, not an external clock
00076 }
00077 
00078 void Timer_TPM::__stop_timer() {
00079     TPM0->SC = 0; //Reset TPM
00080 }
00081 
00082 void Timer_TPM::__timer_isr() {
00083     TPM0->SC |= TPM_SC_TOF_MASK;
00084     TPM0->MOD = (uint16_t) __rolloverValue; //Set the modulo register
00085     if ((__periodic || __num_callbacks > 0) && __user_fptr != NULL) { //user callback
00086         __user_fptr->call();
00087         if (!__periodic)
00088             __num_callbacks--;
00089     }   
00090     __count++;
00091 }
00092 
00093 void Timer_TPM::__tpm_isr_wrapper() {
00094     __obj->__timer_isr();   
00095 }