PWM output frequency or prescaler change and configuration

Dear ,

I am using the nRF52833-DK development board with the NCS1.7.0 SDK.

I am trying to get a PWM waveform output at 50% duty cycle with 409.6kHz frequency based on the blinky_pwm and fade_led sample projects. However, it was unsuccessful.

Could you please kindly advise and help? How could I config/change the clock frequency for PWM peripheral? Currently, it seems to be 1MHz.

Thanks and regards, Kevin

  • Hi,

    In blinky_pwm, try changing the 2 pwm_pin_set_usec() functions to pwm_pin_set_nsec(), and set MAX_PERIOD_USEC to 2500 and MIN_PERIOD_USEC to 625.

    Does that produce a waveform closer to what you are after?

  • Dear Øivind,

    Thanks for your reply.

    I managed to make it work by switching it to pwm_pin_set_nsec(). However, to be able to get a better understanding, I still have a few questions.

    1. What's the purpose of setting MAX_PERIOD_USEC and MIN_PERIOD_USEC? Are they purely for the calibration? Is the calibration process compulsory for using PWM?

    2. When I tried different period values to see the waveform changes, it seems that it works normally even if I use a value that's not within the range of MAX_PERIOD_USEC and MIN_PERIOD_USEC. Is it normal? If so, then what's the purpose of the MAX_PERIOD_USEC and MIN_PERIOD_USEC?

    3. When supplying period = 2 and pulse = 1 for pwm_pin_set_usec() function, it generates a waveform with 500kHz frequency observed on the oscilloscope. If I am getting this right, it means that the PWM is working at 1MHz, i.e. 32MHz with a prescaler of 32. Can I change this prescaler value? 

    Thanks again for your kind assistance.

    Kind regards, Kevin

  • pigno5e said:
    1. What's the purpose of setting MAX_PERIOD_USEC and MIN_PERIOD_USEC? Are they purely for the calibration? Is the calibration process compulsory for using PWM?

    The blinky_pwm sample is designed to show changing pwm frequency, by doubling the frequency every 4 seconds, followed by halving the frequency every 4 seconds until it is back at the starting frequency, then it repeats.
    MAX_PERIOD_USEC and MIN_PERIOD_USEC are arbitrarily chosen as the target limits of this cycle, and are specific to this sample's demonstration.
    As blinky_pwm is a zephyr sample, it is designed to be compatible with a wide range of different boards, with different capabilities. Some of these boards may not support the default MAX_PERIOD_USEC of 1 second, and the "calibration" is simply the sample attempting to set the pwm period to 1 second, and if the function returns an error, it keeps retrying with a shorter and shorter period until the function call succeeds.
    So you don't need the constants if you aren't going to bounce between frequencies like the sample. And you don't need the "calibration" process if you know the capabilities of the hardware.
    To me it seems like you won't need any of those things.

    pigno5e said:
    2. When I tried different period values to see the waveform changes, it seems that it works normally even if I use a value that's not within the range of MAX_PERIOD_USEC and MIN_PERIOD_USEC. Is it normal? If so, then what's the purpose of the MAX_PERIOD_USEC and MIN_PERIOD_USEC?

    See previous answer, they are purely for the frequency changing behavior that the sample demonstrates.

    pigno5e said:
    3. When supplying period = 2 and pulse = 1 for pwm_pin_set_usec() function, it generates a waveform with 500kHz frequency observed on the oscilloscope. If I am getting this right, it means that the PWM is working at 1MHz, i.e. 32MHz with a prescaler of 32. Can I change this prescaler value? 

    The PWM clock is 16MHz, and the Zephyr driver chooses the prescaler such that the PWM has the highest frequency possibly, while still being able to fit the entire period within 32767 cycles. That means that any period shorter than 2048 usec will have the PWM working at 16MHz.

  • Dear Øivind,

    Thanks a lot for your info and they are very helpful.

    Meanwhile, I still have got one more issue.

    When I combined the blinky_pwm and button samples, I found that the button interrupt callback function cannot execute if pwm_pin_set_nsec() is called.

    After pwm_pin_set_nsec() is commented, the button callback function returns back to normal. (NRF TERMINAL displays the button_pressed message generated by the code below.

    void button_pressed(const struct device *dev, struct gpio_callback *cb,
    		    uint32_t pins)
    {
    	printk("Button pressed at %" PRIu32 "\n", k_cycle_get_32());
    }

    Does it have anything to do with the interrupt priority or similar configurations? How can I resolve this issue and make them all work properly at the same time?

    And what is the proper way to stop the PWM output? Do I just simply set the const struct device pointer variable *pwm to NULL?

    Thanks and kind regards, Kevin

  • Can you zip and send me the project, so I can take a look? You can attach files to your reply with Insert->Image/video/file.

    You can stop the PWM output by setting the duty cycle to 0.

Related