Update repo
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
<projectSpec>
|
||||
<project
|
||||
name="eqep_ex1_freq_cal"
|
||||
device="TMS320F28377D"
|
||||
cgtVersion="22.6.0.LTS"
|
||||
products="C2000WARE"
|
||||
outputFormat="ELF"
|
||||
launchWizard="False"
|
||||
linkerCommandFile=""
|
||||
enableSysConfigTool="true"
|
||||
sysConfigBuildOptions="--product ${C2000WARE_ROOT}/.metadata/sdk.json --device F2837xD"
|
||||
>
|
||||
<configuration name="CPU1_RAM" compilerBuildOptions="--opt_level=off -I${PROJECT_ROOT}/device -I${C2000WARE_DLIB_ROOT} -I${C2000WARE_IQMATH_ROOT}/c28/include -v28 -ml -mt --define=DEBUG --cla_support=cla1 --float_support=fpu32 --tmu_support=tmu0 --vcu_support=vcu2 --define=CPU1 --diag_warning=225 --diag_suppress=10063 --display_error_number --diag_suppress=16002" linkerBuildOptions="--entry_point code_start --stack_size=0x100 " />
|
||||
<configuration name="CPU1_FLASH" compilerBuildOptions="--opt_level=off -I${PROJECT_ROOT}/device -I${C2000WARE_DLIB_ROOT} -I${C2000WARE_IQMATH_ROOT}/c28/include -v28 -ml -mt --define=DEBUG --cla_support=cla1 --float_support=fpu32 --tmu_support=tmu0 --vcu_support=vcu2 --define=CPU1 --define=_FLASH --diag_warning=225 --diag_suppress=10063 --display_error_number --diag_suppress=16002" linkerBuildOptions="--entry_point code_start --stack_size=0x100 " />
|
||||
<pathVariable name="C2000WARE_IQMATH_ROOT" path="../../../../../../libraries/math/IQmath/" scope="project" />
|
||||
<pathVariable name="C2000WARE_DLIB_ROOT" path="../../../../driverlib/" scope="project" />
|
||||
<pathVariable name="C2000WARE_ROOT" path="../../../../../../" scope="project" />
|
||||
<file action="copy" path="../../../../../../device_support/f2837xd/common/include/driverlib.h" targetDirectory="device" />
|
||||
<file action="copy" path="../../../../../../device_support/f2837xd/common/include/device.h" targetDirectory="device" />
|
||||
<file action="copy" path="../../../../../../device_support/f2837xd/common/source/device.c" targetDirectory="device" />
|
||||
<file action="copy" path="../../../../../../device_support/f2837xd/common/targetConfigs/TMS320F28377D.ccxml" targetDirectory="targetConfigs" />
|
||||
<file action="copy" path="../../../../../../device_support/f2837xd/common/cmd/2837xD_RAM_IQMATH_lnk_cpu1.cmd" targetDirectory="" applicableConfigurations="CPU1_RAM"/>
|
||||
<file action="copy" path="../../../../../../device_support/f2837xd/common/cmd/2837xD_FLASH_IQMATH_lnk_cpu1.cmd" targetDirectory="" applicableConfigurations="CPU1_FLASH"/>
|
||||
<file action="copy" path="../../../../../../device_support/f2837xd/common/source/F2837xD_CodeStartBranch.asm" targetDirectory="device" />
|
||||
<file action="link" path="../../../../driverlib/ccs/Debug/driverlib.lib" targetDirectory="" />
|
||||
<file action="copy" path="../../../../driverlib/" targetDirectory="device" excludeFromBuild="True"/>
|
||||
<file action="link" path="../../../../../../libraries/math/IQmath/c28/lib/IQmath_fpu32.lib" targetDirectory="" />
|
||||
<file action="copy" path="../eqep_ex1_calculation.c" targetDirectory="" />
|
||||
<file action="copy" path="../eqep_ex1_calculation.h" targetDirectory="" />
|
||||
<file action="copy" path="../eqep_ex1_freq_cal.c" targetDirectory="" />
|
||||
<file action="copy" path="../eqep_ex1_calculation.xls" targetDirectory="" />
|
||||
</project>
|
||||
</projectSpec>
|
||||
@@ -0,0 +1,33 @@
|
||||
<projectSpec>
|
||||
<project
|
||||
name="eqep_ex2_pos_speed"
|
||||
device="TMS320F28377D"
|
||||
cgtVersion="22.6.0.LTS"
|
||||
products="C2000WARE"
|
||||
outputFormat="ELF"
|
||||
launchWizard="False"
|
||||
linkerCommandFile=""
|
||||
enableSysConfigTool="true"
|
||||
sysConfigBuildOptions="--product ${C2000WARE_ROOT}/.metadata/sdk.json --device F2837xD"
|
||||
>
|
||||
<configuration name="CPU1_RAM" compilerBuildOptions="--opt_level=off -I${PROJECT_ROOT}/device -I${C2000WARE_DLIB_ROOT} -I${C2000WARE_IQMATH_ROOT}/c28/include -v28 -ml -mt --define=DEBUG --cla_support=cla1 --float_support=fpu32 --tmu_support=tmu0 --vcu_support=vcu2 --define=CPU1 --diag_warning=225 --diag_suppress=10063 --display_error_number --diag_suppress=16002" linkerBuildOptions="--entry_point code_start --stack_size=0x100 " />
|
||||
<configuration name="CPU1_FLASH" compilerBuildOptions="--opt_level=off -I${PROJECT_ROOT}/device -I${C2000WARE_DLIB_ROOT} -I${C2000WARE_IQMATH_ROOT}/c28/include -v28 -ml -mt --define=DEBUG --define=_FLASH --cla_support=cla1 --float_support=fpu32 --tmu_support=tmu0 --vcu_support=vcu2 --define=CPU1 --diag_warning=225 --diag_suppress=10063 --display_error_number --diag_suppress=16002" linkerBuildOptions="--entry_point code_start --stack_size=0x100 " />
|
||||
<pathVariable name="C2000WARE_IQMATH_ROOT" path="../../../../../../libraries/math/IQmath/" scope="project" />
|
||||
<pathVariable name="C2000WARE_DLIB_ROOT" path="../../../../driverlib/" scope="project" />
|
||||
<pathVariable name="C2000WARE_ROOT" path="../../../../../../" scope="project" />
|
||||
<file action="copy" path="../../../../../../device_support/f2837xd/common/include/driverlib.h" targetDirectory="device" />
|
||||
<file action="copy" path="../../../../../../device_support/f2837xd/common/include/device.h" targetDirectory="device" />
|
||||
<file action="copy" path="../../../../../../device_support/f2837xd/common/source/device.c" targetDirectory="device" />
|
||||
<file action="copy" path="../../../../../../device_support/f2837xd/common/targetConfigs/TMS320F28377D.ccxml" targetDirectory="targetConfigs" />
|
||||
<file action="copy" path="../../../../../../device_support/f2837xd/common/cmd/2837xD_RAM_IQMATH_lnk_cpu1.cmd" targetDirectory="" applicableConfigurations="CPU1_RAM" />
|
||||
<file action="copy" path="../../../../../../device_support/f2837xd/common/cmd/2837xD_FLASH_IQMATH_lnk_cpu1.cmd" targetDirectory="" applicableConfigurations="CPU1_FLASH" />
|
||||
<file action="copy" path="../../../../../../device_support/f2837xd/common/source/F2837xD_CodeStartBranch.asm" targetDirectory="device" />
|
||||
<file action="link" path="../../../../driverlib/ccs/Debug/driverlib.lib" targetDirectory="" />
|
||||
<file action="copy" path="../../../../driverlib/" targetDirectory="device" excludeFromBuild="True"/>
|
||||
<file action="link" path="../../../../../../libraries/math/IQmath/c28/lib/IQmath_fpu32.lib" targetDirectory="" />
|
||||
<file action="copy" path="../eqep_ex2_calculation.c" targetDirectory="" />
|
||||
<file action="copy" path="../eqep_ex2_calculation.h" targetDirectory="" />
|
||||
<file action="copy" path="../eqep_ex2_pos_speed.c" targetDirectory="" />
|
||||
<file action="copy" path="../eqep_ex2_calculation.xls" targetDirectory="" />
|
||||
</project>
|
||||
</projectSpec>
|
||||
@@ -0,0 +1,260 @@
|
||||
//#############################################################################
|
||||
//
|
||||
// FILE: eqep_ex1_calculation.c
|
||||
//
|
||||
// TITLE: Frequency Measurement Using eQEP (Calculations)
|
||||
//
|
||||
// This file includes the eQEP frequency calculation function called by
|
||||
// eqep_ex1_freq_cal.c. The frequency calculation steps performed by
|
||||
// FreqCal_calculate() are described below:
|
||||
//
|
||||
// 1. This program calculates: **freqHzFR**
|
||||
//
|
||||
// freqHzFR or v = (x2 - x1) / T -Equation 1
|
||||
//
|
||||
// If max/base freq = 10kHz:
|
||||
//
|
||||
// 10kHz = (x2 - x1) / (2 / 100Hz) -Equation 2
|
||||
// max (x2 - x1) = 200 counts = freqScalerFR
|
||||
//
|
||||
// Note: T = 2 / 100Hz. 2 is from (x2 - x1) / 2 because QPOSCNT counts 2 edges
|
||||
// per cycle.
|
||||
//
|
||||
// If both sides of Equation 2 are divided by 10 kHz, then:
|
||||
//
|
||||
// 1 = (x2 - x1) / [10kHz * (2 / 100Hz)] where [10kHz * (2 / 100Hz)] = 200
|
||||
//
|
||||
// Because (x2 - x1) must be < 200 (max), (x2 - x1) / 200 < 1 for all
|
||||
// frequencies less than max.
|
||||
//
|
||||
// freqFR = (x2 - x1) / 200
|
||||
// = (x2 - x1) / [10kHz * (2 / 100Hz)] -Equation 3
|
||||
//
|
||||
// To get back to original velocity equation, Equation 1, multiply Equation 3
|
||||
// by 10 kHz:
|
||||
//
|
||||
// freqHzFR = 10kHz * (x2 - x1) / [10kHz * (2 / 100Hz)]
|
||||
// = (x2 - x1) / (2 / 100Hz) -Final Equation
|
||||
//
|
||||
// 2. **min freq** = 1 count / (2 / 100Hz) = 50 Hz
|
||||
//
|
||||
// 3. **freqHzPR**
|
||||
//
|
||||
// freqHzPR or v = X / (t2 - t1) -Equation 4
|
||||
//
|
||||
// If max/base freq = 10kHz:
|
||||
//
|
||||
// 10kHz = (8 / 2) / T = 8 / 2T
|
||||
//
|
||||
// where 8 = prescaler selected by QCAPCTL.UPPS (unit time out every 8 edges)
|
||||
// 2 = divide by 2 because QPOSCNT counts 2 edges per cycle
|
||||
// T = time in seconds = t2 - t1 / (SYSCLKFREQ / 128)
|
||||
// t2 - t1 = # of QCAPCLK cycles
|
||||
// 1 QCAPCLK cycle = 1 / (SYSCLKFREQ / 128) = QCPRDLAT
|
||||
//
|
||||
// Note: 128 is the prescaler selected by QCAPCTL.CCPS
|
||||
//
|
||||
// So:
|
||||
//
|
||||
// 10 kHz = 8(SYSCLKFREQ / 128) / 2(t2 - t1)
|
||||
// t2 - t1 = 8(SYSCLKFREQ / 128) / (10kHz * 2)
|
||||
// = (SYSCLKFREQ / 128) / (2 * 10kHz / 8) -Equation 5
|
||||
// = maximum (t2 - t1) = freqScalerPR
|
||||
//
|
||||
// Divide both sides by (t2 - t1) and:
|
||||
//
|
||||
// 1 = freqScalerPR / (t2 - t1)
|
||||
// = [(SYSCLKFREQ / 128) / (2 * 10kHz / 8)] / (t2 - t1)
|
||||
//
|
||||
// Because (t2 - t1) must be < freqScalerPR (max), freqScalerPR / (t2 - t1) < 1
|
||||
// for all frequencies less than max.
|
||||
//
|
||||
// freqPR = freqScalerPR / (t2 - t1)
|
||||
// = [(SYSCLKFREQ / 128) / (2 * 10kHz / 8)] / (t2 - t1) -Equation 6
|
||||
//
|
||||
// Now within velocity limits, to get back to original velocity equation,
|
||||
// Equation 1, multiply Equation 6 by 10 kHz:
|
||||
//
|
||||
// freqHzFR = 10kHz * [(SYSCLKFREQ / 128) / (2 * 10kHz / 8)] / (t2 - t1)
|
||||
// = (SYSCLKFREQ / 128) * 8 / [2 * (t2 - t1)]
|
||||
// = 8 / [2 * (t2 - t1) * QCPRDLAT] -Final Equation
|
||||
//
|
||||
// More detailed calculation results can be found in the
|
||||
// eqep_ex1_calculation.xls spreadsheet included in the example folder.
|
||||
//
|
||||
//#############################################################################
|
||||
//
|
||||
//
|
||||
// $Copyright:
|
||||
// Copyright (C) 2013-2024 Texas Instruments Incorporated - http://www.ti.com/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// Neither the name of Texas Instruments Incorporated nor the names of
|
||||
// its contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// $
|
||||
//#############################################################################
|
||||
|
||||
//
|
||||
// Included Files
|
||||
//
|
||||
#include "eqep_ex1_calculation.h"
|
||||
|
||||
//
|
||||
// FreqCal_calculate - Function to calculate the frequency of the input signal using both the unit
|
||||
// timer and the quadrature capture units.
|
||||
//
|
||||
// For a more detailed explanation of the calculations, read the description at
|
||||
// the top of this file.
|
||||
//
|
||||
void
|
||||
FreqCal_calculate(FreqCal_Object *p)
|
||||
{
|
||||
uint32_t temp;
|
||||
_iq newPosCnt, oldPosCnt;
|
||||
|
||||
//
|
||||
// **** Frequency calculation using eQEP position counter ****
|
||||
//
|
||||
// Check for unit time out event
|
||||
//
|
||||
if((EQEP_getInterruptStatus(EQEP1_BASE) & EQEP_INT_UNIT_TIME_OUT) != 0)
|
||||
{
|
||||
//
|
||||
// Get latched POSCNT value
|
||||
//
|
||||
newPosCnt = EQEP_getPositionLatch(EQEP1_BASE);
|
||||
oldPosCnt = p->oldPos;
|
||||
|
||||
if(newPosCnt > oldPosCnt)
|
||||
{
|
||||
//
|
||||
// x2 - x1 in v = (x2 - x1) / T equation
|
||||
//
|
||||
temp = newPosCnt - oldPosCnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = (0xFFFFFFFF - oldPosCnt) + newPosCnt;
|
||||
}
|
||||
|
||||
//
|
||||
// p->freqFR = (x2 - x1) / (T * 10kHz)
|
||||
//
|
||||
p->freqFR = _IQdiv(temp, p->freqScalerFR);
|
||||
temp=p->freqFR;
|
||||
|
||||
//
|
||||
// Is freq greater than max freq (10kHz for this example)?
|
||||
//
|
||||
if(temp >= _IQ(1))
|
||||
{
|
||||
p->freqFR = _IQ(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
p->freqFR = temp;
|
||||
}
|
||||
|
||||
//
|
||||
// Q0 = Q0 * GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
|
||||
// p->freqHzFR = (p->freqFR) * 10kHz = (x2 - x1) / T
|
||||
//
|
||||
p->freqHzFR = _IQmpy(p->baseFreq,p->freqFR);
|
||||
|
||||
//
|
||||
// Update old position counter value and clear unit time out flag
|
||||
//
|
||||
p->oldPos = newPosCnt;
|
||||
p->FR_calc_count++;
|
||||
if(p->FR_calc_count >= 2)
|
||||
{
|
||||
p->task_complete_FR = 1;
|
||||
}
|
||||
|
||||
EQEP_clearInterruptStatus(EQEP1_BASE, EQEP_INT_UNIT_TIME_OUT);
|
||||
}
|
||||
|
||||
//
|
||||
// **** Frequency calculation using eQEP capture counter ****
|
||||
//
|
||||
// Check for unit position event
|
||||
//
|
||||
if((EQEP_getStatus(EQEP1_BASE) & EQEP_STS_UNIT_POS_EVNT) != 0)
|
||||
{
|
||||
//
|
||||
// No capture overflow
|
||||
//
|
||||
if((EQEP_getStatus(EQEP1_BASE) & EQEP_STS_CAP_OVRFLW_ERROR) == 0)
|
||||
{
|
||||
temp = (uint32_t)EQEP_getCapturePeriodLatch(EQEP1_BASE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Capture overflow, saturate the result
|
||||
//
|
||||
temp = 0xFFFF;
|
||||
}
|
||||
|
||||
//
|
||||
// p->freqPR = X / [(t2 - t1) * 10kHz]
|
||||
//
|
||||
p->freqPR = _IQdiv(p->freqScalerPR, temp);
|
||||
temp = p->freqPR;
|
||||
|
||||
if(temp > _IQ(1))
|
||||
{
|
||||
p->freqPR = _IQ(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
p->freqPR = temp;
|
||||
}
|
||||
|
||||
//
|
||||
// Q0 = Q0 * GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
|
||||
// p->freqHzPR = (p->freqPR) * 10kHz = X / (t2 - t1)
|
||||
//
|
||||
p->freqHzPR = _IQmpy(p->baseFreq, p->freqPR);
|
||||
p->PR_calc_count++;
|
||||
if(p->PR_calc_count >= 2)
|
||||
{
|
||||
p->task_complete_PR = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Clear unit position event flag and overflow error flag
|
||||
//
|
||||
EQEP_clearStatus(EQEP1_BASE, (EQEP_STS_UNIT_POS_EVNT |
|
||||
EQEP_STS_CAP_OVRFLW_ERROR));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// End of File
|
||||
//
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
//#############################################################################
|
||||
//
|
||||
// FILE: eqep_ex1_calculation.h
|
||||
//
|
||||
// TITLE: Frequency Measurement Using eQEP (Calculations)
|
||||
//
|
||||
//#############################################################################
|
||||
//
|
||||
//
|
||||
// $Copyright:
|
||||
// Copyright (C) 2013-2024 Texas Instruments Incorporated - http://www.ti.com/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// Neither the name of Texas Instruments Incorporated nor the names of
|
||||
// its contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// $
|
||||
//#############################################################################
|
||||
|
||||
#ifndef EQEP_EX1_CALCULATION_H
|
||||
#define EQEP_EX1_CALCULATION_H
|
||||
|
||||
//
|
||||
// Included Files
|
||||
//
|
||||
#include "IQmathLib.h"
|
||||
#include "driverlib.h"
|
||||
|
||||
//
|
||||
// Typedefs
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
uint32_t freqScalerPR; // Parameter: Scaler converting 1/N cycles to a
|
||||
// GLOBAL_Q freq (Q0) - independently with global Q
|
||||
uint32_t freqScalerFR; // Parameter: Scaler converting 1/N cycles to a
|
||||
// GLOBAL_Q freq (Q0) - independently with global Q
|
||||
uint32_t baseFreq; // Parameter: Maximum freq
|
||||
|
||||
_iq freqPR; // Output: Freq in per-unit using capture unit
|
||||
int32_t freqHzPR; // Output: Freq in Hz, measured using Capture unit
|
||||
uint32_t oldPos;
|
||||
|
||||
_iq freqFR; // Output: Freq in per-unit using position counter
|
||||
int32_t freqHzFR; // Output: Freq in Hz, measured using Capture unit
|
||||
bool task_complete_FR,task_complete_PR; // Output : calculation is done.
|
||||
int16_t FR_calc_count,PR_calc_count; // Output : calculation is done.
|
||||
} FreqCal_Object;
|
||||
|
||||
typedef FreqCal_Object *FreqCal_Handle;
|
||||
|
||||
//
|
||||
// Function Prototypes
|
||||
//
|
||||
void FreqCal_calculate(FreqCal_Handle);
|
||||
|
||||
#endif // EQEP_EX1_CALCULATION_H
|
||||
|
||||
//
|
||||
// End of File
|
||||
//
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,364 @@
|
||||
//#############################################################################
|
||||
//
|
||||
// FILE: eqep_ex1_freq_cal.c
|
||||
//
|
||||
// TITLE: Frequency Measurement Using eQEP
|
||||
//
|
||||
//! \addtogroup driver_example_list
|
||||
//! <h1>Frequency Measurement Using eQEP</h1>
|
||||
//!
|
||||
//! This example will calculate the frequency of an input signal using the eQEP
|
||||
//! module. ePWM1A is configured to generate this input signal with a
|
||||
//! frequency of 5 kHz. It will interrupt once every period and call the
|
||||
//! frequency calculation function. This example uses the IQMath library to
|
||||
//! simplify high-precision calculations.
|
||||
//!
|
||||
//! In addition to the main example file, the following files must be included
|
||||
//! in this project:
|
||||
//! - \b eqep_ex1_calculation.c - contains frequency calculation function
|
||||
//! - \b eqep_ex1_calculation.h - includes initialization values for frequency
|
||||
//! structure
|
||||
//!
|
||||
//! The configuration for this example is as follows
|
||||
//! - Maximum frequency is configured to 10KHz (baseFreq)
|
||||
//! - Minimum frequency is assumed at 50Hz for capture pre-scalar selection
|
||||
//!
|
||||
//! \b SPEED_FR: High Frequency Measurement is obtained by counting the
|
||||
//! external input pulses for 10ms (unit timer set to 100Hz).
|
||||
//! \f[ SPEED\_FR = \frac{Count\ Delta}{10ms} \f]
|
||||
//!
|
||||
//! \b SPEED_PR: Low Frequency Measurement is obtained by measuring time
|
||||
//! period of input edges. Time measurement is averaged over 64 edges for
|
||||
//! better results and the capture unit performs the time measurement using
|
||||
//! pre-scaled SYSCLK.
|
||||
//!
|
||||
//! Note that the pre-scaler for capture unit clock is selected such that the
|
||||
//! capture timer does not overflow at the required minimum frequency. This
|
||||
//! example runs indefinitely until the user stops it.
|
||||
//!
|
||||
//! For more information about the frequency calculation see the comments at
|
||||
//! the beginning of eqep_ex1_calculation.c and the XLS file provided with the
|
||||
//! project, eqep_ex1_calculation.xls.
|
||||
//!
|
||||
//! \b External \b Connections \n
|
||||
//! - Connect GPIO20/eQEP1A to GPIO0/ePWM1A
|
||||
//!
|
||||
//! \b Watch \b Variables \n
|
||||
//! - \b freq.freqHzFR - Frequency measurement using position counter/unit
|
||||
//! time out
|
||||
//! - \b freq.freqHzPR - Frequency measurement using capture unit
|
||||
//!
|
||||
//
|
||||
//#############################################################################
|
||||
//
|
||||
//
|
||||
// $Copyright:
|
||||
// Copyright (C) 2013-2024 Texas Instruments Incorporated - http://www.ti.com/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// Neither the name of Texas Instruments Incorporated nor the names of
|
||||
// its contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// $
|
||||
//#############################################################################
|
||||
|
||||
//
|
||||
// Included Files
|
||||
//
|
||||
#include "driverlib.h"
|
||||
#include "device.h"
|
||||
#include "IQmathLib.h"
|
||||
#include "eqep_ex1_calculation.h"
|
||||
|
||||
//
|
||||
// Defines
|
||||
//
|
||||
#define TB_CLK DEVICE_SYSCLK_FREQ / 2 // Time base clock is SYSCLK / 2
|
||||
#define PWM_CLK 5000 // We want to output at 5 kHz
|
||||
#define PRD_VAL (TB_CLK / (PWM_CLK * 2)) // Calculate value period value
|
||||
// for up-down count mode
|
||||
|
||||
// Base/max frequency is 10 kHz
|
||||
#define BASE_FREQ 10000
|
||||
// See Equation 5 in eqep_ex1_calculation.c
|
||||
#define FREQ_SCALER_PR (((DEVICE_SYSCLK_FREQ / 128) * 8) / (2 * BASE_FREQ))
|
||||
// See Equation 2 in eqep_ex1_calculation.c
|
||||
#define FREQ_SCALER_FR ((BASE_FREQ * 2) / 100)
|
||||
|
||||
//
|
||||
// Function Prototypes
|
||||
//
|
||||
void initEPWM(void);
|
||||
void initEQEP(void);
|
||||
__interrupt void epwmISR(void);
|
||||
|
||||
//
|
||||
// Globals
|
||||
//
|
||||
FreqCal_Object freq =
|
||||
{
|
||||
FREQ_SCALER_PR, // freqScalerPR
|
||||
FREQ_SCALER_FR, // freqScalerFR
|
||||
BASE_FREQ, // baseFreq
|
||||
0, 0, 0, 0, 0,0,0,0,0 // Initialize outputs to zero
|
||||
};
|
||||
|
||||
//
|
||||
// Main
|
||||
//
|
||||
void main(void)
|
||||
{
|
||||
//
|
||||
// Initialize device clock and peripherals
|
||||
//
|
||||
Device_init();
|
||||
|
||||
//
|
||||
// Disable pin locks and enable internal pullups.
|
||||
//
|
||||
Device_initGPIO();
|
||||
|
||||
//
|
||||
// Initialize GPIOs for use as EPWM1A and EQEP1A
|
||||
//
|
||||
GPIO_setPinConfig(GPIO_0_EPWM1A);
|
||||
GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);
|
||||
GPIO_setPinConfig(GPIO_20_EQEP1A);
|
||||
GPIO_setPadConfig(20, GPIO_PIN_TYPE_STD);
|
||||
|
||||
//
|
||||
// Initialize PIE and clear PIE registers. Disables CPU interrupts.
|
||||
//
|
||||
Interrupt_initModule();
|
||||
|
||||
//
|
||||
// Initialize the PIE vector table with pointers to the shell Interrupt
|
||||
// Service Routines (ISR).
|
||||
//
|
||||
Interrupt_initVectorTable();
|
||||
|
||||
//
|
||||
// Interrupts that are used in this example are re-mapped to ISR functions
|
||||
// found within this file.
|
||||
//
|
||||
Interrupt_register(INT_EPWM1, &epwmISR);
|
||||
|
||||
//
|
||||
// Setup ePWM1 to generate a 5 kHz signal to be an input to the eQEP
|
||||
//
|
||||
initEPWM();
|
||||
|
||||
//
|
||||
// Enable interrupts required for this example
|
||||
//
|
||||
Interrupt_enable(INT_EPWM1);
|
||||
|
||||
//
|
||||
// Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
|
||||
//
|
||||
EINT;
|
||||
ERTM;
|
||||
|
||||
//
|
||||
// Setup eQEP1, configuring the unit timer and quadrature capture units
|
||||
//
|
||||
initEQEP();
|
||||
|
||||
//
|
||||
// Loop indefinitely
|
||||
//
|
||||
while (1)
|
||||
{
|
||||
if((freq.task_complete_FR == 1) && (freq.task_complete_PR == 1))
|
||||
{
|
||||
if(((freq.freqHzFR - PWM_CLK) < 50) &&
|
||||
((freq.freqHzFR - PWM_CLK) > -50) &&
|
||||
((freq.freqHzPR - PWM_CLK) < 50) &&
|
||||
((freq.freqHzPR - PWM_CLK) > -50))
|
||||
{
|
||||
Example_PassCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Example_Fail = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// initEQEP - Function to configure eQEP1.
|
||||
//
|
||||
void
|
||||
initEQEP(void)
|
||||
{
|
||||
//
|
||||
// Configure the decoder for up-count mode, counting both rising and
|
||||
// falling edges (that is, 2x resolution)
|
||||
//
|
||||
EQEP_setDecoderConfig(EQEP1_BASE, (EQEP_CONFIG_2X_RESOLUTION |
|
||||
EQEP_CONFIG_UP_COUNT |
|
||||
EQEP_CONFIG_NO_SWAP));
|
||||
EQEP_setEmulationMode(EQEP1_BASE, EQEP_EMULATIONMODE_RUNFREE);
|
||||
|
||||
//
|
||||
// Configure the position counter to reset on an index event
|
||||
//
|
||||
EQEP_setPositionCounterConfig(EQEP1_BASE, EQEP_POSITION_RESET_IDX,
|
||||
0xFFFFFFFF);
|
||||
|
||||
//
|
||||
// Enable the unit timer, setting the frequency to 100 Hz
|
||||
//
|
||||
EQEP_enableUnitTimer(EQEP1_BASE, (DEVICE_SYSCLK_FREQ / 100));
|
||||
|
||||
//
|
||||
// Configure the position counter to be latched on a unit time out
|
||||
//
|
||||
EQEP_setLatchMode(EQEP1_BASE, EQEP_LATCH_UNIT_TIME_OUT);
|
||||
|
||||
//
|
||||
// Enable the eQEP1 module
|
||||
//
|
||||
EQEP_enableModule(EQEP1_BASE);
|
||||
|
||||
//
|
||||
// Configure and enable the edge-capture unit. The capture clock divider is
|
||||
// SYSCLKOUT/128. The unit-position event divider is QCLK/8.
|
||||
//
|
||||
EQEP_setCaptureConfig(EQEP1_BASE, EQEP_CAPTURE_CLK_DIV_128,
|
||||
EQEP_UNIT_POS_EVNT_DIV_8);
|
||||
EQEP_enableCapture(EQEP1_BASE);
|
||||
}
|
||||
|
||||
//
|
||||
// initEPWM - Function to configure ePWM1 to generate a 5 kHz signal.
|
||||
//
|
||||
void
|
||||
initEPWM(void)
|
||||
{
|
||||
//
|
||||
// Disable the ePWM time base clock before configuring the module
|
||||
//
|
||||
SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
|
||||
|
||||
//
|
||||
// Set phase shift to 0 and clear the time base counter
|
||||
//
|
||||
EPWM_setPhaseShift(EPWM1_BASE, 0);
|
||||
EPWM_setTimeBaseCounter(EPWM1_BASE, 0);
|
||||
|
||||
//
|
||||
// Disable the shadow load; the load will be immediate instead
|
||||
//
|
||||
EPWM_disableCounterCompareShadowLoadMode(EPWM1_BASE,
|
||||
EPWM_COUNTER_COMPARE_A);
|
||||
EPWM_disableCounterCompareShadowLoadMode(EPWM1_BASE,
|
||||
EPWM_COUNTER_COMPARE_B);
|
||||
|
||||
//
|
||||
// Set the compare A value to half the period value, compare B to 0
|
||||
//
|
||||
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, PRD_VAL/2);
|
||||
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_B, 0);
|
||||
|
||||
//
|
||||
// Set action qualifier behavior on compare A events
|
||||
// - EPWM1A --> 1 when CTR = CMPA and increasing
|
||||
// - EPWM1A --> 0 when CTR = CMPA and decreasing
|
||||
//
|
||||
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
|
||||
EPWM_AQ_OUTPUT_HIGH,
|
||||
EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
|
||||
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
|
||||
EPWM_AQ_OUTPUT_LOW,
|
||||
EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
|
||||
|
||||
//
|
||||
// Configure EPWM1B to be complementary to EPWM1A
|
||||
//
|
||||
EPWM_setDeadBandDelayPolarity(EPWM1_BASE, EPWM_DB_FED,
|
||||
EPWM_DB_POLARITY_ACTIVE_LOW);
|
||||
EPWM_setDeadBandDelayMode(EPWM1_BASE, EPWM_DB_FED, true);
|
||||
EPWM_setDeadBandDelayMode(EPWM1_BASE, EPWM_DB_RED, true);
|
||||
|
||||
//
|
||||
// Enable interrupt when the counter is equal to 0
|
||||
//
|
||||
EPWM_setInterruptSource(EPWM1_BASE, EPWM_INT_TBCTR_ZERO);
|
||||
EPWM_enableInterrupt(EPWM1_BASE);
|
||||
|
||||
//
|
||||
// Interrupt on first event
|
||||
//
|
||||
EPWM_setInterruptEventCount(EPWM1_BASE, 1);
|
||||
|
||||
//
|
||||
// Set the time base clock prescaler to /1
|
||||
//
|
||||
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1,
|
||||
EPWM_HSCLOCK_DIVIDER_1);
|
||||
|
||||
//
|
||||
// Set the period value; don't shadow the register
|
||||
//
|
||||
EPWM_setPeriodLoadMode(EPWM1_BASE, EPWM_PERIOD_DIRECT_LOAD);
|
||||
EPWM_setTimeBasePeriod(EPWM1_BASE, PRD_VAL);
|
||||
|
||||
//
|
||||
// Put the time base counter into up-down count mode
|
||||
//
|
||||
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP_DOWN);
|
||||
|
||||
//
|
||||
// Sync the ePWM time base clock
|
||||
//
|
||||
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
|
||||
}
|
||||
|
||||
//
|
||||
// ePWM1 ISR- interrupts once per ePWM period
|
||||
//
|
||||
__interrupt void
|
||||
epwmISR(void)
|
||||
{
|
||||
//
|
||||
// Checks for events and calculates frequency.
|
||||
//
|
||||
FreqCal_calculate(&freq);
|
||||
|
||||
//
|
||||
// Clear interrupt flag and issue ACK
|
||||
//
|
||||
EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);
|
||||
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
|
||||
}
|
||||
|
||||
//
|
||||
// End of File
|
||||
//
|
||||
|
||||
@@ -0,0 +1,348 @@
|
||||
//#############################################################################
|
||||
//
|
||||
// FILE: eqep_ex1_calculation.c
|
||||
//
|
||||
// TITLE: Position and Speed Measurement Using eQEP (Calculations)
|
||||
//
|
||||
// This file includes the eQEP position and speed calculation function called
|
||||
// by eqep_ex2_pos_speed.c. The position and speed calculation steps performed
|
||||
// by PosSpeed_calculate() are described below:
|
||||
//
|
||||
// 1. This program calculates: **thetaMech**
|
||||
//
|
||||
// thetaMech = QPOSCNT / mechScaler
|
||||
// = QPOSCNT / 4000, where 4000 is the number of counts in 1 rev
|
||||
// (4000 / 4 = 1000 line/rev quadrature encoder)
|
||||
//
|
||||
// Note this example uses mechScaler = 16776 which is _IQ26(1 / 4000)
|
||||
//
|
||||
// 2. This program calculates: **thetaElec**
|
||||
//
|
||||
// thetaElec = (pole pairs) * thetaMech = 2 * QPOSCNT / 4000 in this case
|
||||
//
|
||||
// 3. This program calculates: **speedRPMFR**
|
||||
//
|
||||
// speedRPMFR = [(x2 - x1) / 4000] / T -Equation 1
|
||||
//
|
||||
// Note (x2 - x1) = difference in number of QPOSCNT counts. Dividing (x2 - x1)
|
||||
// by 4000 gives position relative to Index in one revolution.
|
||||
//
|
||||
// If base RPM = 6000 rpm:
|
||||
// 6000 rpm = [(x2 - x1) / 4000] / 10ms -Equation 2
|
||||
// = [(x2 - x1) / 4000] / (.01s * 1 min / 60 sec)
|
||||
// = [(x2 - x1) / 4000] / (1 / 6000) min
|
||||
//
|
||||
// max (x2 - x1) = 4000 counts or 1 revolution in 10 ms
|
||||
//
|
||||
// If both sides of Equation 2 are divided by 6000 rpm, then:
|
||||
// 1 = [(x2 - x1) / 4000] rev / [(1 / 6000) min * 6000rpm]
|
||||
//
|
||||
// Because (x2 - x1) must be < 4000 (max) for QPOSCNT increment,
|
||||
// (x2 - x1) / 4000 < 1 for CW rotation, and because (x2 - x1) must be >- 4000
|
||||
// for QPOSCNT decrement, (x2 - x1) / 4000 > -1 for CCW rotation
|
||||
//
|
||||
// speedFR = [(x2 - x1) / 4000] / [(1 / 6000) min * 6000rpm]
|
||||
// = (x2 - x1) / 4000 -Equation 3
|
||||
//
|
||||
// To convert speedFR to RPM, multiply Equation 3 by 6000 rpm:
|
||||
// speedRPMFR = 6000rpm * (x2 - x1) / 4000 -Final Equation
|
||||
//
|
||||
//
|
||||
// 2. **min rpm ** = selected at 10 rpm based on CCPS prescaler options
|
||||
// available (128 is greatest)
|
||||
//
|
||||
// 3. **speedRPMPR**
|
||||
// speedRPMPR = X / (t2 - t1) -Equation 4
|
||||
//
|
||||
// where X = QCAPCTL [UPPS] / 4000 rev (position relative to Index in 1 rev)
|
||||
//
|
||||
// If max / base speed = 6000 rpm:
|
||||
// 6000 = (32 / 4000) / [(t2 - t1) / (SYSCLKFREQ / 64)]
|
||||
//
|
||||
// where 32 = QCAPCTL[UPPS] (Unit timeout once every 32 edges)
|
||||
//
|
||||
// 32 / 4000 = position in 1 rev (position as a fraction of 1 revolution)
|
||||
//
|
||||
// t2 - t1 / (SYSCLKFREQ / 64), t2 - t1 = # of QCAPCLK cycles
|
||||
//
|
||||
// QCAPCLK cycle = 1 / (SYSCLKFREQ / 64)
|
||||
// = QCPRDLAT
|
||||
//
|
||||
// So:
|
||||
// 6000 rpm = [32(SYSCLKFREQ / 64) * 60s/min] / [4000(t2 - t1)]
|
||||
//
|
||||
// t2 - t1 = [32(SYSCLKFREQ / 64) * 60s/min]/(4000 * 6000rpm) -Equation 5
|
||||
// = 250 CAPCLK cycles
|
||||
// = maximum (t2 - t1) = speedScaler
|
||||
//
|
||||
// Divide both sides by (t2 - t1) and:
|
||||
// 1 = 32 / (t2 - t1)
|
||||
// = [32(SYSCLKFREQ / 64) * 60 s/min] / (4000 * 6000rpm) / (t2 - t1)
|
||||
//
|
||||
// Because (t2 - t1) must be < 250 for QPOSCNT, increment 250 / (t2 - t1) < 1
|
||||
// for CW rotation, and because (t2 - t1) must be > -250 for QPOSCNT decrement
|
||||
// 250 / (t2 - t1) > -1 for CCW rotation
|
||||
//
|
||||
// speedPR = 250 / (t2 - t1)
|
||||
// = [32(SYSCLKFREQ / 64) * 60 s/min] / (4000 * 6000rpm) / (t2 - t1)
|
||||
// -Equation 6
|
||||
//
|
||||
// To convert speedPR to RPM, multiply Equation 6 by 6000rpm:
|
||||
// speedRPMFR = [32(SYSCLKFREQ / 64) * 60s/min] / [4000 * (t2 - t1)]
|
||||
// = [(32 / 4000) rev * 60s/min] / [(t2 - t1)(QCPRDLAT)]
|
||||
// -Final Equation
|
||||
//
|
||||
// More detailed calculation results can be found in the
|
||||
// eqep_ex2_calculation.xls spreadsheet included in the example folder.
|
||||
//
|
||||
//#############################################################################
|
||||
//
|
||||
//
|
||||
// $Copyright:
|
||||
// Copyright (C) 2013-2024 Texas Instruments Incorporated - http://www.ti.com/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// Neither the name of Texas Instruments Incorporated nor the names of
|
||||
// its contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// $
|
||||
//#############################################################################
|
||||
|
||||
//
|
||||
// Included Files
|
||||
//
|
||||
#include "eqep_ex2_calculation.h"
|
||||
|
||||
//
|
||||
// Function to calculate the frequency of the input signal using both the unit
|
||||
// timer and the quadrature capture units.
|
||||
//
|
||||
// For a more detailed explanation of the calculations, read the description at
|
||||
// the top of this file.
|
||||
//
|
||||
void PosSpeed_calculate(PosSpeed_Object *p)
|
||||
{
|
||||
int32_t temp;
|
||||
uint16_t pos16bVal, temp1;
|
||||
_iq temp2, newPosCnt, oldPosCnt;
|
||||
|
||||
//
|
||||
// **** Position calculation - mechanical and electrical motor angle ****
|
||||
//
|
||||
// Get the motor direction: -1 = CCW/reverse, 1 = CW/forward
|
||||
//
|
||||
p->directionQEP = EQEP_getDirection(EQEP1_BASE);
|
||||
|
||||
//
|
||||
// Capture position once per QA/QB period
|
||||
//
|
||||
pos16bVal = (uint16_t)EQEP_getPosition(EQEP1_BASE);
|
||||
|
||||
//
|
||||
// Raw theta = current pos. + ang. offset from QA
|
||||
//
|
||||
p->thetaRaw = pos16bVal + p->calAngle;
|
||||
|
||||
//
|
||||
// The following lines calculate
|
||||
//
|
||||
// p->thetaMech ~= QPOSCNT / mechScaler [current cnt/(total cnt in 1 rev)]
|
||||
//
|
||||
// where mechScaler = 4000 cnts/revolution
|
||||
//
|
||||
temp = (int32_t)p->thetaRaw * (int32_t)p->mechScaler; // Q0 * Q26 = Q26
|
||||
temp &= 0x03FFF000;
|
||||
|
||||
p->thetaMech = (int16_t)(temp >> 11); // Q26 -> Q15
|
||||
p->thetaMech &= 0x7FFF;
|
||||
|
||||
//
|
||||
// The following lines calculate p->elec_mech
|
||||
//
|
||||
p->thetaElec = p->polePairs * p->thetaMech; // Q0 * Q15 = Q15
|
||||
p->thetaElec &= 0x7FFF;
|
||||
|
||||
//
|
||||
// Check for an index occurrence
|
||||
//
|
||||
if((EQEP_getInterruptStatus(EQEP1_BASE) & EQEP_INT_INDEX_EVNT_LATCH) != 0U)
|
||||
{
|
||||
EQEP_clearInterruptStatus(EQEP1_BASE, EQEP_INT_INDEX_EVNT_LATCH);
|
||||
}
|
||||
|
||||
//
|
||||
// **** High Speed Calculation using QEP Position counter ****
|
||||
//
|
||||
// Check for unit timeout event
|
||||
//
|
||||
if((EQEP_getInterruptStatus(EQEP1_BASE) & EQEP_INT_UNIT_TIME_OUT) != 0)
|
||||
{
|
||||
//
|
||||
// The following lines calculate position:
|
||||
// (x2 - x1) / 4000 (position in 1 revolution)
|
||||
//
|
||||
pos16bVal = (uint16_t)EQEP_getPositionLatch(EQEP1_BASE);
|
||||
temp = (int32_t)pos16bVal * (int32_t)p->mechScaler; // Q0 * Q26 = Q26
|
||||
temp &= 0x03FFF000;
|
||||
|
||||
temp = (int16_t)(temp >> 11); // Q26 -> Q15
|
||||
temp &= 0x7FFF;
|
||||
|
||||
newPosCnt = _IQ15toIQ(temp);
|
||||
oldPosCnt = p->oldPos;
|
||||
|
||||
//
|
||||
// POSCNT is counting down
|
||||
//
|
||||
if(p->directionQEP == -1)
|
||||
{
|
||||
if(newPosCnt > oldPosCnt)
|
||||
{
|
||||
//
|
||||
// x2 - x1 should be negative
|
||||
//
|
||||
temp2 = -(_IQ(1) - newPosCnt + oldPosCnt);
|
||||
}
|
||||
else
|
||||
{
|
||||
temp2 = newPosCnt -oldPosCnt;
|
||||
}
|
||||
}
|
||||
//
|
||||
// POSCNT is counting up
|
||||
//
|
||||
else if(p->directionQEP == 1)
|
||||
{
|
||||
if(newPosCnt < oldPosCnt)
|
||||
{
|
||||
temp2 = _IQ(1) + newPosCnt - oldPosCnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// x2 - x1 should be positive
|
||||
//
|
||||
temp2 = newPosCnt - oldPosCnt;
|
||||
}
|
||||
}
|
||||
|
||||
if(temp2 > _IQ(1))
|
||||
{
|
||||
p->speedFR = _IQ(1);
|
||||
}
|
||||
else if(temp2 < _IQ(-1))
|
||||
{
|
||||
p->speedFR = _IQ(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
p->speedFR = temp2;
|
||||
}
|
||||
|
||||
//
|
||||
// Update the electrical angle
|
||||
//
|
||||
p->oldPos = newPosCnt;
|
||||
|
||||
//
|
||||
// Change motor speed from pu value to rpm value (Q15 -> Q0)
|
||||
// Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
|
||||
//
|
||||
p->speedRPMFR = _IQmpy(p->baseRPM, p->speedFR);
|
||||
|
||||
//
|
||||
// Clear unit time out flag
|
||||
//
|
||||
EQEP_clearInterruptStatus(EQEP1_BASE, EQEP_INT_UNIT_TIME_OUT);
|
||||
}
|
||||
|
||||
//
|
||||
// **** Low-speed computation using QEP capture counter ****
|
||||
//
|
||||
// Check for unit position event
|
||||
//
|
||||
if((EQEP_getStatus(EQEP1_BASE) & EQEP_STS_UNIT_POS_EVNT) != 0)
|
||||
{
|
||||
//
|
||||
// No Capture overflow
|
||||
//
|
||||
if((EQEP_getStatus(EQEP1_BASE) & EQEP_STS_CAP_OVRFLW_ERROR) == 0)
|
||||
{
|
||||
temp1 = (uint32_t)EQEP_getCapturePeriodLatch(EQEP1_BASE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Capture overflow, saturate the result
|
||||
//
|
||||
temp1 = 0xFFFF;
|
||||
}
|
||||
|
||||
//
|
||||
// p->speedPR = p->speedScaler / temp1
|
||||
//
|
||||
p->speedPR = _IQdiv(p->speedScaler, temp1);
|
||||
temp2 = p->speedPR;
|
||||
|
||||
if(temp2 > _IQ(1))
|
||||
{
|
||||
p->speedPR = _IQ(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
p->speedPR = temp2;
|
||||
}
|
||||
|
||||
//
|
||||
// Convert p->speedPR to RPM
|
||||
//
|
||||
// Reverse direction = negative
|
||||
//
|
||||
if(p->directionQEP == -1)
|
||||
{
|
||||
//
|
||||
// Q0 = Q0 * GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
|
||||
//
|
||||
p->speedRPMPR = -_IQmpy(p->baseRPM, p->speedPR);
|
||||
}
|
||||
//
|
||||
// Forward direction = positive
|
||||
//
|
||||
else
|
||||
{
|
||||
//
|
||||
// Q0 = Q0 * GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
|
||||
//
|
||||
p->speedRPMPR = _IQmpy(p->baseRPM, p->speedPR);
|
||||
}
|
||||
|
||||
//
|
||||
// Clear unit position event flag and overflow error flag
|
||||
//
|
||||
EQEP_clearStatus(EQEP1_BASE, (EQEP_STS_UNIT_POS_EVNT |
|
||||
EQEP_STS_CAP_OVRFLW_ERROR));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
//#############################################################################
|
||||
//
|
||||
// FILE: eqep_ex2_calculation.h
|
||||
//
|
||||
// TITLE: Position and Speed Measurement Using eQEP (Calculations)
|
||||
//
|
||||
//#############################################################################
|
||||
//
|
||||
//
|
||||
// $Copyright:
|
||||
// Copyright (C) 2013-2024 Texas Instruments Incorporated - http://www.ti.com/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// Neither the name of Texas Instruments Incorporated nor the names of
|
||||
// its contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// $
|
||||
//#############################################################################
|
||||
|
||||
#ifndef EQEP_EX2_CALCULATION_H
|
||||
#define EQEP_EX2_CALCULATION_H
|
||||
|
||||
//
|
||||
// Included Files
|
||||
//
|
||||
#include "IQmathLib.h"
|
||||
#include "driverlib.h"
|
||||
|
||||
//
|
||||
// Typedefs
|
||||
//
|
||||
typedef struct {
|
||||
int16_t thetaElec; // Output: Motor electrical angle (Q15)
|
||||
int16_t thetaMech; // Output: Motor mechanical angle (Q15)
|
||||
int16_t directionQEP; // Output: Motor rotation direction (Q0)
|
||||
int16_t thetaRaw; // Variable: Raw angle from timer 2 (Q0)
|
||||
int16_t mechScaler; // Parameter: 0.9999 / total count,
|
||||
// total count = 4000 (Q26)
|
||||
int16_t polePairs; // Parameter: Number of pole pairs (Q0)
|
||||
int16_t calAngle; // Parameter: Raw angular offset between encoder
|
||||
// and Phase A (Q0)
|
||||
|
||||
uint32_t speedScaler; // Parameter: Scaler converting 1/N cycles to a
|
||||
// GLOBAL_Q speed (Q0) - independently
|
||||
// with global Q
|
||||
_iq speedPR; // Output: Speed in per-unit
|
||||
uint32_t baseRPM; // Parameter: Scaler converting GLOBAL_Q speed to
|
||||
// rpm (Q0) speed - independently with
|
||||
// global Q
|
||||
int16_t speedRPMPR; // Output: Speed in rpm (Q0) - independently with
|
||||
// global Q
|
||||
|
||||
_iq oldPos;
|
||||
_iq speedFR; // Output: Speed in per-unit
|
||||
int16_t speedRPMFR; // Output: Speed in rpm (Q0) - independently with
|
||||
// global Q
|
||||
} PosSpeed_Object;
|
||||
|
||||
typedef PosSpeed_Object *PosSpeed_Handle;
|
||||
|
||||
//
|
||||
// Function Prototypes
|
||||
//
|
||||
void PosSpeed_calculate(PosSpeed_Handle);
|
||||
|
||||
#endif // EQEP_EX2_CALCULATION_H
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,404 @@
|
||||
//#############################################################################
|
||||
//
|
||||
// FILE: eqep_ex2_pos_speed.c
|
||||
//
|
||||
// TITLE: Position and Speed Measurement Using eQEP
|
||||
//
|
||||
//! \addtogroup driver_example_list
|
||||
//! <h1> Position and Speed Measurement Using eQEP</h1>
|
||||
//!
|
||||
//! This example provides position and speed measurement using the
|
||||
//! capture unit and speed measurement using unit time out of the eQEP module.
|
||||
//! ePWM1 and a GPIO are configured to generate simulated eQEP signals. The
|
||||
//! ePWM module will interrupt once every period and call the position/speed
|
||||
//! calculation function. This example uses the IQMath library to simplify
|
||||
//! high-precision calculations.
|
||||
//!
|
||||
//! In addition to the main example file, the following files must be included
|
||||
//! in this project:
|
||||
//! - \b eqep_ex2_calculation.c - contains position/speed calculation function
|
||||
//! - \b eqep_ex2_calculation.h - includes initialization values for
|
||||
//! position/speed structure
|
||||
//!
|
||||
//! The configuration for this example is as follows
|
||||
//! - Maximum speed is configured to 6000rpm (baseRPM)
|
||||
//! - Minimum speed is assumed at 10rpm for capture pre-scalar selection
|
||||
//! - Pole pair is configured to 2 (polePairs)
|
||||
//! - Encoder resolution is configured to 4000 counts/revolution (mechScaler)
|
||||
//! - Which means: 4000 / 4 = 1000 line/revolution quadrature encoder
|
||||
//! (simulated by ePWM1)
|
||||
//! - ePWM1 (simulating QEP encoder signals) is configured for a 5kHz frequency
|
||||
//! or 300 rpm (= 4 * 5000 cnts/sec * 60 sec/min) / 4000 cnts/rev)
|
||||
//!
|
||||
//! \b SPEEDRPM_FR: High Speed Measurement is obtained by counting the QEP
|
||||
//! input pulses for 10ms (unit timer set to 100Hz).
|
||||
//!
|
||||
//! \b SPEEDRPM_FR = (Position Delta / 10ms) * 60 rpm
|
||||
//!
|
||||
//! \b SPEEDRPM_PR: Low Speed Measurement is obtained by measuring time period
|
||||
//! of QEP edges. Time measurement is averaged over 64 edges for better results
|
||||
//! and the capture unit performs the time measurement using pre-scaled SYSCLK.
|
||||
//!
|
||||
//! Note that the pre-scaler for capture unit clock is selected such that the
|
||||
//! capture timer does not overflow at the required minimum frequency. This
|
||||
//! example runs indefinitely until the user stops it.
|
||||
//!
|
||||
//! For more information about the position/speed calculation see the comments
|
||||
//! at the beginning of eqep_ex2_calculation.c and the XLS file provided with
|
||||
//! the project, eqep_ex2_calculation.xls.
|
||||
//!
|
||||
//! \b External \b Connections \n
|
||||
//! - Connect GPIO20/eQEP1A to GPIO0/ePWM1A (simulates eQEP Phase A signal)
|
||||
//! - Connect GPIO21/eQEP1B to GPIO1/ePWM1B (simulates eQEP Phase B signal)
|
||||
//! - Connect GPIO23/eQEP1I to GPIO2 (simulates eQEP Index Signal)
|
||||
//!
|
||||
//! \b Watch \b Variables \n
|
||||
//! - \b posSpeed.speedRPMFR - Speed meas. in rpm using QEP position counter
|
||||
//! - \b posSpeed.speedRPMPR - Speed meas. in rpm using capture unit
|
||||
//! - \b posSpeed.thetaMech - Motor mechanical angle (Q15)
|
||||
//! - \b posSpeed.thetaElec - Motor electrical angle (Q15)
|
||||
//!
|
||||
//
|
||||
//#############################################################################
|
||||
//
|
||||
//
|
||||
// $Copyright:
|
||||
// Copyright (C) 2013-2024 Texas Instruments Incorporated - http://www.ti.com/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// Neither the name of Texas Instruments Incorporated nor the names of
|
||||
// its contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// $
|
||||
//#############################################################################
|
||||
|
||||
//
|
||||
// Included Files
|
||||
//
|
||||
#include "driverlib.h"
|
||||
#include "device.h"
|
||||
#include "IQmathLib.h"
|
||||
#include "eqep_ex2_calculation.h"
|
||||
|
||||
//
|
||||
// Defines
|
||||
//
|
||||
#define TB_CLK DEVICE_SYSCLK_FREQ / 2 // Time base clock is SYSCLK / 2
|
||||
#define PWM_CLK 5000 // We want to output at 5 kHz
|
||||
// (300 rpm)
|
||||
#define PRD_VAL (TB_CLK / (PWM_CLK * 2)) // Calculate value period value
|
||||
// for up-down count mode
|
||||
|
||||
// .9999 / 4000 converted to IQ26 fixed point format
|
||||
#define MECH_SCALER 16776
|
||||
// 2 pole pairs in this example
|
||||
#define POLE_PAIRS 2
|
||||
// Angular offset between encoder and Phase A
|
||||
#define CAL_ANGLE 0
|
||||
// See Equation 5 in eqep_ex2_calculation.c
|
||||
#define SPEED_SCALER ((((uint64_t)32 * DEVICE_SYSCLK_FREQ / 64) * 60) / (24000000))
|
||||
// Base/max rpm is 6000rpm
|
||||
#define BASE_RPM 6000
|
||||
|
||||
//
|
||||
// Function Prototypes
|
||||
//
|
||||
void initEPWM(void);
|
||||
void initEQEP(void);
|
||||
__interrupt void epwmISR(void);
|
||||
|
||||
//
|
||||
// Globals
|
||||
//
|
||||
PosSpeed_Object posSpeed =
|
||||
{
|
||||
0, 0, 0, 0, // Initialize outputs to zero
|
||||
MECH_SCALER, // mechScaler
|
||||
POLE_PAIRS, // polePairs
|
||||
CAL_ANGLE, // calAngle
|
||||
SPEED_SCALER, // speedScaler
|
||||
0, // Initialize output to zero
|
||||
BASE_RPM, // baseRPM
|
||||
0, 0, 0, 0 // Initialize outputs to zero
|
||||
};
|
||||
|
||||
uint16_t interruptCount = 0;
|
||||
|
||||
//
|
||||
// Main
|
||||
//
|
||||
void main(void)
|
||||
{
|
||||
//
|
||||
// Initialize device clock and peripherals
|
||||
//
|
||||
Device_init();
|
||||
|
||||
//
|
||||
// Disable pin locks and enable internal pullups.
|
||||
//
|
||||
Device_initGPIO();
|
||||
|
||||
//
|
||||
// Initialize GPIO0 to ePWM1A, GPIO1 to ePWM1B, and GPIO4 as an output.
|
||||
// They will be used to simulate incoming eQEP Phase A, Phase B, and Index
|
||||
// signals respectively.
|
||||
//
|
||||
GPIO_setPinConfig(GPIO_0_EPWM1A);
|
||||
GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);
|
||||
|
||||
GPIO_setPinConfig(GPIO_1_EPWM1B);
|
||||
GPIO_setPadConfig(1, GPIO_PIN_TYPE_STD);
|
||||
|
||||
GPIO_setPinConfig(GPIO_2_GPIO2);
|
||||
GPIO_setDirectionMode(2, GPIO_DIR_MODE_OUT);
|
||||
GPIO_writePin(2, 0);
|
||||
|
||||
//
|
||||
// Initialize GPIOs for use as EQEP1A, EQEP1B, and EQEP1I
|
||||
//
|
||||
GPIO_setPinConfig(GPIO_20_EQEP1A);
|
||||
GPIO_setPadConfig(20, GPIO_PIN_TYPE_STD);
|
||||
|
||||
GPIO_setPinConfig(GPIO_21_EQEP1B);
|
||||
GPIO_setPadConfig(21, GPIO_PIN_TYPE_STD);
|
||||
|
||||
GPIO_setPinConfig(GPIO_23_EQEP1I);
|
||||
GPIO_setPadConfig(23, GPIO_PIN_TYPE_STD);
|
||||
|
||||
//
|
||||
// Initialize PIE and clear PIE registers. Disables CPU interrupts.
|
||||
//
|
||||
Interrupt_initModule();
|
||||
|
||||
//
|
||||
// Initialize the PIE vector table with pointers to the shell Interrupt
|
||||
// Service Routines (ISR).
|
||||
//
|
||||
Interrupt_initVectorTable();
|
||||
|
||||
//
|
||||
// Interrupts that are used in this example are re-mapped to ISR functions
|
||||
// found within this file.
|
||||
//
|
||||
Interrupt_register(INT_EPWM1, &epwmISR);
|
||||
|
||||
//
|
||||
// Setup ePWM1 to generate a 5 kHz signal to be an input to the eQEP
|
||||
//
|
||||
initEPWM();
|
||||
|
||||
//
|
||||
// Enable interrupts required for this example
|
||||
//
|
||||
Interrupt_enable(INT_EPWM1);
|
||||
|
||||
//
|
||||
// Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
|
||||
//
|
||||
EINT;
|
||||
ERTM;
|
||||
|
||||
//
|
||||
// Setup eQEP1, configuring the unit timer and quadrature capture units
|
||||
//
|
||||
initEQEP();
|
||||
|
||||
//
|
||||
// Loop indefinitely
|
||||
//
|
||||
while(1)
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Function to configure eQEP1.
|
||||
//
|
||||
void initEQEP(void)
|
||||
{
|
||||
//
|
||||
// Configure the decoder for quadrature count mode
|
||||
//
|
||||
EQEP_setDecoderConfig(EQEP1_BASE, (EQEP_CONFIG_1X_RESOLUTION |
|
||||
EQEP_CONFIG_QUADRATURE |
|
||||
EQEP_CONFIG_NO_SWAP));
|
||||
EQEP_setEmulationMode(EQEP1_BASE, EQEP_EMULATIONMODE_RUNFREE);
|
||||
|
||||
//
|
||||
// Configure the position counter to reset on an index event
|
||||
//
|
||||
EQEP_setPositionCounterConfig(EQEP1_BASE, EQEP_POSITION_RESET_IDX,
|
||||
0xFFFFFFFF);
|
||||
|
||||
//
|
||||
// Enable the unit timer, setting the frequency to 100 Hz
|
||||
//
|
||||
EQEP_enableUnitTimer(EQEP1_BASE, (DEVICE_SYSCLK_FREQ / 100));
|
||||
|
||||
//
|
||||
// Configure the position counter to be latched on a unit time out
|
||||
//
|
||||
EQEP_setLatchMode(EQEP1_BASE, EQEP_LATCH_UNIT_TIME_OUT);
|
||||
|
||||
//
|
||||
// Enable the eQEP1 module
|
||||
//
|
||||
EQEP_enableModule(EQEP1_BASE);
|
||||
|
||||
//
|
||||
// Configure and enable the edge-capture unit. The capture clock divider is
|
||||
// SYSCLKOUT/64. The unit-position event divider is QCLK/32.
|
||||
//
|
||||
EQEP_setCaptureConfig(EQEP1_BASE, EQEP_CAPTURE_CLK_DIV_64,
|
||||
EQEP_UNIT_POS_EVNT_DIV_32);
|
||||
EQEP_enableCapture(EQEP1_BASE);
|
||||
}
|
||||
|
||||
//
|
||||
// Function to configure ePWM1 to generate a 5 kHz signal.
|
||||
//
|
||||
void initEPWM(void)
|
||||
{
|
||||
//
|
||||
// Disable the ePWM time base clock before configuring the module
|
||||
//
|
||||
SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
|
||||
|
||||
//
|
||||
// Set phase shift to 0 and clear the time base counter
|
||||
//
|
||||
EPWM_setPhaseShift(EPWM1_BASE, 0);
|
||||
EPWM_setTimeBaseCounter(EPWM1_BASE, 0);
|
||||
|
||||
//
|
||||
// Disable the shadow load; the load will be immediate instead
|
||||
//
|
||||
EPWM_disableCounterCompareShadowLoadMode(EPWM1_BASE,
|
||||
EPWM_COUNTER_COMPARE_A);
|
||||
EPWM_disableCounterCompareShadowLoadMode(EPWM1_BASE,
|
||||
EPWM_COUNTER_COMPARE_B);
|
||||
|
||||
//
|
||||
// Set the compare A value to half the period value, compare B to 0
|
||||
//
|
||||
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, PRD_VAL/2);
|
||||
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_B, 0);
|
||||
|
||||
//
|
||||
// Set action qualifier behavior on compare A events
|
||||
// - EPWM1A --> 1 when CTR = CMPA and increasing
|
||||
// - EPWM1A --> 0 when CTR = CMPA and decreasing
|
||||
//
|
||||
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
|
||||
EPWM_AQ_OUTPUT_HIGH,
|
||||
EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
|
||||
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
|
||||
EPWM_AQ_OUTPUT_LOW,
|
||||
EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
|
||||
|
||||
//
|
||||
// Set action qualifier behavior on compare B events
|
||||
// - EPWM1B --> 1 when CTR = PRD and increasing
|
||||
// - EPWM1B --> 0 when CTR = 0 and decreasing
|
||||
//
|
||||
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_B,
|
||||
EPWM_AQ_OUTPUT_HIGH,
|
||||
EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
|
||||
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_B,
|
||||
EPWM_AQ_OUTPUT_LOW,
|
||||
EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
|
||||
|
||||
//
|
||||
// Enable interrupt when the counter is equal to PRD
|
||||
//
|
||||
EPWM_setInterruptSource(EPWM1_BASE, EPWM_INT_TBCTR_PERIOD);
|
||||
EPWM_enableInterrupt(EPWM1_BASE);
|
||||
|
||||
//
|
||||
// Interrupt on first event
|
||||
//
|
||||
EPWM_setInterruptEventCount(EPWM1_BASE, 1);
|
||||
|
||||
//
|
||||
// Set the time base clock prescaler to /1
|
||||
//
|
||||
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1,
|
||||
EPWM_HSCLOCK_DIVIDER_1);
|
||||
|
||||
//
|
||||
// Set the period value; don't shadow the register
|
||||
//
|
||||
EPWM_setPeriodLoadMode(EPWM1_BASE, EPWM_PERIOD_DIRECT_LOAD);
|
||||
EPWM_setTimeBasePeriod(EPWM1_BASE, PRD_VAL);
|
||||
|
||||
//
|
||||
// Put the time base counter into up-down count mode
|
||||
//
|
||||
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP_DOWN);
|
||||
|
||||
//
|
||||
// Sync the ePWM time base clock
|
||||
//
|
||||
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
|
||||
}
|
||||
|
||||
//
|
||||
// ePWM1 ISR--interrupts once every 4 QCLK counts (one period)
|
||||
//
|
||||
__interrupt void epwmISR(void)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
//
|
||||
// Position speed and measurement
|
||||
//
|
||||
PosSpeed_calculate(&posSpeed);
|
||||
|
||||
//
|
||||
// Control loop for position control and speed control
|
||||
//
|
||||
interruptCount++;
|
||||
if(interruptCount == 1000)
|
||||
{
|
||||
//
|
||||
// Pulse index signal (1 pulse/rev)
|
||||
//
|
||||
GPIO_writePin(2, 1);
|
||||
for(i = 0; i < 700; i++)
|
||||
{
|
||||
;
|
||||
}
|
||||
GPIO_writePin(2, 0);
|
||||
}
|
||||
|
||||
//
|
||||
// Clear interrupt flag and issue ACK
|
||||
//
|
||||
EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);
|
||||
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
|
||||
}
|
||||
Reference in New Issue
Block a user