Position Measurement AN4064

Thread Starter

Vihaan@123

Joined Oct 7, 2025
220
I am referring to the position measurement in the microchip application note AN4064 attached
1759837291751.png
1759837305851.png
'I am struck up in understanding the equation2. I know 65536/6 is 60 degrees in terms of integer, The equation is probably trying to estimate how much rotor is moved in each PWM. If i take the angular speed formula angular speed = angular displacement (Theta) / time = (Final angle - Initial angle) / Time
The Time is the Average Period between the hall changes. But how FCY, Prescaler, PWM Switching Frequency are used to build the equation, i am unable to connect the dots and it is the most important calculation i need to understand as i am facing issues of invalid theta calculations. Can someone please guide how the equation is derived.
 

Attachments

nsaspook

Joined Aug 27, 2009
16,249
https://forum.allaboutcircuits.com/...r-for-3-phase-115v-supply.181424/post-1660981

FCY, Prescaler, PWM Switching Frequency along with the interrupt time determine the actual coil current using a calculated offset (new PWM phase-duty cycle value) from the reference phase value current.
1759935459320.png
1759936806426.png
Simple static 90 degree two-phase servo signal generation example. This all happens in a ISR
https://forum.allaboutcircuits.com/...drature-phase-400hz-motor.187708/post-1746642

// code fragments
C:
    phase_duty(&m35_1, m35_1.current + m35_1.current_offset, V.m_speed, 2);
    phase_duty(&m35_2, m35_2.current + m35_2.current_offset, V.m_speed, 2);
    phase_duty(&m35_3, m35_2.current + m35_3.current_offset, V.m_speed, 2);
    phase_duty(&m35_4, m35_2.current + m35_4.current_offset, V.m_speed, 2);

    /*
     * set channel duty cycle for phase-shifted sinewave outputs at ISR time 1ms intervals
     */

    MCPWM_ChannelPrimaryDutySet(MCPWM_CH_1, m35_1.duty); // 2P servo reference phase
    if (++rev > 0) {
        MCPWM_ChannelPrimaryDutySet(MCPWM_CH_3, m35_2.duty); // 2P servo control phase #1 -90
        MCPWM_ChannelPrimaryDutySet(MCPWM_CH_2, m35_3.duty); // 2P servo control phase #2 +90
        m35_2.clockwise = true;
    } else {
        MCPWM_ChannelPrimaryDutySet(MCPWM_CH_2, m35_2.duty); // 2P servo control phase #1 +90
        MCPWM_ChannelPrimaryDutySet(MCPWM_CH_3, m35_3.duty); // 2P servo control phase #2 -90
        m35_2.clockwise = false;
    }
    MCPWM_ChannelPrimaryDutySet(MCPWM_CH_4, m35_4.duty); // 2P servo control phase #3
    V.pwm_update = false;
C:
/*
* micro-stepping  sinusoidal commutation for PWM using sine_foo or constant table
*/
int32_t phase_duty(
    volatile struct QEI_DATA * const phase, const double mag, const M_SPEED mode, const int32_t adj)
{
    if (mode == M_SLEW) {
        return phase_duty_table(phase, mag, adj);
    } else {
        phase->duty = (int32_t) (hpwm_mid_duty_f + (mag * sine_foo(phase)));

        if (phase->duty > hpwm_high_duty) {
            phase->duty = hpwm_high_duty;
        }
        if (phase->duty < hpwm_low_duty) {
            phase->duty = hpwm_low_duty;
        }
        return phase->duty;
    }
}

/*
* generate one complete sine-wave cycle at one step per call
*/
static double sine_foo(volatile struct QEI_DATA * const phase)
{
    /* Increment the phase accumulator */
    phase->phaseAccumulator += phase->phaseIncrement;
    /* Limit the phase accumulator to 24 bits.
       The lower 16 bits are the fractional table
       index part, while the remaining 8 bits
       are the integer index into the waveform
       table.
     */
    phase->phaseAccumulator &= (256 * 65536) - 1;

    /* Calculate the table index. */
    uint32_t index = phase->phaseAccumulator >> 16;

    /* Get the table entry and the one
       directly following it.
     */
    double v_sin = table[index];
    double v_cos = table[(index + 64) & 255];
    double frac = 2.0f * PI * (double) (phase->phaseAccumulator & 65535) / 65536.0f / 256.0f;

    // fractional sin/cos
    double f_sin = frac;
    double f_cos = 1.0f - 0.5f * frac*frac;

    double result = v_sin * f_cos + v_cos*f_sin;

    if (++phase->phase_steps >= SAMPLERATE) { // reset per electrical rotation cycle
        phase->phase_steps = 0;
        phase->phaseAccumulator = 0;
    }
    phase->sin = result;
    return result;
}
 
Last edited:
Top