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

How to setup a 20KHz PWM for vibration motor and control the duty cycle?

Hi all,

I am working on a project which uses a vibration motor. I want the vibration motor to vibrate with different patterns. I have read online that a 20kHz PWM can be used to control the vibration power by varying the duty cycle.

I am using the PWM driver example from the SDK as a reference and sort of understand how it works, but please correct me if my understanding is wrong.

The PWM frequency is set by Fclk/ .top value and the duty cycle is set by the seq_values array. For example if .base_clock is NRF_PWM_CLK_125kHz and .top_value is 25000, then the PWM frequency is 5Hz. If I use the seq_values:

  static uint16_t /*const*/ seq_values[] =
    {
        0x8000,
             0,
        0x8000,
             0,
        0x8000,
             0
    };

This means the I will have duty cycle of 32% for the first clock period (200ms) then 0% for the next clock cycle (200ms) , and this repeats 3 times.

In my application, I want to have the motor PWM at 20kHz ramping up from 0% duty cycle to 100% duty cycle over a period of 2 seconds, then off for 2 seconds and repeat again.

To get 20kHz PWM frequency, I would need to set .base_clock NRF_PWM_CLK_1MHz and .top_value to 50. If I want to ramp up from 0% duty cycle to 100% duty cycle over a period of 2 seconds, does it mean that I would need a seq_values array with 40000 elements? But somehow it seems like its not the right way to do it. Is there a better way to do this?

Another vibration pattern I am looking at is ON  at 75%  for 1 sec, OFF(1 sec) and repeat.

Any one can advise? Thanks!

Parents
  • Hello,

     

    The PWM frequency is set by Fclk/ .top value and the duty cycle is set by the seq_values array. For example if .base_clock is NRF_PWM_CLK_125kHz and .top_value is 25000, then the PWM frequency is 5Hz. If I use the seq_values:

     That would be correct.

     

    This means the I will have duty cycle of 32% for the first clock period (200ms) then 0% for the next clock cycle (200ms) , and this repeats 3 times.

     Not exactly. In the PWM driver, the first bit (MSB) of the value will say whether the PWM signal should have an active high or active low signal. The rest of the value is the duty cycle for the PWM signal. So in this case, it is only 100% duty cycles, but with different polarities.

    If you want a continuous increase from 0 to 100%, you need to represent these with a set of sec_values, but perhaps you don't need 40 000 elements. Perhaps you can increase by 1% or even 5% every step, and stay on each step for 1/20th second? See how it is done in demo4() in the pwm_driver example from the SDK. Look at how the array fade_in_out_values[] is set.

        static nrf_pwm_values_common_t fade_in_out_values[2 * STEP_COUNT];
        uint16_t value = 0;
        uint16_t step  = TOP / STEP_COUNT;
        uint8_t  i;
        for (i = 0; i < STEP_COUNT; ++i)
        {
            value                             += step;
            fade_in_out_values[i]              = value;
            fade_in_out_values[STEP_COUNT + i] = TOP - value;
        }

    Then you can use the 4th element in nrf_drv_pwm_complex_playback() to decide how many time each value from the fade_in_out_values[] should be played. With the correct combination, this can be from 0% to 100% in 100 seconds.

    Best regards,

    Edvin

Reply
  • Hello,

     

    The PWM frequency is set by Fclk/ .top value and the duty cycle is set by the seq_values array. For example if .base_clock is NRF_PWM_CLK_125kHz and .top_value is 25000, then the PWM frequency is 5Hz. If I use the seq_values:

     That would be correct.

     

    This means the I will have duty cycle of 32% for the first clock period (200ms) then 0% for the next clock cycle (200ms) , and this repeats 3 times.

     Not exactly. In the PWM driver, the first bit (MSB) of the value will say whether the PWM signal should have an active high or active low signal. The rest of the value is the duty cycle for the PWM signal. So in this case, it is only 100% duty cycles, but with different polarities.

    If you want a continuous increase from 0 to 100%, you need to represent these with a set of sec_values, but perhaps you don't need 40 000 elements. Perhaps you can increase by 1% or even 5% every step, and stay on each step for 1/20th second? See how it is done in demo4() in the pwm_driver example from the SDK. Look at how the array fade_in_out_values[] is set.

        static nrf_pwm_values_common_t fade_in_out_values[2 * STEP_COUNT];
        uint16_t value = 0;
        uint16_t step  = TOP / STEP_COUNT;
        uint8_t  i;
        for (i = 0; i < STEP_COUNT; ++i)
        {
            value                             += step;
            fade_in_out_values[i]              = value;
            fade_in_out_values[STEP_COUNT + i] = TOP - value;
        }

    Then you can use the 4th element in nrf_drv_pwm_complex_playback() to decide how many time each value from the fade_in_out_values[] should be played. With the correct combination, this can be from 0% to 100% in 100 seconds.

    Best regards,

    Edvin

Children
No Data
Related