Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.arch.embedded > #29293 > unrolled thread
| Started by | pozz <pozzugno@gmail.com> |
|---|---|
| First post | 2020-03-13 15:38 +0100 |
| Last post | 2020-03-18 16:24 +0000 |
| Articles | 9 on this page of 49 — 12 participants |
Back to article view | Back to comp.arch.embedded
Cortex-M: share an int between two tasks pozz <pozzugno@gmail.com> - 2020-03-13 15:38 +0100
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-13 17:49 +0100
Re: Cortex-M: share an int between two tasks pozz <pozzugno@gmail.com> - 2020-03-18 09:09 +0100
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-18 09:17 +0100
Re: Cortex-M: share an int between two tasks Hans-Bernhard Bröker <HBBroeker@t-online.de> - 2020-03-18 17:37 +0100
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-18 19:23 +0100
Re: Cortex-M: share an int between two tasks Les Cargill <lcargill99@comcast.com> - 2020-03-22 13:42 -0500
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-22 21:45 +0100
Re: Cortex-M: share an int between two tasks Richard Damon <Richard@Damon-Family.org> - 2020-03-22 20:50 -0400
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-23 09:09 +0100
Re: Cortex-M: share an int between two tasks Richard Damon <Richard@Damon-Family.org> - 2020-03-23 08:00 -0400
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-23 14:21 +0100
Re: Cortex-M: share an int between two tasks Clifford Heath <no.spam@please.net> - 2020-03-25 09:55 +1100
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-30 16:07 +0200
Re: Cortex-M: share an int between two tasks Clifford Heath <no.spam@please.net> - 2020-03-31 09:02 +1100
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-31 10:57 +0200
Re: Cortex-M: share an int between two tasks Clifford Heath <no.spam@please.net> - 2020-04-01 12:05 +1100
Re: Cortex-M: share an int between two tasks Tauno Voipio <tauno.voipio@notused.fi.invalid> - 2020-03-30 17:49 +0300
Re: Cortex-M: share an int between two tasks kegs@provalid.com (Kent Dickey) - 2020-05-19 00:34 -0500
Re: Cortex-M: share an int between two tasks Clifford Heath <no.spam@please.net> - 2020-05-19 17:40 +1000
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-05-19 12:00 +0200
Re: Cortex-M: share an int between two tasks Tom Gardner <spamjunk@blueyonder.co.uk> - 2020-05-19 13:48 +0100
Re: Cortex-M: share an int between two tasks pozz <pozzugno@gmail.com> - 2020-03-18 09:20 +0100
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-18 10:06 +0100
Re: Cortex-M: share an int between two tasks pozz <pozzugno@gmail.com> - 2020-03-18 10:59 +0100
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-18 11:48 +0100
Re: Cortex-M: share an int between two tasks upsidedown@downunder.com - 2020-03-18 20:37 +0200
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-18 21:24 +0100
Re: Cortex-M: share an int between two tasks Tauno Voipio <tauno.voipio@notused.fi.invalid> - 2020-03-19 14:05 +0200
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-19 13:16 +0100
Re: Cortex-M: share an int between two tasks Tauno Voipio <tauno.voipio@notused.fi.invalid> - 2020-03-19 14:27 +0200
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-19 14:13 +0100
Re: Cortex-M: share an int between two tasks pozz <pozzugno@gmail.com> - 2020-03-19 08:03 +0100
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-19 09:10 +0100
Re: Cortex-M: share an int between two tasks upsidedown@downunder.com - 2020-03-19 12:51 +0200
Re: Cortex-M: share an int between two tasks pozz <pozzugno@gmail.com> - 2020-03-19 07:40 +0100
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-19 09:38 +0100
Re: Cortex-M: share an int between two tasks pozz <pozzugno@gmail.com> - 2020-03-19 11:26 +0100
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-19 12:12 +0100
Re: Cortex-M: share an int between two tasks pozz <pozzugno@gmail.com> - 2020-03-19 15:31 +0100
Re: Cortex-M: share an int between two tasks pozz <pozzugno@gmail.com> - 2020-03-23 09:22 +0100
Re: Cortex-M: share an int between two tasks Richard Damon <Richard@Damon-Family.org> - 2020-03-23 08:10 -0400
Re: Cortex-M: share an int between two tasks pozz <pozzugno@gmail.com> - 2020-03-23 13:47 +0100
Re: Cortex-M: share an int between two tasks David Brown <david.brown@hesbynett.no> - 2020-03-23 14:31 +0100
Re: Cortex-M: share an int between two tasks Richard Damon <Richard@Damon-Family.org> - 2020-03-23 13:50 -0400
Re: Cortex-M: share an int between two tasks Niklas Holsti <niklas.holsti@tidorum.invalid> - 2020-03-19 12:27 +0200
Re: Cortex-M: share an int between two tasks pozz <pozzugno@gmail.com> - 2020-03-19 11:45 +0100
Re: Cortex-M: share an int between two tasks upsidedown@downunder.com - 2020-03-19 13:27 +0200
Re: Cortex-M: share an int between two tasks antispam@math.uni.wroc.pl - 2020-03-18 16:24 +0000
Page 3 of 3 — ← Prev page 1 2 [3]
| From | pozz <pozzugno@gmail.com> |
|---|---|
| Date | 2020-03-23 09:22 +0100 |
| Message-ID | <r59rki$pjq$1@dont-email.me> |
| In reply to | #29320 |
Il 19/03/2020 15:31, pozz ha scritto:
> Il 19/03/2020 12:12, David Brown ha scritto:
> [...]
>> One possible arrangement could be:
>>
>>
>> static volatile bool sensor_stopped;
>> static SemaphoreHandle_t sensor_semaphore;
>>
>> // TaskA
>> static const TickType_t delay_ticks = pdMS_TO_TICKS(10);
>>
>> while (true) {
>> // Get sample and process
>> if (sensor_stopped) {
>> // Wait for semaphore to be ready
>> xSemaphoreTake(sensor_semaphore, portMAX_DELAY);
>> // Then release it again
>> xSemaphoreGive(sensor_semaphore);
>> }
>> vTaskDelay(delay_ticks); // DelayUntil
>> }
>>
>>
>> // TaskB
>> static void turn_off_sensor(void) {
>> sensor_stopped = True;
>> xSemaphoreTake(sensor_semaphore, 0);
>> }
>>
>> static void turn_on_sensor(void) {
>> sensor_stopped = False;
>> xSemaphoreGive(sensor_semaphore);
>> }
>>
>> The "sensor_stopped" flag is really just an optimisation, so that
>> TaskA doesn't have to keep checking the semaphore. It can be dropped
>> if you want.
>
> I'm not sure about xSemaphoreTake(sensor_semaphore, 0) in
> turn_off_sensor(). You pass a zero timeout. Are you sure you will be
> able to take the semaphore in *every* situation? What happens if
> turn_off_sensor() is run immediately after xSemaphoreTake(...,
> portMAX_DELAY) returns?
> In this case, I think taskB wouldn't be able to take the semaphore and
> so taskA doesn't really block. You will have sensor_stopped true, but
> the semaphore released.
David I hope you can answer to this. This topic is quite confusing to
me. Thank you.
[toc] | [prev] | [next] | [standalone]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2020-03-23 08:10 -0400 |
| Message-ID | <4H1eG.131641$xv4.107395@fx18.iad> |
| In reply to | #29320 |
On 3/19/20 10:31 AM, pozz wrote:
> Il 19/03/2020 12:12, David Brown ha scritto:
> ...
>>>> It would be possible, but it does not look good to me. I'd be
>>>> looking at an atomic flag (volatile bool, pre-C11) to indicate task
>>>> A should be shutting down after the current sample, then wait on a
>>>> semaphore. But I'd need a clearer picture of the whole system and
>>>> interaction between threads.
>>>
>>> This is what I thought, but I'm not able to implement it without any
>>> race conditions.
>>>
>>> // TaskA
>>> static volatile bool stopped;
>>> static volatile unsigned int delay_ms;
>>>
>>> stopped = false;
>>> while(1) {
>>> // get sample and process
>>> if (stopped) { (1)
>>> vTaskDelay(portMAX_DELAY); (2)
>>
>> This is a stop forever!
>
> Yes, but in my example I used vTaskDelayAbort(), so it isn't really a
> stop forever.
>
>
>>> } else {
>>> vTaskDelay(pdMS_TO_TICKS(delay_ms));
>>> }
>>> }
>>>
>>> void set_delay(unsigned int new_delay) {
>>> // This is TaskB
>>> if (new_delay == 0) {
>>> stopped = true;
>>> } else {
>>> stopped = false;
>>> delay_ms = new_delay;
>>> vTaskDelayAbort(taskA);
>>> }
>>> }
>>>
>>> This code has some race conditions if both tasks can be interrupted
>>> in any point by the other.
>>> For example, if stopped is true and taskB enters immediately after
>>> (1) and before (2) with set_delay(3), I will have taskA blocked
>>> forever!!
>>>
>>> Could you suggest a solution with a simple volatile bool flag?
>>>
>>
>> You use a flag to indicate that you should be stopping, and a
>> semaphore to handle the wakeup (semaphores are intended for one task
>> to give them, and another to take them).
>>
>> Stop messing around with varying delays - that is an irrelevancy, and
>> is complicating your code. Either your sensor task is running with
>> regular samples, or it is stopped.
>
> Sincerely taskB should change the sampling interval too. Anyway the big
> issue is stopping and restarting, not changing the interval.
>
>
>> One possible arrangement could be:
>>
>>
>> static volatile bool sensor_stopped;
>> static SemaphoreHandle_t sensor_semaphore;
>>
>> // TaskA
>> static const TickType_t delay_ticks = pdMS_TO_TICKS(10);
>>
>> while (true) {
>> // Get sample and process
>> if (sensor_stopped) {
>> // Wait for semaphore to be ready
>> xSemaphoreTake(sensor_semaphore, portMAX_DELAY);
>> // Then release it again
>> xSemaphoreGive(sensor_semaphore);
>> }
>> vTaskDelay(delay_ticks); // DelayUntil
>> }
>>
>>
>> // TaskB
>> static void turn_off_sensor(void) {
>> sensor_stopped = True;
>> xSemaphoreTake(sensor_semaphore, 0);
>> }
>>
>> static void turn_on_sensor(void) {
>> sensor_stopped = False;
>> xSemaphoreGive(sensor_semaphore);
>> }
>>
>> The "sensor_stopped" flag is really just an optimisation, so that
>> TaskA doesn't have to keep checking the semaphore. It can be dropped
>> if you want.
>
> I'm not sure about xSemaphoreTake(sensor_semaphore, 0) in
> turn_off_sensor(). You pass a zero timeout. Are you sure you will be
> able to take the semaphore in *every* situation? What happens if
> turn_off_sensor() is run immediately after xSemaphoreTake(...,
> portMAX_DELAY) returns?
> In this case, I think taskB wouldn't be able to take the semaphore and
> so taskA doesn't really block. You will have sensor_stopped true, but
> the semaphore released.
>
A Take with a zero timeout will lower the semaphore if it happens to be
raised, and continue if is was lowered. This will cause task A to go and
block on the Semaphore until task B gives it again. The take operation
returns a flag as to if it succeeded, and Task a should really use a:
if(xSemaphoreTake(sensor_semaphore, portMAX_DELAY)) {
xSemaphoreGive(sensor_semaphore);
}
Otherwise if something causes the Take to abort, the the sampling will
start back up.
I would probably do the take before setting the flag, so if TaskA runs
between the statements it doesn't do its take, and pass.
>
>> A really simple solution would be:
>>
>> static volatile bool sensor_stopped;
>>
>> // TaskA
>> static const TickType_t delay_ticks = pdMS_TO_TICKS(10);
>>
>> while (true) {
>> if (!sensor_stopped) {
>> // Get sample and process
>> }
>> vTaskDelay(delay_ticks); // DelayUntil
>> }
>>
>>
>> // TaskB
>> static void turn_off_sensor(void) {
>> sensor_stopped = True;
>> }
>>
>> static void turn_on_sensor(void) {
>> sensor_stopped = False;
>> }
>>
>>
>> This all depends on why you want to stop the sensor task - if you are
>> going into low power modes, for example, then it may be best to block
>> the task. If you don't mind a regular task doing nothing useful, then
>> the second choice is fine.
>
> Yes, this is another solution that doesn't really stop the task, but
> only the sampling process.
>
>
[toc] | [prev] | [next] | [standalone]
| From | pozz <pozzugno@gmail.com> |
|---|---|
| Date | 2020-03-23 13:47 +0100 |
| Message-ID | <r5ab4n$jag$1@dont-email.me> |
| In reply to | #29336 |
Il 23/03/2020 13:10, Richard Damon ha scritto:
> On 3/19/20 10:31 AM, pozz wrote:
>> Il 19/03/2020 12:12, David Brown ha scritto:
>>> One possible arrangement could be:
>>>
>>>
>>> static volatile bool sensor_stopped;
>>> static SemaphoreHandle_t sensor_semaphore;
>>>
>>> // TaskA
>>> static const TickType_t delay_ticks = pdMS_TO_TICKS(10);
>>>
>>> while (true) {
>>> // Get sample and process
>>> if (sensor_stopped) {
>>> // Wait for semaphore to be ready
>>> xSemaphoreTake(sensor_semaphore, portMAX_DELAY);
>>> // Then release it again
>>> xSemaphoreGive(sensor_semaphore);
>>> }
>>> vTaskDelay(delay_ticks); // DelayUntil
>>> }
>>>
>>>
>>> // TaskB
>>> static void turn_off_sensor(void) {
>>> sensor_stopped = True;
>>> xSemaphoreTake(sensor_semaphore, 0);
>>> }
>>>
>>> static void turn_on_sensor(void) {
>>> sensor_stopped = False;
>>> xSemaphoreGive(sensor_semaphore);
>>> }
>>>
>>> The "sensor_stopped" flag is really just an optimisation, so that
>>> TaskA doesn't have to keep checking the semaphore. It can be dropped
>>> if you want.
>>
>> I'm not sure about xSemaphoreTake(sensor_semaphore, 0) in
>> turn_off_sensor(). You pass a zero timeout. Are you sure you will be
>> able to take the semaphore in *every* situation? What happens if
>> turn_off_sensor() is run immediately after xSemaphoreTake(...,
>> portMAX_DELAY) returns?
>> In this case, I think taskB wouldn't be able to take the semaphore and
>> so taskA doesn't really block. You will have sensor_stopped true, but
>> the semaphore released.
>>
> A Take with a zero timeout will lower the semaphore if it happens to be
> raised, and continue if is was lowered. This will cause task A to go and
> block on the Semaphore until task B gives it again. The take operation
> returns a flag as to if it succeeded, and Task a should really use a:
> if(xSemaphoreTake(sensor_semaphore, portMAX_DELAY)) {
> xSemaphoreGive(sensor_semaphore);
> }
If portMAX_DELAY is used in xSemaphoreTake(), I think the function
returns only if it was able to take the semaphore (if we don't use
functions that abruptly let one task out of blocked state).
> Otherwise if something causes the Take to abort, the the sampling will
> start back up.
>
> I would probably do the take before setting the flag, so if TaskA runs
> between the statements it doesn't do its take, and pass.
Anyway my objection is still there. If turn_off_sensor() is executed
immediately after xSemaphoreTake(sensor_semaphore, portMAX_DELAY)
returns, taskB wouldn't be able to take the semaphore, so taskA will
wrongly continue doing its work.
I think we can use portMAX_DELAY in turn_off_sensor() too. In the worst
case, taskB would wait for a very short time to take the semaphore, but
usually it takes the semaphore immediately.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2020-03-23 14:31 +0100 |
| Message-ID | <r5admv$9ho$1@dont-email.me> |
| In reply to | #29337 |
On 23/03/2020 13:47, pozz wrote:
> Il 23/03/2020 13:10, Richard Damon ha scritto:
>> On 3/19/20 10:31 AM, pozz wrote:
>>> Il 19/03/2020 12:12, David Brown ha scritto:
>
>>>> One possible arrangement could be:
>>>>
>>>>
>>>> static volatile bool sensor_stopped;
>>>> static SemaphoreHandle_t sensor_semaphore;
>>>>
>>>> // TaskA
>>>> static const TickType_t delay_ticks = pdMS_TO_TICKS(10);
>>>>
>>>> while (true) {
>>>> // Get sample and process
>>>> if (sensor_stopped) {
>>>> // Wait for semaphore to be ready
>>>> xSemaphoreTake(sensor_semaphore, portMAX_DELAY);
>>>> // Then release it again
>>>> xSemaphoreGive(sensor_semaphore);
>>>> }
>>>> vTaskDelay(delay_ticks); // DelayUntil
>>>> }
>>>>
>>>>
>>>> // TaskB
>>>> static void turn_off_sensor(void) {
>>>> sensor_stopped = True;
>>>> xSemaphoreTake(sensor_semaphore, 0);
>>>> }
>>>>
>>>> static void turn_on_sensor(void) {
>>>> sensor_stopped = False;
>>>> xSemaphoreGive(sensor_semaphore);
>>>> }
>>>>
>>>> The "sensor_stopped" flag is really just an optimisation, so that
>>>> TaskA doesn't have to keep checking the semaphore. It can be dropped
>>>> if you want.
>>>
>>> I'm not sure about xSemaphoreTake(sensor_semaphore, 0) in
>>> turn_off_sensor(). You pass a zero timeout. Are you sure you will be
>>> able to take the semaphore in *every* situation? What happens if
>>> turn_off_sensor() is run immediately after xSemaphoreTake(...,
>>> portMAX_DELAY) returns?
>>> In this case, I think taskB wouldn't be able to take the semaphore and
>>> so taskA doesn't really block. You will have sensor_stopped true, but
>>> the semaphore released.
>>>
>> A Take with a zero timeout will lower the semaphore if it happens to be
>> raised, and continue if is was lowered. This will cause task A to go and
>> block on the Semaphore until task B gives it again. The take operation
>> returns a flag as to if it succeeded, and Task a should really use a:
>> if(xSemaphoreTake(sensor_semaphore, portMAX_DELAY)) {
>> xSemaphoreGive(sensor_semaphore);
>> }
>
> If portMAX_DELAY is used in xSemaphoreTake(), I think the function
> returns only if it was able to take the semaphore (if we don't use
> functions that abruptly let one task out of blocked state).
>
>> Otherwise if something causes the Take to abort, the the sampling will
>> start back up.
>>
>> I would probably do the take before setting the flag, so if TaskA runs
>> between the statements it doesn't do its take, and pass.
>
> Anyway my objection is still there. If turn_off_sensor() is executed
> immediately after xSemaphoreTake(sensor_semaphore, portMAX_DELAY)
> returns, taskB wouldn't be able to take the semaphore, so taskA will
> wrongly continue doing its work.
Yes, I think the code is not quite right. I am not happy about it
anyway - it doesn't feel good. But as I said before, I think you would
be better with a re-think of the design at a higher level.
>
> I think we can use portMAX_DELAY in turn_off_sensor() too. In the worst
> case, taskB would wait for a very short time to take the semaphore, but
> usually it takes the semaphore immediately.
>
That depends on the timing requirements, but could work.
[toc] | [prev] | [next] | [standalone]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2020-03-23 13:50 -0400 |
| Message-ID | <BF6eG.18908$ZT6.17858@fx01.iad> |
| In reply to | #29337 |
On 3/23/20 8:47 AM, pozz wrote:
>
> Anyway my objection is still there. If turn_off_sensor() is executed
> immediately after xSemaphoreTake(sensor_semaphore, portMAX_DELAY)
> returns, taskB wouldn't be able to take the semaphore, so taskA will
> wrongly continue doing its work.
Yes, if TaskB has priority greater than or equal to TaskA, then it could
come in between the Take and the Give. One solution would be to make the
Give back conditional on not stopped, as well as the getting and
processing of the sample. Something like:
while (true) {
if(sensor_stopped) {
xSemaphoreTake(sensor_semaphore, portMAX_DELAY);
if(!sensor_stopped) {
xSemaphoreGive(sensor_semaphore);
}
} else {
// Get sample and process
vTaskDelay(delay_ticks;
}
}
With this, if TaskB just sets the stopped flag, TaskA will take the
semaphore, not give it, then loop around and take it again and wait. If
TaskB does a 0 timeout take, it can prevent that extra loop.
If TaskA gets accidentally woken up, then it still doesn't give the
semaphore and blocks on the next loop.
[toc] | [prev] | [next] | [standalone]
| From | Niklas Holsti <niklas.holsti@tidorum.invalid> |
|---|---|
| Date | 2020-03-19 12:27 +0200 |
| Message-ID | <hdgvpeF4ktdU1@mid.individual.net> |
| In reply to | #29306 |
On 2020-03-19 8:40, pozz wrote:
[snip long discussion]
> I simply wanted a management taskB to stop and restart sensor sampling
> done by taskA. taskA uses vTaskDelay() for sampling at precise timings.
[snip]
> After many years using cooperative schedulers, it appears to me
> incredible how difficult, error prone and resource consuming is to
> implement even simple mechanisms like this one with a preemptive scheduler.
It's not so hard once you absorb a set of high-level solution patterns
and apply them consistently and with a high-level design approach.
I realize that this response may not be helpful, but here is how it can
be done in Ada, as an example of a high-level approach.
The SW will have a subsystem that does "sampling", and you want some
other "managing" subsystem to be able to set the sampling period and to
start/stop sampling. The sampling subsystem interface (API) is then:
package Sampling is
procedure Set_Period (To : in Duration);
procedure Start;
procedure Stop;
end Sampling;
That Ada text is put in its own file (by current convention named
sampling.ads).
The body (implementation) of the sampling subsystem is put in its own
file (conventionally named sampling.adb) and will start with
package body Sampling is
The rest of this post will add the parts of the package body one by one.
The sampling package will have a concurrent task, called Sampler for
example, and declared as:
task Sampler;
The task body is shown later below.
The data to be communicated to the Sampler task will be the sampling
period and whether sampling should be active. These shared data are
placed in a "protected object" to ensure mutually exclusive access. The
actions on these shared data are the following:
- Actions from the "manager" (exterior to the Sampling package):
-- set the sampling period
-- start sampling
-- stop sampling.
- Actions from the Sampler task:
-- get the current sampling period-
Moreover, the Sampler task should be suspended when sampling is stopped,
which is convenient to implement with an Ada "entry" operation that
suspends the caller if its "guard" expression is false. The declaration
of the protected object is then:
protected Sampling_Control is
procedure Set_Period (To : in Duration);
procedure Start;
procedure Stop;
entry Get_Period (Giving : out Duration);
private
Running : Boolean := False;
Period : Duration := 1.0;
end Sampling_Control;
The shared but protected data are thus the Running flag, which will be
the guard for the Get_Period entry, and the current sampling Period.
Note that sampling is initially stopped (Running is initially False) and
the initial sampling period is one second.
The implementation is rather trivial:
protected body Sampling_Control is
procedure Set_Period (To : in Duration) is
begin
Period := To;
end Set_Period;
procedure Start is
begin
Running := True;
end Start;
procedure Stop is
begin
Running := False;
end Stop;
entry Get_Period (Giving : out Duration)
when Running
is
begin
Giving := Period;
end Get_Period;
end Sampling_Control;
Note the guard "when Running" on the Get_Period entry. This means that a
task that calls Get_Period when Running is False is suspended, at the
point of the call, until Running becomes True. If Running is True, the
call succeeds at once.
Note that Set_Period does not automatically start sampling. If that is
desired, add the statement "Running := True" in Set_Period.
The Sampler task body can now be implemented simply:
task body Sampler is
Period : Duration;
begin
loop
Sampling_Control.Get_Period (Giving => Period);
-- Take the sample, etc.
delay Period;
end loop;
end Sampler;
(This code is a bit sloppy, because the use of a "relative" delay
statement brings lag and jitter into sample timing. It is better to use
the "absolute" delay statement ("delay until"), but this complication is
not relevant to the task interactions so I skipped it.)
The public (API) operations of the Sampling package just call the
corresponding operations of Sampling_Control (this circumlocation can of
course be avoided by making Sampling_Control itself public, but that
would harm encapsulation and increase inter-module coupling):
procedure Set_Period (To : in Duration) is
begin
Sampling_Control.Set_Period (To);
end Set_Period;
procedure Start is
begin
Sampling_Control.Start;
end Start;
procedure Stop is
begin
Sampling_Control.Stop;
end Stop;
The implementation of the Sampling subsystem is now complete, and the
file sampling.adb ends with:
end Sampling;
The "manager" part of the SW accesses the Sampling subsystem by saying
with Sampling;
and can then use the Sampling interface, for example as
Sampling.Set_Period (To => 0.1); -- 10 Hz
Sampling.Start;
...
Sampling.Set_Period (To => 2.5);
...
Sampling.Stop;
and so on.
To map this Ada code into some C+RTOS combination, one should use a
mutex to make the executions of the protected operations
(Sampling_Control.Set_Period, .Start, .Stop, .Get_Period) mutually
exclusive, and use some "condition" variable or semaphore to implement
the guard (caller suspension) of Sampling_Control.Get_Period.
That last point (caller suspension) has some subtleties that depend on
the actual set of RTOS primitives available. But I recommend a simpler
solution: instead of suspending/resuming the sampling task, just let it
run normally at the sampling period, but make the actual sampling (and
sample processing, I assume) conditional on a "Running" flag (by
returning this flag, too, from Get_Period). Usually the processor effort
saved by actually suspending tasks that normally run periodically is not
significant.
--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .
[toc] | [prev] | [next] | [standalone]
| From | pozz <pozzugno@gmail.com> |
|---|---|
| Date | 2020-03-19 11:45 +0100 |
| Message-ID | <r4vigh$k06$1@dont-email.me> |
| In reply to | #29311 |
Il 19/03/2020 11:27, Niklas Holsti ha scritto: > On 2020-03-19 8:40, pozz wrote: > > [snip long discussion] > >> I simply wanted a management taskB to stop and restart sensor sampling >> done by taskA. taskA uses vTaskDelay() for sampling at precise timings. > > [snip] > >> After many years using cooperative schedulers, it appears to me >> incredible how difficult, error prone and resource consuming is to >> implement even simple mechanisms like this one with a preemptive >> scheduler. > > It's not so hard once you absorb a set of high-level solution patterns > and apply them consistently and with a high-level design approach. Ok, where do I study those "high-level solution patterns"? Because I didn't find good docs that explain non-trivial real examples. > I realize that this response may not be helpful, but here is how it can > be done in Ada, as an example of a high-level approach. > [...] Unfortunatley I don't know Ada. > To map this Ada code into some C+RTOS combination, one should use a > mutex to make the executions of the protected operations > (Sampling_Control.Set_Period, .Start, .Stop, .Get_Period) mutually > exclusive, and use some "condition" variable or semaphore to implement > the guard (caller suspension) of Sampling_Control.Get_Period. > > That last point (caller suspension) has some subtleties that depend on > the actual set of RTOS primitives available. But I recommend a simpler > solution: instead of suspending/resuming the sampling task, just let it > run normally at the sampling period, but make the actual sampling (and > sample processing, I assume) conditional on a "Running" flag (by > returning this flag, too, from Get_Period). Usually the processor effort > saved by actually suspending tasks that normally run periodically is not > significant. Yes, I didn't imagine that controlling a task from another task was so difficult with a full-features RTOS like FreeRTOS. So your suggestion to let the sampling task always run even when it should be suspended is good. It's a pity, because I have many sensors, but only a few of them are active at any time.
[toc] | [prev] | [next] | [standalone]
| From | upsidedown@downunder.com |
|---|---|
| Date | 2020-03-19 13:27 +0200 |
| Message-ID | <ltk67fp1jsimrd0k14hcnjcphkqad5b9ae@4ax.com> |
| In reply to | #29312 |
On Thu, 19 Mar 2020 11:45:37 +0100, pozz <pozzugno@gmail.com> wrote:
>
>Unfortunatley I don't know Ada.
>
>> To map this Ada code into some C+RTOS combination, one should use a
>> mutex to make the executions of the protected operations
>> (Sampling_Control.Set_Period, .Start, .Stop, .Get_Period) mutually
>> exclusive, and use some "condition" variable or semaphore to implement
>> the guard (caller suspension) of Sampling_Control.Get_Period.
>>
>> That last point (caller suspension) has some subtleties that depend on
>> the actual set of RTOS primitives available. But I recommend a simpler
>> solution: instead of suspending/resuming the sampling task, just let it
>> run normally at the sampling period, but make the actual sampling (and
>> sample processing, I assume) conditional on a "Running" flag (by
>> returning this flag, too, from Get_Period). Usually the processor effort
>> saved by actually suspending tasks that normally run periodically is not
>> significant.
>
>Yes, I didn't imagine that controlling a task from another task was so
>difficult with a full-features RTOS like FreeRTOS.
>So your suggestion to let the sampling task always run even when it
>should be suspended is good. It's a pity, because I have many sensors,
>but only a few of them are active at any time.
Why don't you simply make each sampling task like
loop
wait_for_event()
do_the_sampling
end loop
Then have a separate timing task, which runs at say every millisecond
and increment a single integer counter.
For each task, calculate (Counter modulo NN) and send a message to a
specific sampler task, when modulo is zero. NN is the number of clock
ticks before a specific sampling is done.
If you want to do sampling say every 10 ms, but want to spread out the
sampling times, add a constant 1, 2, 3 to a copy of the counter before
performing the module and one task will sample at xx7, the other at
xx8 and third at xx9 milliseconds every 10 ms.
This way, you can control the sampling times and periods from a single
point in the timing task and no need to spread out this to individual
sampler tasks.
[toc] | [prev] | [next] | [standalone]
| From | antispam@math.uni.wroc.pl |
|---|---|
| Date | 2020-03-18 16:24 +0000 |
| Message-ID | <r4ti0d$h14$1@z-news.wcss.wroc.pl> |
| In reply to | #29297 |
pozz <pozzugno@gmail.com> wrote:
>
> Ok the example was extremely simple. If I have something a little more
> complex:
>
> ---
> volatile uint32_t wait_period;
>
> while(1) {
> // make some things
> if (wait_period > 0) {
> vTaskDelay(pdMS_TO_TICKS(wait_period));
> } else {
> vTaskSuspend(myTask);
> }
> }
>
> void set_waiting_period(uint32_t new_period) {
> wait_period = new_period;
> if (wait_period > 0) {
> vTaskResume(myTask);
> }
> }
> ---
>
> I think this doesn't work in all the cases. For example, if
> wait_period=0 and set_waiting_period(3) is executed from another higher
> priority task immediately after
>
> if(wait_period > 0) // the if in the endless loop
>
> wait_period is changed to 3, but vTaskSuspended() is executed in the
> else branch, so leaving the task suspended with a not-null wait_period.
To me the above looks like very natural anti-pattern. Namely,
code testing 'wait_period' _and_ execution of 'vTaskSuspend'
logically form a single ciritical section. AFAICS any placement
of locks above leads to races.
My solution to the above is have _whole thing_ in scheduler,
so that testing flags and switching process is atomic.
In your case messages look like step to solution, but
you still need to think about messaging protocol...
--
Waldek Hebisch
[toc] | [prev] | [standalone]
Page 3 of 3 — ← Prev page 1 2 [3]
Back to top | Article view | comp.arch.embedded
csiph-web