Adding PWM Channels in Zephyr

I am developing a custom board application in Zephyr 3.2.99.  I have a single PWM Channel running now but having trouble adding addtional channels.

In the 52811.dtsi, I have a single pwm node:

                pwm0: pwm@4001c000 {
                        compatible = "nordic,nrf-pwm";
                        reg = <0x4001c000 0x1000>;
                        interrupts = <28 NRF_DEFAULT_IRQ_PRIORITY>;
                        status = "disabled";
                        #pwm-cells = <3>;
                };

then, in my pinctrl-dtsi I have:

	pwm0_default: pwm0_default {
		// Channel 0
		group1 {
			psels = <NRF_PSEL(PWM_OUT0, 0, 23)>; 
			nordic,invert;
		};

	};

	pwm0_sleep: pwm0_sleep {
		group1 {
			psels = <NRF_PSEL(PWM_OUT0, 0, 23)>;
			low-power-enable;
		};
	};

The in my .dts I have:

	pwmleds {
		compatible = "pwm-leds";
			// pwm0 Ch 0 
			pwm_led0: pwm_led_0 { 
					pwms = <&pwm0 0 PWM_NSEC(62500) PWM_POLARITY_INVERTED>;
			};
	};

and:

&pwm0 {
	status = "okay";
	//status = "disabled";
	pinctrl-0 = <&pwm0_default>;
	pinctrl-1 = <&pwm0_sleep>;
	pinctrl-names = "default", "sleep";
};

in my main driver, I have followed the Zephyr example code:

static const struct pwm_dt_spec pwm_led0 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led0));

	#define NUM_STEPS       1024U
	#define SLEEP_MSEC      25U

	uint32_t pulse_width = 0U;
	uint32_t step = pwm_led0.period / NUM_STEPS;
	//uint32_t step = pwm_led1.period / NUM_STEPS;
	uint8_t dir = 1U;
	int ret;

	printk("PWM-based LED fade\n");

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

	while (1) {
		ret = pwm_set_pulse_dt(&pwm_led0, pulse_width);
		if (ret) {
				printk("Error %d: failed to set pulse width\n", ret);
				return;
		}

		if (dir) {
				pulse_width += step;
				if (pulse_width >= pwm_led0.period) {
						pulse_width = pwm_led0.period - step;
						dir = 0U;
				}
		} else {
				if (pulse_width >= step) {
						pulse_width -= step;
				} else {
						pulse_width = step;
						dir = 1U;
				}
		}


		k_sleep(K_MSEC(SLEEP_MSEC));
	}

}

I have been stuck on this for a while and now I'm really in a bind.

Thanks,

Drew

Parents
  • Hi Drew

    I think the problem is that you haven't properly added the additional channels to the pinctrl and pwmleds nodes. 

    I was able to add a second channel to the led_pwm sample in Zephyr simply by adding the following overlay file to the example:

    &pinctrl {
        pwm0_default: pwm0_default {
    		group1 {
    			psels = <NRF_PSEL(PWM_OUT0, 0, 13)>,
                        <NRF_PSEL(PWM_OUT1, 0, 14)>;
    			nordic,invert;
    		};
    	};
    
    	pwm0_sleep: pwm0_sleep {
    		group1 {
    			psels = <NRF_PSEL(PWM_OUT0, 0, 13)>,
                        <NRF_PSEL(PWM_OUT1, 0, 14)>;
    			low-power-enable;
    		};
    	};
    };
    
    /{
    	pwmleds {
    		compatible = "pwm-leds";
    		pwm_led0: pwm_led_0 {
    			pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_INVERTED>;
    		};
            pwm_led1: pwm_led_1 {
    			pwms = <&pwm0 1 PWM_MSEC(20) PWM_POLARITY_INVERTED>;
    		};
    	};
    };

    Please note I used a nRF52840DK for the test, but the code should look similar for the nRF52811. 

    Best regards
    Torbjørn

  • Thanks for the reply. I figured that out shortly after I posted. The problem was that I had the pwmleds configured as the default PWM_POLARITY_INVERTED. So the led's would turn on as soon as the board started.  I switched to PWM_POLARITY_NORMAL and now everything is behaving as we desire.

    	pwm0_default: pwm0_default {
    		// Channel 0
    		group1 {
    			psels = <NRF_PSEL(PWM_OUT0, 0, 23)>, // Channel 0 
    					<NRF_PSEL(PWM_OUT1, 0, 15)>, // Channel 1
    					<NRF_PSEL(PWM_OUT2, 0, 22)>; // Channel 2
    
    			//nordic,invert;
    		};
    
    	};
    
    	pwmleds {
    		compatible = "pwm-leds";
    			// pwm0 Ch 0
    			pwm_led0: pwm_led_0 { 
    					//pwms = <&pwm0 0 PWM_NSEC(62500) PWM_POLARITY_INVERTED>;
    					pwms = <&pwm0 0 PWM_NSEC(62500) PWM_POLARITY_NORMAL>;
    			};
    			// pwm0 Ch 1
    			pwm_led1: pwm_led_1 { 
    					pwms = <&pwm0 1 PWM_NSEC(62500) PWM_POLARITY_NORMAL>;
    
    			};
    			// pwm0 Ch 2
    			pwm_led2: pwm_led_2 {
    					pwms = <&pwm0 2 PWM_NSEC(62500) PWM_POLARITY_NORMAL>;
    			};
    	
    	};

    I simply commented out the "nordic,invert" property in the pinctrl-dtsi but I'm not sure if that is the proper way to handle that.

    Drew

Reply
  • Thanks for the reply. I figured that out shortly after I posted. The problem was that I had the pwmleds configured as the default PWM_POLARITY_INVERTED. So the led's would turn on as soon as the board started.  I switched to PWM_POLARITY_NORMAL and now everything is behaving as we desire.

    	pwm0_default: pwm0_default {
    		// Channel 0
    		group1 {
    			psels = <NRF_PSEL(PWM_OUT0, 0, 23)>, // Channel 0 
    					<NRF_PSEL(PWM_OUT1, 0, 15)>, // Channel 1
    					<NRF_PSEL(PWM_OUT2, 0, 22)>; // Channel 2
    
    			//nordic,invert;
    		};
    
    	};
    
    	pwmleds {
    		compatible = "pwm-leds";
    			// pwm0 Ch 0
    			pwm_led0: pwm_led_0 { 
    					//pwms = <&pwm0 0 PWM_NSEC(62500) PWM_POLARITY_INVERTED>;
    					pwms = <&pwm0 0 PWM_NSEC(62500) PWM_POLARITY_NORMAL>;
    			};
    			// pwm0 Ch 1
    			pwm_led1: pwm_led_1 { 
    					pwms = <&pwm0 1 PWM_NSEC(62500) PWM_POLARITY_NORMAL>;
    
    			};
    			// pwm0 Ch 2
    			pwm_led2: pwm_led_2 {
    					pwms = <&pwm0 2 PWM_NSEC(62500) PWM_POLARITY_NORMAL>;
    			};
    	
    	};

    I simply commented out the "nordic,invert" property in the pinctrl-dtsi but I'm not sure if that is the proper way to handle that.

    Drew

Children
Related