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
Libs/IMD/IMD.cpp
- Committer:
- pspatel321
- Date:
- 2015-02-11
- Revision:
- 39:ddf38df9699e
- Parent:
- 38:8efacce315ae
File content as of revision 39:ddf38df9699e:
#include "IMD.h"
#include <math.h>
#include "pinmap.h"
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
const float EXTRA = 0.02; // Margin on the IMD PWM limits
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
static IMD* instance[4] = { 0 }; // Access member from static frame, one IMD permitted per timer module (4 total IMD objects)
// Interrupt functions, must be static context
void tim0_IRQ() {
if (LPC_TIM0->IR & (1<<4|1<<5)) instance[0]->edgeIRQ(); // Capture pin interrupt
if (LPC_TIM0->IR & 1) instance[0]->zeroIRQ(); // MR0 interrupt
LPC_TIM0->IR=0x3F; // Clear interrupt flags
}
void tim1_IRQ() {
if (LPC_TIM1->IR & (1<<4|1<<5)) instance[1]->edgeIRQ();
if (LPC_TIM1->IR & 1) instance[1]->zeroIRQ();
LPC_TIM1->IR=0x3F; // Clear interrupt flags
}
void tim2_IRQ() {
if (LPC_TIM2->IR & (1<<4|1<<5)) instance[2]->edgeIRQ();
if (LPC_TIM2->IR & 1) instance[2]->zeroIRQ();
LPC_TIM2->IR=0x3F; // Clear interrupt flags
}
void tim3_IRQ() {
if (LPC_TIM3->IR & (1<<4|1<<5)) instance[3]->edgeIRQ();
if (LPC_TIM3->IR & 1) instance[3]->zeroIRQ();
LPC_TIM3->IR=0x3F; // Clear interrupt flags
}
IMD::IMD(PinName _pin) {
// Setup the timer/pin access variables
if (_pin == P1_26) { // CAP0.0
timer=0;
pin=0;
timerBase=LPC_TIM0;
} else if (_pin == P1_27) { // CAP0.1
timer=0;
pin=1;
timerBase=LPC_TIM0;
} else if (_pin == P1_18) { // CAP1.0
timer=1;
pin=0;
timerBase=LPC_TIM1;
} else if (_pin == P1_19) { // CAP1.1
timer=1;
pin=1;
timerBase=LPC_TIM1;
} else if (_pin == P0_4) { // CAP2.0
timer=2;
pin=0;
timerBase=LPC_TIM2;
} else if (_pin == P0_5) { // CAP2.1
timer=2;
pin=1;
timerBase=LPC_TIM2;
} else if (_pin == P0_23) { // CAP3.0
timer=3;
pin=0;
timerBase=LPC_TIM3;
} else if (_pin == P0_24) { // CAP3.1
timer=3;
pin=1;
timerBase=LPC_TIM3;
} else { // Invalid pin
timerBase=0;
pin=0;
timer=0;
return;
}
instance[timer] = this;
first = true;
startTime = 0;
widthTicks = 0; // Zero low, so that duty = 0/1 = 0%
periodTicks = 1;
// Enable power and set pclk at 24Mhz
if (timer==0) {
LPC_SC->PCONP |= (1<<1);
LPC_SC->PCLKSEL0 &= ~(3<<2);
} if (timer==1) {
LPC_SC->PCONP |= (1<<2);
LPC_SC->PCLKSEL0 &= ~(3<<4);
} if (timer==2) {
LPC_SC->PCONP |= (1<<22);
LPC_SC->PCLKSEL1 &= ~(3<<12);
} if (timer==3) {
LPC_SC->PCONP |= (1<<23);
LPC_SC->PCLKSEL1 &= ~(3<<14);
}
pin_function(_pin, 3); // Capture input
pin_mode(_pin, PullDown); // Pull-down
timerBase->TCR=2; // Stop counter and hold at 0, for configuration
timerBase->IR=0x3F; // Clear any interrupt flags
timerBase->CTCR=0; // Use pclk, not external pin
timerBase->PR=0; // No prescale value, clock at full pclk=24Mhz
timerBase->EMR=0; // Do not use external match pins
if (timer == 0) NVIC_SetVector(TIMER0_IRQn, (uint32_t)&tim0_IRQ); // Set irq handler for timer0
if (timer == 1) NVIC_SetVector(TIMER1_IRQn, (uint32_t)&tim1_IRQ); // Set irq handler for timer1
if (timer == 2) NVIC_SetVector(TIMER2_IRQn, (uint32_t)&tim2_IRQ); // Set irq handler for timer2
if (timer == 3) NVIC_SetVector(TIMER3_IRQn, (uint32_t)&tim3_IRQ); // Set irq handler for timer3
NVIC_EnableIRQ((IRQn_Type)(timer+1));
NVIC_SetPriority((IRQn_Type)(timer+1), 0); // Highest priority (default)
timerBase->CCR = pin?5<<3:5; // Generate interrupt on rising edge of capture pin
timerBase->MCR = 1; // Interrupt on MR0 to establish the zero speed timeout
zeroIRQ(); // Zero the values
timerBase->TCR = 1; // Start counting, GO!
}
void IMD::edgeIRQ() {
bool rising = pin?timerBase->CCR&(1<<3):timerBase->CCR&1;
uint32_t capTime = pin?timerBase->CR1:timerBase->CR0; // Get the time of the capture event
timerBase->MR0 = capTime + TIMEOUT_TICKS; // Move the zero timeout ahead
// 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 (rising) {
periodTicks = capTime - startTime; // Get the period on Rising edge
startTime = capTime; // Set the start of the next pulse
} else {
widthTicks = capTime - startTime; // Get the pulse width on Falling edge
}
// Switch interrupt types to capture the next edge
if (rising) timerBase->CCR = pin?6<<3:6;
else timerBase->CCR = pin?5<<3:5;
}
void IMD::zeroIRQ() {
periodTicks = 1;
first = true; // Reset the first edge detection case
bool rising = pin?timerBase->CCR&(1<<3):timerBase->CCR&1;
// Timeout occurred after FALLING edge, RISING edge never happened
if (rising) {
widthTicks = 0; // Signal is low = 0/1 = 0% duty
} else {
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 OFF; // IMD off
else if (05 < freq && freq <= 15) return NORMAL; // 10Hz normal mode
else if (15 < freq && freq <= 25) return UNDERVOLT; // 20Hz undervoltage mode
else if (25 < freq && freq <= 35) return SPEEDSTART; // 30Hz speed start mode
else if (35 < freq && freq <= 45) return ERROR; // 40Hz IMD error
else if (45 < freq && freq <= 55) return GROUNDERR; // 50Hz Ground error
else return INVALID; // Invalid
}
float IMD::resistance() {
char stat = status();
float dut = duty();
// In normal or undervoltage mode, where Rf is available
if (stat == NORMAL || stat == UNDERVOLT) {
if (0.05-EXTRA <= dut && dut <= 0.95+EXTRA) {
if (dut > 0.95) dut = 0.95; // Ceiling
if (dut < 0.05) dut = 0.05; // Floor so it doesnt mess up the equation below
float rf = (0.9*1200e3/(dut-0.05)) - 1200e3;
if (rf < 1000) rf = 0; // Floor to hit 0
if (rf > 50e6) rf = 50e6; // Ceil to stay at 50e6
return rf;
}
else return NAN;
}
// In speed start, where only good/bad estimate is available
if (stat == SPEEDSTART) {
if (0.05-EXTRA <= dut && dut <= 0.10+EXTRA) return 50e6; // Good
else if (0.90-EXTRA <= dut && dut <= 0.95+EXTRA) return 0; // Bad
else return NAN;
}
return NAN; // Measurement not available in this mode
}
