This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

I am looking for a timer example which can be used to time the scanned packets interval in millisecond resolution

Dear All

Could you point me a timer example, can be used to time the interval in ms between something? like read the system time when something happens and then read again when it happens again?

Thank you!

Ping

Parents
  • Hi Ping

    You should be able to use the k_uptime_get() or k_uptime_get_32() functions for this. They will return the number of milliseconds that have passed since the system booted, either as a 64-bit or 32-bit value, and if you call this twice and compare the two values you can see how much time has passed. 

    Best regards
    Torbjørn 

  • Thanks, Torbjorn

    That works fine.

    I also need to create a timer to do a periodic task like blink a LED, I don't want to use k_sleep() , what is the best way to do it please?

    I am sorry keep asking you the small questions like this, but I am new to Zephyr.

    Thanks

    Ping

  • Hi, Torbjorn

    Thanks for your help, I tried the timer again and I think I have found a bug in my UART thread. It seems working fine now. 

    I also tried the below thread for blink LED like the Thread sample:

    void blink0(void)
    {
    	while(1) {
    		k_sleep(K_SECONDS(1));
    		gpio_pin_set(dev, PIN, (int)led_is_on);
    		led_is_on = !led_is_on;	
    	}
    }
    K_THREAD_DEFINE(blink0_id, STACKSIZE, blink0, NULL, NULL, NULL,
    		PRIORITY, 0, 0);

    Wonder what is the difference between two implements - the timer one and above thread one, my UART thread is similar to above blink0 , in terms of priority, are they same?

    Regards!

    Ping

  • Hi Ping

    Any callbacks that you schedule through the k_work_submit(..) call will be handled by the system workqueue, which is handled by a dedicated system workqueue thread. 

    The practical difference of running your own dedicated thread is not very large, but every thread you create requires quite a bit of memory, so there is some memory overhead of using more threads. 

    Usually it makes sense to use a dedicated thread if you are planning to do a lot of time consuming tasks, or if you need to be able to prioritize different parts of your application. 

    All the items in the system workqueue will by default run at the lowest priority, and if you schedule multiple callbacks then they will be handled in a first in first out manner. For this reason it is not a good idea to use sleep functions or other slow, blocking function calls in a work item, since it will delay the processing of all the other work items. 

    If you make your own thread then any blocking call or delay will only block that thread, and not affect other parts of the system. 

    When you make your own thread you can also decide the priority of each thread. 

    All items on the system workqueue will have the same priority, but if you want you can change this priority by changing the SYSTEM_CONFIG_PRIORITY configuration.

    Best regards
    Torbjørn

  • Hi, Torbjørn

    Thank you for your reply!

    Sounds like my blink0 thread above uses more memory, and it also uses sleep function which might delay the other processing, so it is better to use system workqueue by k_work_submit(), if I understand correctly.

    I have also need to run some simple start_scan/stop_scan function according to some RAM flags like below - I used to put it in while(1) loop in bare metal system and always get checked, but now I am not sure where to put them, 

    	if(dataMode == 1 && scanRunning == false) {
    		scanRunning = true;
    		start_scan();	
    	}
    	if(dataMode == 0 && scanRunning == true) {
    		scanRunning = false;
    		stop_scan();	
    	}

    It works fine when I put them into the LED toggle handler - my_work_handler(), but it means only be executed every second, I wonder what is the best way to do it like in bare metal while(1) loop situation. Do I need to create another workqueue? if so, how?

    Sorry to keep bothering you with basic questions, I am new to Zephyr.

    Thank you!

    Ping

  • Hi Ping

    PingISTL said:
    Sounds like my blink0 thread above uses more memory, and it also uses sleep function which might delay the other processing, so it is better to use system workqueue by k_work_submit(), if I understand correctly.

    Your thread will use more memory, yes, since you need to provide a dedicated stack for each thread. You can decide how large the stack should be though, depending on how much stack is needed by the functions running from the thread. 

    Calling k_sleep() or k_msleep() from a thread is completely fine, and will not delay other processing. When you call sleep from a thread the thread will be disabled completely by the scheduler, so that other threads can run. If all the threads are disabled the system will automatically go into power down in order to reduce the current consumption. 

    One the sleep function expires the thread will be activated again. 

    Still, if you are just doing something quick and simple I agree that using a work queue is a good approach. 

    PingISTL said:
    It works fine when I put them into the LED toggle handler - my_work_handler(), but it means only be executed every second, I wonder what is the best way to do it like in bare metal while(1) loop situation. Do I need to create another workqueue? if so, how?

    Where in the code do you write to the dataMode variable?

    It seems like you should trigger this code from that place, rather than run it from a timer. 

    In either case you can simply create another work item using the K_WORK_DEFINE macro, and point it to another callback function where you do the scan start or stop. 

    All the work items you register in this way will use the system workqueue, which means there is very little memory overhead when you register new items. 

    The only drawback is that only one work item can be executed at the same time, so if you perform very time consuming tasks inside the callback function it might delay the other tasks that you want to perform. 

    As long as the start_scan() and stop_scan() functions execute quickly this should not be a problem. 

    If you still want to run the code on a timer, but at a different interval than 1 second, you can create a new timer as well, and configure it with a different interval. 

    PingISTL said:
    Sorry to keep bothering you with basic questions, I am new to Zephyr.

    No need to be sorry, we're here to help with all kinds of questions Slight smile

    Best regards
    Torbjørn

  • Hello, Torbjørn

    Thank for your patient explanation.

    Where in the code do you write to the dataMode variable?

    It seems like you should trigger this code from that place, rather than run it from a timer. 

    dataMode  variable is written in another file module called serial.c, where I created a UART process thread when something is received. You are right that the scan/stop function should be called here whenever dataMode is changed, I just tried and works now,  didn't work before for some reason, thank you for pointing out.

    In either case you can simply create another work item using the K_WORK_DEFINE macro, and point it to another callback function where you do the scan start or stop. 

    I also tried to  use work queue like this:

    void my_scan_handler(struct k_work *work)
    {
    	/* check the scan condition too */
    	if(dataMode == 1 && scanRunning == false) {
    		scanRunning = true;
    		start_scan();	
    	}
    	if(dataMode == 0 && scanRunning == true) {
    		scanRunning = false;
    		stop_scan();	
    	}
    }
    K_WORK_DEFINE(my_scan, my_scan_handler);

    but it doesn't work, have I missed something?

    Best Regards!

    Ping

Reply
  • Hello, Torbjørn

    Thank for your patient explanation.

    Where in the code do you write to the dataMode variable?

    It seems like you should trigger this code from that place, rather than run it from a timer. 

    dataMode  variable is written in another file module called serial.c, where I created a UART process thread when something is received. You are right that the scan/stop function should be called here whenever dataMode is changed, I just tried and works now,  didn't work before for some reason, thank you for pointing out.

    In either case you can simply create another work item using the K_WORK_DEFINE macro, and point it to another callback function where you do the scan start or stop. 

    I also tried to  use work queue like this:

    void my_scan_handler(struct k_work *work)
    {
    	/* check the scan condition too */
    	if(dataMode == 1 && scanRunning == false) {
    		scanRunning = true;
    		start_scan();	
    	}
    	if(dataMode == 0 && scanRunning == true) {
    		scanRunning = false;
    		stop_scan();	
    	}
    }
    K_WORK_DEFINE(my_scan, my_scan_handler);

    but it doesn't work, have I missed something?

    Best Regards!

    Ping

Children
  • Hi Ping

    Good to hear it worked fine to start/stop scan directly from the UART process thread Slight smile

    In order for the work item to be run you need to use the k_work_submit(..) function. If you call k_work_submit(&my_scan) after you change the dataMode variable then the work item should run soon after the variable is changed. 

    If you are changing the dataMode variable in a thread it is not strictly necessary to use a work item, then you can just call the function directly. Work items are necessary if you want to call these functions from an ISR context (such as a callback function triggered by an interrupt). 

    Best regards
    Torbjørn

Related