示例#1
0
//*****************************************************************************
//
// Gets the H-bridge brake/coast configuration.
//
//*****************************************************************************
void
MotorBrakePositionClean(enum MOTOR motor)
{
    //
    // Clean the stow/pilot status.
    //	
    if(motor == PITCH_MOTOR)
		HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_PITCH) = 0;
	else
		HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_ROLL) = 0;

}
示例#2
0
文件: encoder.c 项目: jmesmon/jaguar
//*****************************************************************************
//
// This function is called to handle the GPIO edge interrupt from the
// quadrature encoder.
//
//*****************************************************************************
void
EncoderIntHandler(void)
{
    unsigned long ulNow;

    //
    // Save the time.
    //
    ulNow = ROM_SysTickValueGet();

    //
    // Clear the encoder interrupt.
    //
    ROM_GPIOPinIntClear(QEI_PHA_PORT, QEI_PHA_PIN);

    //
    // Determine the number of system clocks between the previous edge and this
    // edge.
    //
    if(g_ulEncoderPrevious > ulNow)
    {
        g_ulEncoderClocks = g_ulEncoderPrevious - ulNow;
    }
    else
    {
        g_ulEncoderClocks = (16777216 - ulNow) + g_ulEncoderPrevious;
    }

    //
    // Save the time of the current edge as the time of the previous edge.
    //
    g_ulEncoderPrevious = ulNow;

    //
    // Indicate that an edge has been seen.
    //
    HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_EDGE) = 1;

    //
    // If the previous edge time was valid, then indicate that the time between
    // edges is also now valid.
    //
    if(HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_PREVIOUS) == 1)
    {
        HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_VALID) = 1;
    }

    //
    // Indicate that the previous edge time is valid.
    //
    HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_PREVIOUS) = 1;
}
示例#3
0
//*****************************************************************************
//
// Sets the H-bridge brake/coast configuration.
//
//*****************************************************************************
void
MotorBrakePositionSet(enum MOTOR motor,unsigned long point)
{
    //
    // Set the stow position point.  This will be applied on the
    //	
    if(motor == PITCH_MOTOR)
    {
		Motor[motor].stowpoint = point;
		HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_PITCH) = 1;
    }
	else
	{
		Motor[motor].stowpoint = point;
		HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_ROLL) = 1;
	}
}
示例#4
0
//*****************************************************************************
//
// Set or clear deferred operation flags in an "atomic" manner.
//
// \param pusDeferredOp points to the flags variable which is to be modified.
// \param usBit indicates which bit number is to be set or cleared.
// \param bSet indicates the state that the flag must be set to.  If \b true,
// the flag is set, if \b false, the flag is cleared.
//
// This function safely sets or clears a bit in a flag variable.  The operation
// makes use of bitbanding to ensure that the operation is atomic (no read-
// modify-write is required).
//
// \return None.
//
//*****************************************************************************
static void
SetDeferredOpFlag(volatile unsigned short *pusDeferredOp, unsigned short usBit,
                  tBoolean bSet)
{
    //
    // Set the flag bit to 1 or 0 using a bitband access.
    //
    HWREGBITH(pusDeferredOp, usBit) = bSet ? 1 : 0;
}
示例#5
0
文件: usbdbulk.c 项目: x893/OpenBLT
//*****************************************************************************
//
// Set or clear deferred operation flags in an "atomic" manner.
//
// \param pui16DeferredOp points to the flags variable which is to be modified.
// \param ui16Bit indicates which bit number is to be set or cleared.
// \param bSet indicates the state that the flag must be set to.  If \b true,
// the flag is set, if \b false, the flag is cleared.
//
// This function safely sets or clears a bit in a flag variable.  The operation
// makes use of bitbanding to ensure that the operation is atomic (no read-
// modify-write is required).
//
// \return None.
//
//*****************************************************************************
static void
SetDeferredOpFlag(volatile uint16_t *pui16DeferredOp, uint16_t ui16Bit,
                  bool bSet)
{
    //
    // Set the flag bit to 1 or 0 using a bitband access.
    //
    HWREGBITH(pui16DeferredOp, ui16Bit) = bSet ? 1 : 0;
}
示例#6
0
//*****************************************************************************
//
// Gets the H-bridge brake/coast configuration.
//
//*****************************************************************************
int
MotorPositionError(enum MOTOR motor)
{
    //
    // Clean the stow/pilot status.
    //	
    if(motor == PITCH_MOTOR)
    {
		if(HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_EDGE_FUALSE) == 1)		
			return -1;			
    }
	else
	{
		if(HWREGBITH(&g_usEncoder1Flags, ENCODER_FLAG_EDGE_FUALSE) == 1)		
			return -1;
	}

	return 0;
}
示例#7
0
文件: encoder.c 项目: jmesmon/jaguar
//*****************************************************************************
//
// This function is called periodically to determine when the encoder has
// stopped rotating (based on too much time passing between edges).
//
//*****************************************************************************
void
EncoderTick(void)
{
    //
    // See if an edge has been seen since the last call.
    //
    if(HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_EDGE) == 1)
    {
        //
        // Clear the edge flag.
        //
        HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_EDGE) = 0;

        //
        // Reset the delay counter.
        //
        g_usEncoderCount = ENCODER_WAIT_TIME;
    }

    //
    // Otherwise, see if the delay counter is still active.
    //
    else if(g_usEncoderCount != 0)
    {
        //
        // Decrement the delay counter.
        //
        g_usEncoderCount--;

        //
        // If the delay counter has reached zero, then indicate that there are
        // no valid speed values from the encoder.
        //
        if(g_usEncoderCount == 0)
        {
            HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_PREVIOUS) = 0;
            HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_VALID) = 0;
        }
    }
}
示例#8
0
//*****************************************************************************
//
// Gets the current speed of the encoder, specified as an unsigned 16.16 fixed-
// point value that represents the speed in revolutions per minute (RPM).
//
//*****************************************************************************
long
Encoder1VelocityGet(long lSigned)
{
    //
    // If the time between edges is not valid, then the speed is zero.
    //
    if(HWREGBITH(&g_usEncoder1Flags, ENCODER_FLAG_VALID) == 0)
    {
        return(0);
    }

    //
    // Convert the time between edges into a speed in RPM and return it.
    //
    //return(MathDiv16x16(SYSCLK * 60, g_ulEncoderClocks * g_ulEncoderLines));
	return( (SYSCLK * 60) / (g_ulEncoder1Clocks * g_ulEncoder1Lines));
}
示例#9
0
//*****************************************************************************
//
//! Gets the amplitude based on the frequency.
//!
//! \param ulFrequency is the current motor frequency as a 16.16 fixed point
//! value.
//!
//! This function performs the V/f computation to convert a motor frequency
//! into the amplitude of the waveform.  A V/f table is used to define the
//! mapping of frequency to amplitude; linear interpolation is utilized for
//! frequencies that are not directly defined in the V/f table.
//!
//! \return The amplitude as a 16.16 fixed point value.
//
//*****************************************************************************
unsigned long
VFGetAmplitude(unsigned long ulFrequency)
{
    unsigned long ulRange, ulMin, ulMax;

    //
    // Get the range of the V/f table.
    //
    if(HWREGBITH(&(g_sParameters.usFlags), FLAG_VF_RANGE_BIT) ==
       FLAG_VF_RANGE_100)
    {
        ulRange = 100;
    }
    else
    {
        ulRange = 400;
    }

    //
    // If the input frequency corresponds to a frequency that is beyond the end
    // of the V/f table, simply return the final value of the V/f table.
    //
    if(ulFrequency >= (ulRange * 65536))
    {
        return(g_sParameters.usVFTable[20] * 2);
    }

    //
    // Convert the frequency to the offset into the V/f table of the entry less
    // than or equal to the given frequency.
    //
    ulFrequency = (ulFrequency * 20) / ulRange;

    //
    // Get the two entries from the V/f that surround the distance computed
    // above.
    //
    ulMin = g_sParameters.usVFTable[ulFrequency / 65536] * 2;
    ulMax = g_sParameters.usVFTable[(ulFrequency / 65536) + 1] * 2;

    //
    // Perform linear interpolation between the two V/f entries to get the
    // amplitude for the given frequency.
    //
    return(ulMin + (((ulMax - ulMin) * (ulFrequency & 0xffff)) / 65536));
}
示例#10
0
文件: encoder.c 项目: jmesmon/jaguar
//*****************************************************************************
//
// Gets the current speed of the encoder, specified as an unsigned 16.16 fixed-
// point value that represents the speed in revolutions per minute (RPM).
//
//*****************************************************************************
long
EncoderVelocityGet(long lSigned)
{
    long lDir;

    //
    // If the time between edges is not valid, then the speed is zero.
    //
    if(HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_VALID) == 0)
    {
        return(0);
    }

    //
    // See if a signed velocity should be returned.
    //
    if(lSigned)
    {
        //
        // Get the current direction from the QEI module.
        //
        lDir = ROM_QEIDirectionGet(QEI0_BASE);
    }
    else
    {
        //
        // An unsigned velocity is requested, so assume the direction is
        // positive.
        //
        lDir = 1;
    }

    //
    // Convert the time between edges into a speed in RPM and return it.
    //
    return(MathDiv16x16(lDir * SYSCLK * 60,
                        g_ulEncoderClocks * g_ulEncoderLines));
}
示例#11
0
//*****************************************************************************
//
// This function is called periodically to determine when the encoder has
// stopped rotating (based on too much time passing between edges).
//
//*****************************************************************************
void
EncoderTick(unsigned long ulBase)
{
	if(ulBase == QEI0_BASE)
	{
		#if 0
	    //
	    // See if an edge has been seen since the last call.
	    //
	    if(HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_EDGE) == 1)
	    {
	        //
	        // Clear the edge flag.
	        //
	        HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_EDGE) = 0;

	        //
	        // Reset the delay counter.
	        //
	        g_usEncoderCount = ENCODER_WAIT_TIME;
			
	    }
	    //
	    // Otherwise, see if the delay counter is still active.
	    //
	    else if(g_usEncoderCount != 0)
	    {
	        //
	        // Decrement the delay counter.
	        //
	        g_usEncoderCount--;

	        //
	        // If the delay counter has reached zero, then indicate that there are
	        // no valid speed values from the encoder.
	        //
	        if(g_usEncoderCount == 0)
	        {
	            HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_PREVIOUS) = 0;
	            HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_VALID) = 0;
	        }
	    }
		#endif

		Motor[PITCH_MOTOR].position = QEIPositionGet(QEI0_BASE);
		Motor[PITCH_MOTOR].direction= QEIDirectionGet(QEI0_BASE);
		Motor[PITCH_MOTOR].aangle= ((Motor[PITCH_MOTOR].position - Motor[PITCH_MOTOR].zero_pos) / 924.444f);	// 180

		//
		// If the previous edge time was valid, then indicate that the time between
		// edges is also now valid.
		//
		if(HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_PITCH) == 1)
		{
			if(QEIPositionGet(QEI0_BASE) == Motor[PITCH_MOTOR].stowpoint)   
			{
				GeneralPitchRoll(PITCH_MOTOR,A3906_BRAKE,ulPeriod);	 
				HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_PITCH) = 0;
			}
			else
			if((QEIPositionGet(QEI0_BASE) > Motor[PITCH_MOTOR].stowpoint))
				GeneralPitchRoll(PITCH_MOTOR,A3906_REVERSE,((ulPeriod*25)/100));				
			else	  
			if((QEIPositionGet(QEI0_BASE) < Motor[PITCH_MOTOR].stowpoint))			  
				GeneralPitchRoll(PITCH_MOTOR,A3906_FORWARD,((ulPeriod*25)/100));
							
			
						
		}
		
		
	}
	else
	if(ulBase == QEI1_BASE)
	{
		#if 0
		//
		// See if an edge has been seen since the last call.
		//
		if(HWREGBITH(&g_usEncoder1Flags, ENCODER_FLAG_EDGE) == 1)
		{
			//
			// Clear the edge flag.
			//
			HWREGBITH(&g_usEncoder1Flags, ENCODER_FLAG_EDGE) = 0;
		
			//
			// Reset the delay counter.
			//
			g_usEncoder1Count = ENCODER_WAIT_TIME;

		}
		
		//
		// Otherwise, see if the delay counter is still active.
		//
		else if(g_usEncoder1Count != 0)
		{
			//
			// Decrement the delay counter.
			//
			g_usEncoder1Count--;
		
			//
			// If the delay counter has reached zero, then indicate that there are
			// no valid speed values from the encoder.
			//
			if(g_usEncoder1Count == 0)
			{
				HWREGBITH(&g_usEncoder1Flags, ENCODER_FLAG_PREVIOUS) = 0;
				HWREGBITH(&g_usEncoder1Flags, ENCODER_FLAG_VALID) = 0;
			}
		}
		#endif

		Motor[ROLL_MOTOR].position = QEIPositionGet(QEI1_BASE);
		Motor[ROLL_MOTOR].direction= QEIDirectionGet(QEI1_BASE);
		Motor[ROLL_MOTOR].aangle= ((Motor[ROLL_MOTOR].position - Motor[ROLL_MOTOR].zero_pos) / 924.444f);	// 180

	
		//
		// If the previous edge time was valid, then indicate that the time between
		// edges is also now valid.
		//
		if(HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_ROLL) == 1)
		{
			if(QEIPositionGet(QEI1_BASE) == Motor[ROLL_MOTOR].stowpoint)	  
			{
				GeneralPitchRoll(ROLL_MOTOR,A3906_BRAKE,ulPeriod);	
				HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_ROLL) = 0;
			}
			else
			if((QEIPositionGet(QEI1_BASE) < Motor[ROLL_MOTOR].stowpoint))
				GeneralPitchRoll(ROLL_MOTOR,A3906_FORWARD,((ulPeriod*25)/100));				
			else	  
			if((QEIPositionGet(QEI1_BASE) > Motor[ROLL_MOTOR].stowpoint))			  
				GeneralPitchRoll(ROLL_MOTOR,A3906_REVERSE,((ulPeriod*25)/100));				
			
		}			

	}
}
示例#12
0
//*****************************************************************************
//
// This function is called to handle the GPIO edge interrupt from the
// quadrature encoder.
//
//*****************************************************************************
void
QEI1IntHandler(void)
{
    unsigned long ulNow;

    //
    // Save the time.
    //
    ulNow = SysTickValueGet();

    //
    // Clear the encoder interrupt.
    //
    GPIOPinIntClear(QEI_ROLL_PHA_PORT, QEI_ROLL_PHA_PIN);

	ulstatus1 = QEIIntStatus(QEI1_BASE,false); 
	if (  (ulstatus1 & QEI_INTDIR) == QEI_INTDIR) 
	{ 
	  // 
	  // clear	Interrupt Bit	 
	   QEIIntClear(QEI1_BASE, QEI_INTDIR); 
	  // 
	  //code for Direction change 
	  //.............. 
	} 
	if (  (ulstatus1 & QEI_INTINDEX) == QEI_INTINDEX) 
	{ 
	  // 
	  // clear	Interrupt Bit	 
	   QEIIntClear(QEI1_BASE, QEI_INTINDEX); 
	  // 
	  //code for Index change 
	  //.............. 
	}		
	if (  (ulstatus1 & QEI_INTERROR) == QEI_INTERROR) 
	{ 
	  //	 
	  // clear	Interrupt Bit	 
		QEIIntClear(QEI1_BASE, QEI_INTERROR); 
	  // 
	  //code for Phase ERROR 
	  //.............. 
	} 

    //
    // Determine the number of system clocks between the previous edge and this
    // edge.
    //
    if(g_ulEncoder1Previous > ulNow)
    {
        g_ulEncoder1Clocks = g_ulEncoder1Previous - ulNow;
    }
    else
    {
        g_ulEncoder1Clocks = (SYSCLK_50MHZ - ulNow) + g_ulEncoder1Previous;		
		
    }

    //
    // Save the time of the current edge as the time of the previous edge.
    //
    g_ulEncoder1Previous = ulNow;

    //
    // Indicate that an edge has been seen.
    //
    HWREGBITH(&g_usEncoder1Flags, ENCODER_FLAG_EDGE) = 1;

    //
    // If the previous edge time was valid, then indicate that the time between
    // edges is also now valid.
    //
    if(HWREGBITH(&g_usEncoder1Flags, ENCODER_FLAG_PREVIOUS) == 1)
    {
        HWREGBITH(&g_usEncoder1Flags, ENCODER_FLAG_VALID) = 1;
    }

    //
    // Indicate that the previous edge time is valid.
    //
    HWREGBITH(&g_usEncoder1Flags, ENCODER_FLAG_PREVIOUS) = 1;
}
示例#13
0
void EncoderInitReset(unsigned long ulBase,enum MOTOR motor,enum A3906Logic logic)
{
	  unsigned long start;
	  tBoolean encChanged;
	  start = g_ulTickCount;
	  // move until encoders show no change
	  encChanged = true;
	  prevenc = QEIPositionGet(ulBase);
	  GeneralPitchRoll(motor,logic,motor == PITCH_MOTOR ? ((ulPeriod*30)/100): ((ulPeriod*40)/100));	  
	  while(encChanged)
	  {
		while ((g_ulTickCount - start) < 1000);   // encoder samples at 500Hz, we check at 10Hz
		encChanged = (prevenc != QEIPositionGet(ulBase));
		prevenc = QEIPositionGet(ulBase);
		start = g_ulTickCount;
	  }
	  
	  GeneralPitchRoll(motor,A3906_BRAKE,ulPeriod);
	  
	  if(ulBase == QEI0_BASE) // PITCH_MOTOR
	  {
		  if(logic == A3906_FORWARD)
		  {
			  //
			  // Indicate that an full edge has been seen.
			  //

			  //Motor[motor].max_position = QEIPositionGet(QEI0_BASE);
			  //Motor[motor].avg_position = QEIPositionGet(QEI0_BASE)/2;
			  
		  	  if( QEIPositionGet(QEI0_BASE) > FULL_SCALE_PITCH_MOTOR)
			    HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_EDGE_FUALSE) = 0;
			  else
				  HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_EDGE_FUALSE) = 1;
			  				  
		  }
		  else
		  {
			  QEIPositionSet(ulBase, 0);
			  Motor[motor].min_position = 1000;			  
			  Motor[motor].max_position = 120000;			  
			  Motor[motor].relative = 45263;
			  HWREGBITH(&g_usEncoderFlags, ENCODER_FLAG_EDGE_FUALSE) = 0;
			  
			  
		  }
	  }
	  else					//	ROLL_MOTOR
	  {
		  if(logic == A3906_FORWARD)
		  {
		  
			  QEIPositionSet(ulBase, 0);
			  Motor[motor].min_position = 315500;			  
			  Motor[motor].max_position = 156000;
			  Motor[motor].relative = 230770;			  
  			  HWREGBITH(&g_usEncoder1Flags, ENCODER_FLAG_EDGE_FUALSE) = 0;
			  
		  }
		  else
		  {
			  //Motor[motor].max_position = QEIPositionGet(QEI1_BASE);							  
			  //Motor[motor].avg_position = (QEIPositionGet(QEI1_BASE)/2)+5500;	// Fix symmetry 							  

			  if( QEIPositionGet(QEI1_BASE) < FULL_SCALE_ROLL_MOTOR)
				HWREGBITH(&g_usEncoder1Flags, ENCODER_FLAG_EDGE_FUALSE) = 1;
			  else
				  HWREGBITH(&g_usEncoder1Flags, ENCODER_FLAG_EDGE_FUALSE) = 0;
			  
		  }
	
	  }

}
示例#14
0
//*****************************************************************************
//
//! 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 the new ADC data in the FIFO.
//!
//! \return None.
//
//*****************************************************************************
void
ADC0IntHandler(void)
{
    unsigned long ulIdx;
    unsigned short pusADCData[8];

    //
    // Clear the ADC interrupt.
    //
    ADCIntClear(ADC0_BASE, 0);

    //
    // Read the samples from the ADC FIFO.
    //
    ulIdx = 0;
    while(!(HWREG(ADC0_BASE + ADC_O_SSFSTAT0) & ADC_SSFSTAT0_EMPTY) &&
          (ulIdx < 8))
    {
        //
        // Read the next sample.
        //
        pusADCData[ulIdx] = HWREG(ADC0_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;
    }

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

    //
    // Convert the ADC DC bus reading to volts.  Each volt at the ADC input
    // corresponds to 150 volts of bus voltage.
    //
    g_usBusVoltage = ((unsigned long)g_pusFilteredData[3] * 450) / 1024;

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

    //
    // See if the motor drive is running.
    //
    if(!MainIsRunning())
    {
        //
        // Since the motor drive is not running, there is no current through
        // the motor.
        //
        g_pusPhaseCurrentRMS[0] = 0;
        g_pusPhaseCurrentRMS[1] = 0;
        g_pusPhaseCurrentRMS[2] = 0;
        g_usMotorCurrent = 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.  The phase current is measured as the voltage dropped
            // across a 0.04 Ohm resistor, so current is 25 times the voltage.
            // This is then passed through an op amp that multiplies the value
            // by 11.  The resulting phase current is put into a 8.8 fixed
            // point representation and must therefore be multiplied by 256.
            // This is the peak current, which is then divided by 1.4 to get
            // the RMS current.  Since the ADC reading is 0 to 1023 for
            // voltages between 0 V and 3 V, the final equation is:
            //
            //     A = R * (25 / 11) * (3 / 1024) * (10 / 14) * 256
            //
            // Reducing the constants results in R * 375 / 308.
            //
            g_pusPhaseCurrentRMS[ulIdx] = (((long)g_pusPhaseMax[ulIdx] * 375) /
                                           308);

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

        //
        // See if this is a single phase or three phase motor.
        //
        if(HWREGBITH(&(g_sParameters.usFlags), FLAG_MOTOR_TYPE_BIT) ==
           FLAG_MOTOR_TYPE_1PHASE)
        {
            //
            // Average the RMS current of the two phases to get the RMS motor
            // current.
            //
            pusADCData[0] = g_pusPhaseCurrentRMS[0];
            pusADCData[1] = g_pusPhaseCurrentRMS[1];
            g_usMotorCurrent = ((pusADCData[0] + pusADCData[1]) / 2);
        }
        else
        {
            //
            // Average the RMS current of the three phases to get the RMS motor
            // current.
            //
            pusADCData[0] = g_pusPhaseCurrentRMS[0];
            pusADCData[1] = g_pusPhaseCurrentRMS[1];
            pusADCData[2] = g_pusPhaseCurrentRMS[2];
            g_usMotorCurrent = ((pusADCData[0] + pusADCData[1] +
                                 pusADCData[2]) / 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_pusFilteredData[ulIdx] > g_pusPhaseMax[ulIdx])
        {
            //
            // Save this ADC reading as the maximum.
            //
            g_pusPhaseMax[ulIdx] = g_pusFilteredData[ulIdx];
        }
    }

    //
    // Save the current motor drive angle for the next set of samples.
    //
    g_ulPrevAngle = g_ulAngle;
}
示例#15
0
//*****************************************************************************
//
//! Updates the dynamic brake.
//!
//! This function will update the state of the dynamic brake.  It must be
//! called at the PWM frequency to provide a time base for determining when to
//! turn off the brake to avoid overheating.
//!
//! \return None.
//
//*****************************************************************************
void
BrakeTick(void)
{
    //
    // See if the bus voltage exceeds the voltage required to turn on the
    // dynamic brake.
    //
    if(g_ulBusVoltage >= g_sParameters.ulBrakeOnV)
    {
        //
        // The bus voltage is too high, so see if the brake is currently off.
        //
        if((g_ulBrakeState == STATE_BRAKE_OFF) &&
           (HWREGBITH(&(g_sParameters.usFlags), FLAG_BRAKE_BIT) ==
            FLAG_BRAKE_ON))
        {
            //
            // Turn on the dynamic brake.
            //
            GPIOPinWrite(PIN_BRAKE_PORT, PIN_BRAKE_PIN, 0);

            //
            // Change the brake state to on.
            //
            g_ulBrakeState = STATE_BRAKE_ON;
        }
    }

    //
    // Otherwise, see if the dynamic brake is on and the bus voltage is less
    // than the voltage required to turn it off.
    //
    else if((g_ulBusVoltage < g_sParameters.ulBrakeOffV) &&
            (g_ulBrakeState == STATE_BRAKE_ON))
    {
        //
        // Turn off the dynamic brake.
        //
        GPIOPinWrite(PIN_BRAKE_PORT, PIN_BRAKE_PIN, PIN_BRAKE_PIN);

        //
        // Change the brake state to off.
        //
        g_ulBrakeState = STATE_BRAKE_OFF;
    }

    //
    // See if the dynamic brake is on.
    //
    if(g_ulBrakeState == STATE_BRAKE_ON)
    {
        //
        // Increment the number of brake ticks that the dynamic brake has been
        // on.
        //
        g_ulBrakeCount++;

        //
        // See if the dynamic brake has been on for too long.
        //
        if(g_ulBrakeCount == g_sParameters.ulBrakeMax)
        {
            //
            // Turn off the dynamic brake.
            //
            GPIOPinWrite(PIN_BRAKE_PORT, PIN_BRAKE_PIN, PIN_BRAKE_PIN);

            //
            // Change the brake state to cool to allow the braking resistor to
            // cool off (to avoid overheating).
            //
            g_ulBrakeState = STATE_BRAKE_COOL;
        }
    }

    //
    // Otherwise, see if the dynamic brake tick count is non-zero.
    //
    else if(g_ulBrakeCount != 0)
    {
        //
        // Decrement the number of brake ticks that the dynamic brake has been
        // off.
        //
        g_ulBrakeCount--;

        //
        // See if the dynamic brake is in the cooling state and has cooled off
        // for long enough.
        //
        if((g_ulBrakeState == STATE_BRAKE_COOL) &&
           (g_ulBrakeCount == g_sParameters.ulBrakeCool))
        {
            //
            // The dynamic brake has cooled off enough, so see if the bus
            // voltage exceeds the voltage required to turn it on.
            //
            if(g_ulBusVoltage >= g_sParameters.ulBrakeOnV)
            {
                //
                // Turn on the dynamic brake.
                //
                GPIOPinWrite(PIN_BRAKE_PORT, PIN_BRAKE_PIN, 0);

                //
                // Change the brake state to on.
                //
                g_ulBrakeState = STATE_BRAKE_ON;
            }

            //
            // Otherwise, the voltage is low enough that the brake should
            // remain off.
            //
            else
            {
                //
                // Change the brake state to off.
                //
                g_ulBrakeState = STATE_BRAKE_OFF;
            }
        }
    }
}
//*****************************************************************************
//
//! Updates the duty cycle in the PWM module.
//!
//! This function programs the duty cycle of the PWM waveforms into the PWM
//! module.  The changes will be written to the hardware and the hardware
//! instructed to start using the new values the next time its counters reach
//! zero.
//!
//! \return None.
//
//*****************************************************************************
static void
PWMUpdateDutyCycle(void)
{
    unsigned long ulWidthA, ulWidthB, ulWidthC;

    //
    // Get the pulse width of the A phase of the motor.
    //
    ulWidthA = (g_ulPWMDutyCycleA * g_ulPWMClock) / 65536;
    if(ulWidthA > g_ulPWMClock)
    {
        ulWidthA = g_ulPWMClock;
    }
    if(ulWidthA < g_ulMinPulseWidth)
    {
        ulWidthA = g_ulMinPulseWidth;
    }
    if((g_ulPWMClock - ulWidthA) < g_ulMinPulseWidth)
    {
        ulWidthA = g_ulPWMClock - g_ulMinPulseWidth;
    }

    //
    // Get the pulse width of the B phase of the motor.
    //
    ulWidthB = (g_ulPWMDutyCycleB * g_ulPWMClock) / 65536;
    if(ulWidthB > g_ulPWMClock)
    {
        ulWidthB = g_ulPWMClock;
    }
    if(ulWidthB < g_ulMinPulseWidth)
    {
        ulWidthB = g_ulMinPulseWidth;
    }
    if((g_ulPWMClock - ulWidthB) < g_ulMinPulseWidth)
    {
        ulWidthB = g_ulPWMClock - g_ulMinPulseWidth;
    }

    //
    // Get the pulse width of the C phase of the motor.
    //
    ulWidthC = (g_ulPWMDutyCycleC * g_ulPWMClock) / 65536;
    if(ulWidthC > g_ulPWMClock)
    {
        ulWidthC = g_ulPWMClock;
    }
    if(ulWidthC < g_ulMinPulseWidth)
    {
        ulWidthC = g_ulMinPulseWidth;
    }
    if((g_ulPWMClock - ulWidthC) < g_ulMinPulseWidth)
    {
        ulWidthC = g_ulPWMClock - g_ulMinPulseWidth;
    }

    //
    // Update global parameters (for Trapezoid, A=B=C, for Sinusoid, don't
    // matter).
    //
    g_ulPWMWidth = (ulWidthA + ulWidthB + ulWidthC) / 3;
    g_ulTrapDutyCycle = (g_ulPWMWidth * 10000) / g_ulPWMClock;

    //
    // Set A, B, and C PWM output duty cycles (all generator outputs).
    //
    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0, ulWidthA);
    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_1, ulWidthA);
    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_2, ulWidthB);
    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_3, ulWidthB);
    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_4, ulWidthC);
    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_5, ulWidthC);

    //
    // If trapezoid (not sine), and slow decay, set the odd PWM at near
    // 100% duty cycle.
    //
    if((g_sParameters.ucModulationType != MOD_TYPE_SINE) &&
       (HWREGBITH(&(g_sParameters.usFlags), FLAG_DECAY_BIT) ==
            FLAG_DECAY_SLOW))
    {
        PWMPulseWidthSet(PWM0_BASE, PWM_OUT_1,
                         (g_ulPWMClock - g_sParameters.ucDeadTime));
        PWMPulseWidthSet(PWM0_BASE, PWM_OUT_3,
                         (g_ulPWMClock - g_sParameters.ucDeadTime));
        PWMPulseWidthSet(PWM0_BASE, PWM_OUT_5,
                         (g_ulPWMClock - g_sParameters.ucDeadTime));
    }

    //
    // Perform a synchronous update of all three PWM generators.
    //
    PWMSyncUpdate(PWM0_BASE, PWM_GEN_0_BIT | PWM_GEN_1_BIT | PWM_GEN_2_BIT);

    //
    // And we're done for now.
    //
    return;
}