//###########################################################################
//
// FILE:   epwm_pending_isr_example.c
//
// TITLE:  EPWM Pending ISR Issue - INT Counter Resolution
//
//!
//! This example configures ePWM1 to 4kHz (250usec period).
//! This example configures ePWM2 to 25kHz (40usec period).
//!
//! CMPA and CMPB are static and yield 50% duty on each PWM channel output.
//! The TB counter is in up-count mode.
//!
//! - ePWM2 generates an interrupt every cycle on CTR = 0.
//! - ePWM1 generates a syncout pulse to ePWM2.
//! - ePWM2 TBPHS is 0, so- by nature- an interrupt will be generated every sync pulse.
//! - ePWM2 ISR lasts ~20 usec long and stores the PWM counter.
//!
//! Waveforms to view via oscilloscope:
//! - EPWM1A/B on GPIO0 & GPIO1
//! - EPWM2A/B on GPIO2 & GPIO3
//! - EPWM1 SYNCOUT pulse ("EXTSYNCOUT") on GPIO24
//! - EPWM2 ISR start and end (via GPIO toggle) on GPIO25
//!
//! E2E ISSUE: EPWM1 issues a sync pulse to EPWM2 *during* EPWM2 ISR.
//!   This pending interrupt is stored during the ISR despite
//!   clearing the flag, and causes unwanted back-to-back interrupts on sync.
//!
//! RESOLUTION: Disable PWM interrupts at start of ISR and re-enable at and AND
//!   only trigger EPWM2 interrupts at a specific interrupt count value.
//!   This example triggers interrupts when INT count = 2. During each ISR, we
//!   Force a reload of the INT count value to be '1' right before re-enabling
//!   interrupts. Any interrupt triggers that come in during an ISR will be ignored.
//!   This method prevents the unwanted pending interrupt from being carried out,
//!   but still allows for the next ISR to be triggered as needed.
//!
//!   See comments below for further details.
//!
//###########################################################################

//
// Included Files
//
#include "driverlib.h"
#include "device.h"
#include "board.h"

//
// Defines
//
uint16_t CounterVal; // To check TBCTR value

//
//  Function Prototypes
//
__interrupt void INT_myEPWM2_ISR(void); // EPWM2 ISR Triggered on CTR = 0

//
// Main
//
void main(void)
{
    //
    // Initialize counter value to 0
    //
    CounterVal = 0;

    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Disable pin locks and enable internal pull-ups.
    //
    Device_initGPIO();

    //
    // 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();

    //
    // Disable sync(Freeze clock to PWM as well)
    //
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    //
    // Configure GPIO pins and EPWM Modules
    //
    Board_init();

    //
    // Enable sync and clock to PWM
    //
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    //
    // Enable global Interrupts and higher priority real-time debug events:
    //
    EINT;  // Enable Global interrupt INTM
    ERTM;  // Enable Global realtime interrupt DBGM

    //
    // IDLE loop. Just sit and loop forever (optional):
    //
    for(;;)
    {
        asm ("  NOP");
    }
}

//
// epwm2ISR - EPWM2 ISR
//
__interrupt void INT_myEPWM2_ISR(void)
{
    //
    // Toggle GPIO25 high to show start of ISR
    //
    GPIO_writePin(myGPIO25, 1);

    //
    // Disable PWM interrupts
    //
    EPWM_disableInterrupt(myEPWM2_BASE);

    //
    // Read TBCTR Value
    //
    CounterVal = EPWM_getTimeBaseCounterValue(myEPWM2_BASE);

    //
    // Delay to simulate 20usec long ISR
    //
    DEVICE_DELAY_US(20);

    //
    // Clear INT flag for this timer
    //
    EPWM_clearEventTriggerInterruptFlag(myEPWM2_BASE);

    //
    // Acknowledge this interrupt to receive more interrupts from group 3
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);

    //
    // SOLUTION: Force load the INT event count to '1' (interrupt is triggered when INT event count is '2')
    //
    // Comment out this line and change the Event Trigger "Interrupt Event Count" in sysconfig back to
    // "Every 1 event generates Interrupts" to see the issue appear (see back to back interrupts triggered on EPWM1 sync).
    //
    // Un-comment this line and change the Event Trigger "Interrupt Event Count" in sysconfig to
    // "Every 2 event generates Interrupts" to see the resolution (no back to back interrupts).
    //
    EPWM_forceInterruptEventCountInit(myEPWM2_BASE);

    //
    // Re-enable PWM interrupts
    //
    EPWM_enableInterrupt(myEPWM2_BASE);

    //
    // Toggle GPIO25 low to show end of ISR
    //
    GPIO_writePin(myGPIO25, 0);

}

//
// End of file
//
