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

📄 pwm_ctrl.c

📁 Luminary Micro BLDC motor control software
💻 C
📖 第 1 页 / 共 3 页
字号:
//*****************************************************************************
//
// pwm_ctrl.c - PWM control routines.
//
// Copyright (c) 2007-2008 Luminary Micro, Inc.  All rights reserved.
// 
// Software License Agreement
// 
// Luminary Micro, Inc. (LMI) is supplying this software for use solely and
// exclusively on LMI's microcontroller products.
// 
// The software is owned by LMI and/or its suppliers, and is protected under
// applicable copyright laws.  All rights are reserved.  You may not combine
// this software with "viral" open-source software in order to form a larger
// program.  Any use in violation of the foregoing restrictions may subject
// the user to criminal sanctions under applicable laws, as well as to civil
// liability for the breach of the terms and conditions of this license.
// 
// THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
// OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
// LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
// CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
// 
// This is part of revision 716 of the BLDC motor application.
//
//*****************************************************************************

#include "../../DriverLib/hw_ints.h"
#include "../../DriverLib/hw_memmap.h"
#include "../../DriverLib/hw_nvic.h"
#include "../../DriverLib/hw_pwm.h"
#include "../../DriverLib/hw_types.h"
#include "../../DriverLib/src/gpio.h"
#include "../../DriverLib/src/interrupt.h"
#include "../../DriverLib/src/pwm.h"
#include "../../DriverLib/src/sysctl.h"
#include "../../DriverLib/src/watchdog.h"
#include "faults.h"
#include "main.h"
#include "pins.h"
#include "pwm_ctrl.h"
#include "ui.h"

//*****************************************************************************
//
//! \page pwm_ctrl_intro Introduction
//!
//! The generated motor drive waveforms are driven to the inverter bridge with
//! the PWM module.  The PWM generators are run in a fully synchronous manner;
//! the counters are synchronized (that is, the values of the three counters
//! are always the same) and updates to the duty cycle registers are
//! synchronized to the zero value of the PWM counters.
//!
//! The dead-band unit in each PWM generator is used to prevent shoot-through
//! current in the inverter bridge when switching between the high side to the
//! low of a phase.  Shoot-through occurs because the turn-on time of one gate
//! doesn't always match the turn-off time of the other, so both may be on for
//! a short period despite the fact that only one of their inputs is on.  By
//! providing a period of time where both inputs are off when making the
//! transition, shoot-through is not possible.
//!
//! The PWM outputs can be in one of four modes during the operation of the
//! motor drive.  The first is off, where all six outputs are in the inactive
//! state.  This is the state used when the motor drive is stopped; the motor
//! is electrically disconnected during this time (effectively the same as
//! disconnecting the cable) and is free to spin as if it were unplugged.
//!
//! The next mode is precharge, where the three outputs to the high
//! side switches are inactive and the three outputs to the low side switches
//! are switches at a 50% duty cycle.  The high side gate drivers have a
//! bootstrap circuit for generating the voltage to drive the gates that only
//! charges when the low side is switching; this precharge mode allows the
//! bootstrap circuit to generate the required gate drive voltage before real
//! waveforms are driven.  Failure to precharge the high side gate drivers
//! would simply result in distortion of the first part of the output waveform
//! (until the bootstrap circuit generates a voltage high enough to turn on the
//! high side gate).  This mode is used briefly when going from a non-driving
//! state to a driving state.
//!
//! The next mode is running, where all six outputs are actively toggling.
//! This will create a magnetic field in the stator of the motor, inducing a
//! magnetic field in the rotor and causing it to spin.  This mode is used to
//! drive the motor.
//!
//! The final mode is DC injection braking, where the first PWM pair are
//! actively toggling, the low side of the second PWM pair is always on, and
//! the third PWM pair is inactive.  This results in a fixed DC voltage being
//! applied across the motor, resulting in braking.  This mode is optionally
//! used briefly when going from a driving state to a non-driving state in
//! order to completely stop the rotation of the rotor.  For loads with high
//! inertia, or low friction rotors, this can reduce the rotor stop time from
//! minutes to seconds.  This mode should only be used for as long as required
//! to stop the rotor and no longer.
//!
//! The PWM outputs are configured to immediately switch to the inactive state
//! when the processor is stopped by a debugger.  This prevents the current
//! PWM state from becoming a DC voltage (since the processor is no longer
//! running to change the duty cycles) and damaging the motor.  In general,
//! though, it is not a good idea to stop the processor when the motor is
//! running.  When no longer driven, the motor will start to slow down due to
//! friction; when the processor is restarted, it will continue driving at the
//! previous drive frequency.  The difference between rotor and target
//! speed has become much greater due to the time that the motor was not being
//! driven.  This will likely result in an immediate motor over-current fault
//! since the increased slip will result in a rise in motor current.  While not
//! harmful, it does not allow the typically desired behavior of being able to
//! stop the application, look at the internal state, then restart the
//! application as if nothing had happened.
//!
//! An interrupt is generated at each zero value of the counter in PWM
//! generator zero; this is used as a time base for the generation of waveforms
//! as well as a time to queue the next duty cycle update into the hardware.
//! At any given time, the PWM module is outputting the duty cycle for period
//! N, has the duty cycle for period N+1 queued in its holding registers
//! waiting for the next zero value of the counter, and the microcontroller is
//! computing the duty cycle for period N+2.
//!
//! Two ``software'' interrupts are generated by the PWM interrupt handler.
//! One is used to update the waveform; this occurs at a configurable rate of
//! every X PWM period.  The other is used to update the drive frequency and
//! perform other periodic system tasks such as fault monitoring; this occurs
//! every millisecond.  The unused interrupts from the second and third PWM
//! generator are used for these ``software'' interrupts; the ability to fake
//! the assertion of an interrupt through the NVIC software interrupt trigger
//! register is used to generate these ``software'' interrupts.
//!
//! The code for handling the PWM module is contained in <tt>pwm_ctrl.c</tt>,
//! with <tt>pwm_ctrl.h</tt> containing the definitions for the variables and
//! functions exported to the remainder of the application.
//
//*****************************************************************************

//*****************************************************************************
//
//! \defgroup pwm_ctrl_api Definitions
//! @{
//
//*****************************************************************************

//*****************************************************************************
//
//! The frequency of the clock that drives the PWM generators.
//
//*****************************************************************************
#define PWM_CLOCK               50000000

//*****************************************************************************
//
//! The width of a single PWM clock, in nanoseconds.
//
//*****************************************************************************
#define PWM_CLOCK_WIDTH         20

//*****************************************************************************
//
//! The number of PWM clocks in a single PWM period.
//
//*****************************************************************************
static unsigned long g_ulPWMClock;

//*****************************************************************************
//
//! The frequency of the output PWM waveforms.
//
//*****************************************************************************
unsigned long g_ulPWMFrequency;

//*****************************************************************************
//
//! The duty cycle of the waveform output to the A phase of the bridge.
//
//*****************************************************************************
static unsigned long g_ulPWMDutyCycleA;

//*****************************************************************************
//
//! The duty cycle of the waveform output to the B phase of the bridge.
//
//*****************************************************************************
static unsigned long g_ulPWMDutyCycleB;

//*****************************************************************************
//
//! The duty cycle of the waveform output to the C phase of the bridge.
//
//*****************************************************************************
static unsigned long g_ulPWMDutyCycleC;

//*****************************************************************************
//
//! The minimum width of an output PWM pulse, in PWM clocks.
//
//*****************************************************************************
static unsigned long g_ulMinPulseWidth;

//*****************************************************************************
//
//! A set of flags that control the operation of the PWM control routines.  The
//! flags are #PWM_FLAG_NEW_FREQUENCY, and #PWM_FLAG_NEW_DUTY_CYCLE.
//
//*****************************************************************************
static unsigned long g_ulPWMFlags = 0;

//*****************************************************************************
//
//! The bit number of the flag in #g_ulPWMFlags that indicates that a new
//! PWM frequency (that is, period) is ready to be supplied to the PWM module.
//
//*****************************************************************************
#define PWM_FLAG_NEW_FREQUENCY  0

//*****************************************************************************
//
//! The bit number of the flag in #g_ulPWMFlags that indicates that a new duty
//! cycle (that is, compare) is ready to be supplied to the PWM module.
//
//*****************************************************************************
#define PWM_FLAG_NEW_DUTY_CYCLE 1

//*****************************************************************************
//
//! The bit number of the flag in #g_ulPWMFlags that indicates that a Pre-
//! charge process has been started.
//
//*****************************************************************************
#define PWM_FLAG_NEW_PRECHARGE  2

//*****************************************************************************
//
//! A count of the number of PWM periods have occurred, based on the number of
//! PWM module interrupts.  This is incremented when a PWM interrupt is handled
//! and decremented by the waveform generation handler.
//
//*****************************************************************************
static unsigned long g_ulPWMPeriodCount;

//*****************************************************************************
//
//! A counter that is used to determine when a millisecond has passed.  The
//! millisecond software interrupt is triggered based on this count.
//
//*****************************************************************************
static unsigned long g_ulPWMMillisecondCount;

//*****************************************************************************
//
//! The duty cycle (0 to 100) used for trapezoid current calculations.
//
//*****************************************************************************
unsigned long g_ulTrapDutyCycle = 0;


//*****************************************************************************
//
//! Computes the minimum PWM pulse width.
//!
//! This function computes the minimum PWM pulse width based on the minimum
//! pulse width parameter and the dead time parameter.  The dead timers will
//! reduce the width of a PWM pulse, so their value must be considered to avoid
//! pulses shorter than the parameter value being produced.
//!
//! \return None.
//
//*****************************************************************************
void
PWMSetMinPulseWidth(void)
{
    //
    // Compute the minimum pulse width in PWM clocks.
    //
    g_ulMinPulseWidth = ((((g_sParameters.ucDeadTime + 1) * 20) +
                          (g_sParameters.ucMinPulseWidth * 100) +
                          (PWM_CLOCK_WIDTH - 1)) / PWM_CLOCK_WIDTH);

    //
    // If the minimum pulse width parameter is zero, then increment the minimum
    // pulse width (that is, the dead time) by one to avoid sending pulses into
    // the dead band unit that are too short.
    //
    if(g_sParameters.ucMinPulseWidth == 0)
    {
        g_ulMinPulseWidth++;
    }
}

//*****************************************************************************
//
//! Configures the dead timers for the PWM generators.
//!
//! This function configures the dead timers for all three PWM generators based
//! on the dead time parameter.
//!
//! \return None.
//
//*****************************************************************************
void
PWMSetDeadBand(void)
{
    //
    // Set the dead band times for all three PWM generators.
    //
    PWMDeadBandEnable(PWM_BASE, PWM_GEN_0, g_sParameters.ucDeadTime,
                      g_sParameters.ucDeadTime);
    PWMDeadBandEnable(PWM_BASE, PWM_GEN_1, g_sParameters.ucDeadTime,
                      g_sParameters.ucDeadTime);
    PWMDeadBandEnable(PWM_BASE, PWM_GEN_2, g_sParameters.ucDeadTime,
                      g_sParameters.ucDeadTime);

    //
    // Update the minimum PWM pulse width.
    //
    PWMSetMinPulseWidth();
}

//*****************************************************************************
//
//! Sets the frequency of the generated PWM waveforms.
//!
//! This function configures the frequency of the generated PWM waveforms.  The
//! frequency update will not occur immediately; the change will be registered
//! for synchronous application to the output waveforms to avoid
//! discontinuities.
//!
//! \return None.
//
//*****************************************************************************
void
PWMSetFrequency(void)
{
    //
    // Disable the PWM interrupt temporarily.
    //
    IntDisable(INT_PWM0);

    //
    // Determine the configured PWM frequency.
    //
    switch(g_sParameters.usFlags & FLAG_PWM_FREQUENCY_MASK)
    {
        //
        // The PWM frequency is 8 KHz.
        //
        case FLAG_PWM_FREQUENCY_8K:
        {
            //
            // Set the PWM frequency variable.
            //
            g_ulPWMFrequency = 8000;

            //
            // Get the number of PWM clocks in a 8 KHz period.
            //
            g_ulPWMClock = PWM_CLOCK / 8000;

            //
            // Done with this PWM frequency.
            //
            break;
        }

        //
        // The PWM frequency is 12.5 KHz.
        //
        case FLAG_PWM_FREQUENCY_12K:
        {
            //
            // Set the PWM frequency variable.
            //
            g_ulPWMFrequency = 12500;

            //
            // Get the number of PWM clocks in a 12.5 KHz period.
            //
            g_ulPWMClock = PWM_CLOCK / 12500;

⌨️ 快捷键说明

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