Pumpkin, Inc.

Pumpkin User Forums

New time oriented function

Have an idea on how to make Salvo better? Post it here!

New time oriented function

Postby luben » Thu Sep 20, 2001 4:41 am

Hello,

First, I hope all you're alive and OK after the tragedy in WTC, I'm really sorry about all this, for me was a big shock.

Working some time with SALVO I found that there is missing one function, that could be easy implemented and could be very useful for many users.
It's similar to OS_Delay(), but could be used for doing some actions on fixed interval of time, let's call it OS_Sync().

Imagine that we have a project and one of the task should do something every 50ms. It's OK to put OS_Delay(time_50ms,Label) and we'll have precision +/- one tick of the OSTimer(). That error could be very high if the interval is shorter. But if after waking up the task have to wait for some event like OS_WaitXYZ() then using the OS_Delay(time_50ms,L) will produce bigger error. I mean, if after OS_Delay the user have to use some time related features of SALVO, the error will grow more.

Now imagine that you have the function OS_Sync(time_period, Label). Description of the function - it makes delay like OS_Delay(). You can get the difference only in some cases (let's say you need 20Hz pace rate) - if you call OS_Delay() and after that you make other delay, to keep the pace rate you have to recalculate the OS_Delay value if you want next time to wake up the task exactly after 50ms . In that case OS_Sync will return the control without carrying if there was other delay before or not. Well, if you call the function after this 50ms it will return immediately the control and will reload the value of delay automatically. OS_Sync() will look like hardware autorunning timer, that makes interrupts on regular rate. OS_Delay looks like single pulse timer, OS_Sync() - like multivibrator. If having such function it is very easy to make high precision delays, and to make other delays within them in one and the same task.

For sure OS_Sync() will consume an additional RAM memory - for each different task that uses OS_Sync() 1,2 or 4 bytes counter.

In short - OS_Sync() is similar to OS_Delay, with that difference that it wakes the task not after fixed time from starting the function, but after fixed time after last triggering of the function (looks like multivibrator).

With current functions of SALVO is possible to implement such structure too. What I can imagine right now is to make separate task that controls Sync timers and signals binary flags. I don't insist that such function is extremely useful, but just sharing my ideas. For sure it's useful in some applications, where fixed pace rate is needed (even for RS232 communication, where fits excellent)

[edited by Salvo Tech Support]

Best regards
Luben

[This message has been edited by Salvo Tech Support (edited September 20, 2001).]

luben
 
Posts: 324
Joined: Sun Nov 19, 2000 12:00 am
Location: Sofia, Bulgaria

Re: New time oriented function

Postby aek » Fri Sep 21, 2001 12:14 am

I think the support for this feature will be in two Salvo services:

1) OSSyncInterval(), which would normally be called when the task is initialized, and

2) OS_Interval(interval, label).

Something like this:

code:
void TaskPeriodic( void )
{
OSSyncInterval();


while ( TRUE ) {
OS_Interval(20, label); // do every 200ms
...
}
}


As you already know, a means of synchronizing the interval's "trigger" against the current value of the system ticks is required, and that's what OSSyncInterval() does.

------------------

[This message has been edited by aek (edited September 21, 2001).]

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: New time oriented function

Postby aek » Fri Sep 21, 2001 6:37 am

We are OK after the WTC attack, though things here in California have not returned to "business as usual." Perhaps they never will ...

Re: OS_Sync():

Such a feature might have been quite useful when I wrote AN-8 ... :-)

Note that in v2.2.0, you can do something like this by monitoring the system timer (e.g. via OSGetTicks()) and then setting your argument to OS_Delay() accordingly. Remember, the delay in OS_Delay(delay, label) need not be a constant -- it can be a variable, of course.

Anyway, I think there's a very easy way to do your OS_Sync() without requiring any additional RAM, and just a few instructions in ROM. The scheme I'm thinking of has no impact on the scheduler. The only limitation is that the interval will have the same resolution as the delay in OS_Delay(), i.e. you can't set a repetitive interval of, say, 1000 ticks if you're using 8-bit delays.

I plan to call this new service OS_Interval(). I'll try to get it into the v2.3.0 release.

------------------

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: New time oriented function

Postby luben » Fri Sep 21, 2001 8:14 am

Hello,

Even it's possible to increase the resolution of this function. First - if you use prescaller in the timer you can watch the value of this prescaller too in the function. Or other approach - to have different OSTimer() functions, let's say - OSTimer1(), OSTimer2().... or OSTimer(OSNumber_OfTimer). But the second case will need a lot of memory (RAM and ROM).

For sure this function will consume more RAM - every task have to record some "watch value" that is compared with the system timer, or will calculate the estimated time if use function like OS_Delay(). It's possible that when function is called, the time for waking up the task already appeared (for 2 and more Timer ticks for tasks with very low priority and even is possible that the function already delayed for 2 and more Interval periods). So it's possible that OS_Interval() have to return the control of the task immediately many times, just because even already appeared 2 and more times in advance (something like semaphore set to value bigger then 1).
By the way, how you suppose to work your function if the task delayed for 2 and more pace times (one pace time is the interval of waking up the task). Will it wake up now faster - 2 and more times one after other. If YES, then "bombarding problem" could appear - low priority task will consume the time of other tasks - the system could hang for time bigger then Watch Dog period.
I meant - many problems could pop up, depend on how you build the function.

For sure the "ideal" OS_Interval() function should be asynchronous and should have separate timer (that's impossible for current SALVO and for PIC architecture). It have to be able to be started asynchrnously to other tasks (that's usefull for RS232 serial receive) and to keep this displacement to main OSTimer() all the time. Well, some approach to this "ideal" function is to watch the prescaller of OSTimer or to reset the system timer (done with OSSyncInterval). The last thing is not good to be done very often and only one task could use such synchronyzed Timer(). If other task tries to do the same - the first task will lose synchronization.

What I think is hard to implement and will consume RAM and ROM is the synchronization(displacement to the OSTimer) of the OS_Interval() and second - if task already delayed for 2 and more pace times, how to release, free the accumulated events (should be like semaphores - to count the events). Or maybe you should make possible the OSInterval to behave in different ways, when settting some flags in salvocfg.h . The question is - if delayed for 2 and more pace times - how to act. And what about asynchronous processes like RS232 receive - they need different start points, displacement? If you change reset the current hardware timer - other tasks will lose synchronization.

Best regards
Luben

[This message has been edited by luben (edited September 21, 2001).]

luben
 
Posts: 324
Joined: Sun Nov 19, 2000 12:00 am
Location: Sofia, Bulgaria

Re: New time oriented function

Postby luben » Fri Sep 21, 2001 8:18 am

Hello,

Yes, you can do this with OS_Delay even with current version, setting variable as argument in time, but this needs additional calculations. For sure if I have to do such periodical task I'll do it with OS_Delay(). But if this is not very complicated function and will not make SALVO heavier - will be better to use build in function.

I like the name you proposed for the function, it's explains better what it makes.

Best regards
Luben

luben
 
Posts: 324
Joined: Sun Nov 19, 2000 12:00 am
Location: Sofia, Bulgaria

Re: New time oriented function

Postby aek » Sat Sep 22, 2001 10:47 am

Hmmm ... I'm not sure I fully understand where you're taking this. I have to think about this some more ... but for now (at least), Salvo will have only one system timer, and so you'd need to set the system tick rate to the finest resolution you need.

One additional feature I thought of would be to specify an offset when calling OSSyncInterval(), i.e.

code:
OSSyncInterval(offset)

Offset is a signed quantity, i.e. for OSBYTES_OF_DELAYS set to 1, offset ranges from -128 to +127. This means that you could actually synchronize tasks against "phases" of the system clock. For example, by reading the current value of the timer via OSGetTicks(), you could take that value modulo 4 (just as an example) and then have four different tasks synchronize themselves via

code:
OSSyncInterval(-3)
OSInterval(4)

through

code:
OSSyncInterval(0)
OSInterval(4)

As long as the calls to OSSyncInterval() all occured while the system timer didn't change, you would now have TaskA occur every n, n+4, n+8, n+(4*m) ticks, TaskB occurs every n+1, n+5, n+9, n+1+(4*m) ticks, etc. This could be quite useful for things like waveform generation, etc.

------------------

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: New time oriented function

Postby luben » Sun Sep 23, 2001 2:17 am

Hello,
What I think is important - not to skip events and to accumulate them. I mean, if the task is low priority in some cases it could not take the control for 2-3 pace ticks. So after it become running it should realize this 2-3 events. I mean - it have to be like counting SEMAPHORE. So if you make average sum of the calls per time you'll have always fixed value.
But for sure such function could be useful for generating fixed frequencies, RS232 receive, etc. The only one big problem is not the resolution, but the synchronization. It's not good idea if synchronizing one task other ones to lose it.

Maybe this idea needs more time to ripe.


Regards
Luben

luben
 
Posts: 324
Joined: Sun Nov 19, 2000 12:00 am
Location: Sofia, Bulgaria

Re: New time oriented function

Postby luben » Mon Sep 24, 2001 1:45 am

Hello,

I think that talking about the new function OS_Interval() we have to agree that it’s look like events (and more exactly Semaphores) and it’s called from OSTimer. In fact it’s some kind of semaphore, that’s increasing after defined time (and the only one function in SALVO that initalize all other time functions is OSTimer()). So, if we need 3 different OS_Intervals in 3 different tasks we should declare them like 3 different new type events. Let’s call them TimeSem type (I propose for the new function name that includes “semaphore” and something related with the time, period, interval)

code:

OSCreateTimeSem(OSECBP(1), initial_value1);
OSCreateTimeSem(OSECBP(2), initial_value2);
OSCreateTimeSem(OSECBP(3), initial_value3);


What I can say right now is – Intervals are some kind of semaphores (or in worst case BinSemaphores) that increase their value when called OSTimer() and the desired period expires. I think that we can wait for them with the current functions in SALVO like OS_WaitSem(), OSGetSem(), OSTrySem(). In fact they have the same structure like ordinary semaphores, no difference, except that their signaling happens in OSTimer().

It’s not the best solution for them to have functionality like BinSemaphores. I’ll explain why – If one task has low priority it’s possible that it will not get the control from time to time for longer interval, that even can be bigger then 2 pace ticks (of the TimeSemaphore). So, if you get the control you’ll not have a track – is this the first and only one signalling, or there were other signallin too. In second case the user could do some other action – or to skip this delayed event or to try do some action.

Even we can declare them like ordinary semaphores, but them we have to make another declaration that exactly these semaphores will be called in OSTimer(). I think that it’s better to be declared like different type (TimeSemaphores) and then to be read and wait for them with the standard semaphore functions. Using different functions like OS_WaitTimeSem() maybe will make heavier SALVO and will consume more RAM and RAM.

The difference between ordinary semaphores and TimeSemaphores is that with their declaration we declare some additional amount of RAM, where we’ll keep in the future the interval for signaling and the counter of the current calls. That means – using 8 bit delays will consume additional 2 bytes for every TimeSemaphore, using 16 bit delays – 4 bytes and so on.

The structure of such time semaphore needs 2 additional variables – first variable keeps the total interval and second – the current value within the interval. Second variable is one counter of subtraction – after it becomes zero it’s loaded with the value of total interval (for each TimeSemaphore there are 2 different pairs of variables) and in the same moment signals the semaphore. Task that wait for such time semaphore will get this event after some time if it’s in WaitState, or if it’s enter in such function (already signaled) will return the control immediately. Well, attention to avoid “bombarding case” should be made – you know how.

It’s possible to exchange the first variable with “hard” value in the ROM – in the initial declaration of the events we’ll place some value that could not be change during the program execution – this will save some RAM. In that case we don’t need additional function in SALVO to set the interval, except the synchronization function.

Into OSTimer() should be add some part of software, that decrements the TimeSemaphore counters and if they become zero to load them with the interval values (from RAM or ROM ) and to signal one more time the time semaphore. Because you signal semaphore, even if the task doesn’t get the event immediately it will know if some extremely big delay occurred.

To make possible to switch on or off this part of the program I propose some settings like (Time semaphores number is a part of EVENT number):

code:

#define TIME_SEMAPHORES 3
// will add this functionality to SALVO – 3 time semaphores
// default value is 0 – no time semaphores

Of course we need function to reset the counters –

code:

OS_Sync(OSECBP(1));


it will immediately reset the counters – that’s equal to phase synchronization.

And we need function to set the interval for this events like:

code:

OSInterval(OSECBP(1), value_of_interval);


it will set the virst variable, which keeps the amount of interval, if we want to change it after we created them.

Maybe we need some additional function OS_ClearTime() that will reset the value of counter of signalled events (it’s like to reset the value of semaphore). It could be made with loop of OS_TrySem() until it returns zero value, but will consume more time.

code:

OS_ClearTime(OSECBP(1));
// sets the value of this time semaphore to zero
// it’s good to do this before you start the tasks, that waits the timesemaphore


After we set the interval and synchronize the timers we could wait for this event with the good known OS_WaitSem(). Well, because the ECB of the time semaphore is little bit different, maybe time semaphores have to own 2 ECB – one ordinary SEMAPHORE ECB and one additional TIMESEMAPHORE ECB. In fact when we wait for this function we’ll need only the standard semaphore ECB, and only within the OSTimer() we have to use 2 additional variables – for amount of interval and for current decrementing counter. It’s up to you how you’ll make the structure of ECB, but one is definitely sure – TimeSemaphores are ordinary Semaphores with 2 additional variables that’s used to signal the semaphore in OSTimer().

Because they look like so much to ordinary semaphores, I proposed some name that use “semaphore” inside – like Time Semaphores, Interval Semaphores, Sync Semaphores. Unfortunately English is not my native language so I can’t play with words like you can.

What I described covers all what we need to generate periodical signals, without carrying about all other possible delays after we receive control of the OS_WaitSem().

Some improvement – it’s possible to use prescaller of the timer, so we can increase the resolution of the function. When we call OSTimer and we do decrementing the prescaller, we can decrement the counters of TimeSemaphores too.
Maybe using:

code:

#define OSTIMESEMAPHORE_LENGTH 2 // will use 2 bytes variables


we can just set simply what we need. Well, before this we have to declare the prescaller of OSTimer() too.

This will need increasing of the length of the variables of TimeSemaphores too – right now I don’t have clear vision how this could be made with settings of SALVO, need time to ripe the idea. If the OSTimer is quickly enough we can increase the frequency of calling the function via ISR. Time semaphores will get very good resolution, even enough to declare multiple RS232 receive channels on high speed (with this function will be very easy to implement almost any mumber of receive and transmit RS232 channels).

Hope we approach to the final idea.
Regards
Luben

[This message has been edited by aek (edited September 24, 2001).]

luben
 
Posts: 324
Joined: Sun Nov 19, 2000 12:00 am
Location: Sofia, Bulgaria

Re: New time oriented function

Postby aek » Thu Sep 27, 2001 12:52 am

quote:
But what will be if you use OS_Delay (one or more times) between OS_Interval() calls? Will this destroy the pace rythm? OS_Interval() should look like hardware timer - to produce events on fixed intervals. I can't explain exactly but I feel that OS_Delay has a little bit different sense - to produce delay after one start point. OS_Interval() should produce events every defined interval.

Why would you want to? After all, with OS_Interval() you're guaranteed repetitive delays. OS_Delay() "breaks" that.

OS_Interval() and OS_Delay() use the same RAM, so you should not call OS_Delay() when you're using OS_Interval(). If you do call OS_Delay(), the synchronization will be lost.

Here's one way to think about it: OS_Delay() results in a delay in system ticks from now. OS_Interval() results in a delay in system ticks from when the task last timed out due to OS_Interval -- and that timeout is based on the "original value" of the system timer.

Here are two task snippets:

code:
OSSyncInterval(0); 
OS_Interval(4, label1); // A: t = T
...
OS_Interval(4, label2); // B: t = T+4 +/-1
...
OS_Interval(4, label3); // C: t = T+8 +/-1
...

and

code:
OS_Delay(4, label1); // D: t = T
...
OS_Delay(4, label2); // E: t = T+4 +/-1
...
OS_Delay(4, label3); // F: t = T+8 +/-2
...

The potential timing error at F is greater than the timing error at C because OS_Delay() is not synchronized to the system timer at time T. OS_Interval() always results in a delay relative to the time when OSSyncInterval() was called, and thereby avoids accumulated error. OS_Delay()'s delays are relative to the current value of the system timer, and that will depend on when the task runs. OS_Interval() depends on when the task's delay expired, which is as accurate as the means used to call OSTimer(), e.g. via a hardware interrupt.

quote:
OS_Delay() has a little bit different sense - to produce delay after one start point. OS_Interval() should produce events every defined interval.

Exactly.

quote:
The other approach is just to say users have not to use OS_Delay between calls of OS_Interval.

Correct.

------------------

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: New time oriented function

Postby aek » Thu Sep 27, 2001 2:47 am

I've just coded up OS_Interval(). The behavior is as follows for a task with a single OS_Interval(25, label):

Assume the task last timed out at T=30, i.e. it was made eligible at or around T=30 and should have run immediately thereafter. The next two intervals are T=55 and T=80. Here are three cases:

T=31 (typical):
30+25=55, and so the task (now running) will delay itself for 30+25-31=24 ticks. 31+24=55, which is the desired amount.

T=53 (very long "holdoff" by other, higher-priority tasks):
30+25=55, and so the task (now running) will delay itself for 30+25-53=2 ticks. 53+2=55, which is the desired amount.

T=58 (late, massive holdoff by other, higher-priority tasks):
30+25=55, and so the task (now running) is late. It will delay itself for 30+25+25-58=22 ticks. 58+22=80, which is the desired amount to get to the next interval. It's important to note that the task is now running at T=58, though we wanted it to run at T=55. So if a task is late, it will still run, and it will attempt to resynchronize itself for the next desired interval.

So here you see how an "intervaled" task can recover its synchronization by the next interval, whereas a delayed task cannot -- it would end up at T=83, not T=80.

------------------

[This message has been edited by aek (edited September 27, 2001).]

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Next

Return to Feature Requests

Who is online

Users browsing this forum: No registered users and 1 guest

cron