⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 adc_ctrl.c

📁 Luminary Micro BLDC motor control software
💻 C
📖 第 1 页 / 共 4 页
字号:
                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 + -