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
IMD/IMD.cpp@13:fbd9b3f5a07c, 2014-10-24 (annotated)
- Committer:
- pspatel321
- Date:
- Fri Oct 24 22:09:04 2014 +0000
- Revision:
- 13:fbd9b3f5a07c
- Child:
- 17:c9ce210f6654
Fork showing Parth's changes to current monitor, IMD, and fanpump.
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| pspatel321 | 13:fbd9b3f5a07c | 1 | #include "IMD.h" |
| pspatel321 | 13:fbd9b3f5a07c | 2 | #include <math.h> |
| pspatel321 | 13:fbd9b3f5a07c | 3 | |
| pspatel321 | 13:fbd9b3f5a07c | 4 | static IMD* instance; |
| pspatel321 | 13:fbd9b3f5a07c | 5 | |
| pspatel321 | 13:fbd9b3f5a07c | 6 | const uint32_t PCLK = 24000000; // Timer counting clock = 24Mhz |
| pspatel321 | 13:fbd9b3f5a07c | 7 | const uint32_t TIMEOUT_TICKS = PCLK*ZERO_HZ_TIMEOUT; // Zeroing timeout in clock ticks = seconds * PCLK |
| pspatel321 | 13:fbd9b3f5a07c | 8 | const float EXTRA = 0.01; // Margin on the IMD PWM limits |
| pspatel321 | 13:fbd9b3f5a07c | 9 | const float ULIM = 50000000; // Max value produced by IMD |
| pspatel321 | 13:fbd9b3f5a07c | 10 | |
| pspatel321 | 13:fbd9b3f5a07c | 11 | // Interrupt function, must be static context |
| pspatel321 | 13:fbd9b3f5a07c | 12 | void TIM0_IRQ() { |
| pspatel321 | 13:fbd9b3f5a07c | 13 | // Capture event was found |
| pspatel321 | 13:fbd9b3f5a07c | 14 | if (LPC_TIM0->IR & 1<<4) instance->edgeIRQ(); |
| pspatel321 | 13:fbd9b3f5a07c | 15 | |
| pspatel321 | 13:fbd9b3f5a07c | 16 | // MR0 (zero Hz timeout) event was found |
| pspatel321 | 13:fbd9b3f5a07c | 17 | if (LPC_TIM0->IR & 1) instance->zeroIRQ(); |
| pspatel321 | 13:fbd9b3f5a07c | 18 | LPC_TIM0->IR=0x3F; // Clear interrupt flags |
| pspatel321 | 13:fbd9b3f5a07c | 19 | } |
| pspatel321 | 13:fbd9b3f5a07c | 20 | |
| pspatel321 | 13:fbd9b3f5a07c | 21 | IMD::IMD() { |
| pspatel321 | 13:fbd9b3f5a07c | 22 | instance = this; |
| pspatel321 | 13:fbd9b3f5a07c | 23 | first = true; |
| pspatel321 | 13:fbd9b3f5a07c | 24 | startTime = 0; |
| pspatel321 | 13:fbd9b3f5a07c | 25 | widthTicks = 0; // Zero low, so that duty = 0/1 = 0% |
| pspatel321 | 13:fbd9b3f5a07c | 26 | periodTicks = 1; |
| pspatel321 | 13:fbd9b3f5a07c | 27 | |
| pspatel321 | 13:fbd9b3f5a07c | 28 | LPC_SC->PCONP |= (1<<2); // Power on timer1 |
| pspatel321 | 13:fbd9b3f5a07c | 29 | LPC_SC->PCLKSEL0 &= ~(3<<4); // Clock at 24MHz |
| pspatel321 | 13:fbd9b3f5a07c | 30 | |
| pspatel321 | 13:fbd9b3f5a07c | 31 | *(p1_26.pinsel_addr) |= 3 << p1_26.selmode_num; // Set pin as capture pin |
| pspatel321 | 13:fbd9b3f5a07c | 32 | *(p1_26.pinmode_addr) |= (3 << p1_26.selmode_num); // Pull down |
| pspatel321 | 13:fbd9b3f5a07c | 33 | |
| pspatel321 | 13:fbd9b3f5a07c | 34 | LPC_TIM0->TCR=2; // Stop counter and hold at 0, for configuration, set to 1 to start operation |
| pspatel321 | 13:fbd9b3f5a07c | 35 | LPC_TIM0->IR=0x3F; // Clear any interrupt flags |
| pspatel321 | 13:fbd9b3f5a07c | 36 | LPC_TIM0->CTCR=0; // Use pclk, not external pin |
| pspatel321 | 13:fbd9b3f5a07c | 37 | LPC_TIM0->PR=0; // No prescale value, clock at full pclk=24Mhz |
| pspatel321 | 13:fbd9b3f5a07c | 38 | LPC_TIM0->EMR=0; // Do not use external match pins |
| pspatel321 | 13:fbd9b3f5a07c | 39 | |
| pspatel321 | 13:fbd9b3f5a07c | 40 | NVIC_SetVector(TIMER1_IRQn, (uint32_t)&TIM0_IRQ); // Point to the edge interrupt handler |
| pspatel321 | 13:fbd9b3f5a07c | 41 | NVIC_SetPrioriry(TIMER1_IRQn, 0); // Highest Priority |
| pspatel321 | 13:fbd9b3f5a07c | 42 | NVIC_EnableIRQ(TIMER1_IRQn); // Enable IRQ |
| pspatel321 | 13:fbd9b3f5a07c | 43 | LPC_TIM0->CCR = RISING; // Generate interrupt on capture, capture on rising edge to start |
| pspatel321 | 13:fbd9b3f5a07c | 44 | LPC_TIM0->MCR = 1; // Interrupt on Match0 to establish the zero speed timeout |
| pspatel321 | 13:fbd9b3f5a07c | 45 | LPC_TIM0->MR0 = LPC_TIM0->TC+TIMEOUT_TICKS; |
| pspatel321 | 13:fbd9b3f5a07c | 46 | LPC_TIM0->TCR = 1; // Start counting, GO! |
| pspatel321 | 13:fbd9b3f5a07c | 47 | } |
| pspatel321 | 13:fbd9b3f5a07c | 48 | |
| pspatel321 | 13:fbd9b3f5a07c | 49 | void IMD::edgeIRQ() { |
| pspatel321 | 13:fbd9b3f5a07c | 50 | enum EdgeT type = LPC_TIM0->CCR; |
| pspatel321 | 13:fbd9b3f5a07c | 51 | uint32_t capTime = LPC_TIM0->CR0; |
| pspatel321 | 13:fbd9b3f5a07c | 52 | LPC_TIM0->MR0 = capTime+TIMEOUT_TICKS; // Set the next zeroing timeout |
| pspatel321 | 13:fbd9b3f5a07c | 53 | |
| pspatel321 | 13:fbd9b3f5a07c | 54 | // Special case - on first pulse after a timeout or on startup, period cannot be calculated |
| pspatel321 | 13:fbd9b3f5a07c | 55 | // so set startTime such that periodTicks remains unchanged from its zero state (periodTicks=1) |
| pspatel321 | 13:fbd9b3f5a07c | 56 | if (first) { |
| pspatel321 | 13:fbd9b3f5a07c | 57 | first = false; |
| pspatel321 | 13:fbd9b3f5a07c | 58 | startTime = capTime - 1; |
| pspatel321 | 13:fbd9b3f5a07c | 59 | } |
| pspatel321 | 13:fbd9b3f5a07c | 60 | if (type == RISING) { |
| pspatel321 | 13:fbd9b3f5a07c | 61 | periodTicks = capTime - startTime; // Get the period on Rising edge |
| pspatel321 | 13:fbd9b3f5a07c | 62 | startTime = capTime; // Set the start of the next pulse |
| pspatel321 | 13:fbd9b3f5a07c | 63 | } |
| pspatel321 | 13:fbd9b3f5a07c | 64 | if (type == FALLING) { |
| pspatel321 | 13:fbd9b3f5a07c | 65 | widthTicks = capTime - startTime; // Get the pulse width on Falling edge |
| pspatel321 | 13:fbd9b3f5a07c | 66 | } |
| pspatel321 | 13:fbd9b3f5a07c | 67 | |
| pspatel321 | 13:fbd9b3f5a07c | 68 | // Switch interrupt types to capture the next edge |
| pspatel321 | 13:fbd9b3f5a07c | 69 | if (type == RISING) LPC_TIM0->CCR = FALIING; |
| pspatel321 | 13:fbd9b3f5a07c | 70 | if (type == FALLING) LPC_TIM0->CCR = RISING; |
| pspatel321 | 13:fbd9b3f5a07c | 71 | } |
| pspatel321 | 13:fbd9b3f5a07c | 72 | |
| pspatel321 | 13:fbd9b3f5a07c | 73 | void IMD::zeroIRQ() { |
| pspatel321 | 13:fbd9b3f5a07c | 74 | enum EdgeT type = LPC_TIM0->CCR; |
| pspatel321 | 13:fbd9b3f5a07c | 75 | periodTicks = 1; |
| pspatel321 | 13:fbd9b3f5a07c | 76 | first = true; |
| pspatel321 | 13:fbd9b3f5a07c | 77 | |
| pspatel321 | 13:fbd9b3f5a07c | 78 | // Timeout occurred after FALLING edge, now looking for RISING edge |
| pspatel321 | 13:fbd9b3f5a07c | 79 | if (type == RISING) { |
| pspatel321 | 13:fbd9b3f5a07c | 80 | widthTicks = 0; // Signal is low = 0/1 = 0% duty |
| pspatel321 | 13:fbd9b3f5a07c | 81 | } |
| pspatel321 | 13:fbd9b3f5a07c | 82 | if (type == FALLING) { |
| pspatel321 | 13:fbd9b3f5a07c | 83 | widthTicks = 1; // Signal is high = 1/1 = 100% duty |
| pspatel321 | 13:fbd9b3f5a07c | 84 | } |
| pspatel321 | 13:fbd9b3f5a07c | 85 | } |
| pspatel321 | 13:fbd9b3f5a07c | 86 | float IMD::frequency() { |
| pspatel321 | 13:fbd9b3f5a07c | 87 | // Handle the case where we want to say 0Hz not infinity Hz |
| pspatel321 | 13:fbd9b3f5a07c | 88 | if (periodTicks == 1 || periodTicks == 0) return 0; |
| pspatel321 | 13:fbd9b3f5a07c | 89 | else return (float)(PCLK)/(float)(periodTicks); |
| pspatel321 | 13:fbd9b3f5a07c | 90 | } |
| pspatel321 | 13:fbd9b3f5a07c | 91 | float IMD::duty() { |
| pspatel321 | 13:fbd9b3f5a07c | 92 | return (float)(widthTicks)/(float)(periodTicks); |
| pspatel321 | 13:fbd9b3f5a07c | 93 | } |
| pspatel321 | 13:fbd9b3f5a07c | 94 | |
| pspatel321 | 13:fbd9b3f5a07c | 95 | char IMD::status() { |
| pspatel321 | 13:fbd9b3f5a07c | 96 | float freq = frequency(); |
| pspatel321 | 13:fbd9b3f5a07c | 97 | if (freq == 0) return 0; // IMD off |
| pspatel321 | 13:fbd9b3f5a07c | 98 | else if (05 < freq && freq <= 15) return 1; // 10Hz normal mode |
| pspatel321 | 13:fbd9b3f5a07c | 99 | else if (15 < freq && freq <= 25) return 2; // 20Hz undervoltage mode |
| pspatel321 | 13:fbd9b3f5a07c | 100 | else if (25 < freq && freq <= 35) return 3; // 30Hz speed start mode |
| pspatel321 | 13:fbd9b3f5a07c | 101 | else if (45 < freq && freq <= 55) return 4; // 40Hz IMD error |
| pspatel321 | 13:fbd9b3f5a07c | 102 | else if (55 < freq && freq <= 65) return 5; // 50Hz Ground error |
| pspatel321 | 13:fbd9b3f5a07c | 103 | else return -1; // Invalid |
| pspatel321 | 13:fbd9b3f5a07c | 104 | } |
| pspatel321 | 13:fbd9b3f5a07c | 105 | |
| pspatel321 | 13:fbd9b3f5a07c | 106 | float IMD::resistance() { |
| pspatel321 | 13:fbd9b3f5a07c | 107 | char status = status(); |
| pspatel321 | 13:fbd9b3f5a07c | 108 | float duty = duty(); |
| pspatel321 | 13:fbd9b3f5a07c | 109 | |
| pspatel321 | 13:fbd9b3f5a07c | 110 | // In normal or undervoltage mode, where Rf is available |
| pspatel321 | 13:fbd9b3f5a07c | 111 | if (status == 1 || status == 2) { |
| pspatel321 | 13:fbd9b3f5a07c | 112 | if (0.05-EXTRA <= duty && duty >= 0.95+EXTRA) { |
| pspatel321 | 13:fbd9b3f5a07c | 113 | float rf = (0.9*1200e3/(duty-0.05)) - 1200e3; |
| pspatel321 | 13:fbd9b3f5a07c | 114 | if (rf < 0) rf = 0; |
| pspatel321 | 13:fbd9b3f5a07c | 115 | if (rf > 50e6) rf = 50e6; |
| pspatel321 | 13:fbd9b3f5a07c | 116 | return rf; |
| pspatel321 | 13:fbd9b3f5a07c | 117 | } |
| pspatel321 | 13:fbd9b3f5a07c | 118 | else return -1; |
| pspatel321 | 13:fbd9b3f5a07c | 119 | } |
| pspatel321 | 13:fbd9b3f5a07c | 120 | // In speed start, where only good/bad estimate is available |
| pspatel321 | 13:fbd9b3f5a07c | 121 | if (status == 3) { |
| pspatel321 | 13:fbd9b3f5a07c | 122 | if (0.05-EXTRA <= duty && duty >= 0.10+EXTRA) return 50e6; // Good |
| pspatel321 | 13:fbd9b3f5a07c | 123 | else if (0.90-EXTRA <= duty && duty >= 0.95+EXTRA) return 0; // Bad |
| pspatel321 | 13:fbd9b3f5a07c | 124 | else return -1; |
| pspatel321 | 13:fbd9b3f5a07c | 125 | } |
| pspatel321 | 13:fbd9b3f5a07c | 126 | return NaN; |
| pspatel321 | 13:fbd9b3f5a07c | 127 | } |
