/*******************************************************************************
* FILE NAME: etpu_rslv.c          COPYRIGHT (c) Freescale Semiconductor 2009
*                                               All Rights Reserved
* DESCRIPTION START
* =================
*
* INTRODUCTION
* ------------
*
* This file contains the eTPU Function implementing software interface for
* resolver.
*
* The resolver software interface can be viewed as a callable discrete routine,
* which implements special discrete state function: the Angle Tracking
* Observer.  The routine can be accessed by several methods.
*
* The Angle Tracking Observer algorithm is based on the integrator and PI
* regulator connected in series and closed by the unit feedback loop.  The
* error is computed as the sine of difference of the input (from the resolver)
* and output (from computations) angles.
*
* As input to the Angle Tracking Observer, the angle in form of since and
* cosine signals from the resolver are provided.  On output The Angle Tracking
* Observer computes rotor position and angular velocity.
*
* The Angle Tracking Observer transfer function can be expressed as:
*
*     F(s) = Phi_in/Phi_out = K1*(1 + K2*s)/(s^2 + K1*K2*s + K1)
*
* where Phi_in is the input and Phi_out the computed angle.
*
* Apart from the Angle Tracking Observer algorithm, the function provides
* capability of generating left aligned PWM wave.  The PWM wave can be used,
* for example, as a triggering source for ADC conversion.
*
* Access to the Angle Tracking Observer routine as well as callback features of
* the resolver interface are described below.
*
*
* INTERFACE
* ---------
*
* There are three ways the Angle Tracking Observer routine can be called.
* First, by issuing Host Service Request (see fs_etpu_rslv_compute()), secondly
* periodically by specifying period and delay within the period at which the
* routine needs to be invoked (see operating modes: FS_ETPU_RSLV_MODE_MASTER,
* FS_ETPU_RSLV_MODE_PERIODIC and FS_ETPU_RSLV_MODE_NOPERIODIC, the functions:
* fs_etpu_rslv_enable_periodic(), fs_etpu_rslv_disable_periodic(), and the
* fs_etpu_rslv_init() function parameters: period and delay) and thirdly
* through link from another channel.
*
* Particularily if a CMPT Host Service Request is issued (see the function
* fs_etpu_rslv_compute) or a link from another channel is received, the Angle
* Tracking Observer routine is executed once.  The execution takes place also
* when the function is configured to execute the Angle Tracking Observer
* routine periodically.
*
* At the end of the Angle Tracking Observer computation the resolver interface
* can, if enabled, issue CPU interrupt or DMA request or a link to another
* channel.  The rate at which CPU interrupt or link is issued can be controlled
* by fs_etpu_rslv_init() function arguments: rate_irq, rate_link.  At the rate
* equal 0, an CPU interrupt or link to another channel is issued at every
* invocation of the Angle Tracking Observer routine, at the rate of 1 at every
* second, at the rate of 2 at every third ... and so on.
*
* During computation of the Angle Tracking Observer routine some flags are set
* or cleared to show state of the computation. Please see the description
* below.
*
* An invocation and computation of the Angle Tracking Observer routine runs
* through a few steps:
*
*   - if the Angle Tracking Observer routine is invoked, it assumes
*     ready to use input data (sinA, cosA) have been placed (see the
*     function fs_etpu_rslv_set_sincos())
*
*   - computation is started
*
*   - the sine and cosine values are scaled by shifting left by a specified
*     amount (see the function fs_etpu_rslv_init() argument scale)
*
*   - to the sine and cosine values the dc_offset value is added (see the
*     function fs_etpu_rslv_init() argument dc_offset)
*
*   - at the time point, after which the input data will no longer be used at
*     current routine invocation, the flag FS_ETPU_RSLV_STATE_DATAIN is cleared
*     in the state parameter (see fs_etpu_rslv_get_state())
*
*   - computation continues
*
*   - at the time point when all the output data are ready for use, the
*     FS_ETPU_RSLV_STATE_DATAOUT is set in the state parameter
*     (see fs_etpu_rslv_get_state())
*
*   - at the end of the Angle Tracking Observer routine, a CPU interrupt
*     or a DMA request or a link to another channel is issued, if enabled and
*     if rate counter reaches 0.
*   
* The routine does not check whether the data flags are clear or set before
* modification.  This needs to be performed on the application side (if
* needed).
*
* The issue of the eTPU link request is controlled by two mechanisms: (1) at
* the initialization call (see the operating mode FS_ETPU_RSLV_MODE_LINK, the
* arguments rate_link, link_chan and the API call fs_etpu_rslv_init())
* and (2) during operation by API calls: fs_etpu_rslv_enable_link() and
* fs_etpu_rslv_disable_link().
*
* The position of the resolver is represented by three values: angle, angle
* offset and a number of revolution. 
*
* Angle is the numerical value used by the Angle Tracking Observer for
* computation.  The offset is additional value, by which angle is adjusted
* (shifted).  The real resolver position can be computed as:
*   
*   position = angle + offset
*   position_abs = position + revolutions*2*pi
*
* where position is a position within one revolution, position_abs is the
* absolute rotor position.  To acquire position and number of revolutions
* please use fs_etpu_rslv_get_position() and fs_etpu_rslv_get_revolutions().
* To set the offset the function fs_etpu_rslv_set_position() should be used.
*
* To acquire angular velocity please use the function fs_etpu_rslv_get_speed().
*
* The Angle Tracking Observer Algorithm can be initialized in two ways: (1) by
* reset (see fs_etpu_rslv_reset()) or (2) by forcing to specific steady-state
* (see fs_etpu_rslv_steadstate()).  Note that the fs_etpu_rslv_steadystate()
* function needs to be called at the time the Angle Tracking Observer routine
* is NOT computing.
*
* In MASTER operating mode the resolver interface can generate a left-aligned
* PWM wave defined by two parameters: period and duty cycle. The PWM wave
* parameters can be defined at initialization (see the function
* fs_etpu_rslv_init() arguments: period and duty) or while the channel is
* running (see fs_etpu_rslv_set_period() and fs_etpu_rslv_set_duty()).  While
* the channel is running, any change to period and duty will not be effective
* until call to fs_etpu_rslv_update().  If the function fs_etpu_rslv_update()
* is called, the channel will finish the current period and will apply the new
* values from the next period.
*
* In an appropriate operating mode (MASTER and PERIODIC) the resolver interface
* will periodically invoke the Angle Tracking Observer routine once in every
* period.  The time of invocation is defined by the fs_etpu_rslv_init()
* function argument delay. While the channel is running, the delay time can be
* changed by the call to the fs_etpu_rslv_set_duty() function.  The change will
* be effective after the call to fs_etpu_rslv_update().  Similarily to the
* parameters period and duty, the channel will finish the current period and
* will apply the new value from the next period.
*
*
* OPERATING MODES
* ---------------
*
* The channel may operate in various operating modes.  The operating mode
* can be set by the call to fs_etpu_rslv_init() function through the
* argument mode.
*
* The mode value should be calculated by oring various operating mode defines.
* If an option is marked as default, it does not need to be ored.
*
* The mode value are grouped so that only one mode in group can be active. If
* no mode from a group is specified then the one marked as default will
* prevails.  If both the default and a non-default modes are specified the
* non-default value prevails.
*
* Usually operating modes can be set only at the call to the
* fs_etpu_rslv_init() (channel initialization), however some of them can be
* changed as the channel is running, which is indicated.
*
* - FS_ETPU_RSLV_MODE_PERIODIC
*   FS_ETPU_RSLV_MODE_NOPERIODIC (default)
*   FS_ETPU_RSLV_MODE_ONREQEST (synonym to FS_ETPU_RSLV_MODE_NOPERIODIC)
*   Specifies whether computation of the Angle Tracking Observer algorithm
*   occurs periodically, once in every period, or only on host service or link
*   request.  If the FS_ETPU_RSLV_MODE_PERIODIC mode is set then the Angle
*   Tracking Observer algorithm will be called once in every period.  If the
*   FS_ETPU_RSLV_MODE_NOPERIODIC mode is set then the Angle Tracking Observer
*   Algorithm will not be called once in every period and only on host service
*   or link request. The option is effective only if a channel is specified to
*   generate PWM output (see FS_ETPU_RSLV_MODE_CONTROL_MASTER/SLAVE).  This
*   operating mode can be enabled or disabled while the channel is running (see
*   the functions: fs_etpu_rslv_enable_periodic() and
*   fs_etpu_rslv_disable_periodic()).
*
* - FS_ETPU_RSLV_MODE_CONTROL_MASTER
*   FS_ETPU_RSLV_MODE_CONTROL_SLAVE (default)
*   FS_ETPU_RSLV_MODE_MASTER (synonym to FS_ETPU_RSLV_MODE_CONTROL_MASTER)
*   FS_ETPU_RSLV_MODE_SLAVE (synonym to FS_ETPU_RSLV_MODE_CONTROL_SLAVE)
*   Specifies whether the channel generates PWM output or not.  If
*   FS_ETPU_RSLV_MODE_MASTER is set then the PWM wave will be generated.  If
*   FS_ETPU_RSLV_MODE_SLAVE is set then the PWM wave will not be generated.
*   Some other modes of operation are dependent on this mode.  If
*   FS_ETPU_RSLV_MODE_CONTROL_SLAVE is selected, then the modes:
*   FS_ETPU_RSLV_MODE_TIMEBASE_TCR1|TCR2, FS_ETPU_RSLV_MODE_START_ABS/REL,
*   FS_ETPU_RSLV_MODE_PERIODIC/NOPERIODIC do not have any effect.
*
* - FS_ETPU_RSLV_MODE_START_REL (default)
*   FS_ETPU_RSLV_MODE_START_ABS
*   Specifies whether the channel computes the start time of PWM generation
*   relatively to the current time-base counter value or uses directly the
*   start_offset parameter.  If FS_ETPU_RSLV_MODE_START_ABS is chosen, the
*   start time of PWM generation is taken directly from the start_offset
*   parameter.  Otherwise (FS_ETPU_RSLV_MODE_START_REL) the start time of PWM
*   generation is computed as as the sum of: the current value of the time-base
*   counter, one period and the start_offset parameter.  The mode is effective
*   only if FS_ETPU_RSLV_MODE_MASTER is chosen.
*
* - FS_ETPU_RSLV_MODE_TIMEBASE_TCR1 (default)
*   FS_ETPU_RSLV_MODE_TIMEBASE_TCR2
*   FS_ETPU_RSLV_MODE_TCR1 (synonym to FS_ETPU_RSLV_MODE_TIMEBASE_TCR1)
*   FS_ETPU_RSLV_MODE_TCR2 (synonym to FS_ETPU_RSLV_MODE_TIMEBASE_TCR2)
*   Specifies whether timer counter TCR1 or TCR2 is used.  The mode is effective
*   only if FS_ETPU_RSLV_MODE_MASTER is chosen.
*
* - FS_ETPU_RSLV_MODE_LINK
*   FS_ETPU_RSLV_MODE_NOLINK (default)
*   Specifies whether a link request is issued at the end of the Angle Tracking
*   Observer computation.  This operating mode can be enabled or disabled as
*   the channel is running (see the functions: fs_etpu_rslv_enable_link() and
*   fs_etpu_rslv_disable_link()).
* 
* The mode of operation can be read in retrospect from the channel function
* state parameter (see fs_etpu_rslv_get_state()).  To analyse the channel
* function state the defines related to the state parameter (infix _STATE_)
* included in the etpu_rslv_auto.h file should be used.  It should be noticed
* that the state parameter contains operating modes recorded at the call to the
* fs_etpu_rslv_init() function.  If an operating mode is changed while the
* channel is running, it will not be reflected in the state parameter.
*
* In the file etpu_rslv.h many aliases for most common operating modes are
* defined. These aliases are used by ETPU Graphical Configuration Tool for
* computing computational load of the eTPU module.
*
* USAGE SPECIAL CONSIDERATION
* ---------------------------
*
* The resolver interface is designed in the way that it performs especially
* efficiently under some conditions, which are referred as usual conditions:
*
* - start and end of the pulse with the PWM wave and computation of the
*   Angle Tracking Observer routine do NOT occur at the same time 
*
* - all three events (start, end of the pulse and computation) are enough
*   far away from each other, so that the next event is always scheduled
*   for timer counter values after the current value (future events)
*
* If the conditions are not met, the resolver eTPU function will operate
* correctly, however needs to handle simultaneous events, which deteriorates
* the function performance.
*
* The resolver eTPU function possesses a mechanism to detect whether it is in
* or out of synchronization.  The mechanism consists in checking whether the
* beginning of the next PWM period can be scheduled after the current timer
* counter value or not.  If the beginning of the next PWM period cannot be
* scheduled after the current timer counter value, then the resolver eTPU
* function will consider to be out of synchronization and will prevent the
* Angle Tracking Observer routine from computing.  This mechanisms is provided
* to stop computing in the state of desynchronization. 
*
* If the usual conditions are not met, some events may be scheduled before a
* current timer counter value regardless of scheduling latency.  For example,
* this may be the case if the end of the pulse and the computing event are
* scheduled at its maximum value, which is the period minus 1.  This may
* indicate desynchronization to the resolver eTPU function, which will prevent
* the Angle Tracking Observer routine from computing. 
*
* If for any reason, for example a huge latency, the resolver eTPU function
* becomes desynchronized with a current timer counter value, it will try to
* catch up to the timer counter value by requesting service after service to
* the scheduler as long as it stays behind the timer counter value.  During
* this time the Angle Tracking Observer computations are not performed and the
* channel output is driven low.
*
* The resolver eTPU function provides a special mechanism to signal whether
* simultaneous events were serviced or not.  If so, the flag
* FS_ETPU_RSLV_STATE_DBLEVN  in the state parameter is set.
*
* The resolver eTPU function also provides a mechanism to signal whether the
* Angle Tracking Observer routine was not called, because desynchronization was
* detected.  If so the flag FS_ETPU_RSLV_STATE_DESYNC in the state parameter is
* set.
*
* Due to computational reasons the Angle Tracking Observer algorithm does not
* use the coefficients (the first K1 and the second K2) directly, but split
* them into multiplication factor (_d suffix) and scaling constant (_scale
* suffix):
*     
*     K1 = k1_d*2^(-k1_scale)
*     K2 = k2_d*2^k2_scale
*
* It should be noticed that the above description about K1, K2 and scale
* parameters is valid only in context of the initialization routine.  For
* computational purposes the K1, K2 are treated slightly different.  See the
* etpuc_rslv.c file for details.  The same note applies for the scale
* parameter.
*  
* 
* COMPUTATION OF ANGLE TRACKING OBSERVER PARAMETERS
* -------------------------------------------------
*
* The parameters needed to initialize the Angle Tracking Observer can
* be computed from the following Matlab function:
*
* function [K1_D, K2_D, K1_SCALE, K2_SCALE, er1, er2, K1, K2] = ...
*     trackpar(F0, D, Fs);
* %
* % [K1_D, K2_D, K1_SCALE, K2_SCALE, er1, er2] = trackpar(F0, D, Fs);
* %
* % Function calculates parameters of tracking observer.
* % Input parameter:
* %   F0 - natural frequency of tracking observer [Hz]
* %   D  - damping factor [-]
* %   Fs - sampling frequency [Hz]
* %
* % Output parameters are calculated according to these formulas:
* %   K1 = (2*pi*F0/Fs)^2 / pi
* %   K2 = 2*D/(2*pi*F0/Fs)
* %
* % Example:
* %   F0 = 100; D = 0.2; Fs = 8000;
* %   [K1_D, K2_D, K1_SCALE, K2_SCALE, er1, er2, K1, K2] ...
* %       = trackdempar(F0, D, Fs)
* 
* format long
* Q = 1/(2*D);					% quality factor
* K1 = (2*pi*F0/Fs)^2/pi;		% "Omega0^2" = (2*pi*F0/Fs)^2
* K2 = 2*D/(2*pi*F0/Fs);		% "2*Delta/Omega0" = Delta/(2*pi*F0)*Fs
* K1_SCALE = floor(log2(1/K1));
* K2_SCALE = ceil(log2(K2));
* K1_D = K1*2^K1_SCALE;
* K2_D = K2/2^K2_SCALE;
* er1 = K1-K1_D/2^K1_SCALE;   % test if calculation is OK, should be 0
* er2 = K2-K2_D*2^K2_SCALE;   % test if calculation is OK, should be 0
* 
* return;
*
* DESCRIPTION END
* ===============
*
*===============================================================================
* REV      AUTHOR      DATE        DESCRIPTION OF CHANGE
* ---   -----------  ----------    ---------------------
* 0.1   r29302       10/Feb/09     Initial file version.
* 0.2   r29302       16/MAR/09     Alfa release, several featured added.
* 1.0   r29302       30/MAR/09     First official release.
* 1.1   r54529       12/JAN/11     Separate dc offsets for sin and cos.
* 1.2   r54529       31/JAN/11     Resolver fault diagnostics added.
*******************************************************************************/

#include "etpu_util.h"		    /* Utility routines for working eTPU */
#include "etpu_rslv.h"			/* eTPU PWM API defines */

extern uint32_t fs_etpu_data_ram_start;

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_init
*
*PURPOSE      : Initializes an eTPU channel for the RSLV function.
*
*INPUTS NOTES : This function has several parameters:
*    channel  - This is the channel number.
*               0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*    priority - This is the priority to assign to the channel.
*               This parameter should be assigned a value of:
*               FS_ETPU_PRIORITY_HIGH
*               FS_ETPU_PRIORITY_MIDDLE
*               FS_ETPU_PRIORITY_LOW
*               FS_ETPU_PRIOTITY_DISABLE
*    mode     - This is the channel operating mode.  One or more of the
*               following defines should be ored, the entries marked as
*               default do not need to be specified:
*               FS_ETPU_RSLV_MODE_MASTER_<NO>PERIODIC_<NO>LINK
*               FS_ETPU_RSLV_MODE_MASTER_<NO>PERIODIC_<NO>LINK_<TCR1|TCR2>
*               FS_ETPU_RSLV_MODE_SLAVE_<NO>LINK
*               FS_ETPU_RSLV_MODE_PERIODIC
*               FS_ETPU_RSLV_MODE_NOPERIODIC (default)
*               FS_ETPU_RSLV_MODE_ONREQEST
*               FS_ETPU_RSLV_MODE_CONTROL_MASTER
*               FS_ETPU_RSLV_MODE_CONTROL_SLAVE (default)
*               FS_ETPU_RSLV_MODE_MASTER
*               FS_ETPU_RSLV_MODE_SLAVE
*               FS_ETPU_RSLV_MODE_START_REL (default)
*               FS_ETPU_RSLV_MODE_START_ABS
*               FS_ETPU_RSLV_MODE_TIMEBASE_TCR1 (default)
*               FS_ETPU_RSLV_MODE_TIMEBASE_TCR2
*               FS_ETPU_RSLV_MODE_TCR1
*               FS_ETPU_RSLV_MODE_TCR2
*               FS_ETPU_RSLV_MODE_LINK
*               FS_ETPU_RSLV_MODE_NOLINK (default)
*               Strings in <> can be omitted or choosen from.
*    period   - This is a period of the left aligned pulse-width waveform
*               generated by the channel.  The period is expressed as 24-bit
*               unsigned integer in the time base ticks.
*    duty     - This is the duty cycle of the left-aligned
*               pulse-width waveform generated by the channel.
*               The duty cycle is expressed as 24-bit unsigned integer
*               in time base ticks.  The valid range for the parameter
*               is from 0 to period - 1.  For the best performance the parameters
*               duty and delay should be different.
*    delay    - This is the delay between start of the pwm wave
*               and the start of the angle tracking observer computation.  the
*               delay is expressed as 24-bit unsigned integer in time base
*               ticks.  the valid range for the parameter is from 0 to
*               period - 1.  For the best performance the parameters duty and
*               delay should be different.
*    sample_delay -	This parameter is the delay between the RSLV excitation
*               signal rising edge and the sin/cos A/D conversion trigger.
*               The sample_delay is expressed as 24-bit unsigned integer
*               in time base ticks.
*    start_offset - This parameter defines when generation of the PWM wave is
*               activated.  By default, the sum of this parameter and one
*               period specifies a time offset relatively to the current value
*               of a time base before a PWM wave is started.  The parameter is
*               a signed 24-bit integer and can be positive or negative.  By
*               default the mode FS_ETPU_RSLV_MODE_START_REL is active.  If the
*               mode FS_ETPU_RSLV_MODE_START_ABS is selected, then this
*               parameter will define the absolute time when PWM generation
*               starts.
*   gain_sin  - Gain applied to the sin signal from the resolver before
*               the use by the Angle Tracking Observer. 
*               This gain has 2 purposes:
*               1. scale the sin sample into 24-bit signed fractional range
*               2. compensate possible amplitude difference between sin and cos. 
*   gain_cos  - Gain applied to the cos signal from the resolver before
*               the use by the Angle Tracking Observer. 
*               This gain has 2 purposes:
*               1. scale the cos sample into 24-bit signed fractional range
*    dc_offset_sin - Value added to sin signal from the resolver after scaling
*               operation and before use by the Angle Tracking Observer.
*    dc_offset_cos - Value added to cos signal from the resolver after scaling
*               operation and before use by the Angle Tracking Observer.
*    link_chan - Channel number the link is sent to. The channel number needs
*               be right aligned and in line with the format of the eTPU LINK
*               register.
*    rate_irq - Number of the Angle Tracking Observer iterations per one
*               interrupt request.  0 (zero) means one iteration per one
*               interrupt request, 1 means two iterations per one interrupt
*               request, ...  and so on.
*    rate_link - Number of the Angle Tracking Observer iterations per one
*               link request.  0 (zero) means one iteration per one link
*               request, 1 means two iterations per one link request, ...
*               and so on.
*    k1_d     - Multiplication factor of the first Angle Tracking
*               Observer coefficient. It is signed 24-bit fractional number.
*    k1_scale - Scaling constant of the first Angle Tracking 
*               Observer coefficient.  It is unsigned 24-bit integer and must
*               be greater or equal 1.
*    k2_d     - Multiplication factor of the second Angle Tracking
*               Observer coefficient. It is unsigned 24-bit fraction number.
*    k2_scale - Scaling constant of the second Angle Tracking
*               Observer coefficient.   It is unsigned 24-bit integer and must
*               be greater equal 0.
*RETURNS NOTES: Error code if channel could not be initialized.  Error code that
*               can be returned are: FS_ETPU_ERROR_MALLOC ,
*               FS_ETPU_ERROR_VALUE
*WARNING      : This function does not configure the pin only the eTPU.  In a
*               system a pin may need to be configured to select the eTPU.
******************************************************************************/

int32_t fs_etpu_rslv_init( uint8_t channel,
                           uint8_t priority,
                           uint32_t mode,
                           uint32_t period,
                           uint32_t duty,
                           uint32_t delay,
                           int32_t start_offset,
                           uint32_t sample_delay,
                           int32_t gain_sin,
                           int32_t gain_cos,
                           int32_t dc_offset_sin,
                           int32_t dc_offset_cos,
                           uint8_t link_chan,
                           uint32_t rate_irq,
                           uint32_t rate_link,
                           int32_t k1_d,
                           int32_t k1_scale,
                           int32_t k2_d,
                           int32_t k2_scale)
{
    uint32_t k1_scale_mult;
    uint32_t k2_scale_mult;
    uint32_t state;

    uint32_t *pba;	/* parameter base address for channel */

	/* Disable channel to assign function safely */
	fs_etpu_disable( channel );

    if (eTPU->CHAN[channel].CR.B.CPBA == 0 )
    {
        /* get parameter RAM
        number of parameters passed from eTPU C code */
        pba = fs_etpu_malloc(FS_ETPU_RSLV_NUM_PARMS);

    	if (pba == 0)
    	{
    		return (FS_ETPU_ERROR_MALLOC);
    	}
    }
    else /*set pba to what is in the CR register*/
    {
    	pba=fs_etpu_data_ram(channel);
    }

	/* write parameters to data memory */
	*(pba + ((FS_ETPU_RSLV_PERIOD_OFFSET - 1)>>2)) = period & 0x00ffffff;
	*(pba + ((FS_ETPU_RSLV_DUTY_OFFSET - 1)>>2)) = duty & 0x00ffffff;
	*(pba + ((FS_ETPU_RSLV_DELAY_OFFSET - 1)>>2)) = delay & 0x00ffffff;
	*(pba + ((FS_ETPU_RSLV_START_OFFSET_OFFSET - 1)>>2)) = (uint32_t) start_offset;
	*(pba + ((FS_ETPU_RSLV_SAMPLE_DELAY_OFFSET - 1)>>2)) = (uint32_t) sample_delay;

	*(pba + ((FS_ETPU_RSLV_GAIN_SIN_OFFSET - 1)>>2)) = (uint32_t) gain_sin;
	*(pba + ((FS_ETPU_RSLV_GAIN_COS_OFFSET - 1)>>2)) = (uint32_t) gain_cos;
	*(pba + ((FS_ETPU_RSLV_DC_OFFSET_SIN_OFFSET - 1)>>2)) = (uint32_t) dc_offset_sin;
	*(pba + ((FS_ETPU_RSLV_DC_OFFSET_COS_OFFSET - 1)>>2)) = (uint32_t) dc_offset_cos;

	*(pba + ((FS_ETPU_RSLV_SINA_SMPL_OFFSET - 1)>>2)) = 0;
	*(pba + ((FS_ETPU_RSLV_SINB_SMPL_OFFSET - 1)>>2)) = 0;
	*(pba + ((FS_ETPU_RSLV_COSA_SMPL_OFFSET - 1)>>2)) = 0;
	*(pba + ((FS_ETPU_RSLV_COSB_SMPL_OFFSET - 1)>>2)) = 0;

    *(pba + ((FS_ETPU_RSLV_SINA_MAX_OFFSET - 1)>>2)) = 0;
    *(pba + ((FS_ETPU_RSLV_SINA_MIN_OFFSET - 1)>>2)) = 0;
    *(pba + ((FS_ETPU_RSLV_COSA_MAX_OFFSET - 1)>>2)) = 0;
    *(pba + ((FS_ETPU_RSLV_COSA_MIN_OFFSET - 1)>>2)) = 0;

    *((uint8_t*) pba + FS_ETPU_RSLV_LINK_CHAN_OFFSET) = (uint8_t)64 + link_chan;
	
    k1_scale_mult = (uint32_t) 1<<(23 - k1_scale);
    k2_scale_mult = (uint32_t) 1<<k2_scale;
    *(pba + ((FS_ETPU_RSLV_K1_D_OFFSET - 1)>>2)) =
        ((uint32_t)k1_d);
    *(pba + ((FS_ETPU_RSLV_K1_SCALE_OFFSET - 1)>>2)) = 
        ((uint32_t)k1_scale_mult) & 0x00ffffff;
    *(pba + ((FS_ETPU_RSLV_K2_D_OFFSET - 1)>>2)) =
        ((uint32_t)k2_d) & 0x00ffffff;
    *(pba + ((FS_ETPU_RSLV_K2_SCALE_OFFSET - 1)>>2)) =
        ((uint32_t)k2_scale_mult) & 0x00ffffff;
	
    /* diagnostic constants */
    *(pba + ((FS_ETPU_RSLV_ZERO_MAX_OFFSET  - 1)>>2)) = FS_ETPU_RSLV_DIAG_ZERO_MAX;
    *(pba + ((FS_ETPU_RSLV_MEAN_MAX_OFFSET  - 1)>>2)) = FS_ETPU_RSLV_DIAG_MEAN_MAX;
    *(pba + ((FS_ETPU_RSLV_AMPL_MAX_OFFSET  - 1)>>2)) = FS_ETPU_RSLV_DIAG_AMPL_MAX;
    *(pba + ((FS_ETPU_RSLV_ERROR_MAX_OFFSET - 1)>>2)) = FS_ETPU_RSLV_DIAG_ERROR_MAX;
    *(pba + ((FS_ETPU_RSLV_UNIT_CIRCLE_MIN_OFFSET - 1)>>2)) = FS_ETPU_RSLV_DIAG_UNIT_CIRC_MIN;
    *(pba + ((FS_ETPU_RSLV_UNIT_CIRCLE_MAX_OFFSET - 1)>>2)) = FS_ETPU_RSLV_DIAG_UNIT_CIRC_MAX;
	
	/* write channel configuration register */
	eTPU->CHAN[channel].CR.R = (priority << 28) + 
				(FS_ETPU_RSLV_TABLE_SELECT << 24) +
	                        (FS_ETPU_RSLV_FUNCTION_NUMBER << 16) +
	                        (((uint32_t)pba - fs_etpu_data_ram_start)>>3);

    /* Set channel's state parameter */
    state = 0;

	/* write FM (function mode) bits */
    if(mode & FS_ETPU_RSLV_MODE_PERIODIC)
    {
        /* Resolver computation periodically */
	    eTPU->CHAN[channel].SCR.B.FM0 = 1;

        /* Although not required, due to use of FM bits,
         * the PERIODIC operating mode is added to the channel's
         * state parameter.
         */
        state |= FS_ETPU_RSLV_MODE_PERIODIC;
    }
    else
    {
        /* Resolver computation on request */
	    eTPU->CHAN[channel].SCR.B.FM0 = 0;
    }

    if(mode & FS_ETPU_RSLV_MODE_LINK)
    {
        /* Resolver computation periodically */
	    eTPU->CHAN[channel].SCR.B.FM1 = 1;

        /* Although not required, due to use of FM bits,
         * the LINK operating mode is added to the channel's
         * state parameter.
         */
        state |= FS_ETPU_RSLV_MODE_LINK;
    }
    else
    {
        /* Link to another channel disabled */
	    eTPU->CHAN[channel].SCR.B.FM1 = 0;
    }

    if(mode & FS_ETPU_RSLV_MODE_TCR2)
    {
        state |= FS_ETPU_RSLV_MODE_TCR2;
    }

    if(mode & FS_ETPU_RSLV_MODE_MASTER)
    {
        state |= FS_ETPU_RSLV_MODE_MASTER;
    }

    if(mode & FS_ETPU_RSLV_MODE_START_ABS)
    {
        state |= FS_ETPU_RSLV_MODE_START_ABS;
    }
        
    if(mode & FS_ETPU_RSLV_STATE_DIGNOSTICS_ON)
    {
        state |= FS_ETPU_RSLV_STATE_DIGNOSTICS_ON;
    }
        
	*(pba + ((FS_ETPU_RSLV_STATE_OFFSET - 1)>>2)) = state & 0x00ffffff;

    /* Rate control */
	*(pba + ((FS_ETPU_RSLV_RATE_IRQ_OFFSET - 1)>>2)) = rate_irq & 0x00ffffff;
	*(pba + ((FS_ETPU_RSLV_RATE_LINK_OFFSET - 1)>>2)) = rate_link & 0x00ffffff;

	/* write hsr to start channel running */
	eTPU->CHAN[channel].HSRR.R = FS_ETPU_RSLV_INIT;

	return(0);
}


/******************************************************************************
*FUNCTION     : fs_etpu_rslv_compute
*PURPOSE      : Perform a single iteration of the Angle Tracking Observer
*               algorithm.  The function triggers the Angle Tracking Observer
*               computation regardless of the mode of operation.
*INPUTS NOTES : This function has 1 parameter:
*    channel    - This is the channel number.
*                 0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

void fs_etpu_rslv_compute(uint8_t channel )
{
	/* write hsr to compute */
	eTPU->CHAN[channel].HSRR.R = FS_ETPU_RSLV_CMPT;

    return;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_reset
*PURPOSE      : Reset the Angle Tracking Observer computation engine. 
*               This function sets the internal state of the resolver
*               computation to zero including number of revolutions.
*NOTES        : The function sets all internal variables of the Angle Tracking
*               Observer computation engine to zero and sets the sine and
*               cosine parameters so that the Angle Tracking Observer enters
*               steady state at zero angle.  Note that the function does not
*               affect wave generation.
*INPUTS NOTES : This function has 1 parameter:
*    channel    - This is the channel number.
*                 0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

void fs_etpu_rslv_reset(uint8_t channel)
{
	/* write hsr to reset */
	eTPU->CHAN[channel].HSRR.R = FS_ETPU_RSLV_RST;

    return;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_update
*PURPOSE      : Update the parameters of the PWM wave.  From the next period
*               of the PWM wave after the function call the PWM wave will be
*               updated with new parameters.
*INPUTS NOTES : This function has 1 parameter:
*    channel    - This is the channel number.
*                 0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

void fs_etpu_rslv_update(uint8_t channel)
{
	/* write hsr to update */
	eTPU->CHAN[channel].HSRR.R = FS_ETPU_RSLV_UPD;

    return;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_update_ext
*PURPOSE      : Update the parameters of the PWM wave.  From the next period
*               of the PWM wave after the function call the PWM wave will be
*               updated with new paramers.
*NOTES        : The function goes through two steps. In the first steps it
*               changes the PWM parameters provided as arguments and in the
*               second steps it performs update operation as in
*               fs_etpu_rslv_update().
*INPUTS NOTES : This function has 4 parameter:
*    channel    - This is the channel number.  0-31 for FS_ETPU_A and 64-95
*                 for FS_ETPU_B.
*    period     - PWM period in the chosen timer counter ticks.
*    duty       - PWM duty cycle in the chosen timer counter ticks.
*    delay      - Delay of the Angle Tracking Observer computation against
*                 beginning of the period.  Expressed in in the chosen timer
*                 counter ticks.
*RETURNS NOTES: none *WARNING      :
******************************************************************************/

void fs_etpu_rslv_update_ext(uint8_t channel, 
    uint32_t period, uint32_t duty, uint32_t delay)
{
	uint32_t *pba;

	pba = fs_etpu_data_ram (channel);
	*(pba + ((FS_ETPU_RSLV_PERIOD_OFFSET - 1)>>2)) = period;
	*(pba + ((FS_ETPU_RSLV_DUTY_OFFSET - 1)>>2)) = duty;
	*(pba + ((FS_ETPU_RSLV_DELAY_OFFSET - 1)>>2)) = delay;

	/* write hsr to update */
	eTPU->CHAN[channel].HSRR.R = FS_ETPU_RSLV_UPD;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_stop
*PURPOSE      : Stop generation of PWM wave.
*NOTES        : The function stops generation of the PWM wave and also the
*               periodic invocation of the Angle Tracking Observer routine.
*               However the Angle Tracking Observer routine still can be called
*               through fs_etpu_rslv_compute() or a link from another channel.
*INPUTS NOTES : This function has 1 parameter:
*    channel    - This is the channel number.
*                 0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

void fs_etpu_rslv_stop( uint8_t channel )
{
	/* write hsr to start channel running */
	eTPU->CHAN[channel].HSRR.R = FS_ETPU_RSLV_STOP;

    return;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_set_sincos
*PURPOSE      : The functions sets the sine and cosine inputs for the Angle
*               Tracking Observer routine. 
*NOTES:       : The function arguments are 32-bit long. However the sine and
*               cosine values need to be provided in signed 24-bit integer
*               format occupying the less significant bits of the 32-bit word.
*               The 8 most significant bits are neglected.
*
*               Before taken into calculations by the Angle Tracking Observer,
*               the sine and cosine values are first gained by the gain_sin and
*               gain_cos parameters and then secondly the parameters 
*               dc_offset_sin and dc_offset_cos are added.
*               After this operation the sine and cosine value should be within
*               the signed 24-bit fractional range from -1 to 1 and should be
*               positioned symmetrically around 0.
*
*               The signed 24-bit fractional format means that the minimum valid
*               value is -1, which corresponds to 0x00800000, and the maximum
*               valid value is almost 1 (exactly 1 - 2^-23), which corresponds
*               to 0x007fffff.
*
*INPUTS NOTES : This function has 3 parameters:
*    channel    - This is the channel number.
*                 0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*    sina       - The sine signal from a resolver in signed 24-bit integer
*                 format, should occupy 24 less significant bits.
*    cosa       - The cosine signal from a resolver in signed 24-bit
*                 integer format, should occupy 24 less significant bits.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

void fs_etpu_rslv_set_sincos( uint8_t channel, int32_t sina, int32_t cosa)
{
	uint32_t *pba;

	pba = fs_etpu_data_ram (channel);

	*(pba + ((FS_ETPU_RSLV_SINA_SMPL_OFFSET - 1)>>2)) = ((uint32_t)sina) & 0x00ffffff;
	*(pba + ((FS_ETPU_RSLV_COSA_SMPL_OFFSET - 1)>>2)) = ((uint32_t)cosa) & 0x00ffffff;

    return;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_get_sincos_addr
*PURPOSE      : The functions returns the address of the 32-bit word holding
*               the sinA parameter for the Angle Tracking Observer routine.
*               Next 32-bit parameters hold sinB, cosA and cosB in order.
*INPUTS NOTES : This function has 1 parameter:
*    channel    - This is the channel number.
*                 0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/
uint32_t* fs_etpu_rslv_get_sincos_addr(uint8_t channel)
{
	uint32_t *pba;
	uint32_t *p_sina;

	pba = fs_etpu_data_ram(channel);
	p_sina = pba + ((FS_ETPU_RSLV_SINA_SMPL_OFFSET - 1)>>2);

  return p_sina;
}


/******************************************************************************
*FUNCTION     : fs_etpu_rslv_get_error
*PURPOSE      : To acquire current resolver error.
*INPUTS NOTES : This function has 1 parameter:
*    channel    - This is the channel number.
*                 0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

int32_t fs_etpu_rslv_get_error(uint8_t channel)
{
	uint32_t *pba;
  int32_t error;

	pba = fs_etpu_data_ram (channel);

	error = (int32_t) *(pba + ((FS_ETPU_RSLV_ERROR_OFFSET - 1)>>2));
    error = (error<<8)>>8;;

    return error;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_get_state
*PURPOSE      : To acquire the current state of the RSLV eTPU function.
*NOTES        : To analyse the state flags please use the state defines
*               (with the infix _STATE_) included in the etpu_rslv_auto.h
*               header file.
*INPUTS NOTES : This function has 1 parameter:
*    channel    - This is the channel number.
*                 0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

uint32_t fs_etpu_rslv_get_state(uint8_t channel)
{
	uint32_t *pba;
    uint32_t state;

	pba = fs_etpu_data_ram (channel);

	state = (uint32_t) *(pba + ((FS_ETPU_RSLV_STATE_OFFSET - 1)>>2));
    state &= 0x00ffffff;

    return state;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_set_state
*PURPOSE      : To set state of the channel function.
*NOTES        : The function writes directly to the state parameter and will
*               override current flag values.  Care should be exercised in
*               order to avoid unintended modification of state flags.
*
*               In order to modify the contents of the state parameter the
*               state defines (infix _STATE_) in the etpu_rslv_auto.h file 
*               should be used.
*               
*INPUTS NOTES : This function has 2 parameters:
*    channel    - This is the channel number.
*                 0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*    state      - This is the new state parameter value.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

void fs_etpu_rslv_set_state(uint8_t channel, uint32_t state)
{
	uint32_t *pba;

	pba = fs_etpu_data_ram(channel);

	*(pba + ((FS_ETPU_RSLV_STATE_OFFSET - 1)>>2)) = state & 0x00ffffff;

    return;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_get_angle
*PURPOSE      : To acquire current resolver angle.
*NOTES        : Note that the angle is provided in form of 24-bit signed
*               fractional number, with 0xff800000 (-1.0) corresponding to -pi
*               and 0x007fffff (almost 1.0) corresponding to +pi.  The function
*               gets the current Angle Tracking Observer angle without taking
*               into account the Angle Tracking Observer offset.
*INPUTS NOTES : This function has 1 parameter:
*    channel - This is the channel number.
*              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/
int32_t fs_etpu_rslv_get_angle( uint8_t channel)
{
	uint32_t *pba;
    int32_t resAngle;

	pba = fs_etpu_data_ram (channel);

	resAngle = (int32_t) *(pba + ((FS_ETPU_RSLV_RESANGLE_OFFSET - 1)>>2));
    resAngle = (resAngle<<8)>>8;

    return resAngle;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_get_position
*PURPOSE      : To acquire current resolver position.
*NOTES:         The position is provided as a value modulo in form of 24-bit
*               signed fractional number, with 0xff800000 (-1.0) corresponding
*               to -pi and 0x007fffff (almost 1.0) corresponding to +pi.
*
*               The function takes into account the Angle Tracking Observer
*               offset by returning the sum of the computed Angle Tracking
*               Observer angle and the Angle Tracking Observer offset.  The
*               adjustment by the offset can be used to set conveniently the
*               beginning of the angle axis.
*
*               The function fs_etpu_rslv_set_position() can be used to set the
*               Angle Tracking Observer offset.
*
*               The returned value is the angle within a single 360 degree
*               rotation.  The absolute position can be calculated by adding to
*               the returned value the number of revolution multiplied by 2*pi.
*INPUTS NOTES : This function has 1 parameter:
*    channel    - This is the channel number.
*                 0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

int32_t fs_etpu_rslv_get_position(uint8_t channel)
{
	uint32_t *pba;
    int32_t resOffset;
    int32_t resAngle;
    int32_t position;
    
    pba = fs_etpu_data_ram(channel);
    pba += 0x4000>>2;

	  resOffset = (int32_t)*(pba + ((FS_ETPU_RSLV_RESOFFSET_OFFSET - 1)>>2));
	  resAngle  = (int32_t)*(pba + ((FS_ETPU_RSLV_RESANGLE_OFFSET - 1)>>2));
    position = resOffset + resAngle;

    return position;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_set_position
*PURPOSE      : To set new resolver position.
*NOTES        : The function sets offset in the Angle Tracking Observer
*               algorithm, so that the position returned by the immediate call
*               to the fs_etpu_rslv_get_position() will be equal to the value
*               provided as the argument.
*
*               NOTE: the function does not change internal computational state
*               of the Angle Tracking Observer.  For such a purpose use
*               fs_etpu_rslv_set_steadystate().
*INPUTS NOTES : This function has 2 parameters:
*    channel   - This is the channel number.
*                0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*    position  - The new resolver position.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

void fs_etpu_rslv_set_position(uint8_t channel, int32_t position)
{
	uint32_t *pba;
	int32_t resAngle;

	pba = fs_etpu_data_ram(channel);
	resAngle = fs_etpu_rslv_get_angle(channel);

	*(pba + ((FS_ETPU_RSLV_RESOFFSET_OFFSET - 1)>>2)) = 
        (uint32_t) ((position - resAngle) & 0x00ffffff);

  return;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_get_speed
*PURPOSE      : To acquire current resolver speed.
*NOTES        : The returned value is the digital representation of speed.
*               In order to calculate the physical value it is necessary to
*               multiply the returned value by PI*fs, where fs is the sampling
*               frequency.
*INPUTS NOTES : This function has 1 parameter:
*    channel - This is the channel number.
*                0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

int32_t fs_etpu_rslv_get_speed(uint8_t channel)
{
	uint32_t *pba;
    int32_t integAcc1;

	pba = fs_etpu_data_ram (channel);

	integAcc1 = (int32_t) *(pba + ((FS_ETPU_RSLV_INTEGACC1_OFFSET - 1)>>2));
    integAcc1 = (integAcc1<<8)>>8;;

    return integAcc1;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_get_revolutions
*PURPOSE      : To get the number of revolutions. 
*NOTES        : The number of revolutions is necessary to determine the
*               absolute position of the resolver as the resolver position is
*               provided within single 360 degree rotation.  The absolute
*               position can be calculated by adding to the position returned
*               by the fs_etpu_rslv_get_position() function the returned value
*               multiplied by 2*pi.
*INPUTS NOTES : This function has 1 parameter:
*    channel  - This is the channel number.
*               0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

int32_t fs_etpu_rslv_get_revolutions(uint8_t channel)
{
	uint32_t *pba;
    int32_t revolutions;

	pba = fs_etpu_data_ram (channel);

	revolutions = (int32_t) *(pba + ((FS_ETPU_RSLV_RESREVOLUTIONS_OFFSET - 1)>>2));
    revolutions = (revolutions<<8)>>8;

    return revolutions;
}
/******************************************************************************
*FUNCTION     : fs_etpu_rslv_set_revolutions
*PURPOSE      : To set the number of revolutions. 
*NOTES        : The function must be called at the time the Angle Tracking
*               Observer is NOT computing, otherwise the result is undefined.
*INPUTS NOTES : This function has 2 parameters:
*    channel      - This is the channel number.
*                   0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*    revolutions  - New number of revolutions 
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

void fs_etpu_rslv_set_revolutions(uint8_t channel, int32_t revolutions)
{
	uint32_t *pba;

	pba = fs_etpu_data_ram(channel);

	*(pba + ((FS_ETPU_RSLV_RESREVOLUTIONS_OFFSET - 1)>>2)) = 
        (uint32_t) revolutions & 0x00ffffff;

    return;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_set_steadystate
*PURPOSE      : To set computational state of the Angle Tracking Observer
*               so that it becomes steady-state.
*NOTES        : The function sets the internal state of the Angle Tracking
*               Observer computation engine, so that it stays steady-state
*               (subsequent iteration will not change the computational
*               state if inputs do not change). 
*
*               The function must be called at the time the Angle Tracking
*               Observer is NOT computing, otherwise the result is undefined.
*
*               Note that even after setting the computational state of the
*               Angle Tracking Observer, due to compuational reasons, some
*               fluctuations in values may occur.
*               
*               The function does not change the offset of the Angle Tracking
*               Observer and the number of revolutions.
*INPUTS NOTES : This function has 4 parameters:
*    channel   - This is the channel number.
*                0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*    angle     - New Angle Tracking Observer angle.
*    sina      - Sine value of the resolver.
*    cosa      - Cosine value of the resolver.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

void fs_etpu_rslv_set_steadystate(uint8_t channel,
    int32_t angle, int32_t sina, int32_t cosa)
{
	uint32_t *pba;

	pba = fs_etpu_data_ram (channel);

	*(pba + ((FS_ETPU_RSLV_INTEGACC1_OFFSET - 1)>>2)) = 
        (uint32_t) 0x00000000;

	*(pba + ((FS_ETPU_RSLV_INTEGACC2_OFFSET - 1)>>2)) = 
        (uint32_t) angle & 0x00ffffff;

	*(pba + ((FS_ETPU_RSLV_ERROR_OFFSET - 1)>>2)) = 
        (uint32_t) 0x00000000;

	*(pba + ((FS_ETPU_RSLV_RESANGLE_OFFSET - 1)>>2)) = 
        (uint32_t) angle & 0x00ffffff;

    fs_etpu_rslv_set_sincos(channel, sina, cosa);

    return;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_set_duty
*PURPOSE      : To modify a channel duty cycle using a 24-bit unsigned
*               integer.
*NOTES        : The function modifies an internal RSLV function variable
*               containing the duty cycle of PWM wave however no actual change
*               to the PWM wave generation is performed during the function
*               call. In order to apply the modified value the function
*               fs_etpu_rslv_updata() should be used.
*INPUTS NOTES : This function has 2 parameters:
*    channel - This is the channel number.
*                0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*    duty    - This is the duty cycle of the PWM.  This is a 24-bit unsigned
*              integer and represents timer ticks.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

void fs_etpu_rslv_set_duty( uint8_t channel, uint32_t duty)
{
	uint32_t *pba;

	pba = fs_etpu_data_ram (channel);
	*(pba + ((FS_ETPU_RSLV_DUTY_OFFSET - 1)>>2)) = duty;

    return;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_set_dutypercent
*PURPOSE      : To update a channel duty cycle using a percentage value with 0
*               corresponding to 0% and 10000 to 100%.
*NOTES        : The function modifies an internal RSLV function variable
*               containing the duty cycle of the PWM wave however no actual
*               change to the PWM wave generation is performed during the
*               function call. In order to apply the modified value the
*               function fs_etpu_rslv_updata() should be used.
*INPUTS NOTES : This function has 2 parameters:
*    channel - This is the channel number.
*                0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*    duty    - This is the duty cycle of the PWM, 0 corresponds to 0%
*              and 10000 corresponds to 100%.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

void fs_etpu_rslv_set_dutypercent( uint8_t channel, uint32_t dutypercent)
{
	uint32_t *pba;
    uint32_t period;
    uint32_t duty;
    uint64_t m;

	pba = fs_etpu_data_ram (channel);
	period = (uint32_t) *(pba + ((FS_ETPU_RSLV_PERIOD_OFFSET - 1)>>2));
    m = ((uint64_t) dutypercent)*((uint64_t) period);
    duty = (uint32_t) (m/((uint64_t) 10000));
	*(pba + ((FS_ETPU_RSLV_DUTY_OFFSET - 1)>>2)) = duty;

    return;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_set_period
*PURPOSE      : To update a channel period using a 24-bit integer value
*               in a selected timer ticks.
*NOTES        : The function modifies an internal RSLV function variable
*               containing the period of the PWM wave however no actual change
*               to the PWM wave generation is performed during the function
*               call.  In order to apply the modified value the function
*               fs_etpu_rslv_update() should be used.
*INPUTS NOTES : This function has 2 parameters:
*    channel - This is the channel number.
*              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*    period  - This is the period in timer base clock cycles.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

void fs_etpu_rslv_set_period(uint8_t channel, uint32_t period)
{
	uint32_t *pba;

	pba = fs_etpu_data_ram (channel);
	*(pba + ((FS_ETPU_RSLV_PERIOD_OFFSET - 1)>>2)) = period;

    return;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_set_delay
*PURPOSE      : To set the computational delay using a 24-bit integer.
*NOTES        : The function modifies an internal RSLV function variable
*               containing the delay of the PWM wave however no actual change
*               to the PWM wave generation is performed during the function
*               call.  In order to apply the modified value the function
*               fs_etpu_rslv_updata() should be used.
*INPUTS NOTES : This function has 2 parameters:
*    channel - This is the channel number.
*              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*    delay   - This is the delay as portion of period, by which periodic
*              computation of the Angle Tracking Observer is performed.  This
*              is a 24-bit unsigned integer and reprents a number of a selected
*              timer ticks.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

void fs_etpu_rslv_set_delay( uint8_t channel, uint32_t delay)
{
	uint32_t *pba;

	pba = fs_etpu_data_ram (channel);
	*(pba + ((FS_ETPU_RSLV_DELAY_OFFSET - 1)>>2)) = delay;

    return;
}

/******************************************************************************
*FUNCTION     : fs_etpu_rslv_set_delaypercent
*PURPOSE      : To update a channel delay using a percentage value with 0
*               corresponding to 0% and 10000 to 100%.
*NOTES        : The function modifies an internal RSLV function variable
*               containing the delay of the PWM wave however no actual change
*               to the PWM wave generation is performed during the function
*               call.  In order to apply the modified value the function
*               fs_etpu_rslv_updata() should be used.
*INPUTS NOTES : This function has 2 parameters:
*    channel - This is the channel number.
*              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
*    delay   - This is the delay of the invocation of the Angle Tracking
*              Observer routine, 0 corresponds to 0% and 10000 corresponds
*              to 100%.
*RETURNS NOTES: none
*WARNING      :
******************************************************************************/

void fs_etpu_rslv_set_delaypercent( uint8_t channel, uint32_t delaypercent)
{
	uint32_t *pba;
    uint32_t period;
    uint32_t delay;
    uint64_t m;

	pba = fs_etpu_data_ram (channel);
	period = (uint32_t) *(pba + ((FS_ETPU_RSLV_PERIOD_OFFSET - 1)>>2));
    m = ((uint64_t) delaypercent)*((uint64_t) period);
    delay = (uint32_t) (m/(uint64_t)10000);
	*(pba + ((FS_ETPU_RSLV_DELAY_OFFSET - 1)>>2)) = delay;

    return;
}

/******************************************************************************
FUNCTION     : fs_etpu_rslv_enable_periodic
PURPOSE      : The function enables periodic computation of Angle Tracking
               Observer at every PWM period.
INPUTS NOTES : This function has 1 parameter:
    channel - This is the channel number.
              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
RETURNS NOTES: none
WARNING      :
******************************************************************************/
void fs_etpu_rslv_enable_periodic(uint8_t channel)
{
	eTPU->CHAN[channel].SCR.B.FM0 = 1;

    return;
}

/******************************************************************************
FUNCTION     : fs_etpu_rslv_disable_periodic
PURPOSE      : The function disables periodic computation of Angle Tracking
               Observer at every PWM period.
INPUTS NOTES : This function has 1 parameter:
    channel - This is the channel number.
              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
RETURNS NOTES: none
WARNING      :
******************************************************************************/
void fs_etpu_rslv_disable_periodic(uint8_t channel)
{
	eTPU->CHAN[channel].SCR.B.FM0 = 0;

    return;
}

/******************************************************************************
FUNCTION     : fs_etpu_rslv_enable_link
PURPOSE      : The function enables link to another channel at the end of
               Angle Tracking Observer computation.
INPUTS NOTES : This function has 1 parameter:
    channel - This is the channel number.
              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
RETURNS NOTES: none
WARNING      :
******************************************************************************/
void fs_etpu_rslv_enable_link(uint8_t channel)
{
	eTPU->CHAN[channel].SCR.B.FM1 = 1;

    return;
}

/******************************************************************************
FUNCTION     : fs_etpu_rslv_disable_link
PURPOSE      : The function disables link to another channel at the end of
               Angle Tracking Observer computation.
INPUTS NOTES : This function has 1 parameter:
    channel - This is the channel number.
              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
RETURNS NOTES: none
WARNING      :
******************************************************************************/

void fs_etpu_rslv_disable_link(uint8_t channel)
{
	eTPU->CHAN[channel].SCR.B.FM1 = 0;

    return;
}

/******************************************************************************
FUNCTION     : fs_etpu_rslv_autocalibrate
PURPOSE      : .
INPUTS NOTES : This function has 1 parameter:
    channel - This is the channel number.
              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
RETURNS NOTES: none
WARNING      :
******************************************************************************/
uint8_t fs_etpu_rslv_autocalibrate(uint8_t channel)
{
    static int32_t revolutions = 0;
    int32_t revs;
    uint32_t *pba;
    int32_t sinA_max;
    int32_t sinA_min;
    int32_t cosA_max;
    int32_t cosA_min;
    int32_t gain_sin;
    int32_t gain_cos;
    int32_t dc_offset_sin;
    int32_t dc_offset_cos;
    int32_t sinA_max_smpl;
    int32_t sinA_min_smpl;
    int32_t cosA_max_smpl;
    int32_t cosA_min_smpl;
    int32_t dc_offset_sin_smpl;
    int32_t dc_offset_cos_smpl;


    pba = fs_etpu_data_ram(channel);
    pba += 0x4000>>2;

	  revs = (int32_t) *(pba + ((FS_ETPU_RSLV_RESREVOLUTIONS_OFFSET - 1)>>2));
	  if((revs - revolutions > 2) || (revolutions - revs > 2))
	  {
	    revolutions = revs;
	  }
	  else
	  {
	    /* Not enough revolutions passed from the last calibration */
	    return(FS_ETPU_ERROR_FREQ);
	  }
	    
    sinA_max = (int32_t) *(pba + ((FS_ETPU_RSLV_SINA_MAX_OFFSET - 1)>>2));
    sinA_min = (int32_t) *(pba + ((FS_ETPU_RSLV_SINA_MIN_OFFSET - 1)>>2));
    cosA_max = (int32_t) *(pba + ((FS_ETPU_RSLV_COSA_MAX_OFFSET - 1)>>2));
    cosA_min = (int32_t) *(pba + ((FS_ETPU_RSLV_COSA_MIN_OFFSET - 1)>>2));
    gain_sin = (int32_t) *(pba + ((FS_ETPU_RSLV_GAIN_SIN_OFFSET - 1)>>2));
    gain_cos = (int32_t) *(pba + ((FS_ETPU_RSLV_GAIN_COS_OFFSET - 1)>>2));
    dc_offset_sin = (int32_t) *(pba + ((FS_ETPU_RSLV_DC_OFFSET_SIN_OFFSET - 1)>>2));
    dc_offset_cos = (int32_t) *(pba + ((FS_ETPU_RSLV_DC_OFFSET_COS_OFFSET - 1)>>2));

    sinA_max_smpl = (sinA_max - dc_offset_sin)/gain_sin;
    sinA_min_smpl = (sinA_min - dc_offset_sin)/gain_sin;
    cosA_max_smpl = (cosA_max - dc_offset_cos)/gain_cos;
    cosA_min_smpl = (cosA_min - dc_offset_cos)/gain_cos;

    dc_offset_sin_smpl = -(sinA_max_smpl + sinA_min_smpl)/2;
    dc_offset_cos_smpl = -(cosA_max_smpl + cosA_min_smpl)/2;

    gain_sin = FS_ETPU_RSLV_CALIB_AMPL/(sinA_max_smpl + dc_offset_sin_smpl);
    gain_cos = FS_ETPU_RSLV_CALIB_AMPL/(cosA_max_smpl + dc_offset_cos_smpl);
    
    dc_offset_sin = dc_offset_sin_smpl * gain_sin;
    dc_offset_cos = dc_offset_cos_smpl * gain_cos;

    *(pba + ((FS_ETPU_RSLV_GAIN_SIN_OFFSET - 1)>>2)) = gain_sin;
    *(pba + ((FS_ETPU_RSLV_GAIN_COS_OFFSET - 1)>>2)) = gain_cos;
    *(pba + ((FS_ETPU_RSLV_DC_OFFSET_SIN_OFFSET - 1)>>2)) = dc_offset_sin;
    *(pba + ((FS_ETPU_RSLV_DC_OFFSET_COS_OFFSET - 1)>>2)) = dc_offset_cos;
    *(pba + ((FS_ETPU_RSLV_SINA_MAX_OFFSET - 1)>>2)) = 0;
    *(pba + ((FS_ETPU_RSLV_SINA_MIN_OFFSET - 1)>>2)) = 0;
    *(pba + ((FS_ETPU_RSLV_COSA_MAX_OFFSET - 1)>>2)) = 0;
    *(pba + ((FS_ETPU_RSLV_COSA_MIN_OFFSET - 1)>>2)) = 0;
  
    return(0);
}


/* turn on/off diagnostics */
/******************************************************************************
FUNCTION     : fs_etpu_rslv_diagnostics_on
PURPOSE      : .
INPUTS NOTES : This function has 1 parameter:
    channel - This is the channel number.
              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
RETURNS NOTES: none
WARNING      :
******************************************************************************/
void fs_etpu_rslv_diagnostics_on(uint8_t channel)
{
    uint32_t *pba;

    pba = fs_etpu_data_ram(channel);
	  *(pba + ((FS_ETPU_RSLV_STATE_OFFSET - 1)>>2)) |= FS_ETPU_RSLV_STATE_DIGNOSTICS_ON;
}

/******************************************************************************
FUNCTION     : fs_etpu_rslv_diagnostics_off
PURPOSE      : .
INPUTS NOTES : This function has 1 parameter:
    channel - This is the channel number.
              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
RETURNS NOTES: none
WARNING      :
******************************************************************************/
void fs_etpu_rslv_diagnostics_off(uint8_t channel)
{
    uint32_t *pba;

    pba = fs_etpu_data_ram(channel);
	  *(pba + ((FS_ETPU_RSLV_STATE_OFFSET - 1)>>2)) &= ~FS_ETPU_RSLV_STATE_DIGNOSTICS_ON;
}

/* read internal diagnostics */
/******************************************************************************
FUNCTION     : fs_etpu_rslv_get_diags_actual
PURPOSE      : .
INPUTS NOTES : This function has 1 parameter:
    channel - This is the channel number.
              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
RETURNS NOTES: none
WARNING      :
******************************************************************************/
uint32_t fs_etpu_rslv_get_diags_actual(uint8_t channel)
{
    uint32_t *pba;
    uint32_t diags_actual;

    pba = fs_etpu_data_ram(channel);
    pba += 0x4000>>2;

	  diags_actual = (int32_t) *(pba + ((FS_ETPU_RSLV_DIAGS_ACTUAL_OFFSET - 1)>>2));

    return(diags_actual);  
}

/******************************************************************************
FUNCTION     : fs_etpu_rslv_get_diags_cumulative
PURPOSE      : .
INPUTS NOTES : This function has 1 parameter:
    channel - This is the channel number.
              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
RETURNS NOTES: none
WARNING      :
******************************************************************************/
uint32_t fs_etpu_rslv_get_diags_cumulative(uint8_t channel)
{
    uint32_t *pba;
    uint32_t diags_cumulative;

    pba = fs_etpu_data_ram(channel);
    pba += 0x4000>>2;

	  diags_cumulative = (int32_t) *(pba + ((FS_ETPU_RSLV_DIAGS_CUMULATIVE_OFFSET - 1)>>2));

    return(diags_cumulative);  
}

/******************************************************************************
FUNCTION     : fs_etpu_rslv_get_fault
PURPOSE      : .
INPUTS NOTES : This function has 1 parameter:
    channel - This is the channel number.
              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
RETURNS NOTES: none
WARNING      :
******************************************************************************/
uint32_t fs_etpu_rslv_get_fault(uint8_t channel)
{
    uint32_t *pba;
    uint32_t diags_cumulative;
    uint32_t fault = 0;

    pba = fs_etpu_data_ram(channel);
    pba += 0x4000>>2;

	  diags_cumulative = (int32_t) *(pba + ((FS_ETPU_RSLV_DIAGS_CUMULATIVE_OFFSET - 1)>>2));

    /* check for general faults */
    if(diags_cumulative & FS_ETPU_RSLV_DYNAMICS_FAULT_MASK)         fault |= FS_ETPU_RSLV_FAULT_DYNAMICS;
    if(diags_cumulative & FS_ETPU_RSLV_RATIONALITY_FAULT_MASK)      fault |= FS_ETPU_RSLV_FAULT_RATIONALITY;
    if(diags_cumulative & FS_ETPU_RSLV_PLAUSABILITY_SIN_FAULT_MASK) fault |= FS_ETPU_RSLV_FAULT_PLAUSABILITY_SIN;
    if(diags_cumulative & FS_ETPU_RSLV_PLAUSABILITY_COS_FAULT_MASK) fault |= FS_ETPU_RSLV_FAULT_PLAUSABILITY_COS;

    if(fault != 0)
    {
  	  /* check for specific faults */
      if ((diags_cumulative & FS_ETPU_RSLV_FAULT_SHORT_SIN_COS_MASK) == FS_ETPU_RSLV_FAULT_SHORT_SIN_COS_VALUE)
      {
        fault |= FS_ETPU_RSLV_FAULT_SHORT_SIN_COS;
      }
      if ((diags_cumulative & FS_ETPU_RSLV_FAULT_SHORT_SIN_REFSIN_MASK) == FS_ETPU_RSLV_FAULT_SHORT_SIN_REFSIN_VALUE)
      {
        fault &= ~FS_ETPU_RSLV_FAULT_SHORT_SIN_COS;
        fault |= FS_ETPU_RSLV_FAULT_SHORT_SIN_REFSIN;
      }
      if ((diags_cumulative & FS_ETPU_RSLV_FAULT_SHORT_COS_REFCOS_MASK) == FS_ETPU_RSLV_FAULT_SHORT_COS_REFCOS_VALUE)
      {
        fault &= ~FS_ETPU_RSLV_FAULT_SHORT_SIN_COS;
        fault |= FS_ETPU_RSLV_FAULT_SHORT_COS_REFCOS;
      }
      if ((diags_cumulative & FS_ETPU_RSLV_FAULT_SHORT_SIN_REFCOS_MASK) == FS_ETPU_RSLV_FAULT_SHORT_SIN_REFCOS_VALUE)
      {
        fault |= FS_ETPU_RSLV_FAULT_SHORT_SIN_REFCOS;
      }
      if ((diags_cumulative & FS_ETPU_RSLV_FAULT_SHORT_COS_REFSIN_MASK) == FS_ETPU_RSLV_FAULT_SHORT_COS_REFSIN_VALUE)
      {
        fault |= FS_ETPU_RSLV_FAULT_SHORT_COS_REFSIN;
      }
      if ((diags_cumulative & FS_ETPU_RSLV_FAULT_SHORT_REFSIN_REFCOS_MASK) == FS_ETPU_RSLV_FAULT_SHORT_REFSIN_REFCOS_VALUE)
      {
        fault |= FS_ETPU_RSLV_FAULT_SHORT_REFSIN_REFCOS;
      }
      if ((diags_cumulative & FS_ETPU_RSLV_FAULT_OPEN_SINREFSIN_MASK) == FS_ETPU_RSLV_FAULT_OPEN_SINREFSIN_VALUE)
      {
        fault |= FS_ETPU_RSLV_FAULT_OPEN_SINREFSIN;
      }
      if ((diags_cumulative & FS_ETPU_RSLV_FAULT_OPEN_COSREFCOS_MASK) == FS_ETPU_RSLV_FAULT_OPEN_COSREFCOS_VALUE)
      {
        fault |= FS_ETPU_RSLV_FAULT_OPEN_COSREFCOS;
      }
      if ((diags_cumulative & FS_ETPU_RSLV_FAULT_GND_SINREFSIN_MASK) == FS_ETPU_RSLV_FAULT_GND_SINREFSIN_VALUE)
      {
        fault |= FS_ETPU_RSLV_FAULT_GND_SINREFSIN;
      }
      if ((diags_cumulative & FS_ETPU_RSLV_FAULT_GND_COSREFCOS_MASK) == FS_ETPU_RSLV_FAULT_GND_COSREFCOS_VALUE)
      {
        fault |= FS_ETPU_RSLV_FAULT_GND_COSREFCOS;
      }
      if ((diags_cumulative & FS_ETPU_RSLV_FAULT_SHORT_REZGEN_SINREFSIN_MASK) == FS_ETPU_RSLV_FAULT_SHORT_REZGEN_SINREFSIN_VALUE)
      {
        fault &= ~FS_ETPU_RSLV_FAULT_GND_SINREFSIN;
        fault |= FS_ETPU_RSLV_FAULT_SHORT_REZGEN_SINREFSIN;
      }
      if ((diags_cumulative & FS_ETPU_RSLV_FAULT_SHORT_REZGEN_COSREFCOS_MASK) == FS_ETPU_RSLV_FAULT_SHORT_REZGEN_COSREFCOS_VALUE)
      {
        fault &= ~FS_ETPU_RSLV_FAULT_GND_COSREFCOS;
        fault |= FS_ETPU_RSLV_FAULT_SHORT_REZGEN_COSREFCOS;
      }
      if ((diags_cumulative & FS_ETPU_RSLV_FAULT_OPENGND_REZGEN_MASK) == FS_ETPU_RSLV_FAULT_OPENGND_REZGEN_VALUE)
      {
        fault &= ~(FS_ETPU_RSLV_FAULT_SHORT_SIN_REFSIN | FS_ETPU_RSLV_FAULT_SHORT_COS_REFCOS | FS_ETPU_RSLV_FAULT_SHORT_SIN_COS);
        fault |= FS_ETPU_RSLV_FAULT_OPENGND_REZGEN;
      }
    }

    return(fault);  
}

/******************************************************************************
FUNCTION     : fs_etpu_rslv_clear_fault
PURPOSE      : .
INPUTS NOTES : This function has 1 parameter:
    channel - This is the channel number.
              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
RETURNS NOTES: none
WARNING      :
******************************************************************************/
void fs_etpu_rslv_clear_fault(uint8_t channel)
{
    uint32_t *pba;

    pba = fs_etpu_data_ram(channel);
    pba += 0x4000>>2;

	  *(pba + ((FS_ETPU_RSLV_DIAGS_CUMULATIVE_OFFSET - 1)>>2)) = 0;
}

/******************************************************************************
FUNCTION     : fs_etpu_rslv_set_coefs
PURPOSE      : 
INPUTS NOTES : This function has 1 parameter:
    channel - This is the channel number.
              0-31 for FS_ETPU_A and 64-95 for FS_ETPU_B.
RETURNS NOTES: none
WARNING      :
******************************************************************************/
void fs_etpu_rslv_set_coefs(uint8_t  channel, 
                            uint32_t k1_d,
                            uint32_t k1_scale,
                            uint32_t k2_d,
                            uint32_t k2_scale)
{
    uint32_t *pba;
    uint32_t k1_scale_mult;
    uint32_t k2_scale_mult;
    
    pba = fs_etpu_data_ram(channel);
    pba += 0x4000>>2;

    k1_scale_mult = (uint32_t) 1<<(23 - k1_scale);
    k2_scale_mult = (uint32_t) 1<<k2_scale;
    *(pba + ((FS_ETPU_RSLV_K1_D_OFFSET - 1)>>2)) = (uint32_t)k1_d;
    *(pba + ((FS_ETPU_RSLV_K1_SCALE_OFFSET - 1)>>2)) = (uint32_t)k1_scale_mult;
    *(pba + ((FS_ETPU_RSLV_K2_D_OFFSET - 1)>>2)) = (uint32_t)k2_d;
    *(pba + ((FS_ETPU_RSLV_K2_SCALE_OFFSET - 1)>>2)) = (uint32_t)k2_scale_mult;
}


/*********************************************************************
 *
 * Copyright:
 *	Freescale Semiconductor, INC. All Rights Reserved.
 *  You are hereby granted a copyright license to use, modify, and
 *  distribute the SOFTWARE so long as this entire notice is
 *  retained without alteration in any modified and/or redistributed
 *  versions, and that such modified versions are clearly identified
 *  as such. No licenses are granted by implication, estoppel or
 *  otherwise under any patents or trademarks of Freescale
 *  Semiconductor, Inc. This software is provided on an "AS IS"
 *  basis and without warranty.
 *
 *  To the maximum extent permitted by applicable law, Freescale
 *  Semiconductor DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
 *  INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
 *  PARTICULAR PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH
 *  REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF)
 *  AND ANY ACCOMPANYING WRITTEN MATERIALS.
 *
 *  To the maximum extent permitted by applicable law, IN NO EVENT
 *  SHALL Freescale Semiconductor BE LIABLE FOR ANY DAMAGES WHATSOEVER
 *  (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
 *  BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER
 *  PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
 *
 *  Freescale Semiconductor assumes no responsibility for the
 *  maintenance and support of this software
 ********************************************************************/

