System Management code

Dependencies:   mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP

Fork of SystemManagement by Martin Deng

Revision:
30:91af74a299e1
Child:
36:0afc0fc8f86b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/IMD/IMD.cpp	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,201 @@
+#include "IMD.h"
+#include <math.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
+}
+
+bool cmpPin(LPC_pin p1, LPC_pin p2) {
+    if (p1.gpio_addr == p2.gpio_addr && p1.gpio_num == p2.gpio_num) return true;
+    else return false;
+}
+
+IMD::IMD(LPC_pin _pin) {
+    // Setup the timer/pin access variables
+    if (cmpPin(_pin, p1_26)) {          // CAP0.0
+        timer=0;
+        pin=0;
+        timerBase=LPC_TIM0;
+    } else if (cmpPin(_pin, p1_27)) {   // CAP0.1
+        timer=0;
+        pin=1;
+        timerBase=LPC_TIM0;
+    } else if (cmpPin(_pin, p1_18)) {   // CAP1.0
+        timer=1;
+        pin=0;
+        timerBase=LPC_TIM1;
+    } else if (cmpPin(_pin, p1_19)) {   // CAP1.1
+        timer=1;
+        pin=1;
+        timerBase=LPC_TIM1;
+    } else if (cmpPin(_pin, p0_4)) {    // CAP2.0
+        timer=2;
+        pin=0;
+        timerBase=LPC_TIM2;
+    } else if (cmpPin(_pin, p0_5)) {    // CAP2.1
+        timer=2;
+        pin=1;
+        timerBase=LPC_TIM2;
+    } else if (cmpPin(_pin, p0_23)) {   // CAP3.0
+        timer=3;
+        pin=0;
+        timerBase=LPC_TIM3;
+    } else if (cmpPin(_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.pinsel_addr)  |= 3 << _pin.selmode_num;     // Set pin as capture pin
+    *(_pin.pinmode_addr) |= 3 << _pin.selmode_num;     // 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
+}
\ No newline at end of file