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.

AM3358: eHRPWM output issue

Part Number: AM3358

Dear Sir,

I have enabled ehrpwm2a and ehrpwm2b. Using command line I can program the period and duty_cycle in that order. However I have an odd behaviour where enabling ehrpwm2b the other channel 2a turns on too. Has anyone come across this problem. Is this issue related to programming the channel dts or programming order ?

My dts

       ehrpwm2a_pins: pinmux_ehrpwm2a_pins {
            pinctrl-single,pins = <
                        AM33XX_IOPAD(0x820, PIN_OUTPUT_PULLDOWN | MUX_MODE4)       
                >;
        };
        ehrpwm2b_pins: pinmux_ehrpwm2b_pins {
            pinctrl-single,pins = <
            AM33XX_IOPAD(0x824, PIN_OUTPUT_PULLDOWN | MUX_MODE4)
                >;
        };

&epwmss2 {
    status = "okay";

    ehrpwm2: pwm@48304200 {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&ehrpwm2a_pins &ehrpwm2b_pins>;
    };

};

make linux-dtbs, copied am335x-boneblack.dtb to /boot and reboot

Command line

1) program pwm0 first and check pin output

root@am335x-evm:~# cd /sys/class/pwm/pwmchip4
root@am335x-evm:/sys/class/pwm/pwmchip4# echo 0 > export
root@am335x-evm:/sys/class/pwm/pwmchip4# echo 500000 > pwm0/period
root@am335x-evm:/sys/class/pwm/pwmchip4# echo 500000 > pwm0/duty_cycle

root@am335x-evm:/sys/class/pwm/pwmchip4# echo 1 > pwm0/enable
root@am335x-evm:/sys/class/pwm/pwmchip4# echo 0 > pwm0/enable

so far so good, pwm0 pin seen turning on and off

2) now program pwm1

root@am335x-evm:/sys/class/pwm/pwmchip4# echo 1 > export
root@am335x-evm:/sys/class/pwm/pwmchip4# echo 500000 > pwm1/period
root@am335x-evm:/sys/class/pwm/pwmchip4# echo 500000 > pwm1/duty_cycle

root@am335x-evm:/sys/class/pwm/pwmchip4# echo 1 > pwm1/enable

pwm1 came on, OOPS pwm0 has turned on too!

root@am335x-evm:/sys/class/pwm/pwmchip4# echo 0 > pwm1/enable

pwm1 turns off, OOPS pwm0 remains on.

3) Lets check pwm0 enable value

root@am335x-evm:/sys/class/pwm/pwmchip4# cat pwm0/enable
0

So the pin pwm0 output is on yet the enable variable is off.

I must be doing something wrong as I couldn't find this problem  on the forum.

Other info

Beaglebone black

ti SDK 04.02.00.09

Much appreciate any help.

best regards

  • Hi,

    I experience the same behavior on my side. Let me check this further and I will update.

    Best Regards,
    Yordan
  • Ok, here is what I observed on my BBB:

    1. Configure the pwm channels as in your use case:
    echo 0 > export
    echo 500000 > pwm0/period
    echo 500000 > pwm0/duty_cycle

    echo 1 > export
    echo 500000 > pwm1/period
    echo 500000 > pwm1/duty_cycle

    2. Upon enabling pwm0 with echo 1 > pwm0/enable the Action-Qualifier Control Register for Output A (EPWMxA) AQCTLA = 0x001AC350, the Action-Qualifier Software Force Register AQSFRC = 0x0 and AQCTLB = 0x0 (Action-Qualifier Control Register for Output B(EPWMxB)), which results in activating just channel 0.

    3. When I disable pwm0 with echo 0 > pwm0/enable I cannot read any of those registers, because pwm clock is gated and the module is disabled. This is a normal behavior.

    4. The problem comes whe enabling channel 1 with echo 1 > pwm0/enable. Upon execution of this user space command the result is:
    AQCTLA = 0x001AC350
    AQSFRC = 0x0000010A
    AQCTLB = 0x0000010A

    As you can see enabling channel 1 also sets the channel 0 registers.... This is quite strange. I will try to track down the code to see if it gets messed up somewhere, but it is possible that we're missing something in understanding how the controller operates the two channels. Let me check further.

    Best Regards,
    Yordan

  • Hello,

    Just an update, reaching out to the software owner now.

    Regards,
    Nick
  • Hello Naseer,

    Looks like you found a bug, thank you!

    From the Linux team: "There seems to be a bug in drivers/pwm/pwm-tiehrpwm.c::ehrpwm_pwm_disable(). pwm-tiehrpwm driver disables PWM output by putting it in low output state via active AQCSFRC register in ehrpwm_pwm_disable(). But, the AQCSFRC shadow register is not updated. Therefore, when shadow AQCSFRC register is enabled in ehrpwm_pwm_enable(), previous settings are lost as shadow register value is loaded into active register. This results in things like PWMxA getting enabled automatically, when PWMxB is enabled and vice versa"

    The below code patch hasn't been thoroughly tested yet, but give it a shot:

    diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 4c22cb395040..188161936807 100644
    --- a/drivers/pwm/pwm-tiehrpwm.c
    +++ b/drivers/pwm/pwm-tiehrpwm.c
    @@ -388,6 +388,8 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
                    aqcsfrc_mask = AQCSFRC_CSFA_MASK;
            }
     
    +       /* Update shadow register first before modifying active register */
    +       ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, 
    + aqcsfrc_val);
            /*
             * Changes to immediate action on Action Qualifier. This puts
             * Action Qualifier control on PWM output from next TBCLK
    

    Before rebuilding the kernel & modules (so Linux SDK 4.3, out of the box example with modified dts to include your PWMSS2), I tested the value of AQCSFRC with "devmem2 0x4830421c h":

    pwm0 on, pwm1 on ==> pwm0 on, pwm1 off: AQCSFRC = 0x0004

    pwm0 on, pwm1 off ==> pwm0 off, pwm1 off ==> pwm0 on, pwm1 off: AQCSFRC = 0x0000

    pwm0 on, pwm1 off ==> pwm0 on, pwm1 on ==> pwm0 off, pwm1 on:  AQCSFRC = 0x0001

    pwm0 off, pwm1 on ==> pwm0 off, pwm1 off ==> pwm0 off, pwm1 on: AQCSFRC = 0x0000

    After rebuilding the kernel & modules (so add the above patch), the register values were:

    pwm0 on, pwm1 on ==> pwm0 on, pwm1 off: AQCSFRC = 0x0004

    pwm0 on, pwm1 off ==> pwm0 off, pwm1 off ==> pwm0 on, pwm1 off: AQCSFRC = 0x0004

    pwm0 on, pwm1 off ==> pwm0 on, pwm1 on ==> pwm0 off, pwm1 on:  AQCSFRC = 0x0001

    pwm0 off, pwm1 on ==> pwm0 off, pwm1 off ==> pwm0 off, pwm1 on: AQCSFRC = 0x0001

    Regards, 

    Nick