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

How to start pwm sequence after particular time delay of gpio event?

I am working on an application where I need to start pwm sequence after particular delay (accurate delay of multiple of 100us).

I am quite new to nordic environment.

Here is my code . Can please guide me what is wrong here??

#define    Period    20000 //20ms

const nrf_drv_timer_t TIMER_LED = NRF_DRV_TIMER_INSTANCE(0);

APP_PWM_INSTANCE(PWM1,1); 

static int gpio_flag =0;

void pwm_update(void)
{
      uint32_t value;
      value = duty_1;
      ready_flag = false;
      /* Set the duty cycle - keep trying until PWM is ready... */
      
      

      while ((app_pwm_channel_duty_set(&PWM1, 0, value))&(app_pwm_channel_duty_set(&PWM1, 1, value)) == NRF_ERROR_BUSY);
 
      /* ... or wait for callback. */
      while (!ready_flag);
      APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM1, 1, value));
      APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM1, 0, value));

}


void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
   gpio_flag =1;
   nrf_drv_timer_enable(&TIMER_LED);

   
}

void timer0_handler(nrf_timer_event_t event_type, void* p_context)
{
  switch (event_type)
    {
        case NRF_TIMER_EVENT_COMPARE0:
             timer_flg =1;
             nrf_drv_timer_clear(&TIMER_LED);
             gpio_flag=0;
             pwm_update();
            break;

        default:
            //Do nothing.
            break;
    }
}


void timer_init(void)
{
    uint32_t time_us = 500; 
    uint32_t time_ticks;
    uint32_t err_code = NRF_SUCCESS;

    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    err_code = nrf_drv_timer_init(&TIMER_LED, &timer_cfg, timer0_handler);
    APP_ERROR_CHECK(err_code);

    time_ticks = nrf_drv_timer_us_to_ticks(&TIMER_LED, time_us);
    nrf_drv_timer_compare(
         &TIMER_LED, NRF_TIMER_CC_CHANNEL0, time_ticks, true);

    
}

  • Hello Karl,

    You could check that the EVENTS_SEQSTARTED[n] event happens. This will indicate that the sequence has started.
    You can add this event as a case in the pwm handler, and then either add a breakpoint or a logger statement to indicate that the event is generated as expected.

    I created as you told please verify it ,is it right ?

    void pwm_handler(nrf_pwm_event_t event_type)
    {
     switch(event_type)
     {
       case NRF_PWM_EVENT_SEQSTARTED0:
            NRF_LOG_INFO("PWM IS STARTED");
            break;
       default:
       // nothing
            break;
     }
    }
    
    APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, pwm_handler));
     

    Because after adding this code , I tested with debug breakpoint but it never come true that is cursor goes to default never stop in case NRF_PWM_EVENT_SEQSTARTED0.

    Best regards,
    Ram 

  • Hello Ram,

    It looks like you are doing it correct in your code, so I was surprised that this did not work. I looked into the nrfx_pwm driver, which is what is being called behind the scenes of the nrf_drv_pwm_init call, and it seems that it does not forward the _SEQSTARTED0 event after all, my mistake.
    You could either edit the driver to pass the STARTED event to the application layer, or use the SEQEND0 event instead. I would recommend the latter, since it comes with lower risk (modifying a driver is always a potential way to break it), and since using the SEQEND event instead should be fine in this case - we only need to know that the PWM has successfully started in order to disable the startup peripherals.
    Apologies for the inconvenience. Could you try this, and let me know if this resolves the compounded delay issue?

    Best regards,
    Karl

  • Hello Karl,

    You could either edit the driver to pass the STARTED event to the application layer, or use the SEQEND0 event instead. I would recommend the latter, since it comes with lower risk (modifying a driver is always a potential way to break it), and since using the SEQEND event instead should be fine in this case - we only need to know that the PWM has successfully started in order to disable the startup peripherals.

    First I didn't understand how SEQEND0 will return because sequence is going on .

    But still I tried with case NRF_PWM_EVENT_SEQEND0: in the place of  case NRF_PWM_EVENT_SEQSTARTED0: . But in debug the cursor isn't coming as  event_type return 0x0000 value.

    Maybe some where initialization is not happening correctly or some other reason.

    Apologies for the inconvenience. Could you try this, and let me know if this resolves the compounded delay issue?

    No issue Karl,  I am really happy with your support and I really positively hoping  that we are going to solve this very soon.

    Best regards,
    Ram 

  • RAM_MS said:
    No issue Karl,  I am really happy with your support and I really positively hoping  that we are going to solve this very soon.

    I am happy to you that, Ram!
    I too hope we will resolve this last issue soon.

    RAM_MS said:

    First I didn't understand how SEQEND0 will return because sequence is going on .

    But still I tried with case NRF_PWM_EVENT_SEQEND0: in the place of  case NRF_PWM_EVENT_SEQSTARTED0: . But in debug the cursor isn't coming as  event_type return 0x0000 value.

    Maybe some where initialization is not happening correctly or some other reason.

    Oh, I should have been more explicit again, my apologies.
    Please check for the NRFX_PWM_EVT_END_SEQ0 event in your pwm_handler.
    The PWM HAL event NRF_PWM_EVENT_SEQEND0 is only ever used by the nrfx driver behind the scenes, and not actually ever forwarded to the application layer event handler. If the NRF_PWM_EVENT_SEQEND0 event is generated by the PWM peripheral, the nrfx driver will forward NRFX_PWM_EVT_END_SEQ0 to the application layer.

    If my understanding of the end event is correct then the end event will be generated whenever the section has been played once, before it loops.

    void pwm_handler(nrf_pwm_event_t event_type)
    {
        switch(event_type)
        {
            case NRFX_PWM_EVT_END_SEQ0:
                NRF_LOG_INFO("PWM IS STARTED");
                disable_pwm_startup_peripherals();
                break;
            default:
                // nothing
                break;
        }
    }


    Alternatively, you could for debugging's sake add the following to the nrfx_pwm.c irq_handler function:
    ..
        if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_EVENTS_SEQSTARTED0))
        {
            nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_EVENTS_SEQSTARTED0);
    
            p_cb->handler(NRFX_PWM_EVT_STARTED_SEQ0);
        }
    ..

    But since the nrfx_pwm driver does not have a dedicated started event we will also have to add the following modification into nrfx_pwm.h:
    ..
    /** @brief PWM driver event type. */
    typedef enum
    {
        NRFX_PWM_EVT_FINISHED, ///< Sequence playback finished.
        NRFX_PWM_EVT_END_SEQ0, /**< End of sequence 0 reached. Its data can be
                                    safely modified now. */
        NRFX_PWM_EVT_END_SEQ1, /**< End of sequence 1 reached. Its data can be
                                    safely modified now. */
        NRFX_PWM_EVT_STOPPED,  ///< The PWM peripheral has been stopped.
        NRFX_PWM_EVT_STARTED_SEQ0,  ///< Sequence 0 has started.
    } nrfx_pwm_evt_type_t;
    ..


    In general it is recommended to avoid modifying the provided drivers directly, since this may break them or place them into invalid states, but I list it here as an alternative approach nevertheless, since we are in the process of debugging the issue of the growing phase shift of the outputted PWM.
    Keep in mind that this driver modification will make the started event be sent to your application layer frequently, so you should add a check in the pwm_handler so that it only disables the peripherals the first time it is generated.

    The important part here is that we get to test if the disabling of the startup peripherals will resolve the phase shifting issue of the output PWM.

    Best regards,
    Karl

  • Hello Karl,

    Please check for the NRFX_PWM_EVT_END_SEQ0 event in your pwm_handler.
    The PWM HAL event NRF_PWM_EVENT_SEQEND0 is only ever used by the nrfx driver behind the scenes, and not actually ever forwarded to the application layer event handler. If the NRF_PWM_EVENT_SEQEND0 event is generated by the PWM peripheral, the nrfx driver will forward NRFX_PWM_EVT_END_SEQ0 to the application layer.

    NRFX_PWM_EVT_END_SEQ0 is not returned instead NRFX_PWM_EVT_FINISHED is returning.

    So I edited program like this

    static void disable_pwm_startup_peripherals()
    {
     nrf_drv_gpiote_in_event_disable(PIN_IN);
     nrf_drv_ppi_channel_disable(ppi_channel_1);
     nrfx_timer_disable(&PWM_DELAY_TIMER);
     nrf_drv_ppi_channel_disable(ppi_channel_2);
    
    }
    
    static void irq_handler(nrfx_pwm_evt_type_t event_type)
    {
     
     switch(event_type)
     {
       case NRFX_PWM_EVT_FINISHED:
            NRF_LOG_INFO("PWM IS STARTED");
            disable_pwm_startup_peripherals();
            break;
       default:
       // nothing
            break;
     }
    }
    

    But this also not solving the issue .

    Best regards,
    Ram 

Related