This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to flash the leds with a duty cycle that does not equal 50%?

Hello,

I use the nrf5340 pdk. I would like to flash the led1 with a duty cycle which is different from 50%, so i tried to open the binky_pwm project, but the segger shows that there is error.

So, I look on the forum and I find that there are people who have encountered the same problem and it has solved it well. So I follow the same steps, but it's still wrong for me. (ps: https://devzone.nordicsemi.com/f/nordic-q-a/71402/i-am-looking-for-simple-example-of-hw-driver-of-qdec-for-nrf5340)

So I would like to ask if you have any ideas on this?

Or can you give me a simpler example to achieve my goal? (for example: time on equals 2ms and time off equals 1ms.)

Thank you in advance!

  • Hi,

    If you want a simpler example, which works out of the box, try the blinky example.

    There you can make a few simple changes to achieve what you are looking for.

    At the top make two different times:

    /* 1000 msec = 1 sec */
    #define ON_TIME_MS      2000
    #define OFF_TIME_MS     1000

    In the while loop, alternate between the times:

    	while (1) {
    		gpio_pin_set(dev, PIN, (int)led_is_on);
    		led_is_on = false;
    		k_msleep(ON_TIME_MS);
    		gpio_pin_set(dev, PIN, (int)led_is_on);
    		led_is_on = true;
    		k_msleep(OFF_TIME_MS);
    	}

  • Hello, thank you for the example.

    In fact, I successfully ran the example binky_pwm, so I would like to ask if you know how to set a pwm_ledext1 at pin1.00 because I set an external led at PIN1.00 through the file nrf5340pdk_nrf5340_cpuapp.overlay.

     {
    	aliases {
    		pwm-led0 = &pwm_led0;
                    pwm-ledext1 = &pwm_ledext1;
                    ledext1 = &ledext1;
    	};
    };
    
    / {
    pwmleds {
    	compatible = "pwm-leds";
    	pwm_led0: pwm_led_0 {
    		pwms = < &pwm0 0x1c >;
    	};
            pwm_ledext1: pwm_led_ext1 {
    		pwms = < &pwm0 0x1c >;
    	};
    };
    };
    
    / {
    leds {
          compatible = "gpio-leds";
          ledext1: led_ext1 {
    		gpios = <&gpio1 00 GPIO_ACTIVE_LOW>;
    		label = "LED EXTERNE 1";
          };
    };
    };

    Thank you in advance!

  • You can try something along the lines of:

    / {
    	pwmleds {
    		compatible = "pwm-leds";
    		pwm_led0: pwm_led_0 {
    			pwms = <&pwm0 32>;
    		};
    	};
    
    	aliases {
    		pwm-led0 = &pwm_led0;
    	};
    };
    
    &pwm0 {
    	ch0-pin = <32>;
    };

    pin 32 is P1.00.

  • Sorry to bother you again.

    I want to connect led1 and external led with PWM0 to run same frequency.

    In this regard, I set the ch0-pin to 28 followed by led1, then I set the ch1-pin to 32 for the external led.

    &pwm0 {
              ch0-pin = <28>;
              ch1-pin = <32>;
              };
    

    Then in main.c for example blinky-pwm, I write the same code as led1 for external led.

    #include <zephyr.h>
    #include <sys/printk.h>
    #include <device.h>
    #include <drivers/pwm.h>
    
    #define PWM_LED0_NODE	DT_ALIAS(pwm_led0)
    #define PWM_LEDEXT1_NODE	DT_ALIAS(pwm_ledext1)
    
    
    #if DT_NODE_HAS_STATUS(PWM_LED0_NODE, okay)
    #define PWM_LABEL	DT_PWMS_LABEL(PWM_LED0_NODE)
    #define PWM_CHANNEL	DT_PWMS_CHANNEL(PWM_LED0_NODE)
    #define PWM_FLAGS	DT_PWMS_FLAGS(PWM_LED0_NODE)
    #else
    #error "Unsupported board: pwm-led0 devicetree alias is not defined"
    #define PWM_LABEL	""
    #define PWM_CHANNEL	0
    #define PWM_FLAGS	0
    #endif
    
    
    #if DT_NODE_HAS_STATUS(PWM_LEDEXT1_NODE, okay)
    #define PWM_LABELEXT1	DT_PWMS_LABEL(PWM_LEDEXT1_NODE)
    #define PWM_CHANNELEXT1	DT_PWMS_CHANNEL(PWM_LEDEXT1_NODE)
    #define PWM_FLAGSEXT1	DT_PWMS_FLAGS(PWM_LEDEXT1_NODE)
    #else
    #error "Unsupported board: pwm-ledext1 devicetree alias is not defined"
    #define PWM_LABELEXT1	""
    #define PWM_CHANNELEXT1	0
    #define PWM_FLAGSEXT1	0
    #endif
    
    
    #define MIN_PERIOD_USEC	(USEC_PER_SEC / 64U)
    #define MAX_PERIOD_USEC	USEC_PER_SEC
    
    void main(void)
    {
    	const struct device *pwm,*pwmext1;
    	uint32_t max_period;
    	uint32_t period;
    	uint8_t dir = 0U;
    	int ret,retext1;
    
    	printk("PWM-based blinky\n");
    
            pwm = device_get_binding(PWM_LABEL);
            pwmext1 = device_get_binding(PWM_LABELEXT1);
    
            if (!pwm) {
    		printk("Error: didn't find %s device\n", PWM_LABEL);
    		return;
    	}
            if (!pwmext1) {
    		printk("Error: didn't find %s device\n", PWM_LABELEXT1);
    		return;
    	}
            
            printk("Calibrating for device %s channel %d...\n",
    	       PWM_LABEL, PWM_CHANNEL);
            printk("Calibrating for device %s channel %d...\n",
    	       PWM_LABELEXT1, PWM_CHANNELEXT1);
    
    	max_period = MAX_PERIOD_USEC;
    
    	while (pwm_pin_set_usec(pwm, PWM_CHANNELE,
    				max_period, max_period / 2U, PWM_FLAGS)&&
                pwm_pin_set_usec(pwmext1, PWM_CHANNELEXT1,
    				max_period, max_period / 2U, PWM_FLAGSEXT1)) {
    		max_period /= 2U;
    		if (max_period < (4U * MIN_PERIOD_USEC)) {
    			printk("Error: PWM device %s "
    			       "does not support a period at least %u\n",
    			       PWM_LABELEXT1, 4U * MIN_PERIOD_USEC);
    			return;
    		}
    	}
    
    	printk("Done calibrating; maximum/minimum periods %u/%u usec\n",
    	       max_period, MIN_PERIOD_USEC);
    
    	period = max_period;
    
    	while (1) {
    
                    ret = pwm_pin_set_usec(pwm, PWM_CHANNEL,
    				       period, period / 2U, PWM_FLAGS);
    
                    retext1 = pwm_pin_set_usec(pwmext1, PWM_CHANNELEXT1,
    				       period, period*9U/10U, PWM_FLAGSEXT1);
                    
                    if (ret) {
    			printk("Error %d: failed to set pulse width\n", ret);
    			return;
    		}
                    if (retext1) {
    			printk("Error %d: failed to set pulse width\n", retext1);
    			return;
    		}
    
    		period = dir ? (period * 2U) : (period / 2U);
    		if (period > max_period) {
    			period = max_period / 2U;
    			dir = 0U;
    		} else if (period < MIN_PERIOD_USEC) {
    			period = MIN_PERIOD_USEC * 2U;
    			dir = 1U;
    		}
    
    		k_sleep(K_SECONDS(4U));
    	}
    }

    But when I run it, the LED does not change the frequency. Then I saw Termite, here showing Error-22: Failed to Set Pulse Width. Do you know how to solve it?

    Thanks in advance!

  • Hi again,

    You can't change the period when you are using two channels on the same PWM like that:

    /* If any other channel (other than the one being configured) is set up
     * with a non-zero pulse cycle, the period that is currently set cannot
     * be changed, as this would influence the output for this channel.
     */

    Set the pulse to 0 before setting the new period:

    	period = max_period;
    
    	uint32_t period_temp = max_period;
    
    	while (1) {
    
                    ret = pwm_pin_set_usec(pwm, PWM_CHANNEL,
    				       period, period / 2U, PWM_FLAGS);
    
                    retext1 = pwm_pin_set_usec(pwmext1, PWM_CHANNELEXT1,
    				       period, period*9U/10U, PWM_FLAGSEXT1);
                    
                    if (ret) {
    			printk("Error %d: failed to set pulse width for led 0\n", ret);
    			return;
    		}
                    if (retext1) {
    			printk("Error %d: failed to set pulse width for led 1\n", retext1);
    			return;
    		}
    
    		period_temp = period;
    
    		period = dir ? (period * 2U) : (period / 2U);
    		if (period > max_period) {
    			period = max_period / 2U;
    			dir = 0U;
    		} else if (period < MIN_PERIOD_USEC) {
    			period = MIN_PERIOD_USEC * 2U;
    			dir = 1U;
    		}
    
    		k_sleep(K_SECONDS(4U));
    
    		ret = pwm_pin_set_usec(pwm, PWM_CHANNEL,
    				       period_temp, 0, PWM_FLAGS);
    
            retext1 = pwm_pin_set_usec(pwmext1, PWM_CHANNELEXT1,
    				       period_temp, 0, PWM_FLAGSEXT1);
                    
            if (ret) {
    			printk("Error %d: failed to set pulse width to 0 for led 0\n", ret);
    			return;
    		}
            if (retext1) {
    			printk("Error %d: failed to set pulse width to 0 for led 1\n", retext1);
    			return;
    		}
    
    	}
    }

    Or use a second PWM:

    / {
    	pwmleds {
    		compatible = "pwm-leds";
    		pwm_led0: pwm_led_0 {
    			pwms = <&pwm0 28>;
    		};
    		pwm_ledext1: pwm_led_ext1 {
    			pwms = <&pwm1 32>;
    		};
    	};
    
    	aliases {
    		pwm-led0 = &pwm_led0;
    		pwm-ledext1 = &pwm_ledext1;
    	};
    };
    
    &pwm0 {
    	ch0-pin = <28>;
    };
    
    &pwm1 {
    	status = "okay";
    	ch0-pin = <32>;
    };

Related