System Management code
Dependencies: mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP
Fork of SystemManagement by
Libs/IMD/IMD.cpp@30:91af74a299e1, 2014-11-13 (annotated)
- Committer:
- pspatel321
- Date:
- Thu Nov 13 10:53:10 2014 +0000
- Revision:
- 30:91af74a299e1
- Child:
- 36:0afc0fc8f86b
Parth's edits for the week.; DC-DC completed and fixed, IMD updated, LatchMonitor and Temperature added. Serial dashboard updated. File structure changed Everything tested. Compiles and runs.; Still need to write CAN in/out interface.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
pspatel321 | 30:91af74a299e1 | 1 | #include "IMD.h" |
pspatel321 | 30:91af74a299e1 | 2 | #include <math.h> |
pspatel321 | 30:91af74a299e1 | 3 | |
pspatel321 | 30:91af74a299e1 | 4 | static IMD* instance[4] = { 0 }; // Access member from static frame, one IMD permitted per timer module (4 total IMD objects) |
pspatel321 | 30:91af74a299e1 | 5 | |
pspatel321 | 30:91af74a299e1 | 6 | const uint32_t PCLK = 24000000; // Timer counting clock = 24Mhz |
pspatel321 | 30:91af74a299e1 | 7 | const uint32_t TIMEOUT_TICKS = PCLK*ZERO_HZ_TIMEOUT; // Zeroing timeout in clock ticks = seconds * PCLK |
pspatel321 | 30:91af74a299e1 | 8 | const float EXTRA = 0.01; // Margin on the IMD PWM limits |
pspatel321 | 30:91af74a299e1 | 9 | |
pspatel321 | 30:91af74a299e1 | 10 | // Interrupt functions, must be static context |
pspatel321 | 30:91af74a299e1 | 11 | void tim0_IRQ() { |
pspatel321 | 30:91af74a299e1 | 12 | if (LPC_TIM0->IR & (1<<4|1<<5)) instance[0]->edgeIRQ(); // Capture pin interrupt |
pspatel321 | 30:91af74a299e1 | 13 | if (LPC_TIM0->IR & 1) instance[0]->zeroIRQ(); // MR0 interrupt |
pspatel321 | 30:91af74a299e1 | 14 | LPC_TIM0->IR=0x3F; // Clear interrupt flags |
pspatel321 | 30:91af74a299e1 | 15 | } |
pspatel321 | 30:91af74a299e1 | 16 | void tim1_IRQ() { |
pspatel321 | 30:91af74a299e1 | 17 | if (LPC_TIM1->IR & (1<<4|1<<5)) instance[1]->edgeIRQ(); |
pspatel321 | 30:91af74a299e1 | 18 | if (LPC_TIM1->IR & 1) instance[1]->zeroIRQ(); |
pspatel321 | 30:91af74a299e1 | 19 | LPC_TIM1->IR=0x3F; // Clear interrupt flags |
pspatel321 | 30:91af74a299e1 | 20 | } |
pspatel321 | 30:91af74a299e1 | 21 | void tim2_IRQ() { |
pspatel321 | 30:91af74a299e1 | 22 | if (LPC_TIM2->IR & (1<<4|1<<5)) instance[2]->edgeIRQ(); |
pspatel321 | 30:91af74a299e1 | 23 | if (LPC_TIM2->IR & 1) instance[2]->zeroIRQ(); |
pspatel321 | 30:91af74a299e1 | 24 | LPC_TIM2->IR=0x3F; // Clear interrupt flags |
pspatel321 | 30:91af74a299e1 | 25 | } |
pspatel321 | 30:91af74a299e1 | 26 | void tim3_IRQ() { |
pspatel321 | 30:91af74a299e1 | 27 | if (LPC_TIM3->IR & (1<<4|1<<5)) instance[3]->edgeIRQ(); |
pspatel321 | 30:91af74a299e1 | 28 | if (LPC_TIM3->IR & 1) instance[3]->zeroIRQ(); |
pspatel321 | 30:91af74a299e1 | 29 | LPC_TIM3->IR=0x3F; // Clear interrupt flags |
pspatel321 | 30:91af74a299e1 | 30 | } |
pspatel321 | 30:91af74a299e1 | 31 | |
pspatel321 | 30:91af74a299e1 | 32 | bool cmpPin(LPC_pin p1, LPC_pin p2) { |
pspatel321 | 30:91af74a299e1 | 33 | if (p1.gpio_addr == p2.gpio_addr && p1.gpio_num == p2.gpio_num) return true; |
pspatel321 | 30:91af74a299e1 | 34 | else return false; |
pspatel321 | 30:91af74a299e1 | 35 | } |
pspatel321 | 30:91af74a299e1 | 36 | |
pspatel321 | 30:91af74a299e1 | 37 | IMD::IMD(LPC_pin _pin) { |
pspatel321 | 30:91af74a299e1 | 38 | // Setup the timer/pin access variables |
pspatel321 | 30:91af74a299e1 | 39 | if (cmpPin(_pin, p1_26)) { // CAP0.0 |
pspatel321 | 30:91af74a299e1 | 40 | timer=0; |
pspatel321 | 30:91af74a299e1 | 41 | pin=0; |
pspatel321 | 30:91af74a299e1 | 42 | timerBase=LPC_TIM0; |
pspatel321 | 30:91af74a299e1 | 43 | } else if (cmpPin(_pin, p1_27)) { // CAP0.1 |
pspatel321 | 30:91af74a299e1 | 44 | timer=0; |
pspatel321 | 30:91af74a299e1 | 45 | pin=1; |
pspatel321 | 30:91af74a299e1 | 46 | timerBase=LPC_TIM0; |
pspatel321 | 30:91af74a299e1 | 47 | } else if (cmpPin(_pin, p1_18)) { // CAP1.0 |
pspatel321 | 30:91af74a299e1 | 48 | timer=1; |
pspatel321 | 30:91af74a299e1 | 49 | pin=0; |
pspatel321 | 30:91af74a299e1 | 50 | timerBase=LPC_TIM1; |
pspatel321 | 30:91af74a299e1 | 51 | } else if (cmpPin(_pin, p1_19)) { // CAP1.1 |
pspatel321 | 30:91af74a299e1 | 52 | timer=1; |
pspatel321 | 30:91af74a299e1 | 53 | pin=1; |
pspatel321 | 30:91af74a299e1 | 54 | timerBase=LPC_TIM1; |
pspatel321 | 30:91af74a299e1 | 55 | } else if (cmpPin(_pin, p0_4)) { // CAP2.0 |
pspatel321 | 30:91af74a299e1 | 56 | timer=2; |
pspatel321 | 30:91af74a299e1 | 57 | pin=0; |
pspatel321 | 30:91af74a299e1 | 58 | timerBase=LPC_TIM2; |
pspatel321 | 30:91af74a299e1 | 59 | } else if (cmpPin(_pin, p0_5)) { // CAP2.1 |
pspatel321 | 30:91af74a299e1 | 60 | timer=2; |
pspatel321 | 30:91af74a299e1 | 61 | pin=1; |
pspatel321 | 30:91af74a299e1 | 62 | timerBase=LPC_TIM2; |
pspatel321 | 30:91af74a299e1 | 63 | } else if (cmpPin(_pin, p0_23)) { // CAP3.0 |
pspatel321 | 30:91af74a299e1 | 64 | timer=3; |
pspatel321 | 30:91af74a299e1 | 65 | pin=0; |
pspatel321 | 30:91af74a299e1 | 66 | timerBase=LPC_TIM3; |
pspatel321 | 30:91af74a299e1 | 67 | } else if (cmpPin(_pin, p0_24)) { // CAP3.1 |
pspatel321 | 30:91af74a299e1 | 68 | timer=3; |
pspatel321 | 30:91af74a299e1 | 69 | pin=1; |
pspatel321 | 30:91af74a299e1 | 70 | timerBase=LPC_TIM3; |
pspatel321 | 30:91af74a299e1 | 71 | } else { // Invalid pin |
pspatel321 | 30:91af74a299e1 | 72 | timerBase=0; |
pspatel321 | 30:91af74a299e1 | 73 | pin=0; |
pspatel321 | 30:91af74a299e1 | 74 | timer=0; |
pspatel321 | 30:91af74a299e1 | 75 | return; |
pspatel321 | 30:91af74a299e1 | 76 | } |
pspatel321 | 30:91af74a299e1 | 77 | |
pspatel321 | 30:91af74a299e1 | 78 | instance[timer] = this; |
pspatel321 | 30:91af74a299e1 | 79 | first = true; |
pspatel321 | 30:91af74a299e1 | 80 | |
pspatel321 | 30:91af74a299e1 | 81 | startTime = 0; |
pspatel321 | 30:91af74a299e1 | 82 | widthTicks = 0; // Zero low, so that duty = 0/1 = 0% |
pspatel321 | 30:91af74a299e1 | 83 | periodTicks = 1; |
pspatel321 | 30:91af74a299e1 | 84 | |
pspatel321 | 30:91af74a299e1 | 85 | // Enable power and set pclk at 24Mhz |
pspatel321 | 30:91af74a299e1 | 86 | if (timer==0) { |
pspatel321 | 30:91af74a299e1 | 87 | LPC_SC->PCONP |= (1<<1); |
pspatel321 | 30:91af74a299e1 | 88 | LPC_SC->PCLKSEL0 &= ~(3<<2); |
pspatel321 | 30:91af74a299e1 | 89 | } if (timer==1) { |
pspatel321 | 30:91af74a299e1 | 90 | LPC_SC->PCONP |= (1<<2); |
pspatel321 | 30:91af74a299e1 | 91 | LPC_SC->PCLKSEL0 &= ~(3<<4); |
pspatel321 | 30:91af74a299e1 | 92 | } if (timer==2) { |
pspatel321 | 30:91af74a299e1 | 93 | LPC_SC->PCONP |= (1<<22); |
pspatel321 | 30:91af74a299e1 | 94 | LPC_SC->PCLKSEL1 &= ~(3<<12); |
pspatel321 | 30:91af74a299e1 | 95 | } if (timer==3) { |
pspatel321 | 30:91af74a299e1 | 96 | LPC_SC->PCONP |= (1<<23); |
pspatel321 | 30:91af74a299e1 | 97 | LPC_SC->PCLKSEL1 &= ~(3<<14); |
pspatel321 | 30:91af74a299e1 | 98 | } |
pspatel321 | 30:91af74a299e1 | 99 | |
pspatel321 | 30:91af74a299e1 | 100 | *(_pin.pinsel_addr) |= 3 << _pin.selmode_num; // Set pin as capture pin |
pspatel321 | 30:91af74a299e1 | 101 | *(_pin.pinmode_addr) |= 3 << _pin.selmode_num; // Pull down |
pspatel321 | 30:91af74a299e1 | 102 | |
pspatel321 | 30:91af74a299e1 | 103 | timerBase->TCR=2; // Stop counter and hold at 0, for configuration |
pspatel321 | 30:91af74a299e1 | 104 | timerBase->IR=0x3F; // Clear any interrupt flags |
pspatel321 | 30:91af74a299e1 | 105 | timerBase->CTCR=0; // Use pclk, not external pin |
pspatel321 | 30:91af74a299e1 | 106 | timerBase->PR=0; // No prescale value, clock at full pclk=24Mhz |
pspatel321 | 30:91af74a299e1 | 107 | timerBase->EMR=0; // Do not use external match pins |
pspatel321 | 30:91af74a299e1 | 108 | |
pspatel321 | 30:91af74a299e1 | 109 | if (timer == 0) NVIC_SetVector(TIMER0_IRQn, (uint32_t)&tim0_IRQ); // Set irq handler for timer0 |
pspatel321 | 30:91af74a299e1 | 110 | if (timer == 1) NVIC_SetVector(TIMER1_IRQn, (uint32_t)&tim1_IRQ); // Set irq handler for timer1 |
pspatel321 | 30:91af74a299e1 | 111 | if (timer == 2) NVIC_SetVector(TIMER2_IRQn, (uint32_t)&tim2_IRQ); // Set irq handler for timer2 |
pspatel321 | 30:91af74a299e1 | 112 | if (timer == 3) NVIC_SetVector(TIMER3_IRQn, (uint32_t)&tim3_IRQ); // Set irq handler for timer3 |
pspatel321 | 30:91af74a299e1 | 113 | |
pspatel321 | 30:91af74a299e1 | 114 | NVIC_EnableIRQ((IRQn_Type)(timer+1)); |
pspatel321 | 30:91af74a299e1 | 115 | NVIC_SetPriority((IRQn_Type)(timer+1), 0); // Highest priority (default) |
pspatel321 | 30:91af74a299e1 | 116 | |
pspatel321 | 30:91af74a299e1 | 117 | timerBase->CCR = pin?5<<3:5; // Generate interrupt on rising edge of capture pin |
pspatel321 | 30:91af74a299e1 | 118 | timerBase->MCR = 1; // Interrupt on MR0 to establish the zero speed timeout |
pspatel321 | 30:91af74a299e1 | 119 | zeroIRQ(); // Zero the values |
pspatel321 | 30:91af74a299e1 | 120 | timerBase->TCR = 1; // Start counting, GO! |
pspatel321 | 30:91af74a299e1 | 121 | } |
pspatel321 | 30:91af74a299e1 | 122 | |
pspatel321 | 30:91af74a299e1 | 123 | void IMD::edgeIRQ() { |
pspatel321 | 30:91af74a299e1 | 124 | bool rising = pin?timerBase->CCR&(1<<3):timerBase->CCR&1; |
pspatel321 | 30:91af74a299e1 | 125 | uint32_t capTime = pin?timerBase->CR1:timerBase->CR0; // Get the time of the capture event |
pspatel321 | 30:91af74a299e1 | 126 | timerBase->MR0 = capTime + TIMEOUT_TICKS; // Move the zero timeout ahead |
pspatel321 | 30:91af74a299e1 | 127 | |
pspatel321 | 30:91af74a299e1 | 128 | // Special case - on first pulse after a timeout or on startup, period cannot be calculated |
pspatel321 | 30:91af74a299e1 | 129 | // so set startTime such that periodTicks remains unchanged from its zero state (periodTicks=1) |
pspatel321 | 30:91af74a299e1 | 130 | if (first) { |
pspatel321 | 30:91af74a299e1 | 131 | first = false; |
pspatel321 | 30:91af74a299e1 | 132 | startTime = capTime - 1; |
pspatel321 | 30:91af74a299e1 | 133 | } |
pspatel321 | 30:91af74a299e1 | 134 | if (rising) { |
pspatel321 | 30:91af74a299e1 | 135 | periodTicks = capTime - startTime; // Get the period on Rising edge |
pspatel321 | 30:91af74a299e1 | 136 | startTime = capTime; // Set the start of the next pulse |
pspatel321 | 30:91af74a299e1 | 137 | } else { |
pspatel321 | 30:91af74a299e1 | 138 | widthTicks = capTime - startTime; // Get the pulse width on Falling edge |
pspatel321 | 30:91af74a299e1 | 139 | } |
pspatel321 | 30:91af74a299e1 | 140 | |
pspatel321 | 30:91af74a299e1 | 141 | // Switch interrupt types to capture the next edge |
pspatel321 | 30:91af74a299e1 | 142 | if (rising) timerBase->CCR = pin?6<<3:6; |
pspatel321 | 30:91af74a299e1 | 143 | else timerBase->CCR = pin?5<<3:5; |
pspatel321 | 30:91af74a299e1 | 144 | } |
pspatel321 | 30:91af74a299e1 | 145 | |
pspatel321 | 30:91af74a299e1 | 146 | void IMD::zeroIRQ() { |
pspatel321 | 30:91af74a299e1 | 147 | periodTicks = 1; |
pspatel321 | 30:91af74a299e1 | 148 | first = true; // Reset the first edge detection case |
pspatel321 | 30:91af74a299e1 | 149 | |
pspatel321 | 30:91af74a299e1 | 150 | bool rising = pin?timerBase->CCR&(1<<3):timerBase->CCR&1; |
pspatel321 | 30:91af74a299e1 | 151 | // Timeout occurred after FALLING edge, RISING edge never happened |
pspatel321 | 30:91af74a299e1 | 152 | if (rising) { |
pspatel321 | 30:91af74a299e1 | 153 | widthTicks = 0; // Signal is low = 0/1 = 0% duty |
pspatel321 | 30:91af74a299e1 | 154 | } else { |
pspatel321 | 30:91af74a299e1 | 155 | widthTicks = 1; // Signal is high = 1/1 = 100% duty |
pspatel321 | 30:91af74a299e1 | 156 | } |
pspatel321 | 30:91af74a299e1 | 157 | } |
pspatel321 | 30:91af74a299e1 | 158 | float IMD::frequency() { |
pspatel321 | 30:91af74a299e1 | 159 | // Handle the case where we want to say 0Hz not infinity Hz |
pspatel321 | 30:91af74a299e1 | 160 | if (periodTicks == 1 || periodTicks == 0) return 0; |
pspatel321 | 30:91af74a299e1 | 161 | else return (float)(PCLK)/(float)(periodTicks); |
pspatel321 | 30:91af74a299e1 | 162 | } |
pspatel321 | 30:91af74a299e1 | 163 | float IMD::duty() { |
pspatel321 | 30:91af74a299e1 | 164 | return (float)(widthTicks)/(float)(periodTicks); |
pspatel321 | 30:91af74a299e1 | 165 | } |
pspatel321 | 30:91af74a299e1 | 166 | |
pspatel321 | 30:91af74a299e1 | 167 | char IMD::status() { |
pspatel321 | 30:91af74a299e1 | 168 | float freq = frequency(); |
pspatel321 | 30:91af74a299e1 | 169 | if (freq == 0) return OFF; // IMD off |
pspatel321 | 30:91af74a299e1 | 170 | else if (05 < freq && freq <= 15) return NORMAL; // 10Hz normal mode |
pspatel321 | 30:91af74a299e1 | 171 | else if (15 < freq && freq <= 25) return UNDERVOLT; // 20Hz undervoltage mode |
pspatel321 | 30:91af74a299e1 | 172 | else if (25 < freq && freq <= 35) return SPEEDSTART; // 30Hz speed start mode |
pspatel321 | 30:91af74a299e1 | 173 | else if (35 < freq && freq <= 45) return ERROR; // 40Hz IMD error |
pspatel321 | 30:91af74a299e1 | 174 | else if (45 < freq && freq <= 55) return GROUNDERR; // 50Hz Ground error |
pspatel321 | 30:91af74a299e1 | 175 | else return INVALID; // Invalid |
pspatel321 | 30:91af74a299e1 | 176 | } |
pspatel321 | 30:91af74a299e1 | 177 | |
pspatel321 | 30:91af74a299e1 | 178 | float IMD::resistance() { |
pspatel321 | 30:91af74a299e1 | 179 | char stat = status(); |
pspatel321 | 30:91af74a299e1 | 180 | float dut = duty(); |
pspatel321 | 30:91af74a299e1 | 181 | |
pspatel321 | 30:91af74a299e1 | 182 | // In normal or undervoltage mode, where Rf is available |
pspatel321 | 30:91af74a299e1 | 183 | if (stat == NORMAL || stat == UNDERVOLT) { |
pspatel321 | 30:91af74a299e1 | 184 | if (0.05-EXTRA <= dut && dut <= 0.95+EXTRA) { |
pspatel321 | 30:91af74a299e1 | 185 | if (dut > 0.95) dut = 0.95; // Ceiling |
pspatel321 | 30:91af74a299e1 | 186 | if (dut < 0.05) dut = 0.05; // Floor so it doesnt mess up the equation below |
pspatel321 | 30:91af74a299e1 | 187 | float rf = (0.9*1200e3/(dut-0.05)) - 1200e3; |
pspatel321 | 30:91af74a299e1 | 188 | if (rf < 1000) rf = 0; // Floor to hit 0 |
pspatel321 | 30:91af74a299e1 | 189 | if (rf > 50e6) rf = 50e6; // Ceil to stay at 50e6 |
pspatel321 | 30:91af74a299e1 | 190 | return rf; |
pspatel321 | 30:91af74a299e1 | 191 | } |
pspatel321 | 30:91af74a299e1 | 192 | else return NAN; |
pspatel321 | 30:91af74a299e1 | 193 | } |
pspatel321 | 30:91af74a299e1 | 194 | // In speed start, where only good/bad estimate is available |
pspatel321 | 30:91af74a299e1 | 195 | if (stat == SPEEDSTART) { |
pspatel321 | 30:91af74a299e1 | 196 | if (0.05-EXTRA <= dut && dut <= 0.10+EXTRA) return 50e6; // Good |
pspatel321 | 30:91af74a299e1 | 197 | else if (0.90-EXTRA <= dut && dut <= 0.95+EXTRA) return 0; // Bad |
pspatel321 | 30:91af74a299e1 | 198 | else return NAN; |
pspatel321 | 30:91af74a299e1 | 199 | } |
pspatel321 | 30:91af74a299e1 | 200 | return NAN; // Measurement not available in this mode |
pspatel321 | 30:91af74a299e1 | 201 | } |