📄 adc_ctrl.c
字号:
//*****************************************************************************
//
// adc_ctrl.c - ADC 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_memmap.h"
#include "../../DriverLib/hw_types.h"
#include "../../DriverLib/hw_adc.h"
#include "../../DriverLib/hw_ints.h"
#include "../../DriverLib/hw_pwm.h"
#include "../../DriverLib/src/adc.h"
#include "../../DriverLib/src/interrupt.h"
#include "../../DriverLib/src/sysctl.h"
#include "../../DriverLib/src/timer.h"
#include "adc_ctrl.h"
#include "main.h"
#include "pins.h"
#include "ui.h"
#include "pwm_ctrl.h"
//*****************************************************************************
//
//! \page adc_ctrl_intro Introduction
//!
//! Depending on the mode of operation, the ADC is used to monitor the motor
//! phase current, motor phase back EMF voltage, linear hall sensor voltage,
//! DC bus voltage, analog input voltage, and ambient temperature of the
//! microcontroller. Each of these values is sampled every PWM period based
//! on a trigger from the PWM module. Multiple ADC sequences are used to
//! allow optimization of CPU usage.
//!
//! Readings from the ADC may be passed through a single-pole IIR low pass
//! filter. This helps to reduce the effects of high frequency noise (such as
//! switching noise) on the sampled data. A coefficient of 0.75 is used to
//! simplify the integer math (requiring only a multiplication by 3, an
//! addition, and a division by four).
//!
//! The individual motor phase RMS currents, motor RMS current, DC bus voltage,
//! and ambient temperature are used outside this module.
//!
//! The code for handling the ADC is contained in <tt>adc_ctrl.c</tt>, with
//! <tt>adc_ctrl.h</tt> containing the definitions for the variables and
//! functions exported to the remainder of the application.
//
//*****************************************************************************
//*****************************************************************************
//
//! \defgroup adc_ctrl_api Definitions
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
//! The bit number of the flag in #g_ulADCFlags that indicates that the
//! next edge should be ignored by the Back EMF speed calculation code. This
//! is used at startup since there is no previous edge time to be used to
//! calculate the time between edges.
//
//*****************************************************************************
#define FLAG_SKIP_BIT 0
//*****************************************************************************
//
//! The bit number of the flag in #g_ulADCFlags that indicates that an edge
//! has been seen (in the speed processing code). This will prevent the
//! #ADCTickHandler from resetting the rotor speed.
//
//*****************************************************************************
#define FLAG_EDGE_BIT 1
//*****************************************************************************
//
//! The bit number of the flag in #g_ulADCFlags that indicates that the
//! next edge should be ignored by the Linear Hall speed calculation code.
//! This is used at startup since there is no previous edge time to be used to
//! calculate the time between edges.
//
//*****************************************************************************
#define FLAG_SKIP_LINEAR_BIT 2
//*****************************************************************************
//
//! A set of flags that provide status and control of the ADC Control
//! module.
//
//*****************************************************************************
static unsigned long g_ulADCFlags =
((1 << FLAG_SKIP_BIT) |
(1 << FLAG_SKIP_LINEAR_BIT));
//*****************************************************************************
//
//! Arrays containing the raw low pass filtered ADC readings. These are
//! maintained in a raw form since they are required as an input to the next
//! iteration of the IIR low pass filter. There is at most one array for each
//! ADC sequence in use.
//
//*****************************************************************************
static unsigned short g_pusFilteredData0[3];
static unsigned short g_pusFilteredData1[3];
//*****************************************************************************
//
//! The current passing through the three phases of the motor, specified in
//! milliamperes as a signed value.
//
//*****************************************************************************
short g_psPhaseCurrent[3];
//*****************************************************************************
//
//! An array containing the maximum phase currents seen during the last half
//! cycle of each phase. This is used to perform a peak detect on the phase
//! currents.
//
//*****************************************************************************
static unsigned short g_pusPhaseMax[3];
//*****************************************************************************
//
//! The index for the phase current being processed in the ADC sequence
//! handler.
//
//*****************************************************************************
static unsigned char g_ucPhaseCurrentIndex = 0;
//*****************************************************************************
//
//! The total current passing through the motor, specified in milliamperes as
//! a signed value.
//
//*****************************************************************************
short g_sMotorCurrent;
//*****************************************************************************
//
//! The DC bus voltage, specified in millivolts.
//
//*****************************************************************************
unsigned long g_ulBusVoltage;
//*****************************************************************************
//
//! The state of the Back EMF processing state machine.
//
//*****************************************************************************
static unsigned char g_ucBEMFState = 0;
//*****************************************************************************
//
//! A flag to indicate whether the Back EMF trigger point has been found.
//
//*****************************************************************************
static tBoolean g_bBEMFEdge = false;
//*****************************************************************************
//
//! The time at which the last Back EMF speed edge occurred.
//
//*****************************************************************************
static unsigned long g_ulBEMFSpeedPrevious = 0;
//*****************************************************************************
//
//! The time at which the last Back EMF edge occurred.
//
//*****************************************************************************
static unsigned long g_ulBEMFEdgePrevious = 0;
//*****************************************************************************
//
//! The rotor speed as measured by the BEMF processing code.
//
//*****************************************************************************
unsigned long g_ulBEMFRotorSpeed = 0;
//*****************************************************************************
//
//! The next Back EMF Hall state value.
//
//*****************************************************************************
static unsigned long g_ulBEMFNextHall = 0;
//*****************************************************************************
//
//! The Hall state value as determined by the Back EMF processing code.
//
//*****************************************************************************
unsigned long g_ulBEMFHallValue = 0;
//*****************************************************************************
//
//! The Analog Input voltage, specified in millivolts.
//
//*****************************************************************************
unsigned short g_usAnalogInputVoltage;
//*****************************************************************************
//
//! The ambient case temperature of the microcontroller, specified in degrees
//! Celsius.
//
//*****************************************************************************
unsigned char g_ucAmbientTemp;
//*****************************************************************************
//
//! The Linear Hall Sensor ADC values (scaled).
//
//*****************************************************************************
static unsigned short g_pusLinearHallSensor[3];
//*****************************************************************************
//
//! The Linear Hall Sensor ADC Maximum Value.
//
//*****************************************************************************
static unsigned short g_pusLinearHallMax[3] = {1023, 1023, 1023};
//*****************************************************************************
//
//! The Linear Hall Sensor ADC Minimum Value.
//
//*****************************************************************************
static unsigned short g_pusLinearHallMin[3] = {0, 0, 0};
//*****************************************************************************
//
//! The Hall state value as determined by the linear Hall sensor processing
//! code.
//
//*****************************************************************************
unsigned long g_ulLinearHallValue = 0;
//*****************************************************************************
//
//! The time at which the last linear Hall sensor speed edge occurred.
//
//*****************************************************************************
static unsigned long g_ulLinearSpeedPrevious = 0;
//*****************************************************************************
//
//! The rotor speed as measured by the linear Hall sensor processing code.
//
//*****************************************************************************
unsigned long g_ulLinearRotorSpeed = 0;
//*****************************************************************************
//
//! The previous Hall state value as determined by the linear Hall sensor
//! processing code.
//
//*****************************************************************************
static unsigned long g_ulLinearLastHall = 0;
//*****************************************************************************
//
//! The angle of the motor drive on the previous ADC interrupt.
//
//*****************************************************************************
static unsigned long g_ulPrevAngle;
//*****************************************************************************
//
//! Handles the Back EMF Timer Interrupt.
//!
//! This function is called when the Back EMF timer expires. This code will
//! set the Back EMF Hall state value to the next value, as determined by
//! the Back EMF processing code. The actual commutation of the motor takes
//! place in the main module.
//!
//! \return None.
//
//*****************************************************************************
void
Timer0AIntHandler(void)
{
//
// Clear the Timer interrupt.
//
TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
//
// Set the new Hall Sensor value.
//
g_ulBEMFHallValue = g_ulBEMFNextHall;
}
//*****************************************************************************
//
//! Handles the ADC sample sequence zero interrupt for trapezoid mode.
//!
//! This functions processes the ADC sequence zero for trapezoid mode. In
//! this handler, a single phase of current is processed from the sequence.
//! To account for noise, especially during short PWM duty cycles, five
//! readings are taken, the high and low values are discarded, and the
//! remaining three values are averaged. The reported motor current value
//! is averaged over the entire time the phase is active. When the PWM
//! drive changes, the sequence is reset and measurements are started for
//! the next phase.
//!
//! \return None.
//
//*****************************************************************************
static void
ADC0IntHandlerTrapezoid(void)
{
unsigned long ulIdx;
unsigned short pusADCData[6];
long lTemp = 0;
static unsigned char ucLastPhaseIndex = 4;
static unsigned long ulPhaseSum = 0;
static unsigned long ulPhaseCount = 0;
static unsigned long ulLastPWMEnable = 0;
unsigned long ulPWMEnable;
unsigned short usMin, usMax, usSum;
//
// Reset/Reconfigure the sequence if a change in PWM output drive
// state is detected.
//
ulPWMEnable = HWREG(PWM_BASE + PWM_O_INVERT);
if(ulPWMEnable != ulLastPWMEnable)
{
unsigned long ulIPhase;
//
// 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.
//
pusADCData[0] = 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;
//
// Save the PWM output state.
//
ulLastPWMEnable = ulPWMEnable;
//
// If the low side of Phase A is active, enable current readings
// on the Phase A ADC current input signal.
//
if(ulPWMEnable & 0x2)
{
ulIPhase = PIN_IPHASEA;
g_ucPhaseCurrentIndex = 0;
}
//
// If the low side of Phase B is active, enable current readings
// on the Phase B ADC current input signal.
//
else if(ulPWMEnable & 0x8)
{
ulIPhase = PIN_IPHASEB;
g_ucPhaseCurrentIndex = 1;
}
//
// Here, assume Phase C is active, enable current readings
// on the Phase C ADC current input signal.
//
else
{
ulIPhase = PIN_IPHASEC;
g_ucPhaseCurrentIndex = 2;
}
//
// Reprogram the sequence to read Back EMF voltage first (with the
// PWM Pulse Active) and 5 Phase current readings to follow.
//
ADCSequenceStepConfigure(ADC_BASE, 0, 0, ulIPhase);
ADCSequenceStepConfigure(ADC_BASE, 0, 1, ulIPhase);
ADCSequenceStepConfigure(ADC_BASE, 0, 2, ulIPhase);
ADCSequenceStepConfigure(ADC_BASE, 0, 3, ulIPhase);
ADCSequenceStepConfigure(ADC_BASE, 0, 4,
ADC_CTL_END | ADC_CTL_IE | ulIPhase);
//
// Enable the sequence and return.
//
HWREG(ADC_BASE + ADC_O_ACTSS) |= ADC_ACTSS_ASEN0;
return;
}
//
// Read the samples from the ADC FIFO.
//
ulIdx = 0;
while(!(HWREG(ADC_BASE + ADC_O_SSFSTAT0) & ADC_SSFSTAT0_EMPTY) &&
(ulIdx < 5))
{
//
// Read the next sample.
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -