How to change pwm period on runtime in ncs?

Hi, 

I'm trying to play some sounds on a piezo with the help of the pwm. I tried to set the period with pwm_set_dt but only the first call is successful and every subsequent call raised an error. 

Here is my test code:

    for(uint16_t i = 400; i < 800; i++)
    {
        int ret = pwm_set_dt(&piezo_pwm_pos, PWM_HZ(i),
						   PWM_HZ(i) / 2);
        LOG_DBG("pwm_set_dt = %d", ret);

        ret = pwm_set_dt(&piezo_pwm_neg, PWM_HZ(i),
						   PWM_HZ(i) / 2);
        LOG_DBG("pwm_set_dt = %d", ret);
        k_msleep(10);
    }

The results looked like this:

00> D: pwm_set_dt = 0
00> D: pwm_set_dt = 0
00> E: Incompatible period.
00> D: pwm_set_dt = -22
00> E: Incompatible period.
00> D: pwm_set_dt = -22
00> E: Incompatible period.
00> D: pwm_set_dt = -22
00> E: Incompatible period.
00> D: pwm_set_dt = -22
00> E: Incompatible period.
00> D: pwm_set_dt = -22

I didn't find anything in the documentation of pwm_set for the error 22.

How can I change period and pulse while the pwm is running?

Best regards,

Christian

  • Hi, 

    in your case you just changed the period of one pin. If I do it also for only one channel everything works. I want to set two pins exactly inverted with changing frequency over time as seen in the image below.

    But I only can change the frequency for one channel or set it once for two channels. It's not possible to change the frequency while the pwm is active. I could change the frequency if I disable the pwm for both channels before setting the new frequency, but this results in an interrupted output sound on the piezo. 

    How can I invert channel 1 in relation to channel 0? 

    Best regards,

    Christian

  • Try using the  pwm_set_cycles() function. And use PWM_POLARITY_NORMAL on one channel, and  
    PWM_POLARITY_INVERTED on the other. Snippet:
    ret = pwm_set_cycles(pwm_led0->dev, pwm_led0->channel, period_cycles, period_cycles / 2,
    	PWM_POLARITY_INVERTED);
    
    ret = pwm_set_cycles(pwm_led1->dev, pwm_led1->channel, period_cycles, period_cycles / 2,
    		PWM_POLARITY_NORMAL);
  • Hi, 

    you already suggested this, but it also results in "Incompatible period." and the functions return -EINVAL after the first time. Is it a problem, that I call these functions from a timeout handler?

    In the nrf5 SDK there was NRF_DRV_PWM_EVT_FINISHED. In this event handler I could change the frequency of the pwm and it results in a nice alarm sound. Why is this not possible with the nrf connect SDK. 

  • Ah, right!

    How do you define these channels?

    If you do it like this in the dts:

    https://github.com/nrfconnect/sdk-zephyr/blob/v3.7.99-ncs2/boards/nordic/nrf52dk/nrf52dk_nrf52832.dts#L48-L53

    you can have e.g. pwm_led_0 with PWM_POLARITY_INVERTED,

    and define a pwm_led_1 with PWM_POLARITY_NORMAL

  • It's defined like this:

    pwmpiezo0 {
    		compatible = "pwm-leds";
    		status = "okay";
    	
    		piezo_pwm_pos: piezo_pwm_pos {
    				status = "okay";
    				pwms = <&pwm1 0 PWM_HZ(7500) PWM_POLARITY_NORMAL>;
    				label = "Piezo positive";
    		};
    	
    		piezo_pwm_neg: piezo_pwm_neg {
    				status = "okay";
    				pwms = <&pwm1 1 PWM_HZ(7500) PWM_POLARITY_INVERTED>;
    				label = "Piezo negative";
    		};
    	};

    One of the pins is already inverted. I then call 

    ret = pwm_set_dt(&piezo_pwm_pos, PWM_HZ(m_piezo_params.frequency),
    					PWM_HZ(m_piezo_params.frequency) / 2);
    
    ret = pwm_set_dt(&piezo_pwm_neg, PWM_HZ(m_piezo_params.frequency),
    				   PWM_HZ(m_piezo_params.frequency) / 2);

    within a timeout handler every x ms. If m_piezo_params.frequency stays the same, the function calls return 0. But if I change the frequency it breaks after the first timeout. 

Related