Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP
Fork of SystemManagement by
Diff: IMD/IMD.cpp
- Revision:
- 13:fbd9b3f5a07c
- Child:
- 17:c9ce210f6654
--- /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
