System Management code
Dependencies: mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP
Fork of SystemManagement by
Libs/IMD/IMD.cpp
- Committer:
- pspatel321
- Date:
- 2015-01-22
- Revision:
- 36:0afc0fc8f86b
- Parent:
- 30:91af74a299e1
- Child:
- 38:8efacce315ae
File content as of revision 36:0afc0fc8f86b:
#include "IMD.h" #include <math.h> #include "pinmap.h" static IMD* instance[4] = { 0 }; // Access member from static frame, one IMD permitted per timer module (4 total IMD objects) const uint32_t PCLK = 24000000; // Timer counting clock = 24Mhz const uint32_t TIMEOUT_TICKS = PCLK*ZERO_HZ_TIMEOUT; // Zeroing timeout in clock ticks = seconds * PCLK const float EXTRA = 0.01; // Margin on the IMD PWM limits // Interrupt functions, must be static context void tim0_IRQ() { if (LPC_TIM0->IR & (1<<4|1<<5)) instance[0]->edgeIRQ(); // Capture pin interrupt if (LPC_TIM0->IR & 1) instance[0]->zeroIRQ(); // MR0 interrupt LPC_TIM0->IR=0x3F; // Clear interrupt flags } void tim1_IRQ() { if (LPC_TIM1->IR & (1<<4|1<<5)) instance[1]->edgeIRQ(); if (LPC_TIM1->IR & 1) instance[1]->zeroIRQ(); LPC_TIM1->IR=0x3F; // Clear interrupt flags } void tim2_IRQ() { if (LPC_TIM2->IR & (1<<4|1<<5)) instance[2]->edgeIRQ(); if (LPC_TIM2->IR & 1) instance[2]->zeroIRQ(); LPC_TIM2->IR=0x3F; // Clear interrupt flags } void tim3_IRQ() { if (LPC_TIM3->IR & (1<<4|1<<5)) instance[3]->edgeIRQ(); if (LPC_TIM3->IR & 1) instance[3]->zeroIRQ(); LPC_TIM3->IR=0x3F; // Clear interrupt flags } IMD::IMD(PinName _pin) { // Setup the timer/pin access variables if (_pin == P1_26) { // CAP0.0 timer=0; pin=0; timerBase=LPC_TIM0; } else if (_pin == P1_27) { // CAP0.1 timer=0; pin=1; timerBase=LPC_TIM0; } else if (_pin == P1_18) { // CAP1.0 timer=1; pin=0; timerBase=LPC_TIM1; } else if (_pin == P1_19) { // CAP1.1 timer=1; pin=1; timerBase=LPC_TIM1; } else if (_pin == P0_4) { // CAP2.0 timer=2; pin=0; timerBase=LPC_TIM2; } else if (_pin == P0_5) { // CAP2.1 timer=2; pin=1; timerBase=LPC_TIM2; } else if (_pin == P0_23) { // CAP3.0 timer=3; pin=0; timerBase=LPC_TIM3; } else if (_pin == P0_24) { // CAP3.1 timer=3; pin=1; timerBase=LPC_TIM3; } else { // Invalid pin timerBase=0; pin=0; timer=0; return; } instance[timer] = this; first = true; startTime = 0; widthTicks = 0; // Zero low, so that duty = 0/1 = 0% periodTicks = 1; // Enable power and set pclk at 24Mhz if (timer==0) { LPC_SC->PCONP |= (1<<1); LPC_SC->PCLKSEL0 &= ~(3<<2); } if (timer==1) { LPC_SC->PCONP |= (1<<2); LPC_SC->PCLKSEL0 &= ~(3<<4); } if (timer==2) { LPC_SC->PCONP |= (1<<22); LPC_SC->PCLKSEL1 &= ~(3<<12); } if (timer==3) { LPC_SC->PCONP |= (1<<23); LPC_SC->PCLKSEL1 &= ~(3<<14); } pin_function(_pin, 3); // Capture input pin_mode(_pin, PullDown); // Pull-down timerBase->TCR=2; // Stop counter and hold at 0, for configuration timerBase->IR=0x3F; // Clear any interrupt flags timerBase->CTCR=0; // Use pclk, not external pin timerBase->PR=0; // No prescale value, clock at full pclk=24Mhz timerBase->EMR=0; // Do not use external match pins if (timer == 0) NVIC_SetVector(TIMER0_IRQn, (uint32_t)&tim0_IRQ); // Set irq handler for timer0 if (timer == 1) NVIC_SetVector(TIMER1_IRQn, (uint32_t)&tim1_IRQ); // Set irq handler for timer1 if (timer == 2) NVIC_SetVector(TIMER2_IRQn, (uint32_t)&tim2_IRQ); // Set irq handler for timer2 if (timer == 3) NVIC_SetVector(TIMER3_IRQn, (uint32_t)&tim3_IRQ); // Set irq handler for timer3 NVIC_EnableIRQ((IRQn_Type)(timer+1)); NVIC_SetPriority((IRQn_Type)(timer+1), 0); // Highest priority (default) timerBase->CCR = pin?5<<3:5; // Generate interrupt on rising edge of capture pin timerBase->MCR = 1; // Interrupt on MR0 to establish the zero speed timeout zeroIRQ(); // Zero the values timerBase->TCR = 1; // Start counting, GO! } void IMD::edgeIRQ() { bool rising = pin?timerBase->CCR&(1<<3):timerBase->CCR&1; uint32_t capTime = pin?timerBase->CR1:timerBase->CR0; // Get the time of the capture event timerBase->MR0 = capTime + TIMEOUT_TICKS; // Move the zero timeout ahead // Special case - on first pulse after a timeout or on startup == Period cannot be calculated // so set startTime such that periodTicks remains unchanged from its zero state (periodTicks=1) if (first) { first = false; startTime = capTime - 1; } if (rising) { periodTicks = capTime - startTime; // Get the period on Rising edge startTime = capTime; // Set the start of the next pulse } else { widthTicks = capTime - startTime; // Get the pulse width on Falling edge } // Switch interrupt types to capture the next edge if (rising) timerBase->CCR = pin?6<<3:6; else timerBase->CCR = pin?5<<3:5; } void IMD::zeroIRQ() { periodTicks = 1; first = true; // Reset the first edge detection case bool rising = pin?timerBase->CCR&(1<<3):timerBase->CCR&1; // Timeout occurred after FALLING edge, RISING edge never happened if (rising) { widthTicks = 0; // Signal is low = 0/1 = 0% duty } else { widthTicks = 1; // Signal is high = 1/1 = 100% duty } } float IMD::frequency() { // Handle the case where we want to say 0Hz not infinity Hz if (periodTicks == 1 || periodTicks == 0) return 0; else return (float)(PCLK)/(float)(periodTicks); } float IMD::duty() { return (float)(widthTicks)/(float)(periodTicks); } char IMD::status() { float freq = frequency(); if (freq == 0) return OFF; // IMD off else if (05 < freq && freq <= 15) return NORMAL; // 10Hz normal mode else if (15 < freq && freq <= 25) return UNDERVOLT; // 20Hz undervoltage mode else if (25 < freq && freq <= 35) return SPEEDSTART; // 30Hz speed start mode else if (35 < freq && freq <= 45) return ERROR; // 40Hz IMD error else if (45 < freq && freq <= 55) return GROUNDERR; // 50Hz Ground error else return INVALID; // Invalid } float IMD::resistance() { char stat = status(); float dut = duty(); // In normal or undervoltage mode, where Rf is available if (stat == NORMAL || stat == UNDERVOLT) { if (0.05-EXTRA <= dut && dut <= 0.95+EXTRA) { if (dut > 0.95) dut = 0.95; // Ceiling if (dut < 0.05) dut = 0.05; // Floor so it doesnt mess up the equation below float rf = (0.9*1200e3/(dut-0.05)) - 1200e3; if (rf < 1000) rf = 0; // Floor to hit 0 if (rf > 50e6) rf = 50e6; // Ceil to stay at 50e6 return rf; } else return NAN; } // In speed start, where only good/bad estimate is available if (stat == SPEEDSTART) { if (0.05-EXTRA <= dut && dut <= 0.10+EXTRA) return 50e6; // Good else if (0.90-EXTRA <= dut && dut <= 0.95+EXTRA) return 0; // Bad else return NAN; } return NAN; // Measurement not available in this mode }