Penn Electric Racing / Mbed 2 deprecated SystemManagement

Dependencies:   mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP

Fork of SystemManagement by Martin Deng

Revision:
13:fbd9b3f5a07c
Child:
17:c9ce210f6654
diff -r e0adb697fcdb -r fbd9b3f5a07c IMD/IMD.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IMD/IMD.cpp	Fri Oct 24 22:09:04 2014 +0000
@@ -0,0 +1,127 @@
+#include "IMD.h"
+#include <math.h>
+
+static IMD* instance;
+
+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
+const float ULIM = 50000000;        // Max value produced by IMD
+
+// Interrupt function, must be static context
+void TIM0_IRQ() {
+    // Capture event was found
+    if (LPC_TIM0->IR & 1<<4) instance->edgeIRQ();
+    
+    // MR0 (zero Hz timeout) event was found
+    if (LPC_TIM0->IR & 1) instance->zeroIRQ();
+    LPC_TIM0->IR=0x3F;        // Clear interrupt flags
+}
+
+IMD::IMD() {
+    instance = this;
+    first = true;
+    startTime = 0;
+    widthTicks = 0;                 // Zero low, so that duty = 0/1 = 0%
+    periodTicks = 1;
+    
+    LPC_SC->PCONP |= (1<<2);        // Power on timer1
+    LPC_SC->PCLKSEL0 &= ~(3<<4);    // Clock at 24MHz
+    
+    *(p1_26.pinsel_addr) |= 3 << p1_26.selmode_num;     // Set pin as capture pin
+    *(p1_26.pinmode_addr) |= (3 << p1_26.selmode_num);  // Pull down
+    
+    LPC_TIM0->TCR=2;       // Stop counter and hold at 0, for configuration, set to 1 to start operation
+    LPC_TIM0->IR=0x3F;     // Clear any interrupt flags
+    LPC_TIM0->CTCR=0;      // Use pclk, not external pin
+    LPC_TIM0->PR=0;        // No prescale value, clock at full pclk=24Mhz
+    LPC_TIM0->EMR=0;       // Do not use external match pins
+    
+    NVIC_SetVector(TIMER1_IRQn, (uint32_t)&TIM0_IRQ);   // Point to the edge interrupt handler
+    NVIC_SetPrioriry(TIMER1_IRQn, 0);                   // Highest Priority
+    NVIC_EnableIRQ(TIMER1_IRQn);                        // Enable IRQ
+    LPC_TIM0->CCR = RISING;          // Generate interrupt on capture, capture on rising edge to start
+    LPC_TIM0->MCR = 1;               // Interrupt on Match0 to establish the zero speed timeout
+    LPC_TIM0->MR0 = LPC_TIM0->TC+TIMEOUT_TICKS;
+    LPC_TIM0->TCR = 1;               // Start counting, GO!
+}
+
+void IMD::edgeIRQ() {
+    enum EdgeT type = LPC_TIM0->CCR;
+    uint32_t capTime = LPC_TIM0->CR0;
+    LPC_TIM0->MR0 = capTime+TIMEOUT_TICKS;        // Set the next zeroing timeout
+    
+    // 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 (type == RISING) {
+        periodTicks = capTime - startTime;  // Get the period on Rising edge
+        startTime = capTime;                // Set the start of the next pulse
+    }
+    if (type == FALLING) {
+        widthTicks = capTime - startTime;   // Get the pulse width on Falling edge   
+    }
+    
+    // Switch interrupt types to capture the next edge
+    if (type == RISING)  LPC_TIM0->CCR = FALIING;
+    if (type == FALLING) LPC_TIM0->CCR = RISING;
+}
+
+void IMD::zeroIRQ() {
+    enum EdgeT type = LPC_TIM0->CCR;
+    periodTicks = 1;
+    first = true;
+    
+    // Timeout occurred after FALLING edge, now looking for RISING edge
+    if (type == RISING) {
+        widthTicks = 0;     // Signal is low = 0/1 = 0% duty
+    }
+    if (type == FALLING) {
+        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 0;   // IMD off
+    else if (05 < freq && freq <= 15)   return 1;   // 10Hz normal mode
+    else if (15 < freq && freq <= 25)   return 2;   // 20Hz undervoltage mode
+    else if (25 < freq && freq <= 35)   return 3;   // 30Hz speed start mode
+    else if (45 < freq && freq <= 55)   return 4;   // 40Hz IMD error
+    else if (55 < freq && freq <= 65)   return 5;   // 50Hz Ground error
+    else return -1;                                 // Invalid
+}
+
+float IMD::resistance() {
+    char status = status();
+    float duty = duty();
+    
+    // In normal or undervoltage mode, where Rf is available
+    if (status == 1 || status == 2) {
+        if (0.05-EXTRA <= duty && duty >= 0.95+EXTRA) {
+            float rf = (0.9*1200e3/(duty-0.05)) - 1200e3;
+            if (rf < 0) rf = 0;
+            if (rf > 50e6) rf = 50e6;
+            return rf;
+        }
+        else return -1;
+    }
+    // In speed start, where only good/bad estimate is available
+    if (status == 3) {
+        if (0.05-EXTRA <= duty && duty >= 0.10+EXTRA)       return 50e6;        // Good
+        else if (0.90-EXTRA <= duty && duty >= 0.95+EXTRA)  return 0;           // Bad
+        else return -1;
+    }
+    return NaN;
+}
\ No newline at end of file