📄 adc_ctrl.c
字号:
g_bBEMFEdge = true;
g_ulBEMFNextHall = MainIsReverse() ? 3 : 5;
}
break;
case 1:
if(usADCData > (g_pusFilteredData1[1] / 2))
{
g_bBEMFEdge = true;
g_ulBEMFNextHall = MainIsReverse() ? 4 : 2;
}
break;
case 2:
if(usADCData < (g_pusFilteredData1[1] / 2))
{
g_bBEMFEdge = true;
g_ulBEMFNextHall = MainIsReverse() ? 6 : 3;
}
break;
case 3:
if(usADCData > (g_pusFilteredData1[1] / 2))
{
g_bBEMFEdge = true;
g_ulBEMFNextHall = MainIsReverse() ? 1 : 4;
}
break;
case 4:
if(usADCData < (g_pusFilteredData1[1] / 2))
{
g_bBEMFEdge = true;
g_ulBEMFNextHall = MainIsReverse() ? 5 : 6;
}
break;
case 5:
if(usADCData > (g_pusFilteredData1[1] / 2))
{
g_bBEMFEdge = true;
g_ulBEMFNextHall = MainIsReverse() ? 2 : 1;
}
break;
}
//
// If we detected an edge, start a timer to trigger a commutation.
//
if(g_bBEMFEdge && (HWREGBITH(&(g_sParameters.usFlags), FLAG_SENSOR_BIT) ==
FLAG_SENSOR_ABSENT))
{
ulTime = ulNewTime - g_ulBEMFEdgePrevious;
TimerLoadSet(TIMER0_BASE, TIMER_A, (ulTime / 2) - 1);
TimerEnable(TIMER0_BASE, TIMER_A);
g_ulBEMFEdgePrevious = ulNewTime;
}
//
// Compute the new speed from the time between edges.
//
if(g_bBEMFEdge && (g_ucBEMFState == 0))
{
//
// Set the flag to indicate that we have seen an edge.
//
HWREGBITW(&g_ulADCFlags, FLAG_EDGE_BIT) = 1;
//
// See if this edge should be skipped.
//
if(HWREGBITW(&g_ulADCFlags, FLAG_SKIP_BIT))
{
//
// This edge should be skipped, but an edge time now exists so the
// next edge should not be skipped.
//
HWREGBITW(&g_ulADCFlags, FLAG_SKIP_BIT) = 0;
//
// Save the time of the current edge.
//
g_ulBEMFSpeedPrevious = ulNewTime;
//
// There is nothing further to be done.
//
return;
}
//
// Compute the time between this edge and the previous edge.
//
ulTime = ulNewTime - g_ulBEMFSpeedPrevious;
//
// Save the time of the current edge.
//
g_ulBEMFSpeedPrevious = ulNewTime;
//
// Compute the new speed from the time between edges, running it
// through a low pass filter with a coefficient of .875.
//
g_ulBEMFRotorSpeed = ((g_ulBEMFRotorSpeed * 7) +
(((unsigned long)SYSTEM_CLOCK * (unsigned long)60) /
(ulTime * (g_sParameters.ucNumPoles + 1)))) / 8;
}
}
//*****************************************************************************
//
//! Initializes the ADC control routines.
//!
//! This function initializes the ADC module and the control routines,
//! preparing them to monitor currents and voltages on the motor drive.
//!
//! \return None.
//
//*****************************************************************************
void
ADCInit(void)
{
//
// Set the speed of the ADC to 1 million samples per second.
//
SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS);
//
// Configure sample sequence zero to capture Phase Current. Default
// mode is for Trapezoid readings.
//
g_ucPhaseCurrentIndex = 1;
ADCSequenceConfigure(ADC_BASE, 0, ADC_TRIGGER_PWM0, 1);
ADCSequenceStepConfigure(ADC_BASE, 0, 0, PIN_IPHASEB);
ADCSequenceStepConfigure(ADC_BASE, 0, 1, PIN_IPHASEB);
ADCSequenceStepConfigure(ADC_BASE, 0, 2, PIN_IPHASEB);
ADCSequenceStepConfigure(ADC_BASE, 0, 3, PIN_IPHASEB);
ADCSequenceStepConfigure(ADC_BASE, 0, 4,
ADC_CTL_END | ADC_CTL_IE | PIN_IPHASEB);
//
// Configure sample sequence one to capture Analog Input voltage, DC bus
// voltage, and temperature.
//
ADCSequenceConfigure(ADC_BASE, 1, ADC_TRIGGER_PWM0, 3);
ADCSequenceStepConfigure(ADC_BASE, 1, 0, PIN_VANALOG);
ADCSequenceStepConfigure(ADC_BASE, 1, 1, PIN_VSENSE);
ADCSequenceStepConfigure(ADC_BASE, 1, 2,
ADC_CTL_END | ADC_CTL_IE | ADC_CTL_TS);
//
// Configure sample sequence two to capture Linear Hall Sensor input.
// Note: The Linear Hall Sensor input shares ADC input path with
// the Back EMF input. Jumpers Block J9 must be configured properly
// for these inputs to be valid.
//
ADCSequenceConfigure(ADC_BASE, 2, ADC_TRIGGER_PWM0, 2);
ADCSequenceStepConfigure(ADC_BASE, 2, 0, PIN_VBEMFA);
ADCSequenceStepConfigure(ADC_BASE, 2, 1, PIN_VBEMFB);
ADCSequenceStepConfigure(ADC_BASE, 2, 2,
ADC_CTL_END | ADC_CTL_IE | PIN_VBEMFC);
//
// Configure sample sequence three to capture Back EMF samples. This
// should be the highest priority sequence, to ensure that it occurs
// within the PWM pulse.
//
ADCSequenceConfigure(ADC_BASE, 3, ADC_TRIGGER_PWM0, 0);
ADCSequenceStepConfigure(ADC_BASE, 3, 0,
ADC_CTL_END | ADC_CTL_IE | PIN_VBEMFA);
//
// Configure Timer 0 as a one-shot timer to be used for processing the
// Back EMF data and generating the appropriate change in "digital" Hall
// state value at the correct time for the motor speed..
//
TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_OS);
//
// Enable the interrupt handler for the timer.
//
TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
IntEnable(INT_TIMER0A);
//
// Enable sample sequence zero and its interrupt.
//
ADCSequenceEnable(ADC_BASE, 0);
ADCIntEnable(ADC_BASE, 0);
IntEnable(INT_ADC0);
//
// Enable sample sequence one and its interrupt.
//
ADCSequenceEnable(ADC_BASE, 1);
ADCIntEnable(ADC_BASE, 1);
IntEnable(INT_ADC1);
//
// Enable sample sequence two and its interrupt.
//
ADCSequenceEnable(ADC_BASE, 2);
ADCIntEnable(ADC_BASE, 2);
IntEnable(INT_ADC2);
//
// Enable sample sequence three and its interrupt.
//
ADCSequenceEnable(ADC_BASE, 3);
ADCIntEnable(ADC_BASE, 3);
IntEnable(INT_ADC3);
}
//*****************************************************************************
//
//! Handles the ADC System Tick.
//!
//! This function is called by the system tick handler. It's primary
//! purpose is to reset the motor speed to 0 if no "Hall" edges have
//! been detected for some period of time.
//!
//! \return None.
//
//*****************************************************************************
void
ADCTickHandler(void)
{
//
// See if an edge was seen during this tick period.
//
if(HWREGBITW(&g_ulADCFlags, FLAG_EDGE_BIT) == 1)
{
//
// An edge was seen, so clear the flag so the next period can be
// checked as well.
//
HWREGBITW(&g_ulADCFlags, FLAG_EDGE_BIT) = 0;
//
// There is nothing more to do here, so return.
//
return;
}
//
// Check to see if time since the last edge is to large for the
// Back EMF motor speed value.
//
if((UIGetTicks() - g_ulBEMFSpeedPrevious) > (SYSTEM_CLOCK / 5))
{
//
// No edge was seen, so set the rotor speed to zero.
//
g_ulBEMFRotorSpeed = 0;
//
// Since the amount of time the rotor is stopped is indeterminate,
// skip the first edge when the rotor starts rotating again.
//
HWREGBITW(&g_ulADCFlags, FLAG_SKIP_BIT) = 1;
}
//
// Check to see if time since the last edge is to large for the
// linear Hall sensor motor speed value.
//
if((UIGetTicks() - g_ulLinearSpeedPrevious) > (SYSTEM_CLOCK / 5))
{
//
// No edge was seen, so set the rotor speed to zero.
//
g_ulLinearRotorSpeed = 0;
//
// Since the amount of time the rotor is stopped is indeterminate,
// skip the first edge when the rotor starts rotating again.
//
HWREGBITW(&g_ulADCFlags, FLAG_SKIP_LINEAR_BIT) = 1;
}
}
//*****************************************************************************
//
//! Enable/Disable the Linear Hall Sequence.
//!
//! \param bEnable is set to true to enable the linear hall sequence and
//! false to disable.
//!
//! This function is called by the UI code to enable/disable the Linear
//! Hall Sequence processing, based on motor drive configuration.
//!
//! \return None.
//
//*****************************************************************************
void
ADCEnableLinearHallSequence(tBoolean bEnable)
{
//
// If the enable flag is true, enable the Linear Hall Processing sequence.
//
if(bEnable)
{
ADCSequenceEnable(ADC_BASE, 2);
}
//
// Otherwise, disable the sequence to conserve CPU resources.
//
else
{
ADCSequenceDisable(ADC_BASE, 2);
}
}
//*****************************************************************************
//
//! Enable/Disable the Back EMF Sequence
//!
//! \param bEnable is set to true to enable the Back EMF sequence and
//! false to disable.
//!
//! This function is called by the UI code to enable/disable the Back
//! EMF processing, based on motor drive configuration.
//!
//! \return None.
//
//*****************************************************************************
void
ADCEnableBackEMFSequence(tBoolean bEnable)
{
//
// If the enable flag is true, enable the Linear Hall Processing sequence.
//
if(bEnable)
{
ADCSequenceEnable(ADC_BASE, 3);
}
//
// Otherwise, disable the sequence to conserve CPU resources.
//
else
{
ADCSequenceDisable(ADC_BASE, 3);
}
}
//*****************************************************************************
//
//! Configure Phase Current Sequence
//!
//! \param ucMode determines which mode should be use for phase current
//! measurement. 0 indicates that single phase (i.e. Trapezoid Mode) should
//! be used. 1 indicates that all three phases should be measured as RMS
//! phase current.
//!
//! This function is called by the UI code to configure the Phase current
//! measurement sequence.
//!
//! \return None.
//
//*****************************************************************************
void ADCConfigurePhaseCurrentSequence(unsigned char ucMode)
{
volatile unsigned long ulTemp;
//
// Disable the sequence.
//
ADCSequenceDisable(ADC_BASE, 0);
//
// Drain the Sequence FIFO.
//
while(!(HWREG(ADC_BASE + ADC_O_SSFSTAT0) & ADC_SSFSTAT0_EMPTY))
{
//
// Read the next sample.
//
ulTemp = HWREG(ADC_BASE + ADC_O_SSFIFO0);
}
//
// Clear any overflow/underflow conditions that might exist.
//
HWREG(ADC_BASE + ADC_O_OSTAT) = ADC_OSTAT_OV0;
HWREG(ADC_BASE + ADC_O_USTAT) = ADC_USTAT_UV0;
//
// For Mode 0, use single phase at a time (e.g. Trapezoid mode).
//
if(ucMode == 0)
{
//
// Configure sample sequence zero to capture Back EMF voltage and Phase
// current.
//
g_ucPhaseCurrentIndex = 1;
ADCSequenceConfigure(ADC_BASE, 0, ADC_TRIGGER_PWM0, 1);
ADCSequenceStepConfigure(ADC_BASE, 0, 0, PIN_IPHASEB);
ADCSequenceStepConfigure(ADC_BASE, 0, 1, PIN_IPHASEB);
ADCSequenceStepConfigure(ADC_BASE, 0, 2, PIN_IPHASEB);
ADCSequenceStepConfigure(ADC_BASE, 0, 3, PIN_IPHASEB);
ADCSequenceStepConfigure(ADC_BASE, 0, 4,
ADC_CTL_END | ADC_CTL_IE | PIN_IPHASEB);
}
//
// For Mode 1, use all three phases at a time and measure RMS current.
//
else if(ucMode == 1)
{
//
// Configure sample sequence zero to capture all phase currents.
//
ADCSequenceConfigure(ADC_BASE, 0, ADC_TRIGGER_PWM0, 1);
ADCSequenceStepConfigure(ADC_BASE, 0, 0, PIN_IPHASEA);
ADCSequenceStepConfigure(ADC_BASE, 0, 1, PIN_IPHASEB);
ADCSequenceStepConfigure(ADC_BASE, 0, 2,
ADC_CTL_END | ADC_CTL_IE | PIN_IPHASEC);
}
//
// Reneable the sequence.
//
ADCSequenceEnable(ADC_BASE, 0);
}
//*****************************************************************************
//
// Close the Doxyen group.
//! @}
//
//*****************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -