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

📄 adc_ctrl.c

📁 Luminary Micro BLDC motor control software
💻 C
📖 第 1 页 / 共 4 页
字号:
        pusADCData[ulIdx] = HWREG(ADC_BASE + ADC_O_SSFIFO0);

        //
        // Increment the count of samples read.
        //
        ulIdx++;
    }

    //
    // See if five samples were read.
    //
    if(ulIdx != 5)
    {
        //
        // Since there were not precisely five samples in the FIFO, it is not
        // known what analog signal is represented by each sample.  Therefore,
        // return without doing any processing on these samples.
        //
        return;
    }

    //
    // See if the motor drive is running.
    //
    if(!MainIsRunning())
    {
        //
        // Since the motor drive is not running, there is no current through
        // the motor, nor is there any Back EMF voltage.
        //
        g_psPhaseCurrent[0] = 0;
        g_psPhaseCurrent[1] = 0;
        g_psPhaseCurrent[2] = 0;
        g_sMotorCurrent = 0;

        //
        // There is nothing further to be done since the motor is not running.
        //
        return;
    }

    //
    // Get the average Phase Current ADC input value, discarding the high and
    // low value.
    //
    usMin = usMax = usSum = pusADCData[0];
    for(ulIdx = 1; ulIdx < 5; ulIdx++)
    {
        usSum += pusADCData[ulIdx];
        if(pusADCData[ulIdx] < usMin)
        {
            usMin = pusADCData[ulIdx];
        }
        if(pusADCData[ulIdx] > usMax)
        {
            usMax = pusADCData[ulIdx];
        }
    }
    usSum -= usMin;
    usSum -= usMax;
    usSum /= 3;

    //
    // Calculate Phase current.
    //
    lTemp = (usSum * 43032) / 1000;
    lTemp = (lTemp - 16580);
    lTemp = (lTemp * g_ulTrapDutyCycle) / 100;

    //
    // Run it through an IIR low pass filter, with coefficient of 0.75.
    //
    g_psPhaseCurrent[g_ucPhaseCurrentIndex] = 
        (short)((((long)g_psPhaseCurrent[g_ucPhaseCurrentIndex] * 3) + lTemp)
        / 4);

    //
    // Accumulate the phase current sum.
    //
    ulPhaseSum += usSum;
    ulPhaseCount++;
    
    //
    // If we have changed phases, calculate the phase current average.
    //
    if(g_ucPhaseCurrentIndex != ucLastPhaseIndex)
    {
        if(ucLastPhaseIndex <= 2)
        {
            lTemp = (((ulPhaseSum / ulPhaseCount) * 43032) / 1000);
            lTemp = (lTemp - 16580);
            lTemp = (lTemp * g_ulTrapDutyCycle) / 100;
            g_sMotorCurrent = ((g_sMotorCurrent * 3) + lTemp) / 4;
            ulPhaseSum = 0;
            ulPhaseCount = 0;
        }
        ucLastPhaseIndex = g_ucPhaseCurrentIndex;
    }
}

//*****************************************************************************
//
//! Handles the ADC sample sequence zero interrupt for sine mode.
//!
//! This functions processes the ADC sequence zero for sine mode.  In this
//! handler, all three phases of current are processed from the sequence.
//! The peak value is detected for a complete electrical revolution of the
//! motor.  The phase current is converted to an RMS value, and the motor
//! current is taken as the average of all three phases.
//!
//! \return None.
//
//*****************************************************************************
static void
ADC0IntHandlerSine(void)
{
    unsigned long ulIdx;
    unsigned short pusADCData[8];
    long lTemp;

    //
    // Read the samples from the ADC FIFO.
    //
    ulIdx = 0;
    while(!(HWREG(ADC_BASE + ADC_O_SSFSTAT0) & ADC_SSFSTAT0_EMPTY) &&
          (ulIdx < 3))
    {
        //
        // Read the next sample.
        //
        pusADCData[ulIdx] = HWREG(ADC_BASE + ADC_O_SSFIFO0);

        //
        // Increment the count of samples read.
        //
        ulIdx++;
    }

    //
    // See if three samples were read.
    //
    if(ulIdx != 3)
    {
        //
        // Since there were not precisely three samples in the FIFO, it is not
        // known what analog signal is represented by each sample.  Therefore,
        // return without doing any processing on these samples.
        //
        return;
    }

    //
    // Filter the new samples.
    //
    for(ulIdx = 0; ulIdx < 3; ulIdx++)
    {
        //
        // Pass the new data sample through a single pole IIR low pass filter
        // with a coefficient of 0.75.
        //
        g_pusFilteredData0[ulIdx] = (((g_pusFilteredData0[ulIdx] * 3) +
                                     pusADCData[ulIdx]) / 4);
    }

    //
    // See if the motor drive is running.
    //
    if(!MainIsRunning())
    {
        //
        // Since the motor drive is not running, there is no current through
        // the motor, nor is there any Back EMF voltage.
        //
        g_psPhaseCurrent[0] = 0;
        g_psPhaseCurrent[1] = 0;
        g_psPhaseCurrent[2] = 0;
        g_sMotorCurrent = 0;

        //
        // There is nothing further to be done since the motor is not running.
        //
        return;
    }

    //
    // See if the drive angle just crossed zero in either direction.
    //
    if(((g_ulAngle > 0xf0000000) && (g_ulPrevAngle < 0x10000000)) ||
       ((g_ulAngle < 0x10000000) && (g_ulPrevAngle > 0xf0000000)))
    {
        //
        // Loop through the three phases of the motor drive.
        //
        for(ulIdx = 0; ulIdx < 3; ulIdx++)
        {
            //
            // Convert the maximum reading detected during the last cycle into
            // amperes.  This is the peak current, which is then divided by 
            // 1.4 to get the RMS current.
            //
            lTemp = ((long)g_pusPhaseMax[ulIdx] * 43032) / 1000;
            lTemp = lTemp - 16580;
            lTemp = lTemp * 10 / 14;
            g_psPhaseCurrent[ulIdx] = lTemp;

            //
            // Reset the maximum phase current seen to zero to prepare for the
            // next cycle.
            //
            g_pusPhaseMax[ulIdx] = 0;
        }

        //
        // Average the RMS current of the three phases to get the RMS motor
        // current.
        //
        lTemp = (long)g_psPhaseCurrent[0];
        lTemp += (long)g_psPhaseCurrent[1];
        lTemp += (long)g_psPhaseCurrent[2];
        g_sMotorCurrent = (short)(lTemp / 3);
    }

    //
    // Loop through the three phases of the motor drive.
    //
    for(ulIdx = 0; ulIdx < 3; ulIdx++)
    {
        //
        // See if this ADC reading is larger than any previous ADC reading.
        //
        if(g_pusFilteredData0[ulIdx] > g_pusPhaseMax[ulIdx])
        {
            //
            // Save this ADC reading as the maximum.
            //
            g_pusPhaseMax[ulIdx] = g_pusFilteredData0[ulIdx];
        }
    }

    //
    // Save the current motor drive angle for the next set of samples.
    //
    g_ulPrevAngle = g_ulAngle;
}

//*****************************************************************************
//
//! Handles the ADC sample sequence zero interrupt.
//!
//! This function is called when sample sequence zero asserts an interrupt.  It
//! handles clearing the interrupt and processing any sequence overflow
//! conditions.  Then, depending on the modulation scheme that is active, the
//! appropriate sub-handler is called.
//!
//! \return None.
//
//*****************************************************************************
void
ADC0IntHandler(void)
{
    volatile unsigned long ulTemp;

    //
    // Clear the ADC interrupt.
    //
    HWREG(ADC_BASE + ADC_O_ISC) = ADC_ISC_IN0;

    //
    // Reset the sequence if an overflow has occurred.
    //
    if(HWREG(ADC_BASE + ADC_O_OSTAT) & ADC_OSTAT_OV0)
    {
        //
        // Disable the sequence.
        //
        HWREG(ADC_BASE + ADC_O_ACTSS) &= ~ADC_ACTSS_ASEN0;

        //
        // 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;

        //
        // Renable the sequence and return.
        //
        HWREG(ADC_BASE + ADC_O_ACTSS) = ADC_ACTSS_ASEN0;
        return;
    }

    //
    // Process the phase current, one leg at a time, for trapezoid mode.
    //
    if(HWREGBITH(&(g_sParameters.usFlags), FLAG_DRIVE_BIT) ==
            FLAG_DRIVE_TRAPEZOID)
    {
        ADC0IntHandlerTrapezoid();
    }

    //
    // Process the phase current as sum of peak phases for sine mode.
    //
    else if(HWREGBITH(&(g_sParameters.usFlags), FLAG_DRIVE_BIT) ==
            FLAG_DRIVE_SINE)
    {
        ADC0IntHandlerSine();
    }
}

//*****************************************************************************
//
//! Handles the ADC sample sequence one interrupt.
//!
//! This function is called when sample sequence one asserts an interrupt.  It
//! handles clearing the interrupt, processing any sequence overflow
//! conditions, and processing the new ADC data in the FIFO.  This sequence is
//! used to read the DC Bus Voltage, the Analog Input signal, and the
//! temperature.
//!
//! \return None.
//
//*****************************************************************************
void
ADC1IntHandler(void)
{
    unsigned long ulIdx;
    unsigned short pusADCData[3];

    //
    // Clear the ADC interrupt.
    //
    HWREG(ADC_BASE + ADC_O_ISC) = ADC_ISC_IN1;

    //
    // Reset the sequence if an overflow has occurred.
    //
    if(HWREG(ADC_BASE + ADC_O_OSTAT) & ADC_OSTAT_OV1)
    {
        //
        // Disable the sequence.
        //
        HWREG(ADC_BASE + ADC_O_ACTSS) &= ~ADC_ACTSS_ASEN1;

        //
        // Drain the Sequence FIFO.
        //
        while(!(HWREG(ADC_BASE + ADC_O_SSFSTAT1) & ADC_SSFSTAT1_EMPTY))
        {
            //
            // Read the next sample.
            //
            pusADCData[0] = HWREG(ADC_BASE + ADC_O_SSFIFO1);
        }

        //
        // Clear any overflow/underflow conditions that might exist.
        //
        HWREG(ADC_BASE + ADC_O_OSTAT) = ADC_OSTAT_OV1;
        HWREG(ADC_BASE + ADC_O_USTAT) = ADC_USTAT_UV1;

        //
        // Renable the sequence and return.
        //
        HWREG(ADC_BASE + ADC_O_ACTSS) = ADC_ACTSS_ASEN1;
        return;
    }

    //
    // Read the samples from the ADC FIFO.
    //
    ulIdx = 0;
    while(!(HWREG(ADC_BASE + ADC_O_SSFSTAT1) & ADC_SSFSTAT1_EMPTY) &&
          (ulIdx < 3))
    {
        //
        // Read the next sample.
        //
        pusADCData[ulIdx] = HWREG(ADC_BASE + ADC_O_SSFIFO1);

        //
        // Increment the count of samples read.
        //
        ulIdx++;
    }

    //
    // See if three samples were read.
    //
    if(ulIdx != 3)
    {
        //
        // Since there were not precisely thre samples in the FIFO, it is not
        // known what analog signal is represented by each sample.  Therefore,
        // return without doing any processing on these samples.
        //
        return;
    }

    //
    // Filter the new samples.
    //
    for(ulIdx = 0; ulIdx < 3; ulIdx++)
    {
        //
        // Pass the new data sample through a single pole IIR low pass filter
        // with a coefficient of 0.75.
        //
        g_pusFilteredData1[ulIdx] = (((g_pusFilteredData1[ulIdx] * 3) +
                                     pusADCData[ulIdx]) / 4);
    }

    //
    // Convert the ADC DC bus reading to millivolts.  Each volt at the ADC
    // input corresponds to 40 volts of bus voltage.
    //
    g_ulBusVoltage = ((unsigned long)g_pusFilteredData1[1] * 120000) / 1024;

    //
    // Convert the ADC junction temperature reading to ambient case temperature
    // in Celsius.
    //
    g_ucAmbientTemp = (59960 - (g_pusFilteredData1[2] * 100)) / 356;

    //
    // Convert the ADC Analog Input reading to milli-volts.  Each volt at the
    // ADC input corresponds to ~1.714 volts at the Analog Input.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -