//***************************************************************************** // // 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; }
//***************************************************************************** // // 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; }
//***************************************************************************** // // 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; } }
//***************************************************************************** // // 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; }
//***************************************************************************** // // 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; }
//***************************************************************************** // // 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; }
//***************************************************************************** // // 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; } } }
//***************************************************************************** // // 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)); }
//***************************************************************************** // //! 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)); }
//***************************************************************************** // // 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)); }
//***************************************************************************** // // 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)); } } }
//***************************************************************************** // // 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; }
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; } } }
//***************************************************************************** // //! 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; }
//***************************************************************************** // //! 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; }