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,

    You will also have to implement a function for updating the delay, that changes the expiration timeout and starts the timer. I am not yet sure what logic you would like to have trigger this change, but you could start by tying it up to a button press if you have not already decided what should trigger it

    At this point I don't want to update the delay instead at constant 1ms delay my pwm output should follow the in put pwm signal.

    our current pwm_update_duty_cycle is called by the CPU - which leaves it vulnerable to added delay due to other tasks of higher priority that the CPU has to finish handling before triggering the task.
    Instead, you should provide the NRF_DRV_PWM_FLAG_START_VIA_TASK flag to your simple_playback function as well, and connect the TIMER CC event to the PWM START_SEQ task through PPI - this will start the readied sequence as soon as the timer expires.

     pwm_start_task_address =
            nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1,
                NRF_DRV_PWM_FLAG_LOOP |
                NRF_DRV_PWM_FLAG_START_VIA_TASK);
                
    
    compare_event_addr = nrf_drv_timer_task_address_get(&PWM_DELAY_TIMER,NRF_TIMER_CC_CHANNEL0);
    
    nrf_drv_ppi_channel_assign(ppi_channel, compare_event_addr,pwm_start_task_address);

    Is this right way to connecting?

    Best regards,
    Ram

  • Hello Ram,

    RAM_MS said:
    At this point I don't want to update the delay instead at constant 1ms delay my pwm output should follow the in put pwm signal.

    Thank you for clarifying - you can then disregard the section of my previous comment relating to the updated-delay implementation.

    RAM_MS said:
    Is this right way to connecting?

    No, not exactly. Your call to nrf_drv_pwm_simple_playback looks correct, but it should be called at the end of your pwm init function, since this will ready the PWM to output the specified sequence once the start task is triggered. Remember to check its returned error code as well.

    You will need to use the nrf_pwm_task_address_get function to get the task address of the NRF_PWM_TASK_SEQSTART0.

    Best regards,
    Karl

  • Hello Karl,

    No, not exactly. Your call to nrf_drv_pwm_simple_playback looks correct, but it should be called at the end of your pwm init function, since this will ready the PWM to output the specified sequence once the start task is triggered. Remember to check its returned error code as well.

    You will need to use the nrf_pwm_task_address_get function to get the task address of the NRF_PWM_TASK_SEQSTART0.

    static void gpio_init(void)
    {
        ret_code_t err_code;
        
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
        // Initialize the PPI module, make sure its only enabled once in your code
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(err_code);
    
    // Allocate the channel from the available PPI channels
        err_code = nrf_drv_ppi_channel_alloc(&ppi_channel);
        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);
    }
    
    void timers_init(void)
    {
        uint32_t err_code;
        uint32_t timer_ticks;
        
        nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG;
        timer_cfg.frequency = NRF_TIMER_FREQ_1MHz;
        err_code = nrfx_timer_init(&PWM_DELAY_TIMER, &timer_cfg,pwm_delay_timeout_handler);
        APP_ERROR_CHECK(err_code);
    
        timer_ticks = nrfx_timer_us_to_ticks(&PWM_DELAY_TIMER, PWM_DELAY_US);
    
        nrfx_timer_extended_compare(&PWM_DELAY_TIMER, 
                                      NRF_TIMER_CC_CHANNEL0, 
                                      timer_ticks,
                                      NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                      true);
    
       nrfx_timer_enable(&PWM_DELAY_TIMER);
    
        compare_event_addr = nrf_drv_timer_task_address_get(&PWM_DELAY_TIMER,NRF_TIMER_CC_CHANNEL0);
        pwm_task_addr =  nrf_drv_pwm_task_address_get(&m_pwm0,NRF_PWM_TASK_SEQSTART0);
    
        err_code = nrf_drv_ppi_channel_assign(ppi_channel, compare_event_addr,pwm_task_addr);
        APP_ERROR_CHECK(err_code);
    
    
        err_code = nrf_drv_ppi_channel_enable(ppi_channel);
        APP_ERROR_CHECK(err_code);
    
    }
    
    
    
    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));
    
        seq_values->channel_0 = duty ;
        seq_values->channel_1 = duty | 0x8000;
        
        APP_ERROR_CHECK(nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1,NRF_DRV_PWM_FLAG_LOOP|NRF_DRV_PWM_FLAG_START_VIA_TASK));
                    
    }
    

    Did this initialization and connection right ???

     Best regards,
     Ram

  • This looks mostly correct, but I cant see that you have connected the GPIOTE IN EVENT to the TIMER's START task through PPI anywhere.

    Do this, and try to run the code. Let me know what you observe - does anything unexpected happen?

    Best regards,
    Karl

  • Hello Karl,

    This looks mostly correct, but I cant see that you have connected the GPIOTE IN EVENT to the TIMER's START task through PPI anywher

    static void ppi_init(void)
    {
        uint32_t err_code = NRF_SUCCESS;
    
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(err_code);
    
        // Allocate the channel from the available PPI channels
        err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_1);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_assign(ppi_channel_1,
                                              nrf_drv_gpiote_in_event_addr_get(PIN_IN),
                                              nrf_drv_timer_task_address_get(&PWM_DELAY_TIMER,
                                                                             NRF_TIMER_TASK_START));
        APP_ERROR_CHECK(err_code);
    
    
        err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_2);
        APP_ERROR_CHECK(err_code);
    
        compare_event_addr = nrf_drv_timer_task_address_get(&PWM_DELAY_TIMER,NRF_TIMER_CC_CHANNEL0);
        pwm_task_addr =  nrf_drv_pwm_task_address_get(&m_pwm0,NRF_PWM_TASK_SEQSTART0);
    
        err_code = nrf_drv_ppi_channel_assign(ppi_channel_2, compare_event_addr,pwm_task_addr);
        APP_ERROR_CHECK(err_code);
    
    
        err_code = nrf_drv_ppi_channel_enable(ppi_channel_1);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_enable(ppi_channel_2);
        APP_ERROR_CHECK(err_code);
     }
    
    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);
    }
    
    void timers_init(void)
    {
        uint32_t err_code;
        uint32_t timer_ticks;
        
        nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG;
        timer_cfg.frequency = NRF_TIMER_FREQ_1MHz;
        err_code = nrfx_timer_init(&PWM_DELAY_TIMER, &timer_cfg,pwm_delay_timeout_handler);
        APP_ERROR_CHECK(err_code);
    
        timer_ticks = nrfx_timer_us_to_ticks(&PWM_DELAY_TIMER, PWM_DELAY_US);
    
        nrfx_timer_extended_compare(&PWM_DELAY_TIMER, 
                                      NRF_TIMER_CC_CHANNEL0, 
                                      timer_ticks,
                                      NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                      true);
    
       nrfx_timer_enable(&PWM_DELAY_TIMER);
    
    }
    
    
    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));
    
        seq_values->channel_0 = duty ;
        seq_values->channel_1 = duty | 0x8000;
        
        APP_ERROR_CHECK(nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1,NRF_DRV_PWM_FLAG_LOOP|NRF_DRV_PWM_FLAG_START_VIA_TASK));
                    
    }
    

    So this scenario needed two ppi connection .

    1-> From GPIOTE  IN   EVENT to the TIMER START 

    2->TIMER COMPATRE to PWM_TASK_SEQSTART .

    I am implemented in this way ,Please verify is this connection is right now??

      

Reply
  • Hello Karl,

    This looks mostly correct, but I cant see that you have connected the GPIOTE IN EVENT to the TIMER's START task through PPI anywher

    static void ppi_init(void)
    {
        uint32_t err_code = NRF_SUCCESS;
    
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(err_code);
    
        // Allocate the channel from the available PPI channels
        err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_1);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_assign(ppi_channel_1,
                                              nrf_drv_gpiote_in_event_addr_get(PIN_IN),
                                              nrf_drv_timer_task_address_get(&PWM_DELAY_TIMER,
                                                                             NRF_TIMER_TASK_START));
        APP_ERROR_CHECK(err_code);
    
    
        err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_2);
        APP_ERROR_CHECK(err_code);
    
        compare_event_addr = nrf_drv_timer_task_address_get(&PWM_DELAY_TIMER,NRF_TIMER_CC_CHANNEL0);
        pwm_task_addr =  nrf_drv_pwm_task_address_get(&m_pwm0,NRF_PWM_TASK_SEQSTART0);
    
        err_code = nrf_drv_ppi_channel_assign(ppi_channel_2, compare_event_addr,pwm_task_addr);
        APP_ERROR_CHECK(err_code);
    
    
        err_code = nrf_drv_ppi_channel_enable(ppi_channel_1);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_enable(ppi_channel_2);
        APP_ERROR_CHECK(err_code);
     }
    
    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);
    }
    
    void timers_init(void)
    {
        uint32_t err_code;
        uint32_t timer_ticks;
        
        nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG;
        timer_cfg.frequency = NRF_TIMER_FREQ_1MHz;
        err_code = nrfx_timer_init(&PWM_DELAY_TIMER, &timer_cfg,pwm_delay_timeout_handler);
        APP_ERROR_CHECK(err_code);
    
        timer_ticks = nrfx_timer_us_to_ticks(&PWM_DELAY_TIMER, PWM_DELAY_US);
    
        nrfx_timer_extended_compare(&PWM_DELAY_TIMER, 
                                      NRF_TIMER_CC_CHANNEL0, 
                                      timer_ticks,
                                      NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                      true);
    
       nrfx_timer_enable(&PWM_DELAY_TIMER);
    
    }
    
    
    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));
    
        seq_values->channel_0 = duty ;
        seq_values->channel_1 = duty | 0x8000;
        
        APP_ERROR_CHECK(nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1,NRF_DRV_PWM_FLAG_LOOP|NRF_DRV_PWM_FLAG_START_VIA_TASK));
                    
    }
    

    So this scenario needed two ppi connection .

    1-> From GPIOTE  IN   EVENT to the TIMER START 

    2->TIMER COMPATRE to PWM_TASK_SEQSTART .

    I am implemented in this way ,Please verify is this connection is right now??

      

Children
  • RAM_MS said:

    So this scenario needed two ppi connection .

    1-> From GPIOTE  IN   EVENT to the TIMER START 

    2->TIMER COMPATRE to PWM_TASK_SEQSTART .

    Yes, your scenario requires two PPI connections.

    RAM_MS said:
    I am implemented in this way ,Please verify is this connection is right now??

    Yes, I do not immediately spot anything wrong with this configuration.
    What do you see when you now attempt to compile and run this program?

    Best regards,
    Karl

  • Hello Karl,

    What do you see when you now attempt to compile and run this program?

    compiled successfully with zero error but pwm output isn't coming , that means its not triggering.

    But below error coming.

    <error> app: Fatal error

    <warning> app: System reset

    Best regards,
     Ram

  • Please make sure to have DEBUG defined in your preprocessor defines, like shown in the included image:

    This will make the logger output a detailed error message whenever a non-NRF_SUCCESS error is passed to an APP_ERROR_CHECK.
    Try this, and let me know what the logger says when this happens.

    Best regards,
    Karl

  • Hello Karl,

    Try this, and let me know what the logger says when this happens.

    <info> app: PPI example started.

    <info> app: LED started.

    <info> app: gpio started.

    <info> app: timer started.

    <error> app: ERROR 1073856524 [Unknown error code] at C:\Nordic\DeviceDownload\nRF5SDK1702d674dde\nRF5_SDK_17.0.2_d674dde\examples\my proj\pwm_common_mode\main.c:176

    PC at: 0x00006BA5

    <error> app: End of error report

    And my main code is:

    int main(void)
    {
    
        uint32_t err_code;
    
        err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
        ppi_init();
        NRF_LOG_INFO("PPI example started.");
        bsp_board_init(BSP_INIT_LEDS);
        NRF_LOG_INFO("LED started.");
        gpio_init();
        NRF_LOG_INFO("gpio started.");
        timers_init();
        NRF_LOG_INFO("timer  started.");
        pwm_init();
        
        NRF_LOG_INFO("pwm started.");
         
        unsigned int val;
        
        while (1)
        {
          
          
           
        }
    }

    This means Its coming from pwm_init() function.

    Best regards,
     Ram

  • Hello again, Ram

    RAM_MS said:

    <error> app: ERROR 1073856524 [Unknown error code] at C:\Nordic\DeviceDownload\nRF5SDK1702d674dde\nRF5_SDK_17.0.2_d674dde\examples\my proj\pwm_common_mode\main.c:176

    PC at: 0x00006BA5

    Exactly which function call returned the error code passed to an APP_ERROR_CHECK on line 176 of main?
    Could you share the entire pwm_init function as it currently is? To proceed we will need to pinpoint which APP_ERROR_CHECK that triggered the reset, and which function generated the error.

    Best regards,
    Karl

Related