We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hi,
I'm developping on ARM7 chip with ARTX OS and I would like to implement periodic task. My software is based onto the example you can find at the following link : http://www.keil.com/support/docs/3008.htm
During my tests, I've detected some troubles with os_evt_set() an os_evt_wait_or() functions.
If a high task priority post two event before the low task take event with os_evt_wait_or(), sometimes this task is waking-up twice as the event have been store !
I don't understand. Could you help me ?
Thanks for all
The os_evt_set() and os_evt_wait() do work properly.
IF a high priority task calls os_evt_set() twice without doing an os_block at any point, the lower priority task will only wakeup once.
note:
1) os_itv_wait() causes an os_block 2) priorities go from 0 (low priority) to 255 (high priority). This is different than some kernels, but I think it makes more sense. 3) as soon as the low priority task "takes" the event (returns from the os_evt_wait_or()) the evt is cleared and another one can be received BEFORE you call os_evt_wait_or() again. This means as soon as you call os_evt_wait_or() you may wakeup again.
The os_evt_wait() does work as advertised and as it should (this does not mean it works in the way you are trying to make it work)
If you want to post code or describe what you would really like to happen, I would be happy to comment again.
you can find bellow my source
/*---------------------------------------------------------------------------- * *---------------------------------------------------------------------------- * Name: Event.c * *---------------------------------------------------------------------------- * *---------------------------------------------------------------------------*/ #include <RTL.h> /* RTX kernel functions & defines */ #include <LPC21xx.H> /* LPC21xx definitions */ #include <stdio.h> extern void init_serial (void); /* Initialize Serial Interface */ OS_TID tsk1, tsk2; #define INDEFINTE_TIMEOUT 0xffff /*indefinite timeout*/ #define NO_TIMEOUT 0x0000 /*Timeout=0*/ /*---------------------------------------------------------------------------- * Task 1 - High Priority - *---------------------------------------------------------------------------*/ void task1 (void) __task { while (1) { /* Pass control to other tasks for 70 tick*/ tsk_lock(); os_evt_set (0x0001,tsk2) ; /* set the event 0x0001 two times */ os_evt_set (0x0001,tsk2) ; tsk_unlock(); os_dly_wait(70); } } /*---------------------------------------------------------------------------- * Task 2 - Low Priority - *---------------------------------------------------------------------------*/ void task2 (void) __task { while (1) { static OS_RESULT ret ; ret = os_evt_wait_or (0x0001, INDEFINTE_TIMEOUT) ; /* wait for event without timeout */ ret = os_evt_wait_or (0x0001, NO_TIMEOUT) ; /* wait for event with timeout 0 */ if(ret==OS_R_EVT) /* The flag 0x0001 is still set !!!!!!!!! */ { /* if an event is set two times or more os_evt_wait will completed 2 times */ printf("it is not normal\n\r"); /* It is not a good operation */ } /* Normally ret = OS_R_TMO in the second os_evt_wait_or */ } } /*---------------------------------------------------------------------------- * Task 'init' *---------------------------------------------------------------------------*/ void init (void) __task { /* Initialize the UART */ init_serial (); /* Create an instance of task1 with priority 10 */ tsk1 = os_tsk_create (task1, 10); /* Create an instance of task2 with priority 10 */ tsk2 = os_tsk_create (task2, 5); /* Delete the init task */ os_tsk_delete_self (); } /*---------------------------------------------------------------------------- * Main: Initialize and start RTX Kernel *---------------------------------------------------------------------------*/ int main (void) { #ifdef MCB2100 U32 volatile start; /* Wait for debugger connection (about 0.3 sec) */ for (start = 0; start < 1000000; start++) { ; } #endif /* Initialize RTX and start init */ os_sys_init (init); } /*---------------------------------------------------------------------------- * end of file *---------------------------------------------------------------------------*/
thnks for all!
hi,
I make a mistake in the task1 in the following source. In fact the code I'm using to generate the error is :
void task1 (void) __task { while (1) { os_dly_wait(70); /* Pass control to other tasks for 70 tick*/ tsk_lock(); os_evt_set (0x0001,tsk2) ; /* set the event 0x0001 two times */ os_evt_set (0x0001,tsk2) ; tsk_unlock(); } }
thanks!
If you read the above code - do you see anything strange wit the formatting? Doesn't the indenting look a bit aggresive? Did you convert from tab characters to spaces?
You shouldn't expect to get two wakeups for doing two calls to os_evt_set().
Have you read the manual for the function? http://www.keil.com/support/man/docs/rlarm/rlarm_os_evt_set.htm
"The os_evt_set function sets the event flags for the task identified by the function argument. The function only sets the event flags whose corresponding bit is set to 1 in the event_flags argument."
The documentation says nothing about a counter to keep track of number of calls to os_evt_set(). If the second task hasn't run when you call os_evt_set() the second time, there will be no state change.
If you are trying to write a producer-consumer, where one task adds two resources for task 2 to use, then it is up to you to create the queue or counter that contains the amount of work that task 2 has pending..
The code you have posted SHOULD return OS_R_TMO on the second call to os_wait_evt_or(); If it is not there is something wrong. If this is what you are seeing (and I believe you are) then the event system is working properly.
Actually there may be another issue. It is not a good idea to call os_set_evt() while you have interrupts disabled. os_set_evt() MAY dispatch a task other than the currently running task, this has a side effect of causing interrupts to be reenabled at that point in time. (It should only do it if the task you are sending it to is waiting for it and a higher priority) I am not sure, but isr_set_evt() might work better.
tsk_lock and tsk_unlock are not the problem. If I remove them the same problem occured, the code return OS_R_EVT on the second call to os_evt_wait_or...
thanks
OK. I can replicate and explain what it is doing. It is debatable if it is actaully a bug (I would not submit it as a bug, but that is because it is not causing me any problems)
Task2 is WAITING for an event.
Task1 sets the event for Task2.
In the context of Task1, Task2 is set READY to run. The event that caused the wakeup is set. (for os_get_evt) The event(s) that caused the wakeup is cleared.
Task1 continues to run and sets the event again.
Task2 actaully returns from the first wait and runs.
Task2 does a 0 time wait on the event, and finds that it is set and returns it.
Knowing this, you may want to change your logic accordingly. (maybe you should use a mailbox instead of an event)
I've arrived at the same point, but instead using mailbox to fix the problem I would like to use something easier such a flag. I think that it is a bug. The event would be clear by the waiting task when it's running. In my example, the waiting task were never running (low priority task). The scheduler reset the event flag not propaly before waiting task running
Do you have some idea ?
Thanks for all !
You will need to put together code that gives you the behavior that you desire. A "simple" solution that does not do what you want is not a good choice. I do not believe the Keil will be changing the way events work any time soon (if at all) so you will need to either add a flag to your code or use some other technique. It is not clear exactly what you are trying to do so what I did was explain what the event system was doing. If it does not do what you want, then use something that does do what you want.