//###########################################################################
//
// FILE:   Example_freqcal.c
//
// TITLE:  EXAMPLE_FREQCAL_C Frequency Calculation
//
//!  \addtogroup f2833x_example_list
//!  \section EXAMPLE_FREQCAL_C Frequency Calculation (Example_freqal.c)
//!
//!  This file includes the EQEP initialization and frequency calculation
//!  functions called by \b Example_2833xEqep_freqcal.c.  
//!  The frequency calculation steps performed by FREQCAL_Calc()at  
//!  SYSCLKOUT = 150 MHz and 100 MHZ are described below:
//!
//!  -# This program calculates: \b **freqhz_fr** for SYSCLKOUT = 150MHz \n
//!  \f[ freqhz\_fr\ or\ v = \frac{x_{2}-x_{1}}{T} .......... 1 \f] \n
//!  If \f[ \frac{max}{base}\ freq = 10kHz => 10kHz = \
\frac{x_{2}-x_{1}}{(2/100Hz)} .......... 2\f] \n
//!  \f[ max (x_{2}-x_{1}) = 200 counts = freqScaler\_fr \f]
//!
//!  \note \f$ T = \frac{2}{100Hz} \f$ . 2 is from \f$ \frac{x_{2}-x_{1}}{2}\f$
//!  because QPOSCNT counts 2 edges per cycle (rising and falling)
//!
//!  If both sides of Equation 2 are divided by 10 kHz, then: \n
//!  \f[ 1 = \frac{x_{2}-x_{1}}{10kHz*(2/100Hz)}\f]\n where, 
//!  \f[ [10kHz*\frac{2}{100Hz}] = 200 \f]\n
//!  Because \f[ x_{2}-x_{1} < 200 (max)\f]
//!  \f[ \frac{x_{2}-x_{1}}{200} < 1 \f]\n for all frequencies less than max\n
//!  \f[ freq\_fr = \frac{x_{2}-x_{1}}{200}\ or\ \
\frac{x_{2}-x_{1}}{10kHz*(2/100Hz)} .......... 3\f] \n
//!
//!  To get back to original velocity equation, Equation 1, multiply 
//!  Equation 3 by 10 kHz\n
//!  \f[ freqhz\_fr(or\ velocity) = \
10kHz*\frac{x_{2}-x_{1}}{10kHz*(2/100Hz)}\f]\n
//!  \f[ = \frac{x_{2}-x_{1}}{(2/100Hz)} .......... final\ equation\f] \n
//!
//!  -# \b **min \b freq** \f$ = \frac{1\ count}{(2/100Hz)} = 50 Hz\f$
//!  -# \b **freqhz_pr** \n
//!  \f[ freqhz\_pr\ or\ v = \frac{X}{t_{2}-t_{1}} .......... 4\f] \n
//!  If \f[ \frac{max}{base}\ freq = 10kHz => 10kHz = \frac{(4/2)}{T} = \
\frac{4}{2T} \f] \n
//!  where,
//!    - 4 = QCAPCTL [UPPS] (Unit timeout - once every 4 edges)
//!    - 2 = divide by 2 because QPOSCNT counts 2 edges per cycle 
//!          (rising and falling)
//!    - T = time in seconds
//!        = \f$ \frac{t_{2}-t_{1}}{(150MHz/128)}, t_{2}-t_{1} \f$ = 
//!         # of QCAPCLK cycles,
//!        \n and \f$ 1\ QCAPCLK\ cycle = \frac{1}{(150MHz/128)} = QCPRDLAT \f$
//!
//!  So: \f[ 10 kHz = 4*\frac{(150MHz/128)}{2*(t_{2}-t_{1})} \f] \n
//!  \f[ t_{2}-t_{1} = 4*\frac{(150MHz/128)}{10kHz*2} = \
\frac{(150MHz/128)}{((2*10KHz)/4)} .......... 5\f] \n
//!  \f[ = 234\ QCAPCLK\ cycles = maximum (t_{2}-t_{1})  = freqScaler\_pr \f]
//!  Divide both sides by \f$ (t_{2}-t_{1}) \f$, and:\n
//!  \f[ 1 = \frac{234}{t_{2}-t_{1}} = \
\frac{(150MHz/128)/((2*10KHz)/4)}{t_{2}-t_{1}} \f]\n
//!  Because \f$ (t_{2}-t_{1}) < 234 (max) \f$,
//!  \f$ \frac{234}{t_{2}-t_{1}} < 1 \f$ for all frequencies less than max \n
//!  \f[ freq\_pr = \frac{234}{t_{2}-t_{1}}\ or\ \
\frac{(150MHz/128)/((2*10KHz)/4)}{t_{2}-t_{1}} .......... 6\f] \n
//!  Now within velocity limits, to get back to original velocity equation, 
//!  Equation 1, multiply Equation 6 by 10 kHz: \n
//!  \f[ freqhz\_fr(or\ velocity) = \
10kHz*\frac{(150MHz/128)/((2*10KHz)/4)}{t_{2}-t_{1}}\f]\n
//!  \f[ = \frac{(150MHz/128)*4}{2*(t_{2}-t_{1})} \f]\n
//!  or 
//!  \f[ \frac{4}{2*(t_{2}-t_{1})*(QCPRDLAT)} .......... final\ equation\f] \n
//!
//!  For 100 MHz Operation:
//!
//!  The same calculations as above are performed, but with 100 MHz
//!  instead of 150MHz when calculating freqhz_pr, and at UPPS of 8 
//!  instead of 4. The value for freqScaler_pr becomes: 
//!  (100MHz/128)/(2*10kHz/8) = 313
//!
//!  More detailed calculation results can be found in the Example_freqcal.xls
//!  spreadsheet included in the example folder.
//
//###########################################################################
// $TI Release: $
// $Release Date: $
// $Copyright:
// Copyright (C) 2009-2023 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 "DSP28x_Project.h"     // Device Headerfile and Examples Include File
#include "Example_freqcal.h"    // Example specific include file

//
// FREQCAL_Init - 
//
void
FREQCAL_Init(void)
{
#if (CPU_FRQ_150MHZ)
    EQep1Regs.QUPRD=1500000;	// Unit Timer for 100Hz at 150MHz SYSCLKOUT
#endif
#if (CPU_FRQ_100MHZ)
    EQep1Regs.QUPRD=1000000;	// Unit Timer for 100Hz at 100MHz SYSCLKOUT
#endif

    EQep1Regs.QDECCTL.bit.QSRC=2;		// Up count mode (freq. measurement)
    EQep1Regs.QDECCTL.bit.XCR=0;        

    EQep1Regs.QEPCTL.bit.FREE_SOFT=2;
    EQep1Regs.QEPCTL.bit.PCRM=00;		// QPOSCNT reset on index evnt
    EQep1Regs.QEPCTL.bit.UTE=1; 		// Unit Timer Enable
    EQep1Regs.QEPCTL.bit.QCLM=1; 		// Latch on unit time out
    EQep1Regs.QPOSMAX=0xffffffff;
    EQep1Regs.QEPCTL.bit.QPEN=1; 		// QEP enable

#if (CPU_FRQ_150MHZ)
    EQep1Regs.QCAPCTL.bit.UPPS=2;  // 1/4 for unit position at 150MHz SYSCLKOUT
#endif
#if (CPU_FRQ_100MHZ)
    EQep1Regs.QCAPCTL.bit.UPPS=3;  // 1/8 for unit position at 100MHz SYSCLKOUT
#endif

    EQep1Regs.QCAPCTL.bit.CCPS=7;		// 1/128 for CAP clock
    EQep1Regs.QCAPCTL.bit.CEN=1; 		// QEP Capture Enable
}

//
// FREQCAL_Calc - 
//
void 
FREQCAL_Calc(FREQCAL *p)
{
    unsigned long tmp;
    _iq newp,oldp;

    //
    // Freq Calculation using QEP position counter
    // Check unit Time out-event for speed calculation
    //
    
    //
    // Unit Timer is configured for 100Hz in INIT function
    //

    //
    // For a more detailed explanation of the calculation, read
    // the description at the top of this file
    //
    if(EQep1Regs.QFLG.bit.UTO==1)  // Unit Timeout event
    {
        //
        // Differentiator
        //
        newp=EQep1Regs.QPOSLAT;         // Latched POSCNT value
        oldp=p->oldpos;

        if (newp>oldp)
        {
            tmp = newp - oldp;          // x2-x1 in v=(x2-x1)/T equation
        }
        else
        {
            tmp = (0xFFFFFFFF-oldp)+newp;
        }

        //
        // p->freq_fr = (x2-x1)/(T*10KHz)
        //
        p->freq_fr = _IQdiv(tmp,p->freqScaler_fr);
        tmp=p->freq_fr;

        if (tmp>=_IQ(1))
        {
            p->freq_fr = _IQ(1);
        }
        else
        {
            p->freq_fr = tmp;
        }

        //
        // Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
        // p->freqhz_fr = (p->freq_fr)*10kHz = (x2-x1)/T
        //
        p->freqhz_fr = _IQmpy(p->BaseFreq,p->freq_fr);

        //
        // Update position counter
        //
        p->oldpos = newp;

        EQep1Regs.QCLR.bit.UTO=1;		// Clear interrupt flag
    }

    //
    // Freq Calculation using QEP capture counter
    //
    if(EQep1Regs.QEPSTS.bit.UPEVNT==1)        // Unit Position Event
    {
        if(EQep1Regs.QEPSTS.bit.COEF==0)      // No Capture overflow
        {
            tmp=(unsigned long)EQep1Regs.QCPRDLAT;
        }
        else	            // Capture overflow, saturate the result
        {
            tmp=0xFFFF;
        }

        //
        // p->freq_pr = X/[(t2-t1)*10KHz]
        //
        p->freq_pr = _IQdiv(p->freqScaler_pr,tmp);
        tmp=p->freq_pr;

        if (tmp>_IQ(1))
        {
            p->freq_pr = _IQ(1);
        }
        else
        {
            p->freq_pr = tmp;
        }

        //
        // Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
        // p->freqhz_pr =( p->freq_pr)*10kHz = X/(t2-t1)
        //
        p->freqhz_pr = _IQmpy(p->BaseFreq,p->freq_pr);
        
        //
        // Clear Unit position event flag
        // Clear overflow error flag
        //
        EQep1Regs.QEPSTS.all=0x88;
    }
}

//
// End of File
//

