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

There seems to be a problem using multiple app_timer() together.

Hello

I am using sdk v17.0 and nrf52832.
I'm using two timers through a button.

1. Timer for click & double-click. (Single Timer)
2. Timer for Long Press. (Repeated Timer)

Using them separately is not a problem, but if I use them together, It stop when I double-click. I checked by debugging, but no error occurred. (I think it stopped at the RTC.)

static void PairLED_timer_handler(void * p_context) //when advertising toggle led
{
  nrf_gpio_pin_toggle(Pairing_LED); //toggle led
}


uint32_t press_time; //press time count
uint32_t press_time2; //press time count
int click_count; //click count(use double click)
bool buttonTimeout = false; //use double click

static void PowerOff_timer_handler(void * p_context)
{
  press_time++;
  printf("COUNT : %d\n", press_time);

  if(press_time == 2) //press 2sec, Power Off
  {
    printf("Power Off!\n");
    //nrf_gpio_pin_clear(POWER_SW); //LOW : power off
  }
}


static void DoubleClick_timer_handler(void * p_context)
{
  //printf("Timeout\n");
  printf("%d\n", click_count);
  buttonTimeout = true;

  if(click_count == 1)
  {
    printf("One Click\n");
  }

  click_count = 0;
}


static void timers_init(void)
{
    ret_code_t err_code;

    // Initialize timer module.
    err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);

   //Create Pairing LED timers/
    err_code = app_timer_create(&m_PairLED_timerid,
                                APP_TIMER_MODE_REPEATED,
                                PairLED_timer_handler);
    APP_ERROR_CHECK(err_code);

   //Create Power off Time timers/
    err_code = app_timer_create(&m_PowerOff_timer_id,
                                APP_TIMER_MODE_REPEATED,
                                PowerOff_timer_handler);
    APP_ERROR_CHECK(err_code);

   //Create DOuble Click Time timers/
    err_code = app_timer_create(&m_DoubleClick_timer_id,
                                APP_TIMER_MODE_SINGLE_SHOT,
                                DoubleClick_timer_handler);
    APP_ERROR_CHECK(err_code);
}


static void PairLED_timers_start()
{
  ret_code_t err_code;

  err_code = app_timer_start(m_PairLED_timerid, APP_TIMER_TICKS(1000), NULL); //Toggle 1sec
  APP_ERROR_CHECK(err_code);
  printf("Scanning Start\n");
}


static void PairLED_timers_stop() //Stop Timer
{
    ret_code_t err_code;

    err_code = app_timer_stop(m_PairLED_timerid); 
    APP_ERROR_CHECK(err_code);
}


static void PowerOff_timers_start()
{
  ret_code_t err_code;

  err_code = app_timer_start(m_PowerOff_timer_id, APP_TIMER_TICKS(1000), NULL); //count 1sec
  APP_ERROR_CHECK(err_code);
}


static void PowerOff_timers_stop()
{
    ret_code_t err_code;

    //printf("No Power Off\n");
    press_time = 0; //count reset

    err_code = app_timer_stop(m_PowerOff_timer_id); 
    APP_ERROR_CHECK(err_code); 
}

static void DoubleClick_timers_start()
{
  ret_code_t err_code;

  err_code = app_timer_start(m_DoubleClick_timer_id, APP_TIMER_TICKS(500), NULL); 
  APP_ERROR_CHECK(err_code);
}


static void DoubleClick_timers_stop() //Stop Timer
{
    ret_code_t err_code;

    err_code = app_timer_stop(m_DoubleClick_timer_id); 
    APP_ERROR_CHECK(err_code);

    //printf("Stop Timer\n");
}


//==========================================================

static uint32_t pressed_time, released_time, pressed_duration = 0;
static bool pressed_cnt= false;

static uint32_t app_button_duration(void) //press time
{
  pressed_duration = (released_time - pressed_time)*2; //ms
  return pressed_duration;
}

static void app_button_init_time_variable(void)
{
  pressed_duration = 0; //press time
}


static void app_button_event_generator(void) //button press time
{
  ret_code_t err_code;

  app_button_init_time_variable();
}
 

static void app_button_event_handler(uint8_t pin_no, uint8_t button_action)
{
    ret_code_t err_code;

    switch (pin_no)
    {
      case BUTTON_1: 
        switch (button_action)
        {
          case APP_BUTTON_PUSH:
          {
            //printf("Button pressed\n");

            //get pressed time
            /*pressed_time = app_timer_cnt_get()*1000/32768;//milli-sec
            NRF_LOG_INFO("pressed_time: %d", (int)pressed_time);
            printf("pressed_time: %d\n", (int)pressed_time);
            pressed_cnt = true; */

            if(click_count == 0) //first click
            {
              buttonTimeout = false;
              DoubleClick_timers_start();  //buttonTimeout = true, click_count = 0;
            }

            PowerOff_timers_start(); //press time count
          } 

          click_count++;
          break;

           case APP_BUTTON_RELEASE:
           {  
              //printf("Button releaed\n");

              PowerOff_timers_stop();

              /*if (pressed_cnt)
              {
                released_time = app_timer_cnt_get()*1000/32768; //milli-sec
                NRF_LOG_INFO("released_time: %d", (int)released_time);
                printf("released_time: %d\n", (int)released_time);
                click_state = 0;
              }

              pressed_cnt = false; */

              if(click_count == 2 && !buttonTimeout) //double click
              {
                DoubleClick_timers_stop();
                click_count = 0;
                printf("Double Click\n");
              }               
           } break;
        } 
      break;

      default:
         APP_ERROR_HANDLER(pin_no);
      break;
    }

    if(app_button_duration())
    {
      app_button_event_generator();
    }

    app_button_init_time_variable(); 
}


static void app_buttons_init(void)
{
  uint32_t err_code;

  static const app_button_cfg_t app_buttons[BUTTONS_NUMBER] =
  {
    {BUTTON_1, false, BUTTON_PULL, app_button_event_handler},
  };

  err_code = app_button_init((app_button_cfg_t *)app_buttons,
                                       BUTTONS_NUMBER,        // 1
                                       APP_TIMER_TICKS(50)); //debounce
  APP_ERROR_CHECK(err_code);
}

Could you tell me the cause of this problem?

Thank you!

Parents
  • May you figure out the timer op queue size in your sdk_config.h file? In your project the timer id are 3 or more. That means 

    APP_TIMER_CONFIG_OP_QUEUE_SIZE should be more than 3.

  • Hi, Henry.

    APP_TIMER_CONFIG_OP_QUEUE_SIZE is set to 10.

    // <e> APP_TIMER_ENABLED - app_timer - Application timer functionality
    //==========================================================
    #ifndef APP_TIMER_ENABLED
    #define APP_TIMER_ENABLED 1
    #endif
    // <o> APP_TIMER_CONFIG_RTC_FREQUENCY  - Configure RTC prescaler.
     
    // <0=> 32768 Hz 
    // <1=> 16384 Hz 
    // <3=> 8192 Hz 
    // <7=> 4096 Hz 
    // <15=> 2048 Hz 
    // <31=> 1024 Hz 
    
    #ifndef APP_TIMER_CONFIG_RTC_FREQUENCY
    #define APP_TIMER_CONFIG_RTC_FREQUENCY 1
    #endif
    
    // <o> APP_TIMER_CONFIG_IRQ_PRIORITY  - Interrupt priority
     
    
    // <i> Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice
    // <0=> 0 (highest) 
    // <1=> 1 
    // <2=> 2 
    // <3=> 3 
    // <4=> 4 
    // <5=> 5 
    // <6=> 6 
    // <7=> 7 
    
    #ifndef APP_TIMER_CONFIG_IRQ_PRIORITY
    #define APP_TIMER_CONFIG_IRQ_PRIORITY 6
    #endif
    
    // <o> APP_TIMER_CONFIG_OP_QUEUE_SIZE - Capacity of timer requests queue. 
    // <i> Size of the queue depends on how many timers are used
    // <i> in the system, how often timers are started and overall
    // <i> system latency. If queue size is too small app_timer calls
    // <i> will fail.
    
    #ifndef APP_TIMER_CONFIG_OP_QUEUE_SIZE
    #define APP_TIMER_CONFIG_OP_QUEUE_SIZE 10
    #endif
    
    // <q> APP_TIMER_CONFIG_USE_SCHEDULER  - Enable scheduling app_timer events to app_scheduler
     
    
    #ifndef APP_TIMER_CONFIG_USE_SCHEDULER
    #define APP_TIMER_CONFIG_USE_SCHEDULER 0
    #endif
    
    // <q> APP_TIMER_KEEPS_RTC_ACTIVE  - Enable RTC always on
     
    
    // <i> If option is enabled RTC is kept running even if there is no active timers.
    // <i> This option can be used when app_timer is used for timestamping.
    
    #ifndef APP_TIMER_KEEPS_RTC_ACTIVE
    #define APP_TIMER_KEEPS_RTC_ACTIVE 0
    #endif
    
    // <o> APP_TIMER_SAFE_WINDOW_MS - Maximum possible latency (in milliseconds) of handling app_timer event. 
    // <i> Maximum possible timeout that can be set is reduced by safe window.
    // <i> Example: RTC frequency 16384 Hz, maximum possible timeout 1024 seconds - APP_TIMER_SAFE_WINDOW_MS.
    // <i> Since RTC is not stopped when processor is halted in debugging session, this value
    // <i> must cover it if debugging is needed. It is possible to halt processor for APP_TIMER_SAFE_WINDOW_MS
    // <i> without corrupting app_timer behavior.
    
    #ifndef APP_TIMER_SAFE_WINDOW_MS
    #define APP_TIMER_SAFE_WINDOW_MS 300000
    #endif
    
    // <h> App Timer Legacy configuration - Legacy configuration.
    
    //==========================================================
    // <q> APP_TIMER_WITH_PROFILER  - Enable app_timer profiling
     
    
    #ifndef APP_TIMER_WITH_PROFILER
    #define APP_TIMER_WITH_PROFILER 0
    #endif
    
    // <q> APP_TIMER_CONFIG_SWI_NUMBER  - Configure SWI instance used.
     
    
    #ifndef APP_TIMER_CONFIG_SWI_NUMBER
    #define APP_TIMER_CONFIG_SWI_NUMBER 0
    #endif
    

Reply
  • Hi, Henry.

    APP_TIMER_CONFIG_OP_QUEUE_SIZE is set to 10.

    // <e> APP_TIMER_ENABLED - app_timer - Application timer functionality
    //==========================================================
    #ifndef APP_TIMER_ENABLED
    #define APP_TIMER_ENABLED 1
    #endif
    // <o> APP_TIMER_CONFIG_RTC_FREQUENCY  - Configure RTC prescaler.
     
    // <0=> 32768 Hz 
    // <1=> 16384 Hz 
    // <3=> 8192 Hz 
    // <7=> 4096 Hz 
    // <15=> 2048 Hz 
    // <31=> 1024 Hz 
    
    #ifndef APP_TIMER_CONFIG_RTC_FREQUENCY
    #define APP_TIMER_CONFIG_RTC_FREQUENCY 1
    #endif
    
    // <o> APP_TIMER_CONFIG_IRQ_PRIORITY  - Interrupt priority
     
    
    // <i> Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice
    // <0=> 0 (highest) 
    // <1=> 1 
    // <2=> 2 
    // <3=> 3 
    // <4=> 4 
    // <5=> 5 
    // <6=> 6 
    // <7=> 7 
    
    #ifndef APP_TIMER_CONFIG_IRQ_PRIORITY
    #define APP_TIMER_CONFIG_IRQ_PRIORITY 6
    #endif
    
    // <o> APP_TIMER_CONFIG_OP_QUEUE_SIZE - Capacity of timer requests queue. 
    // <i> Size of the queue depends on how many timers are used
    // <i> in the system, how often timers are started and overall
    // <i> system latency. If queue size is too small app_timer calls
    // <i> will fail.
    
    #ifndef APP_TIMER_CONFIG_OP_QUEUE_SIZE
    #define APP_TIMER_CONFIG_OP_QUEUE_SIZE 10
    #endif
    
    // <q> APP_TIMER_CONFIG_USE_SCHEDULER  - Enable scheduling app_timer events to app_scheduler
     
    
    #ifndef APP_TIMER_CONFIG_USE_SCHEDULER
    #define APP_TIMER_CONFIG_USE_SCHEDULER 0
    #endif
    
    // <q> APP_TIMER_KEEPS_RTC_ACTIVE  - Enable RTC always on
     
    
    // <i> If option is enabled RTC is kept running even if there is no active timers.
    // <i> This option can be used when app_timer is used for timestamping.
    
    #ifndef APP_TIMER_KEEPS_RTC_ACTIVE
    #define APP_TIMER_KEEPS_RTC_ACTIVE 0
    #endif
    
    // <o> APP_TIMER_SAFE_WINDOW_MS - Maximum possible latency (in milliseconds) of handling app_timer event. 
    // <i> Maximum possible timeout that can be set is reduced by safe window.
    // <i> Example: RTC frequency 16384 Hz, maximum possible timeout 1024 seconds - APP_TIMER_SAFE_WINDOW_MS.
    // <i> Since RTC is not stopped when processor is halted in debugging session, this value
    // <i> must cover it if debugging is needed. It is possible to halt processor for APP_TIMER_SAFE_WINDOW_MS
    // <i> without corrupting app_timer behavior.
    
    #ifndef APP_TIMER_SAFE_WINDOW_MS
    #define APP_TIMER_SAFE_WINDOW_MS 300000
    #endif
    
    // <h> App Timer Legacy configuration - Legacy configuration.
    
    //==========================================================
    // <q> APP_TIMER_WITH_PROFILER  - Enable app_timer profiling
     
    
    #ifndef APP_TIMER_WITH_PROFILER
    #define APP_TIMER_WITH_PROFILER 0
    #endif
    
    // <q> APP_TIMER_CONFIG_SWI_NUMBER  - Configure SWI instance used.
     
    
    #ifndef APP_TIMER_CONFIG_SWI_NUMBER
    #define APP_TIMER_CONFIG_SWI_NUMBER 0
    #endif
    

Children
  • Ok. It won't be the queue size problems. But I doubt for this

    if(click_count == 2 && !buttonTimeout) //double click
    {
    DoubleClick_timers_stop();
    click_count = 0;
    printf("Double Click\n");
    }

    in your doubleclick handle .The click_count is clear to zero.

    static void DoubleClick_timer_handler(void * p_context)
    {
    //printf("Timeout\n");
    printf("%d\n", click_count);
    buttonTimeout = true;

    if(click_count == 1)
    {
    printf("One Click\n");
    }

    click_count = 0;
    }

    Here.

    That means it never stop the timer. I have no idea, if a timer handle is not stop and start again.

    And the DoubleClick(500ms) timer & PowerOff_timer(1000ms) are quite different. Long key power off 2sec & Double click (500ms*2). I think that the doble click count will not be 2 when you push twice.

  • Hi.
    I'm sorry for the late reply. I'm trying again, but I'm still in the same problem.

    A slightly modified code from the previous code.

    The handler and initialization code of the timer.

    static void PowerOff_timer_handler(void * p_context)
    {
      press_time++;
      printf("COUNT : %d\n", press_time); //button press time
    
      if(press_time >= 3) //press 3sec, Power Off
      {
        printf("Power Off!\n");
      }
    }
    
    
    static void ClickCount_timer_handler(void * p_context)
    {
      buttonTimeout = true;
    
      if(click_count == 1 && !push_state) //If no click after first click
      {
        printf("One Click\n");
        A_timers_start(); //after 5min, stop A timer
        ClickCount_timers_stop();
      }
    
      click_count = 0;
    }
    
    
    static void A_timer_handler(void * p_context) 
    {
      A_timers_stop();
    }
    
    
    static void B_timer_handler(void * p_context) //after 5min
    {
      B_timers_stop();
    }
    
    
    /**@brief Function for the Timer initialization.
     *
     * @details Initializes the timer module. This creates and starts application timers.
     */
    static void timers_init(void)
    {
        ret_code_t err_code;
    
        // Initialize timer module.
        err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    
       //Create Power off Time timers/
        err_code = app_timer_create(&m_PowerOff_timer_id,
                                    APP_TIMER_MODE_REPEATED,
                                    PowerOff_timer_handler);
        APP_ERROR_CHECK(err_code);
    
       //Create Click count Time timers/
        err_code = app_timer_create(&m_ClickCount_timer_id,
                                    APP_TIMER_MODE_REPEATED, 
                                    ClickCount_timer_handler);
        APP_ERROR_CHECK(err_code);
    
       //Create Stop A timers/
        err_code = app_timer_create(&m_A_timer_id,
                                    APP_TIMER_MODE_REPEATED, 
                                    A_timer_handler);
        APP_ERROR_CHECK(err_code);
    
       //Create Stop B timers/
        err_code = app_timer_create(&m_B_timer_id,
                                    APP_TIMER_MODE_REPEATED, 
                                    B_timer_handler);
    }
    
    
    static void PowerOff_timers_start()
    {
      ret_code_t err_code;
    
      err_code = app_timer_start(m_PowerOff_timer_id, APP_TIMER_TICKS(1000), NULL); //count 1sec
      APP_ERROR_CHECK(err_code);
    
      printf("PowerOff timer start\n");
      poweroff_timer_state = true;
    }
    
    
    static void PowerOff_timers_stop()
    {
        ret_code_t err_code;
    
        press_time = 0; //count reset
    
        //printf("check point0\n");
        err_code = app_timer_stop(m_PowerOff_timer_id); 
        APP_ERROR_CHECK(err_code); 
    
        printf("PowerOff timer stop\n");
        poweroff_timer_state = false;
    }
    
    
    static void  ClickCount_timers_start()
    {
      ret_code_t err_code;
    
      err_code = app_timer_start(m_ClickCount_timer_id, APP_TIMER_TICKS(400), NULL); 
      APP_ERROR_CHECK(err_code);
    
      //printf("Start  Click count Timer\n");
    }
    
    
    static void  ClickCount_timers_stop() //Stop Timer
    {
        ret_code_t err_code;
    
        err_code = app_timer_stop(m_ClickCount_timer_id); 
        APP_ERROR_CHECK(err_code);
    }
    
    
    static void A_timers_start() 
    {
      ret_code_t err_code;
    
      printf("Start A Timer\n");
      err_code = app_timer_start(m_A_timer_id, APP_TIMER_TICKS(10000), NULL); //10sec test
      APP_ERROR_CHECK(err_code);
    }
    
    
    static void A_timers_stop() //Stop button or app
    {
        ret_code_t err_code;
    
        err_code = app_timer_stop(m_A_timer_id); 
        APP_ERROR_CHECK(err_code);
    
        printf("Stop A\n");
        A_state = false; //A off
    }
    
    
    static void B_timers_start() 
    {
      ret_code_t err_code;
    
      printf("Start  B Timer\n");
      err_code = app_timer_start(m_B_timer_id, APP_TIMER_TICKS(10000), NULL); //10sec test
      APP_ERROR_CHECK(err_code);
    }
    
    
    static void B_timers_stop() //Stop button or app
    {
        ret_code_t err_code;
        
        err_code = app_timer_stop(m_B_timer_id); 
        APP_ERROR_CHECK(err_code);
        
        printf("Stop B Timer\n");
    }
    

    This is the code for button.

    static void app_button_event_handler(uint8_t pin_no, uint8_t button_action)
    {
        ret_code_t err_code;
    
        switch (pin_no)
        {
          case BUTTON_1: 
            switch (button_action)
            {
    
              case APP_BUTTON_PUSH:
              {
                //printf("Button pressed\n");
                push_state = true;
    
                if(A_state == true) //During a running, press the button to stop
                { 
                  printf("Stop button\n");
                  click_count = 0; 
                  stop_state = true;
                  A_timers_stop(); 
                }
    
                else if(B_state == true)
                {
                  printf("Stop button\n");
                  click_count = 0; 
                  stop_state = true;
                  B_timers_stop();
                }
    
                else
                {
                  if(click_count == 0) //first click
                  {
                    buttonTimeout = false;
                    ClickCount_timers_start();  //after 0.4sec, buttonTimeout = true, click_count = 0;
                  }
    
                PowerOff_timers_start(); //press time count
                }
              }
    
              if(!stop_state)
              {
                click_count++;
              }
    
              stop_state = false;
    
              //printf("Click : %d\n", click_count);
    
              break;
    
               case APP_BUTTON_RELEASE:
               {  
                  //printf("Button releaed\n");
                  push_state = false;
    
                  if(poweroff_timer_state)
                  {
                    PowerOff_timers_stop();
                  }
                  
                  if(click_count == 2 && !buttonTimeout) //double click
                  {
                    ClickCount_timers_stop(); //double click error, timer off
                    click_count = 0;
                    //printf("check point3\n");
                    B_timers_start(); 
                    printf("Double Click\n");
                  }
               } break;
    
            } 
          break;
    
          default:
             APP_ERROR_HANDLER(pin_no);
          break;
         
        }
    
        if(app_button_duration())
        {
          app_button_event_generator();
        }
    
        app_button_init_time_variable();
    }
    

    This is printed on the terminal when double-click. It seems to stop at poweroff_timers_stop() or BUTTON_RELEASE when double-click.

    PowerOff timer start //poweroff timer start, push
    PowerOff timer stop // poweroff timer stop , release
    PowerOff timer start //second click (push)
    P

    Thank you.

  • Hi,

    I have not spotted anything that should explain what you are seeing when looking at your code. Did you resolve this issue? If not, perhaps you could upload a project e that runs on a DK so that I can test on my side?

  • Hello

    I still have a problem with double-click the button.
    I attach my project file. I couldn't show you the whole code, so I wrote only the code for the ble_uart and button.
    Thank you for helping me.8715.TEST.zip

  • Hi,

    There are some issues with the project. It uses A_LED and B_LED, but those are not defined. Removing that the project builds, but fails runtime in app_button_init(). Can you upload a working project (in the sense that it runs out of the box and reproduces the issue described in this thread out of the box)?

Related