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