Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nRF5 SDK15.0 - PWM Driver: Just set a fixed duty cycle?

The PWM Driver has all sorts of fancy stuff for dealing with clever sequences - but I can't see anything to just set a simple, steady, fixed duty cycle!

How does one just set a fixed duty cycle?

What I actually want is to be able to fade an LED up to a certain brightness; so what I really want is to be able to specify an increasing sequence, and then a steady duty cycle to last indefinitely once the fade-up sequence completes.

Is there a simple way to do that?

Parents
  • Hello,

    I would agree to some degree of what you are saying. The PWM driver example is good for fancy PWM LEDs, but if you want a simple PWM with a fixed period and a dimmed LED that is easily controllable, it might be easier to use the PPI module with a timer.

    Attached is a simple PPI example that does this. If you run it on an nRF52DK, it shouldn't need any modifications. It should dim 2 LEDs in a pattern.

    The PPI setup might look a bit scary, but the function that is actually controlling the LEDs duty cycle is controlled from the main() function. Note that for simplicity, the example uses nrf_delay_ms(), which is not a good approach, power consumption vise. 

    ppi_double_channel_pwm.zip

    Note that the pwm[0/1]_set_duty_cycle() doesn't need to use the sin_scaled() function. You can set it to any value between 1 and 1024 (TIMER_RELOAD), which is the number of ticks in the current setup.

    You can change the TIMER_RELOAD to change the period of your PWM signal.

    In the zip-folder attached, only a Keil project is included. But you should be able to change any of the main.c files from the projects in SDK\examples\periperal with this one, if you want to use a different IDE.

    Let me know if anything is unclear, or if you have any questions regarding the PPI, or if you want to use the PWM driver instead of this.

    Best regards,

    Edvin

  • OK -  thanks.

    So, for completeness, is it possible to use the PWM peripheral to give a simple fixed duty cycle that will continue indefinitely?

  • Now I see:

    • nrf_pwm_sequence_t.repeats sets the number of times to repeat each step within the sequence;
       
    • playback_count sets the number of times to repeat the entire sequence.

    Of course, with only a single step in the sequence, they both end up as the same effect!

    EDIT

    To further clarify, nrf_pwm_sequence_t.repeats is the number of repeats after the first iteration; ie,

    • repeats = 0 runs each step once;
    • repeats = 1 runs each step once, plus 1 repeat;
    • repeats = 2 runs each step once, plus 2 repeats;
    • repeats = n runs each step once, plus n repeats

  • Quoting from code doesn't seem to work on this forum?

            .top_value    = 32768, // = 0x8000

    causes nrf_drv_pwm_init() to Assert - the maximum allowed value is 7FFF.

  • Ok. It worked in my tests, but maybe we tried on different chips.

    You can use  7FFF then.

    I can agree that the PWM drivers are a bit confusing, which is why I suggested the PPI implementation, which only uses a timer and the GPIOTE driver to toggle the pins.

    The example actually uses both the GPIO driver and the PWM driver to control the LEDs/pins. The NRF_DRV_PWM_PIN_INVERTED is actually not used when the PWM is running. That is, when you call nrf_drv_pwm_simple_playback(). It is used when the PWM is stopped (which it doesn't do in this example, so it is a bit misleading. 

    If you want to stop the PWM (by not using the loop-flag, but the NRF_DRV_PWM_FLAG_STOP, then the NRF_DRV_PWM_PIN_INVERTED will cause the pin to go high after the sequence. And pin high means LED off. If you remove PIN_INVERTED and use NRF_DRV_PWM_FLAG_STOP, you will see that the LED will turn on after the sequence.

    But if you want to have a constant duty cycle, e.g. for controlling a motor, you might not want to turn it off at all, so then you would have to use the first bit to tell it whether you want to have an active high or an active low PWM signal.

    Best regards,

    Edvin

  • The Assert is actually in nrf_pwm_configure():

    __STATIC_INLINE void nrf_pwm_configure(NRF_PWM_Type * p_reg,
                                           nrf_pwm_clk_t  base_clock,
                                           nrf_pwm_mode_t mode,
                                           uint16_t       top_value)
    {
        NRFX_ASSERT(top_value <= PWM_COUNTERTOP_COUNTERTOP_Msk);
    
        p_reg->PRESCALER  = base_clock;
        p_reg->MODE       = mode;
        p_reg->COUNTERTOP = top_value;
    }
    

    and PWM_COUNTERTOP_COUNTERTOP_Msk is defined in nrf52810_bitfields.h:

    /* Bits 14..0 : Value up to which the pulse generator counter counts. This register is ignored when DECODER.MODE=WaveForm and only values from RAM are used. */
    #define PWM_COUNTERTOP_COUNTERTOP_Pos (0UL) /*!< Position of COUNTERTOP field. */
    #define PWM_COUNTERTOP_COUNTERTOP_Msk (0x7FFFUL << PWM_COUNTERTOP_COUNTERTOP_Pos) /*!< Bit mask of COUNTERTOP field. */
    

  • Hi Guys,

    Any founding on this topics? How the .base_clock   = NRF_PWM_CLK_2MHz influence the .top_value    = 32768, // = 0x8000?

Reply Children
No Data
Related