This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28388D: PWM pending ISR. How do we clear it

Part Number: TMS320F28388D

We have some specific timing requirements on when we can start ADC reading. We use the PWM to trigger the ISR and start our ADC. We use the PWM count and verify that we are withing the first 1-2 usec of the count to start the read. 

What we are doing is running the PWM at 48 usec timer, however, when told to we sync the PWM to the SYNC0 ISR Pulse on EtherCAT (which runs at 250 usecs). What we see and expect is that on occassion we will have a pending interrupt for the PWM. Since we techinically could get the PWM counter ISR and then a few usecs later get the Sync0 Pusle, which should set the PWM counts back down to zero (by the way is this correct?)

I thought that doing EPWM_clearEventTriggerInterruptFlag would clear the current interrupt and any pending interrupt but doing some reading in the forum it doesn't appear that way. If the PWM has a pending ISR once we do the EPWM_clearEventTriggerInterruptFlag then the pending interrupt will fire and once we leave the interrupt handler we will immediately come back into the Interrupt handler again (baring any other higher interrupts). 

Since we know based on timing that we could get 1 interrupt, be processing it and having one pending because the Sync0 pulse came in we are getting back into the ISR handler with the pwm count being to high to start our ADC reads and we throw and error. We know we will get into this situation is there a way to fix this. 

What we would like to do is clear the current PWM interrupt and any pending PWM interrupts before leaving the ISR. This way there is nothing pending. Is there a correct way to do this?

Dorion 

  • Hi Dorion,

    • Firstly, regarding your SYNC0 behavior:
      • Yes, your understanding is correct. When the SYNC0 pulse comes in, it will reset the PWM counter back to zero (or whatever value your TBPHS is). This is part of the normal synchronization behavior- even if you get a PWM interrupt request, jump to the interrupt, and then receive a SYNC pulse during the ISR, the PWM counter will still jump to its TBPHS value (in your case, it sounds like 0 is the TBPHS, so the counter will jump to 0 when a SYNC occurs). 
    • Secondly, regarding clearing interrupts:
      • EPWM_clearEventTriggerInterruptFlag() only clears the current interrupt flag, not pending interrupts. This is why you're seeing the behavior where you return to the ISR immediately after leaving it when there's a pending interrupt.
      • So your understanding of the INT flag clearing is correct: The INT flag indicates that when the flag is already set from the first interrupt, however, a second interrupt can be pending and will still be generated after the ETFLG is cleared. The register assumes the INT flag is set from the first interrupt still (and needs to be cleared within the first interrupt ISR), and by doing so it preserves the pending second interrupt. So in this case, you clearing the flag will not prevent the pending second interrupt from occurring. This is also described in the device register descriptions and Event Trigger section:
    • Lastly, to handle your specific scenario:
      • There are a few possible solutions- assuming you never want there to be a pending interrupt, could you try disabling interrupts at the beginning of your PWM ISR?
      • e.g. // In your SYNC0 ISR:
        EPWM_disableInterrupt(myEPWM_BASE); //Beginning of ISR
        EPWM_clearEventTriggerInterruptFlag(myEPWM_BASE); //Clear current interrupt flag
        EPWM_enableInterrupt(myEPWM_BASE); //End of ISR

    Best Regards,

    Allison

  • Hi Allison, thank you for clarifying.

    If we disable the Interrupt and re-enable on the way out will that start stop the PWM counters (we cannot do that) or will it just prevent the ISR from generating a pending interrupt?. 

    Seems like there might still be a possible window (albeit small) that between the time we get to the ISR and we disable it we could get a pending interrupt if the Sync0 came in. Or are you saying that the pending interrupt would disappear when we disable it?

    So there is no way to clear the pending PWM ISR within the ISR by writing a register AFTER we clear the interrupt or is this a chicken and egg issue? Meaning we clear it and then we get the next ISR regardless

  • Hi Dorion,

    Thanks for the follow up. Please allow another day for me to formulate my response  Appreciate your patience!

    Best Regards,

    Allison

  • Hi Dorion,

    Disabling interrupts and re-enabling will not affect the PWM counters in any way. It would just prevent a new interrupt trigger from coming in while interrupts are disabled.

    The disabling prevents the interrupt event counter from incrementing, so I was thinking through if you could perhaps use the interrupt event count in a way to prevent an unwanted interrupt, but will need to check with a colleague on this first- will update you when I can clarify.

    Best Regards,

    Allison

  • Allison, 

      Any update from checking with your colleague? 

    Dorion 

  • Hi Dorion,

    Let me follow up on this and try to get an update later today. Appreciate the patience.

    Best Regards,

    Allison

  • Hi Dorian,

    I'm working on testing this at the moment - will provide another update tomorrow.

    Best Regards,

    Allison

  • Hi Dorian, 

    Sorry haven't been able to set aside the time I wanted yet. Please allow another day or two on this.

    Best Regards,

    Allison

  • Hi Dorian,

    Apologies I was out of office briefly. Please let me know if anything has changed since your last response and if you still need assistance on this topic. 

    Best Regards,

    Allison

  • Allison,

    I am still waiting on your testing. 

    Were we left off was that you were contacting another person in your office and that you were running a test. (See reply on 11/11). 

    Yes this is still a BIG issue for us. I just need a way to clear any pending Interrupts while still in the Interrupt handler for a PWM as described above. 

    Dorion 

  • Hi Dorion,

    Thanks for the follow up. I’m still trying out my test case. In the meantime if you have a project that isolates the issue as well, feel free to send it to me to test out. Have you also tried implementing the disable interrupt function in your ISR?

    Best Regards,

    Allison

  • Hi Allison, 

      I have tried the disable, the problem is it will run for a while but I will still get a pending ISR since the window is NOT zero. I still need a way to clear any pending ISRs before leaving the PWM interrupt handler. 

      To reproduce the issue do the following, (our code is too proprietary to put here). I have not built a test program. 

    1. Setup a PWM with an ISR at 40usecs and generate and go into your ISR

      1a. Have the PWM ISR do something for about 20 usecs, what we do is dump the PWM count when we get into the ISR.

      1b Set the PWM to be in sync with sync0 (meaning when sync0 arrives the PWM count will go to zero and an ISR will be generated)

      1c You will also get an ISR when the PWM count goes zero after 40 usecs

    2. Setup the Sync0 pulse to run at 250 usecs

      2a setup the Sync0 pulse to trigger the PWM above. 

    You will see the issue that the PWM should get Interrupted and the counter should be less than 1-2 usecs (probably way less), but when the sync0 pulse comes it it will be at 10-30 usecs since there is a pending ISR and we are already in the ISR when the Sync0 Pulse gets triggered. 

    It feels like a normal occurrence to me, however we just need a way to clear it before leaving the PWM ISR including anything pending. 

    Does this help?

    Dorion 

  • Hi Dorion,

    Understood about the non-zero window. And thanks for the description, yes this certainly helps in terms of recreating something closer to your setup. I just finished writing the example per your description and will plan to test out a workaround tomorrow.

    Best Regards,

    Allison

  • Hi Dorion,

    Thanks for the patience. I was able to create a test case for this and believe I found a solution for you. Please find the example attached below. The comments at the top and throughout the main C file should explain the test case and how the resolution works in more detail.

    epwm_pending_counted_isr_example.zip

    To summarize:

    • In PWM initialization:
      • Set PWM interrupt event generation to occur every 'x' events (where x > 1). In this example, I set mine to '2'.
      • Initialize PWM interrupt event count to 'x-1' so that the next event that occurs, an ISR will be triggered. 
    • In PWM ISR:
      • Disable PWM interrupts at start of ISR.
      • Force reload the PWM interrupt event count in the ISR prior to re-enabling PWM interrupts.
      • Re-enable PWM interrupts at end of ISR to allow the next PWM ISR (but prevent any pending ISR from triggering your unwanted back-to-back interrupts).

    Observations:

    • Scope signals:
      • CH1: EPWM2 Channel A (your faster PWM that is triggering ISR every CTR = 0)
      • CH2: EPWM1 Channel A (slower PWM that is sending a SYNC to EPWM2)
      • CH3: GPIO25 which is toggled high at start of ISR and low at end of ISR
    • ISSUE
      • Without the above method implemented:
      • We can see CH3 showing back-to-back interrupts when the CH2 PWM issues a sync pulse (when CH2 goes high).

    • RESOLUTION
      • With the above method implemented:
      • We can see CH3 no longer shows back-to-back interrupts. 

    In case you want to run this yourself, please note that that I am using a Revision of F2838x ControlCard that uses 20MHz crystal (not 25MHz that some Revisions do), so I added the "USE_20MHZ_XTAL" pre-define symbol in the project properties to ensure it runs properly.

    Please try to implement this resolution and let me know if you are able to see change in behavior on your end!

    Best Regards,

    Allison

  • Hi Allison, 

      Let me check all this out and I will get back to you in a few days. OK I can see you reproduce the pending ISR by showing channel 3

      I don't understand doing this: 

    • Set PWM interrupt event generation to occur every 'x' events (where x > 1). In this example, I set mine to '2'.
    • Initialize PWM interrupt event count to 'x-1' so that the next event that occurs, an ISR will be trigger

      Dorion 

  • Hi Dorion,

    The key to controlling PWM ISR occurrence is not the interrupt flag, but the interrupt event counter.

    Currently (in the case you see an issue), you are generating an interrupt every '1' event. When you get back to back ISRs, this is because you first receive a regular ISR trigger, which increments your interrupt count to '1' and immediately resets the interrupt counter to '0' (since the ISR is executed right away). The next interrupt request (when the SYNC occurs) will again increment the count to '1' and hold at that value until the first ISR is finished. Once the second (unwanted) ISR is triggered, the interrupt count will reset to 0 and wait for the next interrupt request. 

    In essence, the interrupt event counter is what is storing your pending interrupt.

    By changing the interrupt event count before re-enabling interrupts, we are resetting the interrupt counter to clear any pending interrupt request that had incremented that counter. I had selected the value of '2' arbitrarily, but this method works with any pair of values as long as you are initializing (force reloading) your interrupt event count to a value that is 1 less than your interrupt generation level. I understand where your confusion may be coming from --> I actually made a typo as 'x' doesn't actually need to be greater than 1; I'll fix that in my post Slight smile

    Here are some values I tested- they all work the same since we initialize to 1 value below the interrupt trigger level.

    • Event generation every '1' event
    • Initialize PWM event count to '0'

    • Event generation every '2' events
    • Initialize PWM event count to '1'

    • Event generation every '4' events
    • Initialize PWM event count to '3'

    Hope this helps explain!

    Best Regards,

    Allison

  • Allison, 


      That explains it very well.  

      I assume that you cannot reset the interrupt count UNLESS the PWM is disabled hence why you disable it when you get the ISR, reset it and re-enable it, therefore clearing any pending ISRS?

    Dorion 

  • Hi Dorion,

    Glad to hear. And yes, of curiosity I did try two other cases (1) resetting the counter after re-enabling interrupts in the ISR as well as (2) resetting the counter without disabling/re-enabling interrupts in the ISR at all --> both cases still saw back to back ISRs.

    Best Regards,

    Allison

  • Hi Allison, 

      Fantastic. Let me get to work on this and see if it helps. I don't see why not since it is basically clearing our pending ISRs. 

      Thank you for your help!

    Dorion 

  • Hi Dorion,

    Amazing, yes let me know if you see the change as well or have further questions as you are trying it out. Happy to help!

    Best Regards,

    Allison

  • Hi Allison

     I was able to try your example. There were a few things that I needed to understand, please verify:
     
    1. if you were to get the event count it tells you how many are currently pending. Meaning in the ISR my count never went to 1 (I am using my ISR trigger of 1) until I had a pending interrupt within the current interrupt. 

    2. Then When I apply your example disable PWM, re-init event counter to zero, enable PWM only if the count is 1 or greater it then works. 

    I only did step number to verify that I had a pending ISR and that it got cleared. 

    In my example I also kept a variable to indicate the PWM count before I left the ISR if I entered the ISR again the PWM count was greater than my last record I know I got back in and I bump a count. When I implemented your example this counter never goes up. Which tells me that your example code is working great. 

    I will indicate that above was the correct solution after I get your answer to number 1 above. 

    Dorion 

  • Hi Dorion,

    Glad to hear the solution is working for you! Slight smile

    Number 1 is correct. The event count will increment when a request comes in, and it will restart at 0 when it overflows the 'threshold' at which an interrupt is actually carried out. So if you are generating an interrupt every '1' event, the first time you receive an interrupt request, the event counter will increment, the ISR will be entered, and the event counter will automatically reset to 0. If you receive another interrupt request during that ISR, it would be pending; hence, the event count should hold at '1' until that interrupt is sent to the interrupt controller to actually carry out the next ISR.

    Best Regards,

    Allison

  • Allison, 

      Fantastic! Thank you for all the help and helping us get this resolved. It is working great. 

    Dorion 

  • Dorion,

    No problem! That's great to hear. Should y'all run into any more issues/questions, feel free to create another thread.

    Best Regards,

    Allison

  • Allison, 

      I was hoping you could answer another question. 

      The code we have is working but now I want to keep a count of how often it happens. It is OK if it happens within the first 1 usec of the ISR handler. 

      So the code we do basically clears any pending ISRS and then at the end of the ISR Handler we check if there is any pending ISRS and if so we count them. 

      What it looks like is that when we clear any pending ISRs (meaning we do it regardless) we never get another Pending ISR unless we leave the ISR handler. If I don't just automatically clear any pending interrupts and just do if if one is set then later in the ISR we do have a pending interrupt.

    In your example if you change your code to make it such that you clear the pending ISR (before you have one) at the top of the ISR handler and then later check if you have one you, I don't think you will see one pending. 

      Is this expected behavior?

    Dorion 

  • Dorion,

    Allison is currently out of office and will get back to you when she returns next week. Thank you!

    Best Regards,

    Aishwarya

  • Hi Dorion,

    Apologies for the delay - I will be out of office for some extended time. I will try to get a response to you next week. Appreciate your patience!

    Best Regards,

    Allison

  • Hi Dorion, 

    I am back in office - thanks for the patience. Regarding your inquiry:

    What it looks like is that when we clear any pending ISRs (meaning we do it regardless) we never get another Pending ISR unless we leave the ISR handler. If I don't just automatically clear any pending interrupts and just do if if one is set then later in the ISR we do have a pending interrupt.

    Can you show a quick snippet of your ISR in the second case for my understanding?

    To clarify, are you trying to only clear a single ISR if it occurs in a specific time frame? Meaning if you receive a pending ISR while you are still processing the first ISR, but the timing is at a later point, you need to keep the pending ISR?

    Best Regards,

    Allison

  • Hi Allison, 

      Hope you enjoyed the holidays. To answer your question. We need to clear the pending ISRs regardless but getting one early in the ISR function is OK, we want to keep track if we get one later in the ISR function which is ILLEGAL 

      Snippet. If we just clear the Pending ISRs in the first check below then the second check will never show a pending ISR. In our case it is LEGAL to have a pending ISR before we service the ADCs but illegal everywhere else. 

    __interrupt void MotorFclISR(void)
    {
         // Make sure the FCL ISR is enabled.
        if (FclServiceISR()) {
          // It is NOT illegal to get here and have a pending ISR
            // If we have one just clear it.
            if (FclCheckForPendingISR())
            {
                FclClearPendingISRs();
            }

            FclHarvestAllAdcValues();

            // Start FCL processing For the correct projects MOTOR_LAST will be setup properly
            for (int i = MOTOR_A; i < MOTOR_LAST; i++) {
                pMotor = &(gMotorPtrs[i]);
                pFclHwResults = pMotor->pFclHwResults;
                pFclSwResults = pMotor->pFclSwResults;

                // We need to harvest from the pFcl structures back the OD before calling trace.
                Cpu2MotorHarvestLocalToOD(pMotor);
            }
        }

        // It takes time to clear any pending interrupts so
        // check to make sure there is something before clearing it.
        if (FclCheckForPendingISR())
        {
            pFclHwResults = gMotorPtrs[MOTOR_A].pFclHwResults;
            *(pFclHwResults->pFclPendingIsrCount) += 1;

            FclClearPendingISRs();
        }

    Does this answer your question?

    Dorion 

  • Hi Dorion,

    Thanks so much for the context. I believe this answers my question - let me see if I can test out what you are seeing as well in the next day or two and I'll report back.

    Best Regards,

    Allison

  • Hi Dorion, 

    Apologies, I was unable to finish testing this week. Let me provide update you early next week, and please let me know should more urgency arise. Appreciate your patience!

    Best Regards,

    Allison

  • Sounds good. 

    Dorion 

  • Hi Dorion,

    Sorry for the delay, but I'm not seeing the same behavior as you described. I made some modification to our example where I can check the interrupt event count at several points to see if an interrupt request had occurred within the ISR, and I increased frequency of EPWM1 so that it triggers EPWM2 sync pulses (and interrupt requests) faster.

    I set breakpoints to pause after every time the Interrupt Count (just a simple IntCount variable) is recorded at the beginning of the ISR (before placeholder delay) and later in the ISR (after placeholder delay). I can see a pending interrupt request populate the first time I check in the beginning of the ISR, I can clear/reset it right after that and see IntCount cleared/reset, and I can also still see a pending interrupt populate later in the ISR when the Interrupt event count IntCount is checked again. This is what I would expect as well.

    So in this case, to me it seems reasonable to check and clear/reset the Interrupt Event Counter in the middle of your ISR so that you don't have an early pending interrupt request in the ISR, but allow a later pending interrupt request in the ISR. 

    Best Regards,

    Allison

  • Allison, 

      As always thank you for your help and responses. I will dig in more on my end. I was playing around a little myself after reading your response if I change the ISR count to 2 instead of 1 I get better results. Odd. 

    Dorion