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 Ram,

    I saw your in_pin_handler function before, but I still do not see where / if it is ever being called.
    Please show me the section of your code in which you initialize your GPIOTE and provide the in_pin_handler as its callback.
    Could you also confirm that you ever enter into the in_pin_handler function as expected?

    RAM_MS said:
    I am not getting the delay I am expecting.

    Please elaborate at much as possible. The more specific you are, the easier it will be for us to help you resolve your issue.
    So you are getting a delay, but it is not what you expect? From your code I assume that you are trying to see a 500 µs delay. What delay are you currently seeing?

    Best regards,
    Karl

  • Hello Karl,

    I saw your in_pin_handler function before, but I still do not see where / if it is ever being called.
    Please show me the section of your code in which you initialize your GPIOTE and provide the in_pin_handler as its callback.
    Could you also confirm that you ever enter into the in_pin_handler function as expected?

    #define    PIN_IN    22
    
    static void gpio_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
        in_config.pull = NRF_GPIO_PIN_PULLDOWN;
    
        err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_event_enable(PIN_IN, true);
    }

    Could you also confirm that you ever enter into the in_pin_handler function as expected?

    Yes ,my in_pin_handler function working as expected. and its not a button like interrupt but it is a square wave signal interrupt with 20ms period and 50% duty cycle.  

    So you are getting a delay, but it is not what you expect? From your code I assume that you are trying to see a 500 µs delay. What delay are you currently seeing?

    Yes, I am getting a delay but which is a random value around 98 µs irrespective of my input .

  • RAM_MS said:
    Yes ,my in_pin_handler function working as expected. and its not a button like interrupt but it is a square wave signal interrupt with 20ms period and 50% duty cycle.  
    RAM_MS said:
    Yes, I am getting a delay but which is a random value around 98 µs irrespective of my input .

    I see, thank you for clarifying.
    It seems very strange to me that you do not see any difference when you change the time_us variable.

    Could I also ask why you are using an external periodic signal to enable the Timer? Is this placeholder functionality for something you will implement later? Is the gpio_flag being set every 10 ms?

    It would also be helpful if you could share with me your sdk_config.h file, so I may take a look at your GPIOTE and TIMER configuration.

    Best regards,
    Karl

  • Could I also ask why you are using an external periodic signal to enable the Timer? Is this placeholder functionality for something you will implement later?

    I want to follow external periodic signal with some user defined delay that why I am starting timer from interrupt.

    My aim is here to create a same periodic signal of 50% duty cycle and 20ms period but with user defined delay(that is vary from 0 to 10ms ).

    Is the gpio_flag being set every 10 ms?

    For now I configured for 20ms but definitely aim is to get in every 10ms.

    It would also be helpful if you could share with me your sdk_config.h file, so I may take a look at your GPIOTE and TIMER configuration.

    3718.sdk_config.h

    Best regards,
    Ram

  • Hello again, ram

    Looking over your sdk_config.h I notice that you have both the NRFX_TIMER_ENABLED and legacy TIMER_ENABLED defined to 1.
    You should only have the one corresponding to the driver you intend to use present. In the current case, if you intend to use the nrfx driver the NRFX_TIMER_ENABLED will be overwritten by TIMER_ENABLED at compile-time.
    If you intend to use the nrfx driver, you should therefore remove the legacy *_ENABLED definitions from the sdk_config all together (remove or comment out, as they can not be left defined).

    In your case it seems that you are using the 16 MHz clock frequency with the 16 bit bit depth, could you try to increase this to 32 bit bit depth and see if that makes a difference on the behavior you are seeing? You could do this by defining NRFX_TIMER_DEFAULT_CONFIG_BIT_WIDTH to 3 (if using the nrfx driver, and having removed all mention of the legacy timer define's).

    Best regards,
    Karl

Reply
  • Hello again, ram

    Looking over your sdk_config.h I notice that you have both the NRFX_TIMER_ENABLED and legacy TIMER_ENABLED defined to 1.
    You should only have the one corresponding to the driver you intend to use present. In the current case, if you intend to use the nrfx driver the NRFX_TIMER_ENABLED will be overwritten by TIMER_ENABLED at compile-time.
    If you intend to use the nrfx driver, you should therefore remove the legacy *_ENABLED definitions from the sdk_config all together (remove or comment out, as they can not be left defined).

    In your case it seems that you are using the 16 MHz clock frequency with the 16 bit bit depth, could you try to increase this to 32 bit bit depth and see if that makes a difference on the behavior you are seeing? You could do this by defining NRFX_TIMER_DEFAULT_CONFIG_BIT_WIDTH to 3 (if using the nrfx driver, and having removed all mention of the legacy timer define's).

    Best regards,
    Karl

Children
  • Hello Karl,

    If you intend to use the nrfx driver, you should therefore remove the legacy *_ENABLED definitions from the sdk_config all together (remove or comment out, as they can not be left defined)

    If I remove legacy *_ENABLED definitions then my PWM_UPDATE() function will not work. 

    You can get idea from the function ,So I am attaching here .

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

    I tried with same logic with PWM_DRIVER but its not working.

    Here is my same logic with pwm_driver example from SDK.

    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    
    
    
    
    
    // Declare variables holding PWM sequence values. In this example only one channel is used 
    nrf_pwm_values_individual_t seq_values[] = {0, 0, 0, 0};
    
    nrf_pwm_sequence_t const seq =
    {
        .values.p_individual = seq_values,
        .length          = NRF_PWM_VALUES_LENGTH(seq_values),
        .repeats         = 0,
        .end_delay       = 0
    };
    
    static void pwm_init(void)
    {
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                OUTPUT_PIN, // channel 0
                OUTPUT_PIN2,             // channel 1
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
            },
            .irq_priority = APP_IRQ_PRIORITY_LOWEST,
            .base_clock   = NRF_PWM_CLK_1MHz,
            .count_mode   = NRF_PWM_MODE_UP,
            .top_value    = 20000,
            .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        // Init PWM without error handler
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
        
    }
    
     void pwm_update_duty_cycle(uint16_t duty_cycle)
    {
        if(duty_cycle == 0)
        {
         seq_values->channel_0 = duty_cycle ;
         seq_values->channel_1 = duty_cycle ;
        }
       else
        {
            seq_values->channel_0 = duty_cycle ;
            seq_values->channel_1 = duty_cycle | 0x8000;
        }
        
        
        nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
    }
    
    int main(void)
    {
       
        bsp_board_init(BSP_INIT_LEDS);
        gpio_init();
        pwm_init();
        
         
        unsigned int val;
        
        while (1)
        {
          
          if(gpio_flag == 1)
          {
           val= duty;
           gpio_flag=0;
           pwm_update_duty_cycle(val); 
     
          }
          else
          {
           pwm_update_duty_cycle(0);   
          }
           
        }
    }
    

    Best regards,
    Ram

  • Hello ram,

    RAM_MS said:
    If I remove legacy *_ENABLED definitions then my PWM_UPDATE() function will not work. 

    What do you mean when you say that the pwm_update function stops working? Please describe the behavior you observe and how it differs from what you would expect.
    Would you mind sharing with me the sdk_config.h file following your removal of legacy define's, so I may take a look?

    Did you try to configure the TIMER to use a bit depth of 32? Did you see any difference then?

    RAM_MS said:
    I tried with same logic with PWM_DRIVER but its not working.

    Please elaborate on what you mean when you say it is not working - does this produce the same result as when you were using the pwm library?
    If so, it may be related to the timer configuration rather than the PWM module usage.

    Best regards,
    Karl

  • Hello Karl,

    What do you mean when you say that the pwm_update function stops working? Please describe the behavior you observe and how it differs from what you would expect.

    Because my pwm_update () is from pwm library example .

    AND after commenting legacy definations, this error message coming during building the project.

    #error "No enabled TIMER instances. Check <nrfx_config.h>."

    Would you mind sharing with me the sdk_config.h file following your removal of legacy define's, so I may take a look?

    here is the sdk_config.h after commenting legacy defines.

    8765.sdk_config.h

    Did you try to configure the TIMER to use a bit depth of 32? Did you see any difference then?

    yes ,I tried but not see any difference.

    Please elaborate on what you mean when you say it is not working - does this produce the same result as when you were using the pwm library?

    working pwm with periodical interrupt is

    if(gpio_flag == 1)
        {
         gpio_flag = 0;
         pwm_update();
        }
        else
        {
         app_pwm_channel_duty_set(&PWM1, 1, 0);
         app_pwm_channel_duty_set(&PWM1, 0, 0);
        }
       

    where if I used pwm_driver then same code not working.

    if(gpio_flag == 1)
        {
         gpio_flag = 0;
          pwm_update_duty_cycle(10000);
        }
        else
        {
         pwm_update_duty_cycle(0);
        }

    where pwm_update () is inspired from pwm_library example and pwm_update_duty_cycle() is inspired from pwm_driver .

    As my pwm algorithm working with legacy defines ,So its better to remove nrfx_timer_driver .

    So if you guide me to generate delay from legacy timer then it may be immediate solution for my issue as per my understanding .

    Best regards,
    Ram

  • Hello again, ram

    RAM_MS said:

    AND after commenting legacy definations, this error message coming during building the project.

    #error "No enabled TIMER instances. Check <nrfx_config.h>."

    Thank you for elaborating. The no TIMER instance error means that you have to make sure that the timer instance you are trying to use is enabled in sdk_config. I see from your code that you have not defined any of the NRFX_TIMER*_ENABLED definitions to 1.
    Please define NRFX_TIMER0_ENABLED 1 if you intend to use the TIMER0 instance. Please also note that TIMER0 is blocked by the SoftDevice - I just mention this in case you intend to add the SoftDevice to your project down the line.

    RAM_MS said:
    As my pwm algorithm working with legacy defines ,So its better to remove nrfx_timer_driver .
    RAM_MS said:
    So if you guide me to generate delay from legacy timer then it may be immediate solution for my issue as per my understanding .

    I would advice you to give it one more try with the nrfx driver, since it did not compile when you had no NRFX_TIMER instances enabled.

    RAM_MS said:
    yes ,I tried but not see any difference.

    Please try to increase the bit depth to 32 again when only using the nrfx driver, with all the legacy TIMER definitions still commented out or removed from the sdk_config. Please do this, and let me know if you then see the constant 98 µs behavior change.

    Best regards,
    Karl

  • Hello Karl,

    Please try to increase the bit depth to 32 again when only using the nrfx driver, with all the legacy TIMER definitions still commented out or removed from the sdk_config. Please do this, and let me know if you then see the constant 98 µs behavior change

    I tried with bit depth 32 and only enabling nrfx_driver ,but still the same issue ..getting constant around 98 µs behaviour.

    here I am attaching my sdk_config.h

    85253.sdk_config.h

    Best regards,
    Ram

Related