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

Timer handler mess up application flow

I have a working application with TIMER1 setup to fire handler every 10us. I would like to add a 560us periodic event to enable/disable a PWM, so I add a little more code to my timer handler:

static uint16_t                         m_10us_cntr2= 0;
void timer_event_handler(nrf_timer_event_t event_type, void* p_context)
{
    // TROUBLESOME_CODE  -----------------------------------------
    m_10us_cntr2++;
    if (m_10us_cntr2>= 56)
    {
//        NOT EVEN DOING ANYTHING HERE YET
        m_10us_cntr2= 0;
    }
    // /TROUBLESOME_CODE  ----------------------------------
    
    m_10us_cntr++;
    if (m_10us_cntr>= 100000)
    {
        m_second_counter++;
        m_10us_cntr= 0;
    }
    //m_second_counter++;
    if (m_second_counter == PERIODIC_TASKS_PERIOD)
    {
        m_periodic_flag = true;
        m_second_counter = 0;
    }
}

To my surprise, just the presence of the if block make the app crash completely during TIMER1 initialization. The debug printf() statement "end of timer_init\n" I had after my TIMER1 initialization function calls could only push out "end" or "end o" before the app crashes.

What is causing this? Is there a way to fix it?

Update: for reference, here is my timer_init() code:

void timer_init()
{
    DEBUG_PRINT(("timer_init\n"));
    
    uint32_t                err_code = NRF_SUCCESS;
    uint32_t                time_us = 10; //Time (in microseconds) between consecutive compare events.
    uint32_t                time_ticks;    

    nrf_drv_timer_config_t  timer_config = NRF_DRV_TIMER_DEFAULT_CONFIG(1);
    timer_config.frequency  = NRF_TIMER_FREQ_16MHz;


    err_code = nrf_drv_timer_init(&m_timer, &timer_config, timer_event_handler);
    if (err_code != NRF_SUCCESS)
    {
       // The only error possible for this function is NRF_ERROR_INVALID_PARAM	according to SDK v10 documentation
       // TODO: handling error
    }

    time_ticks = nrf_drv_timer_us_to_ticks(&m_timer, time_us);
    DEBUG_PRINT(("time_ticks = %d\n", time_ticks));

    nrf_drv_timer_extended_compare(
        &m_timer, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);

    nrf_drv_timer_enable(&m_timer);
    DEBUG_PRINT(("end of timer_init()\n"));
    
}

The app always failed while printing out the last debug print ("end of timer_init()").

Update Apr 20 2016: So I run a few more experiments, and the details bizarre me even more, so please bare with me.

  1. I first tried to use uVision debug to look at what cause the app flow to hang. When I hit stop, I found the current-line-of-execution pointer sometimes points at nrf_timer_event_check(), sometimes at my timer_event_handler(), sometimes at nrf_timer_event_clear(). It feels like this is a case of interrupt handling taking too long and block the code flow.

    I also observed that the "end of timer_init()\n" print not only fails midway, but also sometimes have characters print out of order.

  2. I tried to move the timer_init() call to the bottom of all of my initialization function calls. This moves the following two functions to be called before timer_init():

    a- i2c_slave_drv_init(): A function I used to read confirmation values and initialization values to an I2C slave peripheral. In case it matters, my I2C read and write implementation uses the following blocking wait to wait for TWI Driver events

        watchdog_counter = 0;
        while(!twi_drv_evt_received && watchdog_counter < 60000)
        {
            nrf_delay(1);
            watchdog_counter++;
        }
    

    b- ble_advertising_start()

    The app can now run without major issue after this change. The only minor issue is my 1s flag now takes a lot more than a second to fire. I assume this is due to timer_event_handler() processing delay

  3. Now here comes the bizarre part: I tried to reproduce the issue by moving timer_init() back where it was. And the issue stop happening. However, that is only as long as I don't add another if block to timer_event_handler. If I change the TROUBLESOME_CODE into the following, I can then reproduce the issue:

    if (m_10us_cntr2 > 56)
    {
        if (m_pwm_toggle) {
            // TODO
        } else {
            // TODO
        }
        m_pwm_toggle = !m_pwm_toggle;
        m_10us_cntr2 = 0;
    }
    
  4. At this point, I found out that the app did not actually got stuck entirely. Returning to the console after writing the above, I found that the issue is:

    a- While running initialization code, it just takes almost half a minute to print out a single characters. You can see in this screen record: uart_rate_init.avi (Please excuse the low quality. I need to do so due to the long duration of the process)

    b- While running main()'s super loop code, the app could only print 3-5 characters a second. You could see in this screen record: uart_rate_loop.avi

And that is the last of my observations. I hope somebody have an idea what is going on. This is really too strange for me to have any idea.

Parents
  • You are enabling the timer before configuring it and then after configuring it. This might result in false triggers before the timer is configured.

    If you want 560 us then you should not use 560 as condition but 56 (56*10us = 560us)

    void timer_event_handler(nrf_timer_event_t event_type, void* p_context)
    {
        m_10us_cntr2++;
        if (m_10us_cntr2>= 56)
        {
             //        NOT EVEN DOING ANYTHING HERE YET
            m_10us_cntr2= 0;
        } 
    }
    
    1. I do not know what the last two if statements in the timer_event_handler are doing and i do not know that value of PERIODIC_TASKS_PERIOD so i removed the last if statement.

      void timer_event_handler(nrf_timer_event_t event_type, void* p_context) { m_10us_cntr2++; if (m_10us_cntr2>= 56) { m_10us_cntr2= 0; nrf_gpio_pin_toggle(26); }

      m_10us_cntr++;
      if (m_10us_cntr >= 100000)
      {
          m_second_counter++;
          m_10us_cntr= 0;
      }
      nrf_gpio_pin_toggle(25);
      

      }

    And i get the timer handler with good accuracy (the small error shown is interrupt latency) image description
    image description

    And the debug log which is printed instantly (not half a minute)

    timer_init
    time_ticks = 160
    end of timer_init()

    The conclusion is there is something with your I2C or PWM handling. I am pretty sure you can exclude timer handling from the problem you have.

  • By the way, should we update one of the answer with the conclusion that stack overflow happened?

Reply Children
No Data
Related