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

Initial spike with PWM implementation

Hi,

I am using a PWM to control the output of an LED driver and I am implementing a soft_on function when powering ON the driver, so we have a start_PWM function that looks like this:

static void start_PWM(void)
{
// PWM stuff
    app_pwm_config_t m_pwm0_config = APP_PWM_DEFAULT_CONFIG_1CH(1000, LIGHT_FIXTURE);
    m_pwm0_config.pin_polarity[0] = APP_PWM_POLARITY_ACTIVE_HIGH;

    uint32_t status = app_pwm_init(&PWM0, &m_pwm0_config, NULL);
    APP_ERROR_CHECK(status);
    m_pwm0_max = app_pwm_cycle_ticks_get(&PWM0);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "PWM max ticks: %d\n", m_pwm0_max);

    app_pwm_enable(&PWM0);
    nrf_delay_us(850);
//this is the soft on: for(uint16_t i = 0; i < 300; i++) { //(void) app_pwm_channel_duty_ticks_set(&PWM0, 0, i); while (app_pwm_channel_duty_ticks_set(&PWM0, 0, i) == NRF_ERROR_BUSY); nrf_delay_ms(1); __LOG(LOG_SRC_APP, LOG_LEVEL_ERROR, "Current dimming: %d\n", i); } __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Soft ON\n"); }

Now, the issue is that there is an initial pulse when powering ON and before the soft on happens. we also tried just simply to set to 0 with:

static void start_PWM(void)
{
// PWM stuff
    app_pwm_config_t m_pwm0_config = APP_PWM_DEFAULT_CONFIG_1CH(1000, LIGHT_FIXTURE);
    m_pwm0_config.pin_polarity[0] = APP_PWM_POLARITY_ACTIVE_HIGH;

    uint32_t status = app_pwm_init(&PWM0, &m_pwm0_config, NULL);
    APP_ERROR_CHECK(status);
    m_pwm0_max = app_pwm_cycle_ticks_get(&PWM0);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "PWM max ticks: %d\n", m_pwm0_max);

    app_pwm_enable(&PWM0);
    nrf_delay_us(850);
    (void) app_pwm_channel_duty_ticks_set(&PWM0, 0, 0);

}

But still, there is that initial pulse. We had a similar issue few weeks ago with this thread: https://devzone.nordicsemi.com/f/nordic-q-a/41616/initial-pulse-while-starting-a-pwm-application we thought that we solved but now we have it again...

and just to clarify, if we don't set anything after the enable function then there is no pulse:

static void start_PWM(void)
{
// PWM stuff
    app_pwm_config_t m_pwm0_config = APP_PWM_DEFAULT_CONFIG_1CH(1000, LIGHT_FIXTURE);
    m_pwm0_config.pin_polarity[0] = APP_PWM_POLARITY_ACTIVE_HIGH;

    uint32_t status = app_pwm_init(&PWM0, &m_pwm0_config, NULL);
    APP_ERROR_CHECK(status);
    m_pwm0_max = app_pwm_cycle_ticks_get(&PWM0);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "PWM max ticks: %d\n", m_pwm0_max);

    app_pwm_enable(&PWM0);
}

is there any reason to have that pulse when setting the PWM output?

I am using 15.2.0 SDK and 3.0.0 Mesh SDK.

  • also, we logged the status of the soft on and when checking the logs we see only the first 15 values... while it had to log 300 values

    , main.c,  860, ----- BLE Mesh Dimming Client Demo -----
    , main.c,  787, Initializing and adding models
    , main.c,  227, App OnOff Model Handle: 7
    , main.c,  920, PWM max ticks: 8000
    , main.c,  929, Current dimming: 0
    , main.c,  929, Current dimming: 1
    , main.c,  929, Current dimming: 2
    , main.c,  929, Current dimming: 3
    , main.c,  929, Current dimming: 4
    , main.c,  929, Current dimming: 5
    , main.c,  929, Current dimming: 6
    , main.c,  929, Current dimming: 7
    , main.c,  929, Current dimming: 8
    , main.c,  929, Current dimming: 9
    , main.c,  929, Current dimming: 10
    , main.c,  929, Current dimming: 11
    , main.c,  929, Current dimming: 12
    , main.c,  929, Current dimming: 13
    , main.c,  929, Current dimming: 14
    Current dimming: 15
  • I see multiple bugs in the PWM libraries, not sure whether that would help. A fix worth trying is to use ms-bit inverted, if you haven't tried already.  The startup pulse is different for Low-High PWM (value) vs. High-Low PWM (0x8000|value). I use differential PWM signals so see both simultaneously; maybe try doing this for your LED drive to see if one signal in your case looks preferable. I also control pin initialisation seperately from the library, but can get a 4uSec unwanted pulse on Low-High but not on High-Low startup.

    So the bugs: From the user manual

    // 6.17.5.15 PSEL.OUT[n] (n=0..3)
    //  Address offset: 0x560 + (n × 0x4)
    //  Output pin select for PWM channel n
    //  Bit number 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
    //          ID                                                                         C B A A A A A
    // Reset 0xFFFFFFFF                  1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
    //  ID RW Field Value ID Value Description
    //  A RW PIN [0..31] Pin number
    //  B RW PORT [0..1] Port number
    //  C RW CONNECT Connection   Disconnected 1 Connected 0

    From the library for PWM nrfx_pwm.h and nrfx_pwm.c in SDK 15.2.0:

    /**
     * @brief This value can be added to a pin number to inverse its polarity
     *        (set idle state = 1).
     */
    #define NRFX_PWM_PIN_INVERTED    0x80
    
    static void configure_pins(nrfx_pwm_t const * const p_instance,
                               nrfx_pwm_config_t const * p_config)
    {
        uint32_t out_pins[NRF_PWM_CHANNEL_COUNT];
        uint8_t i;
    
        for (i = 0; i < NRF_PWM_CHANNEL_COUNT; ++i)
        {
            uint8_t output_pin = p_config->output_pins[i];
            if (output_pin != NRFX_PWM_PIN_NOT_USED)
            {
                bool inverted = output_pin &  NRFX_PWM_PIN_INVERTED;
                out_pins[i]   = output_pin & ~NRFX_PWM_PIN_INVERTED;
    
                if (inverted)
                {
                    nrf_gpio_pin_set(out_pins[i]);
                }
                else
                {
                    nrf_gpio_pin_clear(out_pins[i]);
                }
    
                nrf_gpio_cfg_output(out_pins[i]);
            }
            else
            {
                out_pins[i] = NRF_PWM_PIN_NOT_CONNECTED;
            }
        }
    
        nrf_pwm_pins_set(p_instance->p_registers, out_pins);
    }
    

    There is no inverted bit in the manual; this affects port output initialisation and the use of Port 1.x for PWM.

  • I did try inverting the polarity of the PWM pin which is similar to what you are suggesting.
    That also has a similar spike when powering ON the driver.

  • The pin should be set low when you configure it to "active high". Do you get a shorter pulse if you remove the 850 us delay? 

    , the app_pwm library generates the PWM output signal with the TIMER, PPI, and GPIOTE peripherals instead of using the dedicated PWM module available on the 52 series. So this is a different implementation. 

  • Hi,

    The pin should be set low when you configure it to "active high".

    When I set the pin to active high, I need not change anything as the driver (active high) will have the LED connected turned OFF. 

    Do you get a shorter pulse if you remove the 850 us delay? 

    There isn't any difference in the pulse when I remove the delay or have it as the pulse is quite random. On few occasions, I won't even see the pulse/spike. 

    Is there any startup time for the Mesh? Because, when we tried it with the 15.2.0 SDK, we can't see that initial spike while rebooting.

    Thank you. 

Related