Basic Implementation

The PWM Decoder uses the Atmel AVR’s Input Capture Unit (ICP) to measure the PWM pulse width and period. The ICP provides an edge-triggered interrupt, based on the state of AVR’s ICPn pin, along with an internal register, which contains a snapshot of the respective Timer/Counter register at the moment of the trigger. By subtracting successive trigger timestamps, the pulse width and period may be computed.

Specifically, the timer to be used is configured initially to recognize the leading edge of a pulse, which depends on whether Inverted or non-Inverted PWM is to be recognized. When the leading-edge interrupt is triggered, software in the Interrupt Service Routine (ISR) inverts the edge sense flag so that the next ICP interrupt will trigger on the trailing edge of the pulse. Similarly, during the trailing-edge interrupt, the edge sense flag is inverted to detect the next leading edge. During each of these interrupts, the value captured by capture module is saved for later computation.

The leading-edge interrupt also performs additional computation, since it is simultaneously the beginning of a new cycle and the end of the previous cycle. This is thus the point where the pulse width and period are computed by subtracting the stop and start times for the pulse and the current and previous start times, respectively. When these values are known, the duty cycle for the previous cycle is computed and stored.

The pseudo-code for the ISR is:
    icp_isr()
    Reverse sense of ICP interrupt edge 
    if (ICP interrupt was for rising edge)       
        Previous_Period = ICR - Start_Time   
        Previous_Pulse_Width = Stop_Time - Start_Time   
        Start_Time = ICR   
        Previous_Duty_Cycle = Scale_Factor * (Previous_Pulse_Width/Previous_Period) 
    else
        Stop_Time := ICR;
No special provision is made for Inverted PWM, since the Inverted duty cycle may be simply computed as ICP_SCALE - icp_rx().