Hello,
I learned from http://www.keil.com/support/docs/3008.htm: a) It is not possible to mix the wait method os_itv_wait() and os_dly_wait(). b) It is possible to mix os_evt_wait_or(0x0001, 0xffff) (without timeout!) and os_dly_wait(). But is it possible in RTX to use os_evt_wait_or(0x0001, 100) (with timeout!) and os_dly_wait() in the same task? e.g.:
void task1 (void) _task_ 1 { while (1) { os_evt_wait_or (0x0001, 100); // wait for event flag set or timeout (100 ticks) ... // some code os_dly_wait (10); // wait here for 10 ticks ... } } void task2 (void) _task_ 2 { ... if (...) { os_evt_set (0x0001, id1); // send event to task 1 } }
Or is it impossible because of the same timer is used for both delays in task 1?
Thanks in advance for your answers, Norbert
Thank you. It looks a little bit strange. There are own timers for os_dly_wait and for the timeout of os_evt_wait_*. But os_itv_wait and os_dly_wait uses the same timer. That is a trap. - We have to pay attention.
Anything unknown can be a trap.
All 3 of these use a single hardware timer (usually SysTick) and single timer queue (the os_dly queue) in the OS. os_dly_wait(timeout) adds the task to the os_dly queue for timeout ticks.
os_evt_wait(timeout) adds the task to the os_dly queue for timeout ticks, but also can wake up if the event is satisfied before then. If the delay timer goes first, the function returns a timeout status, if the event is satisfied first, the delay is removed from the queue and the event status is returned.
os_itv_wait uses the same timer, AND the same timer queue in the OS.
Your issue is that the ITV wait reuses values in the TCB that are also used by os_dly_wait() ( which are properly "reused"in os_evt_wait). This does not actually cause a crash, it just causes the next interval to likely be different than you expect.
This is "documented" here,
http://www.keil.com/support/docs/3464.htm
or you can just look at the source code.
You will probably find it better to just not use the os_rtv_wait.
You simply need to make a better os_itv_wait function that has it's own counters. There are many places where a brief delay it a task is useful or required but the loop rate should remain constant.
Why this is such a difficult task for tho OS writer to do is beyond me. The RAM cost for this support would be 16 bits if it was in Keil's code.
An on idle type function is also easy to add that runs low priority stuff for the task with a little more code ... that is left to the user.
Chad
#include "rtl.h" /* for os_dly_wait FN. */ #if 0 /*allows to compile stand alone or as part of RTX */ /* library. */ #include "RTX_Config.h" /*OS includes, insert others as needed. */ #include "rt_task.h" /* path to these must be added if being used. */ #else /*if not compiling with the OS library, declare */ /* the types here. */ //typedef unsigned long U32; typedef unsigned char U8; typedef unsigned short U16; typedef U32 OS_RESULT; #endif #ifdef LIBS_OS_ARM7 /* USE ARM7 rtos commands. */ OS_RESULT os_block( U16 timeout, U8 block_state ); #define mOS_BLOCK( x ) os_block ( x, WAIT_DLY ) #define mTASK_LOCK( ) tsk_lock ( ) #define mTASK_UNLOCK( ) tsk_unlock ( ) extern void tsk_lock (void) __swi (5); extern void tsk_unlock( void ); #elif defined ( LIBS_OS_CM ) /* use CM3 libs. */ #define mOS_BLOCK( x ) os_dly_wait ( x ) /*< calls assembly routine. > */ #define mTASK_LOCK( ) /*< not used. > */ #define mTASK_UNLOCK( ) /*< not used. > */ #else #error : NO_LIB_DEFINED . Define LIBS_OS_ARM7 or LIBS_OS_CM #endif typedef struct OS_ITV_DLY_STRUCT { U16 delay_clock; /* < MDK 4.60 / 4.7 changed os_timer to 32 bit */ /* from 16. 16 bit is still used in RTX */ /* source for items so continue to do so. > */ U16 interval; } OS_ITV_DLY_COUNTS; void os_itv_dly_set( U16 Interval, OS_ITV_DLY_COUNTS *Delay ) /*< set the delay counts per interval > */ { Delay->delay_clock = ( ( OS_TIMEType )os_time ); /* get current clock */ Delay->interval = Interval; /* save the desired run interval */ } void os_itv_delay_wait( OS_ITV_DLY_COUNTS *Delay ) /*< pauses task to allow the desired interval to */ /* elapse before allowing task to continue. > */ { U16 NewDelay; mTASK_LOCK( ); /* lock the task if necessary. */ Delay->delay_clock += Delay->interval; /* add the interval to the present target */ /* execution time to get the next desired */ /* execution time. */ NewDelay = Delay->delay_clock - ( ( OS_TIMEType )os_time ); /* subtract desired execution time from the */ /* present time. This = wait time. */ if( NewDelay <= Delay->interval ) /* only delay if desired delay is < = interval. */ /* If >, there was an underflow. */ { mOS_BLOCK( NewDelay ); /* for ARM7 */ } mTASK_UNLOCK( ); /* unlock. */ }