PWM/USBUART conflict - Logic problem?

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hello again, everyone!

I'm having (yet another) issue with my variable PWM project, this time it seems to be some sort of conflict between the USBUART and the PWM, oddly enough.  I created a stripped down version of the code to recreate the problem.

Background

When my code is working normally, it's setup to do the following:

T=0

Valve 1 = on, Valve 2,3,4 off

T=1

Valve2 = on, Valve 1,3,4 off

T=3

Valve 3 = on, Valve 1,2,4 off

T=6

Valve 4 = on, Valve 1,2,3 off

T=10

Valve 1,2,3,4 off

V=12=0

Repeat

Below is what this looks like (In order from Pin_Valve_CH1 to Pin_Valve_CH4):

pastedImage_0.png

Here is my hardware setup, for reference (the whole project is included with this post though, if that's easier.  Just trying to save time for anyone looking at this, in case they can eyeball the problem without needing to simulate it):

pastedImage_15.png

The Problem

This will repeat indefinitely until I write to the USBUART (you can basically send anything, I just have shell code that doesn't really do anything with it in this project).  Once I write to the USBUART, CH1 locks high and never seems to recover:

pastedImage_1.png

I was able to isolate the issue by commenting out sections of the ISR so that my logic goes from this:

CY_ISR(PWM_Interrupt_Handler)

{

    Pin_LED3_Write(~Pin_LED3_Read());

    /* Current Code */

    arrayindex = SR_Channel_Read();

   

    // Temporary Bandaid - Need to fix

    if(arrayindex==NumSensors)

    {

        arrayindex = 0; 

    }

    else

    {

        arrayindex += 1;  

    }

    PWM_WritePeriod(OnTimeArray[arrayindex]);

   

    if(arrayindex==NumSensors)

    {

        PWM_WriteCompare(0);

    }

    else

    {

        PWM_WriteCompare(OnTimeArray[arrayindex]);

    }

    /* End of current code */

   

    PWM_WriteCounter(0);

    uint8 tempdata = PWM_ReadStatusRegister();

}

To this:

CY_ISR(PWM_Interrupt_Handler)

{

    Pin_LED3_Write(~Pin_LED3_Read());

    /*Test Code */

//    PWM_WritePeriod(PWM_ReadPeriod());

//    PWM_WriteCompare(PWM_ReadCompare());

    /* End of test code */

      

    PWM_WriteCounter(0);

    uint8 tempdata = PWM_ReadStatusRegister();

}

If I move to the latter code (effectively just writing out the same current period and compare values), the PWM doesn't lock up but obviously doesn't update the PWM correctly (as shown below):

pastedImage_4.png

You might be wondering why the logic for the PWM update is so chaotic and the reason is when I just tried to input the current code to update based on the SR register, it was off by one cycle.  Below is the code and the output:

pastedImage_5.png

CY_ISR(PWM_Interrupt_Handler)

{

    Pin_LED3_Write(~Pin_LED3_Read());

   /* Current Code */

    arrayindex = SR_Channel_Read();

   

    PWM_WritePeriod(OnTimeArray[arrayindex]);

       

    PWM_WriteCompare(OnTimeArray[arrayindex]);

   

    /* End of current code */

  

      

    PWM_WriteCounter(0);

    uint8 tempdata = PWM_ReadStatusRegister();

}

Interestingly enough, the above code doesn't seem to show the same latching issues so there's some issue with my "bandaid" that's causing the problem.  Maybe I just need a way to add some sort of hardware delay so that the SR_Channel_Read() is correct and then the above code will work but, it appears that my temporary solution is the core of the issue and I don't really understand why.  Any information you can give me would be greatly appreciated.

If you have any solutions or can see what the root cause might be, please let me know,  Sorry for the size of the post but I figure too much info is always better than too little info and I've been trying to resolve this issue for longer than I'd care to admit . . . thanks again!

0 Likes
1 Solution
Anonymous
Not applicable

Hi,

Line number 142 in main.c which clears out NumSensors look suspicious. For any input via USBUART, this variable is getting cleared. Here is what is happening-

1. When data is received over USB-UART, NumSensors gets cleared in line 142.

2. Everything works fine until arrayindex reaches 4. When arrayindex reaches 4, it is incremented by 1 in line 60.

3. PWM period is written 0 in line 63 and interrupt is never triggered again

4. In hardware, ch1 is always selected and it remains high

-Rajiv 

View solution in original post

0 Likes
8 Replies
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Nice problem. Let us see:

The USBUART will not interfere with a PWM. There are millons (if not billions) of PSoCs out there and you are the only one with htat bug.

The one and only connection between PWM and USB are the interrupts. They have different priorities, so one can delay the other from firing.

When looking at your handler i see that you are changing global variables that are not declared as "volatile". This is a potential hard-to-find bug. Change that although this is not the current issue.

I can see that you have made provisions for using printf. Make sure that the heap size is 0x0200 (currently 0x0080) in system view.

You are making changes to a running PWM which might fire interrupts unexpectedly when period and/or compare value get changed.

Think about to stop the PWM, setup anew and then enable it again.

Is there a reason why you connected the isr component to TC instead of the interrupt output? I would suggest to use the latter.

Lastly I would change the PWM priority value to something lower than the USB priority which will result in a higher PWM priority.

Bob

0 Likes
Anonymous
Not applicable

Hi,

Line number 142 in main.c which clears out NumSensors look suspicious. For any input via USBUART, this variable is getting cleared. Here is what is happening-

1. When data is received over USB-UART, NumSensors gets cleared in line 142.

2. Everything works fine until arrayindex reaches 4. When arrayindex reaches 4, it is incremented by 1 in line 60.

3. PWM period is written 0 in line 63 and interrupt is never triggered again

4. In hardware, ch1 is always selected and it remains high

-Rajiv 

0 Likes
Anonymous
Not applicable

rajiv.vasanth.badiger

...I can't believe that was the issue... I've been focused on unintended consequences of hardware, trying to understand if I'm not clearing a register correctly, interrupts, etc... the problem ends up being a leftover relic that should've been removed long ago (I originally had this as a local variable that was initiated at 0, made it a global to be used elsewhere and didn't remember the initialization)...

Thank you so much for your help!  I've been pulling my hair out trying to figure this out, narrowed it down to a small area and didn't notice the obvious right in front of me.  I appreciate it!

bob.marlowe​, thanks for your help as well!  You're right, I do need to make those volatile.  I might experiment with using the interrupt rather than the TC but there was a reason I switched over at one point and I don't remember what it is.  Might be time to revisit this!.  As far as the interrupt suggestions on the PWM, the timing is actually pretty important so I'm trying to not to do anything that might interrupt the timing (I considered disabling and re-enabling at one point but might be worth revisiting again anyway, as you suggested).  Thanks again!

0 Likes
Anonymous
Not applicable

Quick followup, is there a better way of handling my sensor offset using the SR?  Right now, I have that "bandaid" logic but I'm assuming there's probably a better way to do that with hardware so it doesn't need to be adjusted with software.  Let me know when you get the chance.  Thanks!

0 Likes
Anonymous
Not applicable

Jeremy,

I wanted to know why the pins are not being set by firmware, instead of using PWM and MUX logic. The sequence of events, here, seems to be simple and slow enough.

- Rajiv

0 Likes
Anonymous
Not applicable

rajiv.vasanth.badiger

The reason for this is it's used in a bigger system.  I want to be able to change the timing of the PWM via the USBUART but want a harware solution for it's consistency (didn't want to just hardcode all the values).  I figured, even if the code hangs somewhere, the hardware will continue to work (which is important for our system as we can't afford to have the valves lock up).  It also should make it timing proof in times we're using considerably faster switching times (the above is just a proof of concept of the basic structure.  The extended application is much larger)

Maybe there's a better way to do it but this seemed to be the most reliable way of ensuring that the valves keep firing, regardless of what the code does.  Maybe I'm wrong though.

Do you know a better way of handling the active channel issue I'm having above, rather than using the "delay logic" I'm using in the interrupt?  It appears to do the trick, just wanted to know if there's a better approach.  Thanks!

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Jeremy,

For the "temporary band-aid", there are multiple ways to do it. One way is to use both edges of the signal to sequence the tasks. In the design, connect the TC signal of PWM directly to the count input of 3-bit counter. Pass the TC signal to a NOT gate and drive the status register and also generate an interrupt. With this, counter gets updated half PWM input clock prior to the status register update and the generation of interrupt. In the handler, reading of status register will provide the present value of the counter. Much easier way would have been to read the counter directly instead of using a status register; but I am currently not finding a way to read it. I have attached the project for your reference.

There is one more change that I have made. PWM is a down counter; thus I am reloading the counter to the period value instead of zero (this probably explains why you were not able to use TC as the clock input to the counter; TC gets continuously triggered when written with zero).

There was much easier way to build this design. I am not sure, though, how it will fit into your complete solution.

PWMControl.png

In this design, DMA can be used to update the timer period. With every input trigger, DMA will sequence through the steps to update the control register and the timer period value. The advantage with this method is that it doesn't require CPU while it is scrolling through the steps. Modifying the design for a given number of valves is also easy by configuring the transaction descriptors (TDs) of DMA.

-Rajiv

0 Likes
Anonymous
Not applicable

rajiv.vasanth.badiger

Thanks for all your help with this!  I apologize for the delay, I actually was unavailable this weekend and just saw this.  I got my application working in it's current form but your updated file looks like it could simplify the code a bit so I'll try it out sometime this weekend.

Also, thanks for the alternate setup with the DMA as well!  I'll have to do some more reading on this and try some example projects to understand the correct way to use this but, with our current project timing, I probably need to get this solution in place and then circle back to this down the line when trying to optimize things a bit more.  From the way you describe it, it's sounding like your proposed solution is a much better way to approach it.  I wish I had known about that approach a few months ago when I set down this path!  heh . . .

Thanks again for all your help!

0 Likes