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.cpp
00001 #include "IMD.h" 00002 #include <math.h> 00003 #include "pinmap.h" 00004 00005 00006 const float ZERO_HZ_TIMEOUT = 0.21; // Time (sec) that must pass without an edge to call it 0 Hz, set to greater than the longest expected pulse width 00007 const float EXTRA = 0.02; // Margin on the IMD PWM limits 00008 00009 const uint32_t PCLK = 24000000; // Timer counting clock = 24Mhz 00010 const uint32_t TIMEOUT_TICKS = PCLK*ZERO_HZ_TIMEOUT; // Zeroing timeout in clock ticks = seconds * PCLK 00011 00012 static IMD* instance[4] = { 0 }; // Access member from static frame, one IMD permitted per timer module (4 total IMD objects) 00013 00014 // Interrupt functions, must be static context 00015 void tim0_IRQ() { 00016 if (LPC_TIM0->IR & (1<<4|1<<5)) instance[0]->edgeIRQ(); // Capture pin interrupt 00017 if (LPC_TIM0->IR & 1) instance[0]->zeroIRQ(); // MR0 interrupt 00018 LPC_TIM0->IR=0x3F; // Clear interrupt flags 00019 } 00020 void tim1_IRQ() { 00021 if (LPC_TIM1->IR & (1<<4|1<<5)) instance[1]->edgeIRQ(); 00022 if (LPC_TIM1->IR & 1) instance[1]->zeroIRQ(); 00023 LPC_TIM1->IR=0x3F; // Clear interrupt flags 00024 } 00025 void tim2_IRQ() { 00026 if (LPC_TIM2->IR & (1<<4|1<<5)) instance[2]->edgeIRQ(); 00027 if (LPC_TIM2->IR & 1) instance[2]->zeroIRQ(); 00028 LPC_TIM2->IR=0x3F; // Clear interrupt flags 00029 } 00030 void tim3_IRQ() { 00031 if (LPC_TIM3->IR & (1<<4|1<<5)) instance[3]->edgeIRQ(); 00032 if (LPC_TIM3->IR & 1) instance[3]->zeroIRQ(); 00033 LPC_TIM3->IR=0x3F; // Clear interrupt flags 00034 } 00035 00036 IMD::IMD(PinName _pin) { 00037 // Setup the timer/pin access variables 00038 if (_pin == P1_26) { // CAP0.0 00039 timer=0; 00040 pin=0; 00041 timerBase=LPC_TIM0; 00042 } else if (_pin == P1_27) { // CAP0.1 00043 timer=0; 00044 pin=1; 00045 timerBase=LPC_TIM0; 00046 } else if (_pin == P1_18) { // CAP1.0 00047 timer=1; 00048 pin=0; 00049 timerBase=LPC_TIM1; 00050 } else if (_pin == P1_19) { // CAP1.1 00051 timer=1; 00052 pin=1; 00053 timerBase=LPC_TIM1; 00054 } else if (_pin == P0_4) { // CAP2.0 00055 timer=2; 00056 pin=0; 00057 timerBase=LPC_TIM2; 00058 } else if (_pin == P0_5) { // CAP2.1 00059 timer=2; 00060 pin=1; 00061 timerBase=LPC_TIM2; 00062 } else if (_pin == P0_23) { // CAP3.0 00063 timer=3; 00064 pin=0; 00065 timerBase=LPC_TIM3; 00066 } else if (_pin == P0_24) { // CAP3.1 00067 timer=3; 00068 pin=1; 00069 timerBase=LPC_TIM3; 00070 } else { // Invalid pin 00071 timerBase=0; 00072 pin=0; 00073 timer=0; 00074 return; 00075 } 00076 00077 instance[timer] = this; 00078 first = true; 00079 00080 startTime = 0; 00081 widthTicks = 0; // Zero low, so that duty = 0/1 = 0% 00082 periodTicks = 1; 00083 00084 // Enable power and set pclk at 24Mhz 00085 if (timer==0) { 00086 LPC_SC->PCONP |= (1<<1); 00087 LPC_SC->PCLKSEL0 &= ~(3<<2); 00088 } if (timer==1) { 00089 LPC_SC->PCONP |= (1<<2); 00090 LPC_SC->PCLKSEL0 &= ~(3<<4); 00091 } if (timer==2) { 00092 LPC_SC->PCONP |= (1<<22); 00093 LPC_SC->PCLKSEL1 &= ~(3<<12); 00094 } if (timer==3) { 00095 LPC_SC->PCONP |= (1<<23); 00096 LPC_SC->PCLKSEL1 &= ~(3<<14); 00097 } 00098 00099 pin_function(_pin, 3); // Capture input 00100 pin_mode(_pin, PullDown); // Pull-down 00101 00102 timerBase->TCR=2; // Stop counter and hold at 0, for configuration 00103 timerBase->IR=0x3F; // Clear any interrupt flags 00104 timerBase->CTCR=0; // Use pclk, not external pin 00105 timerBase->PR=0; // No prescale value, clock at full pclk=24Mhz 00106 timerBase->EMR=0; // Do not use external match pins 00107 00108 if (timer == 0) NVIC_SetVector(TIMER0_IRQn, (uint32_t)&tim0_IRQ); // Set irq handler for timer0 00109 if (timer == 1) NVIC_SetVector(TIMER1_IRQn, (uint32_t)&tim1_IRQ); // Set irq handler for timer1 00110 if (timer == 2) NVIC_SetVector(TIMER2_IRQn, (uint32_t)&tim2_IRQ); // Set irq handler for timer2 00111 if (timer == 3) NVIC_SetVector(TIMER3_IRQn, (uint32_t)&tim3_IRQ); // Set irq handler for timer3 00112 00113 NVIC_EnableIRQ((IRQn_Type)(timer+1)); 00114 NVIC_SetPriority((IRQn_Type)(timer+1), 0); // Highest priority (default) 00115 00116 timerBase->CCR = pin?5<<3:5; // Generate interrupt on rising edge of capture pin 00117 timerBase->MCR = 1; // Interrupt on MR0 to establish the zero speed timeout 00118 zeroIRQ(); // Zero the values 00119 timerBase->TCR = 1; // Start counting, GO! 00120 } 00121 00122 void IMD::edgeIRQ() { 00123 bool rising = pin?timerBase->CCR&(1<<3):timerBase->CCR&1; 00124 uint32_t capTime = pin?timerBase->CR1:timerBase->CR0; // Get the time of the capture event 00125 timerBase->MR0 = capTime + TIMEOUT_TICKS; // Move the zero timeout ahead 00126 00127 // Special case - on first pulse after a timeout or on startup == Period cannot be calculated 00128 // so set startTime such that periodTicks remains unchanged from its zero state (periodTicks=1) 00129 if (first) { 00130 first = false; 00131 startTime = capTime - 1; 00132 } 00133 if (rising) { 00134 periodTicks = capTime - startTime; // Get the period on Rising edge 00135 startTime = capTime; // Set the start of the next pulse 00136 } else { 00137 widthTicks = capTime - startTime; // Get the pulse width on Falling edge 00138 } 00139 00140 // Switch interrupt types to capture the next edge 00141 if (rising) timerBase->CCR = pin?6<<3:6; 00142 else timerBase->CCR = pin?5<<3:5; 00143 } 00144 00145 void IMD::zeroIRQ() { 00146 periodTicks = 1; 00147 first = true; // Reset the first edge detection case 00148 00149 bool rising = pin?timerBase->CCR&(1<<3):timerBase->CCR&1; 00150 // Timeout occurred after FALLING edge, RISING edge never happened 00151 if (rising) { 00152 widthTicks = 0; // Signal is low = 0/1 = 0% duty 00153 } else { 00154 widthTicks = 1; // Signal is high = 1/1 = 100% duty 00155 } 00156 } 00157 float IMD::frequency() { 00158 // Handle the case where we want to say 0Hz not infinity Hz 00159 if (periodTicks == 1 || periodTicks == 0) return 0; 00160 else return (float)(PCLK)/(float)(periodTicks); 00161 } 00162 float IMD::duty() { 00163 return (float)(widthTicks)/(float)(periodTicks); 00164 } 00165 00166 char IMD::status() { 00167 float freq = frequency(); 00168 if (freq == 0) return OFF; // IMD off 00169 else if (05 < freq && freq <= 15) return NORMAL; // 10Hz normal mode 00170 else if (15 < freq && freq <= 25) return UNDERVOLT; // 20Hz undervoltage mode 00171 else if (25 < freq && freq <= 35) return SPEEDSTART; // 30Hz speed start mode 00172 else if (35 < freq && freq <= 45) return ERROR; // 40Hz IMD error 00173 else if (45 < freq && freq <= 55) return GROUNDERR; // 50Hz Ground error 00174 else return INVALID; // Invalid 00175 } 00176 00177 float IMD::resistance() { 00178 char stat = status(); 00179 float dut = duty(); 00180 00181 // In normal or undervoltage mode, where Rf is available 00182 if (stat == NORMAL || stat == UNDERVOLT) { 00183 if (0.05-EXTRA <= dut && dut <= 0.95+EXTRA) { 00184 if (dut > 0.95) dut = 0.95; // Ceiling 00185 if (dut < 0.05) dut = 0.05; // Floor so it doesnt mess up the equation below 00186 float rf = (0.9*1200e3/(dut-0.05)) - 1200e3; 00187 if (rf < 1000) rf = 0; // Floor to hit 0 00188 if (rf > 50e6) rf = 50e6; // Ceil to stay at 50e6 00189 return rf; 00190 } 00191 else return NAN; 00192 } 00193 // In speed start, where only good/bad estimate is available 00194 if (stat == SPEEDSTART) { 00195 if (0.05-EXTRA <= dut && dut <= 0.10+EXTRA) return 50e6; // Good 00196 else if (0.90-EXTRA <= dut && dut <= 0.95+EXTRA) return 0; // Bad 00197 else return NAN; 00198 } 00199 return NAN; // Measurement not available in this mode 00200 }
Generated on Fri Jul 15 2022 06:07:18 by
1.7.2
