How to use two sw_pwm instances with nrf5340 with Zephyr?

Hi folks,

I've been trying to use the sw_pwm to generate two PWM outputs. I'm using sw_pwm because I want to achieve lower frequencies (1-100Hz) and the hardware PWM API only supports lower frequencies up to 4 HZ.

My issue is when I run both channels, the channel 0 stops working while channel 1 still working as we expect.

This is my overlay file:

&pwm0 {
	status = "disabled";
};

&sw_pwm {
	status = "okay";
	channel-gpios = <&gpio0 30 PWM_POLARITY_NORMAL>, <&gpio0 31 PWM_POLARITY_INVERTED>;
};


/ {
	my_pwm_leds {
		compatible = "pwm-leds";
		pwm_led01: pwm_led_01 {
			pwms = <&sw_pwm 0 PWM_MSEC(200) PWM_POLARITY_NORMAL>;
		};
		pwm_led02: pwm_led_02 {
			pwms = <&sw_pwm 1 PWM_MSEC(100) PWM_POLARITY_INVERTED>;
		};
	};
};

/ {
	aliases {
		pwm-led01 = &pwm_led01;
		pwm-led02 = &pwm_led02;
	};
};

And this is my app code:

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/device.h>
#include <zephyr/drivers/pwm.h>

static const struct pwm_dt_spec pwm_led1 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led01));
static const struct pwm_dt_spec pwm_led2 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led02));

int main(void)
{
	uint32_t max_period;
	printk("PWM-based blinky\n");
	if (!pwm_is_ready_dt(&pwm_led1)) {
		printk("Error: PWM device %s is not ready\n",
		       pwm_led1.dev->name);
		return 0;
	}

	if (!pwm_is_ready_dt(&pwm_led2)) {
		printk("Error: PWM device %s is not ready\n",
		       pwm_led2.dev->name);
		return 0;
	}

	max_period = PWM_HZ(10U);

	pwm_set_dt(&pwm_led1, max_period, max_period / 2U);
	pwm_set_dt(&pwm_led2, max_period, max_period / 2U);
	return 0;
}

Does anyone previously integrated multiple sw_pwm instances? O what other options should I follow to achieve lower frequencies for the pwm output (below to 4Hz)?

Regards!

  • Hi,

     

    I see the same issue as you.

    You will run into issues wrt. the timer instance running, as the pwm_nrf_sw uses GPIOTE+TIMER+PPI, as you cannot get it to clear on two events simultaneously.

    When you start one channel (led0), and queue the next (led1), the timer is already running, thus one will be cleared/restart the timer first, causing the emitted LED pattern to break for the first channel.

    You will then notice a unwanted pattern in how the LEDs behave when both your pwm_led1 and pwm_led2 is concurrently running, although the implementation itself indicates that you can setup more than one index in channel-gpios:

    https://github.com/nrfconnect/sdk-zephyr/blob/v3.7.99-ncs1/drivers/pwm/pwm_nrf_sw.c#L414-L419

     

    I am checking internally to what extent we support multiple outputs with this library.

     

    Kind regards,

    Håkon

Related