📄 pwm_ctrl.c
字号:
//
// Done with this PWM frequency.
//
break;
}
//
// The PWM frequency is 16 KHz.
//
case FLAG_PWM_FREQUENCY_16K:
{
//
// Set the PWM frequency variable.
//
g_ulPWMFrequency = 16000;
//
// Get the number of PWM clocks in a 16 KHz period.
//
g_ulPWMClock = PWM_CLOCK / 16000;
//
// Done with this PWM frequency.
//
break;
}
//
// The PWM frequency is 20 KHz.
//
case FLAG_PWM_FREQUENCY_20K:
default:
{
//
// Set the PWM frequency variable.
//
g_ulPWMFrequency = 20000;
//
// Get the number of PWM clocks in a 20 KHz period.
//
g_ulPWMClock = PWM_CLOCK / 20000;
//
// Done with this PWM frequency.
//
break;
}
}
//
// Indicate that the PWM frequency needs to be updated.
//
HWREGBITW(&g_ulPWMFlags, PWM_FLAG_NEW_FREQUENCY) = 1;
//
// Re-enable the PWM interrupt.
//
IntEnable(INT_PWM0);
}
//*****************************************************************************
//
//! 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 ulWidth;
//
// Get the pulse width of the A phase of the motor.
//
ulWidth = (g_ulPWMDutyCycleA * g_ulPWMClock) / 65536;
if(ulWidth > g_ulPWMClock)
{
ulWidth = g_ulPWMClock;
}
if(ulWidth < g_ulMinPulseWidth)
{
ulWidth = g_ulMinPulseWidth;
}
if((g_ulPWMClock - ulWidth) < g_ulMinPulseWidth)
{
ulWidth = g_ulPWMClock - g_ulMinPulseWidth;
}
//
// Set the pulse width of the A phase of the motor.
//
PWMPulseWidthSet(PWM_BASE, PWM_OUT_0, ulWidth);
//
// Update duty cycle for trapezoid current calculation.
//
g_ulTrapDutyCycle = (ulWidth * 100) / g_ulPWMClock;
//
// Get the pulse width of the B phase of the motor.
//
ulWidth = (g_ulPWMDutyCycleB * g_ulPWMClock) / 65536;
if(ulWidth > g_ulPWMClock)
{
ulWidth = g_ulPWMClock;
}
if(ulWidth < g_ulMinPulseWidth)
{
ulWidth = g_ulMinPulseWidth;
}
if((g_ulPWMClock - ulWidth) < g_ulMinPulseWidth)
{
ulWidth = g_ulPWMClock - g_ulMinPulseWidth;
}
//
// Set the pulse width of the B phase of the motor.
//
PWMPulseWidthSet(PWM_BASE, PWM_OUT_2, ulWidth);
//
// Get the pulse width of the C phase of the motor.
//
ulWidth = (g_ulPWMDutyCycleC * g_ulPWMClock) / 65536;
if(ulWidth > g_ulPWMClock)
{
ulWidth = g_ulPWMClock;
}
if(ulWidth < g_ulMinPulseWidth)
{
ulWidth = g_ulMinPulseWidth;
}
if((g_ulPWMClock - ulWidth) < g_ulMinPulseWidth)
{
ulWidth = g_ulPWMClock - g_ulMinPulseWidth;
}
//
// Set the pulse width of the C phase of the motor.
//
PWMPulseWidthSet(PWM_BASE, PWM_OUT_4, ulWidth);
//
// Perform a synchronous update of all three PWM generators.
//
PWMSyncUpdate(PWM_BASE, PWM_GEN_0_BIT | PWM_GEN_1_BIT | PWM_GEN_2_BIT);
}
//*****************************************************************************
//
//! Handles the PWM interrupt.
//!
//! This function is called as a result of the interrupt generated by the PWM
//! module when the counter reaches zero. If an updated PWM frequency or duty
//! cycle is available, they will be updated in the hardware by this function.
//!
//! \return None.
//
//*****************************************************************************
void
PWM0IntHandler(void)
{
//
// Clear the PWM interrupt. This is done twice since the clear will be
// ignored by hardware if it occurs on the same cycle as another interrupt
// event; the second clear takes care of the case wehre the first gets
// ignored.
//
PWMGenIntClear(PWM_BASE, PWM_GEN_0, PWM_INT_CNT_ZERO);
PWMGenIntClear(PWM_BASE, PWM_GEN_0, PWM_INT_CNT_ZERO);
//
// Increment the count of PWM periods.
//
g_ulPWMPeriodCount++;
//
// See if it is time for a new PWM duty cycle, based on the correct number
// of PWM periods passing and the availability of new duty cycle values.
//
if((g_ulPWMPeriodCount > g_sParameters.ucUpdateRate) &&
(HWREGBITW(&g_ulPWMFlags, PWM_FLAG_NEW_DUTY_CYCLE) == 1))
{
//
// See if the PWM frequency needs to be updated.
//
if(HWREGBITW(&g_ulPWMFlags, PWM_FLAG_NEW_FREQUENCY) == 1)
{
//
// Set the new PWM period in each of the PWM generators.
//
PWMGenPeriodSet(PWM_BASE, PWM_GEN_0, g_ulPWMClock);
PWMGenPeriodSet(PWM_BASE, PWM_GEN_1, g_ulPWMClock);
PWMGenPeriodSet(PWM_BASE, PWM_GEN_2, g_ulPWMClock);
//
// Indicate that the PWM frequency has been updated.
//
HWREGBITW(&g_ulPWMFlags, PWM_FLAG_NEW_FREQUENCY) = 0;
}
//
// Update the duty cycle.
//
PWMUpdateDutyCycle();
//
// Clear the duty cycle update flag.
//
HWREGBITW(&g_ulPWMFlags, PWM_FLAG_NEW_DUTY_CYCLE) = 0;
}
//
// Start a precharge cycle.
//
if(HWREGBITW(&g_ulPWMFlags, PWM_FLAG_NEW_PRECHARGE) == 1)
{
//
// Enable the low side switches.
//
PWMOutputState(PWM_BASE, PWM_OUT_1_BIT | PWM_OUT_3_BIT | PWM_OUT_5_BIT,
true);
//
// Clear the flag.
//
HWREGBITW(&g_ulPWMFlags, PWM_FLAG_NEW_PRECHARGE) = 0;
}
//
// If the required number of PWM periods have expired, request an update of
// the duty cycle computations.
//
if(g_ulPWMPeriodCount >= (g_sParameters.ucUpdateRate + 1))
{
//
// Trigger the waveform update software interrupt.
//
HWREG(NVIC_SW_TRIG) = INT_PWM1 - 16;
}
//
// Increment the millisecond counter. By adding 1000 for each PWM
// interrupt, it will take one millisecond for the counter to reach the PWM
// frequency.
//
g_ulPWMMillisecondCount += 1000;
//
// See if a millisecond has expired.
//
if(g_ulPWMMillisecondCount >= g_ulPWMFrequency)
{
//
// Trigger the millisecond software interrupt.
//
HWREG(NVIC_SW_TRIG) = INT_PWM2 - 16;
//
// Decrement the millisecond counter by the PWM frequency, which
// corresponds to one millisecond.
//
g_ulPWMMillisecondCount -= g_ulPWMFrequency;
}
}
//*****************************************************************************
//
//! Gets the number of PWM interrupts that have occurred.
//!
//! This function returns the number of PWM interrupts that have been counted.
//! Used in conjunction with the desired update rate, missed waveform updates
//! can be detected and compensated for.
//!
//! \return The number of PWM interrupts that have been counted.
//
//*****************************************************************************
unsigned long
PWMGetPeriodCount(void)
{
//
// Return the count of PWM periods.
//
return(g_ulPWMPeriodCount);
}
//*****************************************************************************
//
//! Reduces the count of PWM interrupts.
//!
//! \param ulCount is the number by which to reduce the PWM interrupt count.
//!
//! This function reduces the PWM interrupt count by a given number. When the
//! waveform values are updated, the interrupt count can be reduced by the
//! appropriate amount to maintain a proper indication of when the next
//! waveform update should occur.
//!
//! If the PWM interrupt count is not reduced when the waveforms are
//! recomputed, the waveform update software interrupt will not be triggered as
//! desired.
//!
//! \return None.
//
//*****************************************************************************
void
PWMReducePeriodCount(unsigned long ulCount)
{
//
// Disable the PWM interrupt temporarily.
//
IntDisable(INT_PWM0);
//
// Decrement the PWM period count by the given number.
//
g_ulPWMPeriodCount -= ulCount;
//
// Re-enable the PWM interrupt.
//
IntEnable(INT_PWM0);
}
//*****************************************************************************
//
//! Sets the duty cycle of the generated PWM waveforms.
//!
//! \param ulDutyCycleA is the duty cycle of the waveform for the U phase of
//! the motor, specified as a 16.16 fixed point value between 0.0 and 1.0.
//! \param ulDutyCycleB is the duty cycle of the waveform for the V phase of
//! the motor, specified as a 16.16 fixed point value between 0.0 and 1.0.
//! \param ulDutyCycleC is the duty cycle of the waveform for the W phase of
//! the motor, specified as a 16.16 fixed point value between 0.0 and 1.0.
//!
//! This function configures the duty cycle of the generated PWM waveforms.
//! The duty cycle update will not occur immediately; the change will be
//! registered for synchronous application to the output waveforms to avoid
//! discontinuities.
//!
//! \return None.
//
//*****************************************************************************
void
PWMSetDutyCycle(unsigned long ulDutyCycleA, unsigned long ulDutyCycleB,
unsigned long ulDutyCycleC)
{
//
// Punch the watchdog to make sure we don't get reset.
// (only if we are SINE modulation mode)
//
if(HWREGBITH(&(g_sParameters.usFlags), FLAG_DRIVE_BIT) == FLAG_DRIVE_SINE)
{
WatchdogReloadSet(WATCHDOG_BASE, WATCHDOG_RELOAD_VALUE);
}
//
// Disable the PWM interrupt temporarily.
//
IntDisable(INT_PWM0);
//
// Save the duty cycles for the three phases.
//
g_ulPWMDutyCycleA = ulDutyCycleA;
g_ulPWMDutyCycleB = ulDutyCycleB;
g_ulPWMDutyCycleC = ulDutyCycleC;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -