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);

    
}

Parents
  • Hello,

    I am quite new to nordic environment.

    Welcome! Please do not hesitate to ask if you should have any questions.

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

    Could you show me the entirety of your main.c code?
    Right now I do not see where you setup your gpio for triggering the enabling of the timer, so I am not sure that the timer is ever started, for instance.

    Could you also elaborate on what behavior you are seeing, and how this differs from what you would expect? Does the device reset for example, or is it just that 'nothing' is happening, for example?

    Best regards,
    Karl

  • Hello Karl,

    Right now I do not see where you setup your gpio for triggering the enabling of the timer, so I am not sure that the timer is ever started, for instance.

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

    Could you also elaborate on what behavior you are seeing, and how this differs from what you would expect? Does the device reset for example, or is it just that 'nothing' is happening, for example?

    I am not getting the delay I am expecting.

    I think I have done some wrong configuration in linking to timer from gpio interrupt routine. 

    Best regards,
    Ram



  • Hello Karl,

    Could you show me your code as it is right now? I will take a look and see if I can spot what might be adding the delay.

    Here I attached the code for your reference.

    0310.main.zip

    Did you change it so that you are providing the pwm_start_task_address returned from the nrf_drv_simple_playback call to the PPI initialization?

    Yes ,I changed .

    Please verify once is it right in provided code.

    Could you check whether you are receiving any EVENTS_SEQSTARTED events in your pwm event handler?
    To find out how long it takes from the PWM start task is triggered until the SEQSTARTED event is received you could use the nrf_timer_cc_read function in the timer's event handler for the CC event, and then again in the PWM handler for the SEQSTARTED event - then subtract the initial value and the added delay to find the difference.

    I am trying to test this .I will update you soon.

    Best regards,
    Ram

  • RAM_MS said:
    Here I attached the code for your reference.

    Thank you for sharing the code.
    Looking through the code I notice that you are initializing the GPIOTE as a low-accuracy input, in the line:

    nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(false);

    Could you try to change this to high accuracy, by changing the configuration parameter to true?
    I do not really think that this should matter, since the PORT event will be triggered just as fast as the IN_EVENT, but it would be good to have ruled out as well.

    I also recommend that you define your pins using the NRF_GPIO_PIN_MAP macro instead of just writing their pin number, but this is a very minor comment on my part and it will work just as well with the pins number directly.

    RAM_MS said:

    Yes ,I changed .

    Please verify once is it right in provided code.

    I do not see this change implemented in the code you just shared - it seems like this might be the code that was used to test the TIMER's accuracy.
    I see that you have created a global variable to store the pwm_task_addr returned by the nrf_drv_pwm_simple_playback function call, so I assume you will be using that variable to store it, and pass it to the PPI assign function.
    I would urge you to add a check to the PPI init function that checks if the pwm_task_addr and gpiote_task_addr variables has been set before you proceed to pass them to the PPI peripheral.
    You will also need to run the GPIOTE and PWM init functions before the PPI init function, to make sure that the addresses has been updated before they are connected through the PPI.

    RAM_MS said:
    I am trying to test this .I will update you soon.

    Great, I look forward to hearing what you find out! :) 

    Best regards,
    Karl

  • Hello Karl,

    I do not see this change implemented in the code you just shared - it seems like this might be the code that was used to test the TIMER's accuracy.

    Sorry ,You are right I shared the code that was used to test the TIMER's accuracy.

    I see that you have created a global variable to store the pwm_task_addr returned by the nrf_drv_pwm_simple_playback function call, so I assume you will be using that variable to store it, and pass it to the PPI assign function.

    Yes ,you are right I am using that variable to store it and pass it to the PPI assign function.

    You will also need to run the GPIOTE and PWM init functions before the PPI init function, to make sure that the addresses has been updated before they are connected through the PPI.

    Thank you so much Karl ,this was the problem in my code after arranging this correcting now I am able to get exact TIMING Delay .

    Now ,another problem arises actually .

    For testing purpose I generated inputting PWM signal from PIN NO 11( that is PWM_PIN 11) in the code you might seen it and giving it to (PIN_IN 22). 

    But in real case the inputting PWM will come from outside .

    So for create this scenario I created inputted PWM signal from a different NRF52 DK .

    And what I observed is my Generated PWM Signal is Shifting with time.

    For your reference I am attaching the video of it.

    what could be the reason for this problem ?

    As always Yellow one is INPUTTED PWM SIGNAL and Blue one is my OUTPUT PWM .

    And you can clearly see that blue line is slowly shifting to left .

    Best regards,
    Ram

     

  • Hello again,

    RAM_MS said:
    Thank you so much Karl ,this was the problem in my code after arranging this correcting now I am able to get exact TIMING Delay .

    No problem at all, Ram - I am happy to hear that this resolved the added delay issue!

    RAM_MS said:
    Sorry ,You are right I shared the code that was used to test the TIMER's accuracy.
    RAM_MS said:
    Yes ,you are right I am using that variable to store it and pass it to the PPI assign function.
    RAM_MS said:
    As always Yellow one is INPUTTED PWM SIGNAL and Blue one is my OUTPUT PWM .

    Thank you for clarifying these things.

    RAM_MS said:

    For testing purpose I generated inputting PWM signal from PIN NO 11( that is PWM_PIN 11) in the code you might seen it and giving it to (PIN_IN 22). 

    But in real case the inputting PWM will come from outside .

    So for create this scenario I created inputted PWM signal from a different NRF52 DK .

    And what I observed is my Generated PWM Signal is Shifting with time.

    For your reference I am attaching the video of it.

    That is very strange indeed. Perhaps there is something amiss with the sequence looping.

    Could you share the newest version of the code - the code you ran when you observed this - so I may see if I can spot any potential explanation for this?

    Best regards,
    Karl

  • Hello Karl,

    I am happy to hear that this resolved the added delay issue!

    I am really happy that we patiently progress up to this stage.

    And Thank you a lot .

    That is very strange indeed. Perhaps there is something amiss with the sequence looping.

    Could you share the newest version of the code - the code you ran when you observed this - so I may see if I can spot any potential explanation for this?

    For your reference I am attaching code here.

    7384.main.zip

    As earlier I said for testing purpose I generated 1st in the same DK in PWM_PIN(11).

    But for now I commented this part by commenting pwm1_init();

    And giving INPUTTED PWM Signal from Different DK in PIN_IN (22);

    Best regards,
    Ram

Reply
  • Hello Karl,

    I am happy to hear that this resolved the added delay issue!

    I am really happy that we patiently progress up to this stage.

    And Thank you a lot .

    That is very strange indeed. Perhaps there is something amiss with the sequence looping.

    Could you share the newest version of the code - the code you ran when you observed this - so I may see if I can spot any potential explanation for this?

    For your reference I am attaching code here.

    7384.main.zip

    As earlier I said for testing purpose I generated 1st in the same DK in PWM_PIN(11).

    But for now I commented this part by commenting pwm1_init();

    And giving INPUTTED PWM Signal from Different DK in PIN_IN (22);

    Best regards,
    Ram

Children
  • RAM_MS said:

    I am really happy that we patiently progress up to this stage.

    And Thank you a lot .

    No problem at all, Ram - I am happy to help!

    RAM_MS said:

    As earlier I said for testing purpose I generated 1st in the same DK in PWM_PIN(11).

    But for now I commented this part by commenting pwm1_init();

    And giving INPUTTED PWM Signal from Different DK in PIN_IN (22);

    Thank you for clarifying this.

    RAM_MS said:
    For your reference I am attaching code here.

    I do not immediately see the reason for why the phase shift would be happening, but I suspect that it might be because the PPI channels are left enabled throughout the run of the application, so that there might be happening a brief stopping and re-starting of the waveform generation, or similar, causing the phase shift.
    Could you try to implement the stopping / disabling of the GPIOTE pin, TIMER instance and PPI channels when the PWM is successfully started, like we talked about earlier?

    By the way, you can change your GPIOTE_CONFIG_IN_SENSE_LOTOHI(true); back to false again - since this was not the cause of the added delay earlier.

    I also notice that you are still not using the pwm start task address returned from the nrf_drv_pwm_simple_playback call, since it is overwritten by the call to nrf_pwm_task_addr_get in the ppi_init - this should not matter though, since they should point to the same address - but I point it out to avoid any confusion since you have stated earlier that it is this return address that is being used.

    Best regards,
    Karl

  • Hello Karl,

    By the way, you can change your GPIOTE_CONFIG_IN_SENSE_LOTOHI(true); back to false again - since this was not the cause of the added delay earlier.

    Yes ,I did that.

    I also notice that you are still not using the pwm start task address returned from the nrf_drv_pwm_simple_playback call, since it is overwritten by the call to nrf_pwm_task_addr_get in the ppi_init - this should not matter though, since they should point to the same address - but I point it out to avoid any confusion since you have stated earlier that it is this return address that is being used.

    Yes ,actually that was just a by mistake . I made it proper.

    I do not immediately see the reason for why the phase shift would be happening, but I suspect that it might be because the PPI channels are left enabled throughout the run of the application, so that there might be happening a brief stopping and re-starting of the waveform generation, or similar, causing the phase shift.
    Could you try to implement the stopping / disabling of the GPIOTE pin, TIMER instance and PPI channels when the PWM is successfully started, like we talked about earlier?

    How to check if PWM is successfully started ?

    Is there any function in SDK which return this ?

    Because I checked with return value from pwm_init () which is NRF_SUCCESS.

    But this is not right way may be .

    So can you please guide me here.

    Best regards,
    Ram 

  • Hello Ram,

    RAM_MS said:
    Yes ,actually that was just a by mistake . I made it proper.

    Great - it is no problem at all, I just thought I should mention it since I noticed.

    RAM_MS said:

    How to check if PWM is successfully started ?

    Is there any function in SDK which return this ?

    Because I checked with return value from pwm_init () which is NRF_SUCCESS.

    But this is not right way may be .

    So can you please guide me here.

    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.
    You could use this event to indicate that the PWM is successfully running, so that you may disable the GPIOTE, TIMER and PPI channels used to set it up.

    Best regards,
    Karl

  • 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

Related