Timer accuracy for micro seconds

Hi,

i defined timer 
K_TIMER_DEFINE(my_timer, my_timer_handler, NULL);

then i am starting  the timer with configuration :

k_timer_start(&my_timer, K_USEC(500), K_USEC(500));
The issue that the 
the handler prints log every 581.5 us instead of 500.
What can be the reason?or how to trigger some handler every 500 us
Thanks
  • MaximSh said:
    So how to run polling of some code every 500 microseconds without using timer?

    Not sure if I understand this right, you want to have a time waiting code that waits for 500uS without using any timer? I am guessing that you want to use Kernel API for that instead of directly using timer API.

    In that case you can only sleep with a resolution of the timer tick(SYS_CLOCK_TICKS_PER_SEC default value is 32768 on RTC) . If you want  any better resolution, then you need to use high resolution timer API like nrfx_timer or nrfx_systick. The disadvantage of using high resolution timers is that they keep the high frequency clock on all the time and hence increasing the average power consumption of your application. If your application is running on a battery, it will be drained within days (if not hours)

  • Still have issues if i use counter with timer0

    i set alarm to 500 micro but after 2000 triggers that should print 1000(0.5*2000= 1000 mili)  it prints

    00> I: READ:1748
    00> I: READ:1904
    00> I: READ:1873
    00> I: READ:1751
    00> I: READ:1979
    00> I: READ:1871
    00> I: READ:1784
    00> I: READ:1871

    CONFIG_COUNTER=y
    CONFIG_COUNTER_TIMER0=y

    Here is my code:

    #define THREAD_PRIORITY K_PRIO_PREEMPT(K_HIGHEST_APPLICATION_THREAD_PRIO)
    #define TIMER DT_NODELABEL(timer0)
    #define DELAY 500

    Here is a k_thread_entry_t set_alarm 

    static void set_alarm(void)
    {
        const struct device *const counter_dev = DEVICE_DT_GET(TIMER);
        int err;
    
        printk("Counter alarm sample\n\n");
    
        if (!device_is_ready(counter_dev))
        {
            printk("device not ready.\n");
            return;
        }
    
        counter_start(counter_dev);
    
        alarm_cfg.flags = 0;
        alarm_cfg.ticks = counter_us_to_ticks(counter_dev, DELAY);
        alarm_cfg.callback = test_counter_interrupt_fn;
        alarm_cfg.user_data = &alarm_cfg;
    
        err = counter_set_channel_alarm(counter_dev, ALARM_CHANNEL_ID,
                                        &alarm_cfg);
        printk("Set alarm in %u sec (%u ticks)\n",
               (uint32_t)(counter_ticks_to_us(counter_dev,
                                              alarm_cfg.ticks) /
                          USEC_PER_SEC),
               alarm_cfg.ticks);
    
        if (-EINVAL == err)
        {
            printk("Alarm settings invalid\n");
        }
        else if (-ENOTSUP == err)
        {
            printk("Alarm setting request not supported\n");
        }
        else if (err != 0)
        {
            printk("Error\n");
        }
        while (1)
        {
            static uint16_t c = 0;
            k_sem_take(&timer_semaphore, K_FOREVER);
            static int64_t time = 0;
            if (c == 2000)
            {
                LOG_INF("READ:%lld", k_uptime_delta(&time));
                c = 0;
            }
            if ((c++ % 2) == 0)
            {
    
                struct acc_event *event = new_acc_event();
                EVENT_SUBMIT(event);
            }
        }
    }

    callback that give semaphore to thread loop

    static void test_counter_interrupt_fn(const struct device *counter_dev,
                                          uint8_t chan_id, uint32_t ticks,
                                          void *user_data)
    {
        struct counter_alarm_cfg *config = user_data;
        uint32_t now_ticks;
        uint64_t now_usec;
        int now_sec;
        int err;
    
        k_sem_give(&timer_semaphore);
    
      
    
        err = counter_set_channel_alarm(counter_dev, ALARM_CHANNEL_ID,
                                        user_data);
        if (err != 0)
        {
            printk("Alarm could not be set\n");
        }
    }

    What is wrong?

    Thanks

  • Sorry for late reply maxim. I will try your code snippet right away and see if I can reproduce the same inaccuracies that you see.

  • I am getting confusing results with your code snippet.

    I am not sure what context the semaphore is taken but in my case I am doing this in the main context. 

    This below line is in the main context and is having a lot of latencies before it can execute. Like taking the semaphore. This is not a correct place to read delta. The correct place to read delta would be to get a counter capture from the TIMER to avoid all the overhead of interrupt latencies and latencies from semaphore handling between contexts.

    But in your case, you can try to read the delta  at the beginning of test_counter_interrupt_fn to get better accurate time difference than the one you are getting now. The one you are getting now adds other latencies(interrupt handlng/scheduler switch/semaphore handling etc) into the delta that you are printing.

    printk("READ:%lld\n", k_uptime_delta(&time));

  • 1. I can't read from timer interrupt, i also have a SPI read.
    2. Try to use event manager and submit an event every 500 us and read the event at other modules(for example 2) and proccess some logic(try sleep for random ms)

Related