Penn Electric Racing / Mbed 2 deprecated SystemManagement

Dependencies:   mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP

Fork of SystemManagement by Martin Deng

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers IMD.cpp Source File

IMD.cpp

00001 #include "IMD.h"
00002 #include <math.h>
00003 #include "pinmap.h"
00004 
00005 
00006 const float ZERO_HZ_TIMEOUT = 0.21;     // Time (sec) that must pass without an edge to call it 0 Hz, set to greater than the longest expected pulse width
00007 const float EXTRA = 0.02;               // Margin on the IMD PWM limits
00008 
00009 const uint32_t PCLK = 24000000;         // Timer counting clock = 24Mhz
00010 const uint32_t TIMEOUT_TICKS = PCLK*ZERO_HZ_TIMEOUT;    // Zeroing timeout in clock ticks = seconds * PCLK
00011 
00012 static IMD* instance[4] = { 0 };        // Access member from static frame, one IMD permitted per timer module (4 total IMD objects)
00013 
00014 // Interrupt functions, must be static context
00015 void tim0_IRQ() {    
00016     if (LPC_TIM0->IR & (1<<4|1<<5)) instance[0]->edgeIRQ();     // Capture pin interrupt
00017     if (LPC_TIM0->IR & 1) instance[0]->zeroIRQ();               // MR0 interrupt
00018     LPC_TIM0->IR=0x3F;        // Clear interrupt flags
00019 }
00020 void tim1_IRQ() {
00021     if (LPC_TIM1->IR & (1<<4|1<<5)) instance[1]->edgeIRQ();
00022     if (LPC_TIM1->IR & 1) instance[1]->zeroIRQ();
00023     LPC_TIM1->IR=0x3F;        // Clear interrupt flags
00024 }
00025 void tim2_IRQ() {
00026     if (LPC_TIM2->IR & (1<<4|1<<5)) instance[2]->edgeIRQ();
00027     if (LPC_TIM2->IR & 1) instance[2]->zeroIRQ();
00028     LPC_TIM2->IR=0x3F;        // Clear interrupt flags
00029 }
00030 void tim3_IRQ() {
00031     if (LPC_TIM3->IR & (1<<4|1<<5)) instance[3]->edgeIRQ();
00032     if (LPC_TIM3->IR & 1) instance[3]->zeroIRQ();
00033     LPC_TIM3->IR=0x3F;        // Clear interrupt flags
00034 }
00035 
00036 IMD::IMD(PinName _pin) {
00037     // Setup the timer/pin access variables
00038     if (_pin == P1_26) {          // CAP0.0
00039         timer=0;
00040         pin=0;
00041         timerBase=LPC_TIM0;
00042     } else if (_pin == P1_27) {   // CAP0.1
00043         timer=0;
00044         pin=1;
00045         timerBase=LPC_TIM0;
00046     } else if (_pin == P1_18) {   // CAP1.0
00047         timer=1;
00048         pin=0;
00049         timerBase=LPC_TIM1;
00050     } else if (_pin == P1_19) {   // CAP1.1
00051         timer=1;
00052         pin=1;
00053         timerBase=LPC_TIM1;
00054     } else if (_pin == P0_4) {    // CAP2.0
00055         timer=2;
00056         pin=0;
00057         timerBase=LPC_TIM2;
00058     } else if (_pin == P0_5) {    // CAP2.1
00059         timer=2;
00060         pin=1;
00061         timerBase=LPC_TIM2;
00062     } else if (_pin == P0_23) {   // CAP3.0
00063         timer=3;
00064         pin=0;
00065         timerBase=LPC_TIM3;
00066     } else if (_pin == P0_24) {   // CAP3.1
00067         timer=3;
00068         pin=1;
00069         timerBase=LPC_TIM3;
00070     } else {                        // Invalid pin
00071         timerBase=0;
00072         pin=0;
00073         timer=0;
00074         return;
00075     }
00076     
00077     instance[timer] = this;
00078     first = true;
00079     
00080     startTime = 0;
00081     widthTicks = 0;                 // Zero low, so that duty = 0/1 = 0%
00082     periodTicks = 1;
00083     
00084     // Enable power and set pclk at 24Mhz
00085     if (timer==0) { 
00086         LPC_SC->PCONP |= (1<<1);
00087         LPC_SC->PCLKSEL0 &= ~(3<<2);
00088     } if (timer==1) { 
00089         LPC_SC->PCONP |= (1<<2);
00090         LPC_SC->PCLKSEL0 &= ~(3<<4);
00091     } if (timer==2) { 
00092         LPC_SC->PCONP |= (1<<22);
00093         LPC_SC->PCLKSEL1 &= ~(3<<12);
00094     } if (timer==3) { 
00095         LPC_SC->PCONP |= (1<<23);
00096         LPC_SC->PCLKSEL1 &= ~(3<<14);
00097     }
00098     
00099     pin_function(_pin, 3);      // Capture input
00100     pin_mode(_pin, PullDown);   // Pull-down
00101 
00102     timerBase->TCR=2;       // Stop counter and hold at 0, for configuration
00103     timerBase->IR=0x3F;     // Clear any interrupt flags
00104     timerBase->CTCR=0;      // Use pclk, not external pin
00105     timerBase->PR=0;        // No prescale value, clock at full pclk=24Mhz
00106     timerBase->EMR=0;       // Do not use external match pins
00107     
00108     if (timer == 0) NVIC_SetVector(TIMER0_IRQn, (uint32_t)&tim0_IRQ);    // Set irq handler for timer0
00109     if (timer == 1) NVIC_SetVector(TIMER1_IRQn, (uint32_t)&tim1_IRQ);    // Set irq handler for timer1
00110     if (timer == 2) NVIC_SetVector(TIMER2_IRQn, (uint32_t)&tim2_IRQ);    // Set irq handler for timer2
00111     if (timer == 3) NVIC_SetVector(TIMER3_IRQn, (uint32_t)&tim3_IRQ);    // Set irq handler for timer3
00112 
00113     NVIC_EnableIRQ((IRQn_Type)(timer+1));
00114     NVIC_SetPriority((IRQn_Type)(timer+1), 0);      // Highest priority (default)
00115     
00116     timerBase->CCR = pin?5<<3:5;                    // Generate interrupt on rising edge of capture pin
00117     timerBase->MCR = 1;                             // Interrupt on MR0 to establish the zero speed timeout
00118     zeroIRQ();                                      // Zero the values
00119     timerBase->TCR = 1;                             // Start counting, GO!
00120 }
00121 
00122 void IMD::edgeIRQ() {
00123     bool rising = pin?timerBase->CCR&(1<<3):timerBase->CCR&1;
00124     uint32_t capTime = pin?timerBase->CR1:timerBase->CR0;   // Get the time of the capture event
00125     timerBase->MR0 = capTime + TIMEOUT_TICKS;               // Move the zero timeout ahead
00126     
00127     // Special case - on first pulse after a timeout or on startup == Period cannot be calculated
00128     //    so set startTime such that periodTicks remains unchanged from its zero state (periodTicks=1)
00129     if (first) {
00130         first = false;
00131         startTime = capTime - 1;   
00132     }
00133     if (rising) {
00134         periodTicks = capTime - startTime;  // Get the period on Rising edge
00135         startTime = capTime;                // Set the start of the next pulse
00136     } else {
00137         widthTicks = capTime - startTime;   // Get the pulse width on Falling edge   
00138     }
00139     
00140     // Switch interrupt types to capture the next edge
00141     if (rising) timerBase->CCR = pin?6<<3:6;
00142     else        timerBase->CCR = pin?5<<3:5;
00143 }
00144 
00145 void IMD::zeroIRQ() {
00146     periodTicks = 1;
00147     first = true;           // Reset the first edge detection case
00148     
00149     bool rising = pin?timerBase->CCR&(1<<3):timerBase->CCR&1;
00150     // Timeout occurred after FALLING edge, RISING edge never happened
00151     if (rising) {
00152         widthTicks = 0;     // Signal is low = 0/1 = 0% duty
00153     } else {
00154         widthTicks = 1;     // Signal is high = 1/1 = 100% duty   
00155     }
00156 }
00157 float IMD::frequency() {
00158     // Handle the case where we want to say 0Hz not infinity Hz
00159     if (periodTicks == 1 || periodTicks == 0) return 0;
00160     else return (float)(PCLK)/(float)(periodTicks);
00161 }
00162 float IMD::duty() {
00163     return (float)(widthTicks)/(float)(periodTicks);
00164 }
00165 
00166 char IMD::status() {
00167     float freq = frequency();
00168     if (freq == 0)                      return OFF;         // IMD off
00169     else if (05 < freq && freq <= 15)   return NORMAL;      // 10Hz normal mode
00170     else if (15 < freq && freq <= 25)   return UNDERVOLT;   // 20Hz undervoltage mode
00171     else if (25 < freq && freq <= 35)   return SPEEDSTART;  // 30Hz speed start mode
00172     else if (35 < freq && freq <= 45)   return ERROR;       // 40Hz IMD error
00173     else if (45 < freq && freq <= 55)   return GROUNDERR;   // 50Hz Ground error
00174     else return INVALID;                                    // Invalid
00175 }
00176 
00177 float IMD::resistance() {
00178     char stat = status();
00179     float dut = duty();
00180     
00181     // In normal or undervoltage mode, where Rf is available
00182     if (stat == NORMAL || stat == UNDERVOLT) {
00183         if (0.05-EXTRA <= dut && dut <= 0.95+EXTRA) {
00184             if (dut > 0.95) dut = 0.95;     // Ceiling
00185             if (dut < 0.05) dut = 0.05;     // Floor so it doesnt mess up the equation below
00186             float rf = (0.9*1200e3/(dut-0.05)) - 1200e3;
00187             if (rf < 1000) rf = 0;          // Floor to hit 0
00188             if (rf > 50e6) rf = 50e6;       // Ceil to stay at 50e6
00189             return rf;
00190         }
00191         else return NAN;
00192     }
00193     // In speed start, where only good/bad estimate is available
00194     if (stat == SPEEDSTART) {
00195         if (0.05-EXTRA <= dut && dut <= 0.10+EXTRA)       return 50e6;        // Good
00196         else if (0.90-EXTRA <= dut && dut <= 0.95+EXTRA)  return 0;           // Bad
00197         else return NAN;
00198     }
00199     return NAN;     // Measurement not available in this mode
00200 }