Rocksolid Light

Welcome to novaBBS (click a section below)

mail  files  register  newsreader  groups  login

Message-ID:  

"There is such a fine line between genius and stupidity." -- David St. Hubbins, "Spinal Tap"


devel / comp.arch.embedded / Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on

SubjectAuthor
* How to write a simple driver in bare metal systems: volatile, memorypozz
+- Re: How to write a simple driver in bare metal systems: volatile, memory barrierClifford Heath
+* Re: How to write a simple driver in bare metal systems: volatile,Don Y
|`* Re: How to write a simple driver in bare metal systems: volatile,pozz
| `- Re: How to write a simple driver in bare metal systems: volatile,Don Y
+* Re: How to write a simple driver in bare metal systems: volatile,David Brown
|+* Re: How to write a simple driver in bare metal systems: volatile,pozz
||`* Re: How to write a simple driver in bare metal systems: volatile,David Brown
|| `* Re: How to write a simple driver in bare metal systems: volatile,pozz
||  `- Re: How to write a simple driver in bare metal systems: volatile,David Brown
|`* Re: How to write a simple driver in bare metal systems: volatile,pozz
| +- Re: How to write a simple driver in bare metal systems: volatile,David Brown
| `- Re: How to write a simple driver in bare metal systems: volatile,Richard Damon
`* Re: How to write a simple driver in bare metal systems: volatile,Johann Klammer
 `* Re: How to write a simple driver in bare metal systems: volatile,Dimiter_Popoff
  +* Re: How to write a simple driver in bare metal systems: volatile,Don Y
  |+* Re: How to write a simple driver in bare metal systems: volatile,Dimiter_Popoff
  ||+* Re: How to write a simple driver in bare metal systems: volatile,Don Y
  |||+* Re: How to write a simple driver in bare metal systems: volatile,Dimiter_Popoff
  ||||`* Re: How to write a simple driver in bare metal systems: volatile,Don Y
  |||| `* Re: How to write a simple driver in bare metal systems: volatile,Dimiter_Popoff
  ||||  `- Re: How to write a simple driver in bare metal systems: volatile,Don Y
  |||+- Re: How to write a simple driver in bare metal systems: volatile,David Brown
  |||`* Re: How to write a simple driver in bare metal systems: volatile,Niklas Holsti
  ||| `* Re: How to write a simple driver in bare metal systems: volatile,Don Y
  |||  `* Re: How to write a simple driver in bare metal systems: volatile,Niklas Holsti
  |||   +- Re: How to write a simple driver in bare metal systems: volatile,Don Y
  |||   `* Re: How to write a simple driver in bare metal systems: volatile,David Brown
  |||    `- Re: How to write a simple driver in bare metal systems: volatile,Niklas Holsti
  ||`* Re: How to write a simple driver in bare metal systems: volatile,Niklas Holsti
  || +* Re: How to write a simple driver in bare metal systems: volatile,Don Y
  || |`* Re: How to write a simple driver in bare metal systems: volatile,Niklas Holsti
  || | `- Re: How to write a simple driver in bare metal systems: volatile,Don Y
  || +* Re: How to write a simple driver in bare metal systems: volatile,Dimiter_Popoff
  || |`* Re: How to write a simple driver in bare metal systems: volatile,Niklas Holsti
  || | +* Re: How to write a simple driver in bare metal systems: volatile,Don Y
  || | |`* Re: How to write a simple driver in bare metal systems: volatile,Dimiter_Popoff
  || | | `- Re: How to write a simple driver in bare metal systems: volatile,Don Y
  || | +* Re: How to write a simple driver in bare metal systems: volatile,pozz
  || | |+- Re: How to write a simple driver in bare metal systems: volatile,Don Y
  || | |`* Re: How to write a simple driver in bare metal systems: volatile,Niklas Holsti
  || | | +* Re: How to write a simple driver in bare metal systems: volatile,Dimiter_Popoff
  || | | |`* Re: How to write a simple driver in bare metal systems: volatile,Niklas Holsti
  || | | | `* Re: How to write a simple driver in bare metal systems: volatile,Dimiter_Popoff
  || | | |  `- Re: How to write a simple driver in bare metal systems: volatile,David Brown
  || | | `- Re: How to write a simple driver in bare metal systems: volatile,pozz
  || | `- Re: How to write a simple driver in bare metal systems: volatile,David Brown
  || `- Re: How to write a simple driver in bare metal systems: volatile, memory barrierClifford Heath
  |`* Re: How to write a simple driver in bare metal systems: volatile, memory barrierantispam
  | `* Re: How to write a simple driver in bare metal systems: volatile,Don Y
  |  `* Re: How to write a simple driver in bare metal systems: volatile, memory barrierantispam
  |   `* Re: How to write a simple driver in bare metal systems: volatile,Don Y
  |    `* Re: How to write a simple driver in bare metal systems: volatile, memory barrierantispam
  |     `* Re: How to write a simple driver in bare metal systems: volatile,Don Y
  |      `* Re: How to write a simple driver in bare metal systems: volatile, memory barrierantispam
  |       `* Re: How to write a simple driver in bare metal systems: volatile,Don Y
  |        `* Re: How to write a simple driver in bare metal systems: volatile, memory barrierantispam
  |         `- Re: How to write a simple driver in bare metal systems: volatile,Don Y
  `- Re: How to write a simple driver in bare metal systems: volatile,David Brown

Pages:123
Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on

<k%HdJ.3$no7.2@fx15.iad>

 copy mid

https://www.novabbs.com/devel/article-flat.php?id=695&group=comp.arch.embedded#695

 copy link   Newsgroups: comp.arch.embedded
Path: i2pn2.org!i2pn.org!paganini.bofh.team!news.dns-netz.com!news.freedyn.net!newsreader4.netcologne.de!news.netcologne.de!peer02.ams1!peer.ams1.xlned.com!news.xlned.com!peer01.iad!feed-me.highwinds-media.com!news.highwinds-media.com!fx15.iad.POSTED!not-for-mail
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:91.0)
Gecko/20100101 Thunderbird/91.2.1
Subject: Re: How to write a simple driver in bare metal systems: volatile,
memory barrier, critical sections and so on
Content-Language: en-US
Newsgroups: comp.arch.embedded
References: <skvcnd$5dv$1@dont-email.me> <sl1c3a$dfr$1@dont-email.me>
<sl6s79$jt1$1@dont-email.me>
From: Rich...@Damon-Family.org (Richard Damon)
In-Reply-To: <sl6s79$jt1$1@dont-email.me>
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
Lines: 38
Message-ID: <k%HdJ.3$no7.2@fx15.iad>
X-Complaints-To: abuse@easynews.com
Organization: Forte - www.forteinc.com
X-Complaints-Info: Please be sure to forward a copy of ALL headers otherwise we will be unable to process your complaint properly.
Date: Mon, 25 Oct 2021 20:31:12 -0400
X-Received-Bytes: 2846
 by: Richard Damon - Tue, 26 Oct 2021 00:31 UTC

On 10/25/21 2:15 PM, pozz wrote:
> Il 23/10/2021 18:09, David Brown ha scritto:
> [...]
>> Marking "in" and "buf" as volatile is /far/ better than using a critical
>> section, and likely to be more efficient than a memory barrier.  You can
>> also use volatileAccess rather than making buf volatile, and it is often
>> slightly more efficient to cache volatile variables in a local variable
>> while working with them.
>
> I think I got your point, but I'm wondering why there are plenty of
> examples of ring-buffer implementations that don't use volatile at all,
> even if the author explicitly refers to interrupts and multithreading.
>
> Just an example[1] by Quantum Leaps. It promises to be a *lock-free* (I
> think thread-safe) ring-buffer implementation in the scenario of single
> producer/single consumer (that is my scenario too).
>
> In the source code there's no use of volatile. I could call
> RingBuf_put() in my rx uart ISR and call RingBuf_get() in my mainloop code.
>
> From what I learned from you, this code usually works, but the standard
> doesn't guarantee it will work with every old, current and future
> compilers.
>
>
>
> [1] https://github.com/QuantumLeaps/lock-free-ring-buffer

The issue with not using 'volatile' (or some similar memory barrier) is
that without it, the implementation is allowed to delay the actual write
of the results into the variable.

If optimization is limited to just within a single translation unit, you
can force it to work by having the execution path leave the translation
unit, but with whole program optimization, it is theoretically possible
that the implementation sees that the thread of execution NEVER needs it
to be spilled out of the registers to memory, so the ISR will never see
the change.

Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on

<sla605$b7m$1@z-news.wcss.wroc.pl>

 copy mid

https://www.novabbs.com/devel/article-flat.php?id=702&group=comp.arch.embedded#702

 copy link   Newsgroups: comp.arch.embedded
Path: i2pn2.org!i2pn.org!weretis.net!feeder8.news.weretis.net!3.eu.feeder.erje.net!feeder.erje.net!newsfeed.pionier.net.pl!pwr.wroc.pl!news.wcss.wroc.pl!not-for-mail
From: antis...@math.uni.wroc.pl
Newsgroups: comp.arch.embedded
Subject: Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on
Date: Wed, 27 Oct 2021 00:20:21 +0000 (UTC)
Organization: Politechnika Wroclawska
Lines: 70
Message-ID: <sla605$b7m$1@z-news.wcss.wroc.pl>
References: <skvcnd$5dv$1@dont-email.me> <sl3d4h$17d3$1@gioia.aioe.org> <sl3f65$jdl$1@dont-email.me> <sl4dm3$5ut$1@dont-email.me> <sl77p9$6gt$1@z-news.wcss.wroc.pl> <sl7arc$v0i$1@dont-email.me>
NNTP-Posting-Host: hera.math.uni.wroc.pl
X-Trace: z-news.wcss.wroc.pl 1635294021 11510 156.17.86.1 (27 Oct 2021 00:20:21 GMT)
X-Complaints-To: abuse@news.pwr.wroc.pl
NNTP-Posting-Date: Wed, 27 Oct 2021 00:20:21 +0000 (UTC)
Cancel-Lock: sha1:Pj6qFNBQ+iq0DKP3aCqtyIbaDmg=
User-Agent: tin/2.4.3-20181224 ("Glen Mhor") (UNIX) (Linux/4.19.0-10-amd64 (x86_64))
 by: antis...@math.uni.wroc.pl - Wed, 27 Oct 2021 00:20 UTC

Don Y <blockedofcourse@foo.invalid> wrote:
> On 10/25/2021 2:32 PM, antispam@math.uni.wroc.pl wrote:
> > Don Y <blockedofcourse@foo.invalid> wrote:
> >> On 10/24/2021 4:14 AM, Dimiter_Popoff wrote:
> >>>> Disable interrupts while accessing the fifo. you really have to.
> >>>> alternatively you'll often get away not using a fifo at all,
> >>>> unless you're blocking for a long while in some part of the code.
> >>>
> >>> Why would you do that. The fifo write pointer is only modified by
> >>> the interrupt handler, the read pointer is only modified by the
> >>> interrupted code. Has been done so for times immemorial.
> >>
> >> The OPs code doesn't differentiate between FIFO full and empty.
> >
> > If you read carefuly what he wrote you would know that he does.
> > The trick he uses is that his indices may point outside buffer:
> > empty is equal indices, full is difference equal to buffer
>
> Doesn't matter as any index can increase by any amount and
> invalidate the "reality" of the buffer's contents (i.e.
> actual number of characters that have been tranfered to
> that region of memory).

AFAIK OP considers this not a problem in his application.
Of course, if such changes were a problem he would need to
add test preventing writing to full buffer (he already have
test preventing reading from empty buffer).

> Buffer size is 128, for example. in is 127, out is 127.
> What's that mean?

Empty buffer.

> Can you tell me what has happened prior
> to this point in time? Have 127 characters been received?
> Or, 383? Or, 1151?

Does not matter.

> How many characters have been removed from the buffer?
> (same numeric examples).

The same as has been stored. Point is that received is
always bigger or equal to removed and does not exceed
removed by more than 128. So you can exactly recover
difference between received and removed.

> The biggest practical limitation is that of expectations of
> other developers who may inherit (or copy) his code expecting
> the FIFO to be "well behaved".

Well, personally I would avoid storing to full buffer. And
even on small MCU it is not clear for me if his "savings"
are worth it. But his core design is sound.

Concerning other developers, I always working on assumption
that code is "as is" and any claim what it is doing are of
limited value unless there is convincing argument (proof
or outline of proof) what it is doing. Fact that code
worked well in past system(s) is rather unconvincing.
I have seen small (few lines) pieces of code that contained
multiple bugs. And that code was in "production" use
for several years and passed its tests.

Certainly code like FIFO-s where there are multiple tradeofs
and actual code tends to be relatively small deserves
examination before re-use.

--
Waldek Hebisch

Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on

<sla7tl$gqn$1@dont-email.me>

 copy mid

https://www.novabbs.com/devel/article-flat.php?id=703&group=comp.arch.embedded#703

 copy link   Newsgroups: comp.arch.embedded
Path: i2pn2.org!i2pn.org!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: blockedo...@foo.invalid (Don Y)
Newsgroups: comp.arch.embedded
Subject: Re: How to write a simple driver in bare metal systems: volatile,
memory barrier, critical sections and so on
Date: Tue, 26 Oct 2021 17:52:59 -0700
Organization: A noiseless patient Spider
Lines: 150
Message-ID: <sla7tl$gqn$1@dont-email.me>
References: <skvcnd$5dv$1@dont-email.me> <sl3d4h$17d3$1@gioia.aioe.org>
<sl3f65$jdl$1@dont-email.me> <sl4dm3$5ut$1@dont-email.me>
<sl77p9$6gt$1@z-news.wcss.wroc.pl> <sl7arc$v0i$1@dont-email.me>
<sla605$b7m$1@z-news.wcss.wroc.pl>
Mime-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Wed, 27 Oct 2021 00:53:09 -0000 (UTC)
Injection-Info: reader02.eternal-september.org; posting-host="9f6b31ee7e3a0fa5f8eefef02767aa27";
logging-data="17239"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18BkQJwSb+4WAfNN2HL3ZyY"
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101
Thunderbird/52.1.1
Cancel-Lock: sha1:OA39KLduhx/dvRk/fF91i4dFU94=
In-Reply-To: <sla605$b7m$1@z-news.wcss.wroc.pl>
Content-Language: en-US
 by: Don Y - Wed, 27 Oct 2021 00:52 UTC

On 10/26/2021 5:20 PM, antispam@math.uni.wroc.pl wrote:
> Don Y <blockedofcourse@foo.invalid> wrote:
>> On 10/25/2021 2:32 PM, antispam@math.uni.wroc.pl wrote:
>>> Don Y <blockedofcourse@foo.invalid> wrote:
>>>> On 10/24/2021 4:14 AM, Dimiter_Popoff wrote:
>>>>>> Disable interrupts while accessing the fifo. you really have to.
>>>>>> alternatively you'll often get away not using a fifo at all,
>>>>>> unless you're blocking for a long while in some part of the code.
>>>>>
>>>>> Why would you do that. The fifo write pointer is only modified by
>>>>> the interrupt handler, the read pointer is only modified by the
>>>>> interrupted code. Has been done so for times immemorial.
>>>>
>>>> The OPs code doesn't differentiate between FIFO full and empty.
>>>
>>> If you read carefuly what he wrote you would know that he does.
>>> The trick he uses is that his indices may point outside buffer:
>>> empty is equal indices, full is difference equal to buffer
>>
>> Doesn't matter as any index can increase by any amount and
>> invalidate the "reality" of the buffer's contents (i.e.
>> actual number of characters that have been tranfered to
>> that region of memory).
>
> AFAIK OP considers this not a problem in his application.

And I don't think I have to test for division by zero -- as
*my* code is the code that is passing numerator and denominator
to that operator, right?

Can you remember all of the little assumptions you've made in
any non-trivial piece of code -- a week later? a month later?
6 months later (when a bug manifests or a feature upgrade
is requested)?

Do not check the inputs of routines for validity -- assume everything is
correct (cuz YOU wrote it to be so, right?).

Do not handle error conditions -- because they can't exist (because
you wrote the code and feel confident that you've anticipated
every contingency -- including those for future upgrades).

Ignore compiler warnings -- surely you know better than a silly
"generic" program!

Would you hire someone who viewed your product's quality (and
your reputation) in this regard?

> Of course, if such changes were a problem he would need to
> add test preventing writing to full buffer (he already have
> test preventing reading from empty buffer).
>
>> Buffer size is 128, for example. in is 127, out is 127.
>> What's that mean?
>
> Empty buffer.

No, it means you can't sort out *if* there have been any characters
received, based solely on this fact (and, what other facts are there
to observe?)

>> Can you tell me what has happened prior
>> to this point in time? Have 127 characters been received?
>> Or, 383? Or, 1151?
>
> Does not matter.

Of course it does! Something has happened that the code MIGHT have
detected in other circumstances (e.g., if uart_task had been invoked
more frequently). The world has changed and the code doesn't know it.
Why write code that only *sometimes* works?

>> How many characters have been removed from the buffer?
>> (same numeric examples).
>
> The same as has been stored. Point is that received is
> always bigger or equal to removed and does not exceed
> removed by more than 128. So you can exactly recover
> difference between received and removed.

If it can wrap, then "some data" can look like "no data".
If "no data", then NOTHING has been received -- from the
viewpoint of the code.

Tell me what prevents 256 characters from being received
after .in (and .out) are initially 0 -- without any
indication of their presence. What "limits" the difference
to "128"? Do you see any conditionals in the code that
do so? Is there some magic in the hardware that enforces
this?

This is how you end up with bugs in your code. The sorts
of bugs that you can witness -- with your own eyes -- and
never reproduce (until the code has been released and
lots of customers' eyes witness it as well).

>> The biggest practical limitation is that of expectations of
>> other developers who may inherit (or copy) his code expecting
>> the FIFO to be "well behaved".
>
> Well, personally I would avoid storing to full buffer. And
> even on small MCU it is not clear for me if his "savings"
> are worth it. But his core design is sound.
>
> Concerning other developers, I always working on assumption
> that code is "as is" and any claim what it is doing are of
> limited value unless there is convincing argument (proof
> or outline of proof) what it is doing.

Ever worked on 100KLoC projects? 500KLoC? Do you personally examine
the entire codebase before you get started? Do you purchase source
licenses for every library that you rely upon in your design?
(or, do you just assume software vendors are infallible?)

How would you feel if a fellow worker told you "yeah, the previous
guy had a habit of cutting corners in his FIFO management code"?
Or, "the previous guy always assumed malloc would succeed and
didn't even build an infrastructure to address the possibility
of it failing"

You could, perhaps, grep(1) for "malloc" or "FIFO" and manually
examine those code fragments. What about division operators?
Or, verifying that data types never overflow their limits? Or...

> Fact that code
> worked well in past system(s) is rather unconvincing.
> I have seen small (few lines) pieces of code that contained
> multiple bugs. And that code was in "production" use
> for several years and passed its tests.
>
> Certainly code like FIFO-s where there are multiple tradeofs
> and actual code tends to be relatively small deserves
> examination before re-use.

It's not "FIFO code". It's a UART driver. Do you examine every piece
of code that might *contain* a FIFO? How do you know that there *is* a FIFO
in a piece of code -- without manually inspecting it? What if it is a
FIFO mechanism but not explicitly named as a FIFO?

One wants to be able to move towards the goal of software *components*.
You don't want to have to inspect the design of every *diode* that
you use; you want to look at it's overall specifications and decide
if those fit your needs.

Unlikely that this code will describe itself as "works well enough
SOME of the time..."

And, when/if you stumble on such faults, good luck explaining to
your customer why it's going to take longer to fix and retest the
*existing* codebase before you can get on with your modifications...

Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on

<slannf$qg4$1@z-news.wcss.wroc.pl>

 copy mid

https://www.novabbs.com/devel/article-flat.php?id=705&group=comp.arch.embedded#705

 copy link   Newsgroups: comp.arch.embedded
Path: i2pn2.org!i2pn.org!weretis.net!feeder8.news.weretis.net!2.eu.feeder.erje.net!feeder.erje.net!newsfeed.pionier.net.pl!pwr.wroc.pl!news.wcss.wroc.pl!not-for-mail
From: antis...@math.uni.wroc.pl
Newsgroups: comp.arch.embedded
Subject: Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on
Date: Wed, 27 Oct 2021 05:22:55 +0000 (UTC)
Organization: Politechnika Wroclawska
Lines: 313
Message-ID: <slannf$qg4$1@z-news.wcss.wroc.pl>
References: <skvcnd$5dv$1@dont-email.me> <sl3d4h$17d3$1@gioia.aioe.org> <sl3f65$jdl$1@dont-email.me> <sl4dm3$5ut$1@dont-email.me> <sl77p9$6gt$1@z-news.wcss.wroc.pl> <sl7arc$v0i$1@dont-email.me> <sla605$b7m$1@z-news.wcss.wroc.pl> <sla7tl$gqn$1@dont-email.me>
NNTP-Posting-Host: hera.math.uni.wroc.pl
X-Trace: z-news.wcss.wroc.pl 1635312175 27140 156.17.86.1 (27 Oct 2021 05:22:55 GMT)
X-Complaints-To: abuse@news.pwr.wroc.pl
NNTP-Posting-Date: Wed, 27 Oct 2021 05:22:55 +0000 (UTC)
Cancel-Lock: sha1:V3ji2MaYerz1qamNj3eFw5s601Q=
User-Agent: tin/2.4.3-20181224 ("Glen Mhor") (UNIX) (Linux/4.19.0-10-amd64 (x86_64))
 by: antis...@math.uni.wroc.pl - Wed, 27 Oct 2021 05:22 UTC

Don Y <blockedofcourse@foo.invalid> wrote:
> On 10/26/2021 5:20 PM, antispam@math.uni.wroc.pl wrote:
> > Don Y <blockedofcourse@foo.invalid> wrote:
> >> On 10/25/2021 2:32 PM, antispam@math.uni.wroc.pl wrote:
> >>> Don Y <blockedofcourse@foo.invalid> wrote:
> >>>> On 10/24/2021 4:14 AM, Dimiter_Popoff wrote:
> >>>>>> Disable interrupts while accessing the fifo. you really have to.
> >>>>>> alternatively you'll often get away not using a fifo at all,
> >>>>>> unless you're blocking for a long while in some part of the code.
> >>>>>
> >>>>> Why would you do that. The fifo write pointer is only modified by
> >>>>> the interrupt handler, the read pointer is only modified by the
> >>>>> interrupted code. Has been done so for times immemorial.
> >>>>
> >>>> The OPs code doesn't differentiate between FIFO full and empty.
> >>>
> >>> If you read carefuly what he wrote you would know that he does.
> >>> The trick he uses is that his indices may point outside buffer:
> >>> empty is equal indices, full is difference equal to buffer
> >>
> >> Doesn't matter as any index can increase by any amount and
> >> invalidate the "reality" of the buffer's contents (i.e.
> >> actual number of characters that have been tranfered to
> >> that region of memory).
> >
> > AFAIK OP considers this not a problem in his application.
>
> And I don't think I have to test for division by zero -- as
> *my* code is the code that is passing numerator and denominator
> to that operator, right?

Well, I do not test for zero if I know that divisor must be
nonzero. To put it differently, having zero in such place
is a bug and there is already enough machinery so that
such bug will not remain undetected. Having extra test
adds no value.

OTOH is zero is possible, then handling it is part of program
logic and test is needed to take correct action.

> Can you remember all of the little assumptions you've made in
> any non-trivial piece of code -- a week later? a month later?
> 6 months later (when a bug manifests or a feature upgrade
> is requested)?

Well, my normal practice is that there are no "little assumptions".
To put it differently, code is structured to make things clear,
even if this requires more code than some "clever" solution.
There may be "big assumptions", that is highly nontrivial facts
used by the code. Some of them are considered "well known",
with proper naming in code it is easy to recall them years later.
Some deserve comments/referece. In most of may coding I have
pretty comfortable situation: for human there is quite clear
what is valid and what is invalid. So code makes a lot of
effort to handle valid (but possibly quite unusual) cases

> Do not check the inputs of routines for validity -- assume everything is
> correct (cuz YOU wrote it to be so, right?).

Well, correct inputs are part of contract. Some things (like
array indices inside bounds) are checked, but in general you can
expect garbage if you pass incorrect input. Most of my code is
of sort that called routine can not really check validity of input
(there are complex invariants). Note: here I am talking mostly
about my non-embedded code (which is majority of my coding).
In most of may coding I have pretty comfortable situation: for
human there is quite clear what is valid and what is invalid.
So code makes a lot of effort to handle valid (but possibly quite
unusual) cases. User input is normally checked to give sensible
error message, but some things are deemed to tricky/expensive
to check. Other routines are deemed "system level", and here
there us up to user/caller to respect the contract.

My embedded code consists of rather small systems, and normally
there are no explicit validity checks. To clarify: when system
receives commands it recognizes and handles valid commands.
So there is implicit check: anything not recognized as valid
is invalid. OTOH frequently there is nothing to do in case
of errors: if there are no display to print error message,
no persistent store to log erreor and shuting down is not helpful,
then what else potential error handler would do?

I do not check if 12-bit ADC really returns numbers in range.
My 'print_byte' routine takes integer argument and blindly
truncates it to 8-bit without worring about possible
spurious upper bits. "Safety critical" folks my be worried
by such practice, but my embedded code is fairly non-critical.

> Do not handle error conditions -- because they can't exist (because
> you wrote the code and feel confident that you've anticipated
> every contingency -- including those for future upgrades).
>
> Ignore compiler warnings -- surely you know better than a silly
> "generic" program!
>
> Would you hire someone who viewed your product's quality (and
> your reputation) in this regard?

Well, you do not know what OP code is doing. I would prefer
my code to be robust and I feel that I am doing resonably
well here. OTOH, coming back to serial comunication, it
is not hard to design communication protocal such that in
normal operation there is no possibility for buffer
overflow. It would still make sense to add a single line
to say drop excess characters. But it does not make
sense to make big story of lack of this line. In particular
issue that OP wanted to discuss is still valid.

> > Of course, if such changes were a problem he would need to
> > add test preventing writing to full buffer (he already have
> > test preventing reading from empty buffer).
> >
> >> Buffer size is 128, for example. in is 127, out is 127.
> >> What's that mean?
> >
> > Empty buffer.
>
> No, it means you can't sort out *if* there have been any characters
> received, based solely on this fact (and, what other facts are there
> to observe?)

Of course you can connect to system and change values of variables
in debugger, so specific values mean nothing. I am telling
you what to protocal is. If all part of system (including parts
that OP skipped) obey the protocal, then you have meaning above.
If something misbehaves (say cosmic ray flipped a bit), it does
not mean that protocal is incorrect. Simply _if_ probability
of misbehaviour is too high you need to fix the system (add
radiation shielding, appropiate seal to avoid tampering with
internals, extra checks inside, etc). But what/if to fix
something is for OP to decide.

> >> Can you tell me what has happened prior
> >> to this point in time? Have 127 characters been received?
> >> Or, 383? Or, 1151?
> >
> > Does not matter.
>
> Of course it does! Something has happened that the code MIGHT have
> detected in other circumstances (e.g., if uart_task had been invoked
> more frequently). The world has changed and the code doesn't know it.
> Why write code that only *sometimes* works?

All code works only sometimes. Parafrazing famous answer to
Napoleon: fisrt you need a processor. There are a lot of
conditons so that code works as intended. Granted, I would
not skip needed check in real code. But this is obvious
thing to add. You are somewhat making OP code as "broken
beyond repair". Well, as discussion showed, OP had problem
using "volatile" and that IMHO is much more important to
fix.

> >> How many characters have been removed from the buffer?
> >> (same numeric examples).
> >
> > The same as has been stored. Point is that received is
> > always bigger or equal to removed and does not exceed
> > removed by more than 128. So you can exactly recover
> > difference between received and removed.
>
> If it can wrap, then "some data" can look like "no data".
> If "no data", then NOTHING has been received -- from the
> viewpoint of the code.
>
> Tell me what prevents 256 characters from being received
> after .in (and .out) are initially 0 -- without any
> indication of their presence. What "limits" the difference
> to "128"? Do you see any conditionals in the code that
> do so? Is there some magic in the hardware that enforces
> this?

That is the protocol. How to avoid violation is different
matter: dropping characters _may_ be solution. But dropping
characters means that some data is lost, and how to deal
with lost data is different issue. As is OP code will loose
some old data. It is OP problem to decide which failure
mode is more problematic and how much extra checks are
needed.

> This is how you end up with bugs in your code. The sorts
> of bugs that you can witness -- with your own eyes -- and
> never reproduce (until the code has been released and
> lots of customers' eyes witness it as well).


Click here to read the complete article
Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on

<slht2f$1kj$1@dont-email.me>

 copy mid

https://www.novabbs.com/devel/article-flat.php?id=706&group=comp.arch.embedded#706

 copy link   Newsgroups: comp.arch.embedded
Path: i2pn2.org!i2pn.org!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: blockedo...@foo.invalid (Don Y)
Newsgroups: comp.arch.embedded
Subject: Re: How to write a simple driver in bare metal systems: volatile,
memory barrier, critical sections and so on
Date: Fri, 29 Oct 2021 15:36:49 -0700
Organization: A noiseless patient Spider
Lines: 112
Message-ID: <slht2f$1kj$1@dont-email.me>
References: <skvcnd$5dv$1@dont-email.me> <sl3d4h$17d3$1@gioia.aioe.org>
<sl3f65$jdl$1@dont-email.me> <sl4dm3$5ut$1@dont-email.me>
<sl77p9$6gt$1@z-news.wcss.wroc.pl> <sl7arc$v0i$1@dont-email.me>
<sla605$b7m$1@z-news.wcss.wroc.pl> <sla7tl$gqn$1@dont-email.me>
<slannf$qg4$1@z-news.wcss.wroc.pl>
Mime-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 8bit
Injection-Date: Fri, 29 Oct 2021 22:37:04 -0000 (UTC)
Injection-Info: reader02.eternal-september.org; posting-host="8d323a0d7d78bc3aeb2ce6b04fb2c2c9";
logging-data="1683"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18LYLBbiflBESBLb8vpLv1/"
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101
Thunderbird/52.1.1
Cancel-Lock: sha1:FwSh05WJZeNapQgS1EhaIosTsEo=
In-Reply-To: <slannf$qg4$1@z-news.wcss.wroc.pl>
Content-Language: en-US
 by: Don Y - Fri, 29 Oct 2021 22:36 UTC

On 10/26/2021 10:22 PM, antispam@math.uni.wroc.pl wrote:
>> One wants to be able to move towards the goal of software *components*.
>> You don't want to have to inspect the design of every *diode* that
>> you use; you want to look at it's overall specifications and decide
>> if those fit your needs.
>
> Sure, I would love to see really reusable components. But IMHO we
> are quite far from that.

Do you use the standard libraries? Aren't THEY components?
You rely on the compiler to decide how to divide X by Y -- instead
of writing your own division routine. How often do you reimplement
?printf() to avoid all of the bloat that typically accompanies it?
(when was the last time you needed ALL of those format specifiers
in an application? And modifiers?

> There are some things which are reusable
> if you accept modest to severe overhead.

What you need is components with varying characteristics.
You can buy diodes with all sorts of current carrying capacities,
PIVs, package styles, etc. But, they all still perform the
same function. Why so many different part numbers? Why not
just use the biggest, baddest diode in ALL your circuits?

I.e., we readily accept differences in "standard components"
in other disciplines; why not when it comes to software
modules?

> For example things tends
> to compose nicely if you dynamically allocate everything and use
> garbage collection. But performace cost may be substantial.
> And in embedded setting garbage collection may be unacceptable.
> In some cases I have found out that I can get much better
> speed joing things that could be done as composition of library
> operations into single big routine.

Sure, but now you're tuning a solution to a specific problem.
I've designed custom chips to solve particular problems.
But, they ONLY solve those particular problems! OTOH,
I use lots of OTC components in my designs because those have
been designed (for the most part) with an eye towards
meeting a variety of market needs.

> In other cases I fixed
> bugs by replacing composition of library routines by a single
> routine: there were interactions making simple composition
> incorrect. Correct alterantive was single routine.
>
> As I wrote my embedded programs are simple and small. But I
> use almost no external libraries. Trying some existing libraries
> I have found out that some produce rather large programs, linking
> in a lot of unneeded stuff.

Because they try to address a variety of solution spaces without
trying to be "optimal" for any. You trade flexibility/capability
for speed/performance/etc.

> Of course, writing for scratch
> will not scale to bigger programs. OTOH, I feel that with
> proper tooling it would be possible to retain efficiency and
> small code size at least for large class of microntroller
> programs (but existing tools and libraries do not support this).

Templates are an attempt in this direction. Allowing a class of
problems to be solved once and then tailored to the specific
application.

But, personal experience is where you win the most. You write
your second or third UART driver and start realizing that you
could leverage a previous design if you'd just thought it out
more fully -- instead of tailoring it to the specific needs
of the original application.

And, as you EXPECT to be reusing it in other applications (as
evidenced by the fact that it's your third time writing the same
piece of code!), you anticipate what those *might* need and
think about how to implement those features "economically".

It's rare that an application is *so* constrained that it can't
afford a couple of extra lines of code, here and there. If
you've considered efficiency in the design of your algorithms,
then these little bits of inefficiency will be below the noise floor.

>> Unlikely that this code will describe itself as "works well enough
>> SOME of the time..."
>>
>> And, when/if you stumble on such faults, good luck explaining to
>> your customer why it's going to take longer to fix and retest the
>> *existing* codebase before you can get on with your modifications...
>
> Commercial vendors like to say how good their progam are. But
> market reality is that program my be quite bad and still sell.

The same is true of FOSS -- despite the claim that many eyes (may)
have looked at it (suggesting that bugs would have been caught!)

From "KLEE: Unassisted and Automatic Generation of High-Coverage
Tests for Complex Systems Programs":

KLEE finds important errors in heavily-tested code. It
found ten fatal errors in COREUTILS (including three
that had escaped detection for 15 years), which account
for more crashing bugs than were reported in 2006, 2007
and 2008 combined. It further found 24 bugs in BUSYBOX, 21
bugs in MINIX, and a security vulnerability in HISTAR– a
total of 56 serious bugs.

Ooops! I wonder how many FOSS *eyes* missed those errors?

Every time you reinvent a solution, you lose much of the benefit
of the previous TESTED solution.

Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on

<sln6qu$n86$1@z-news.wcss.wroc.pl>

 copy mid

https://www.novabbs.com/devel/article-flat.php?id=710&group=comp.arch.embedded#710

 copy link   Newsgroups: comp.arch.embedded
Path: i2pn2.org!i2pn.org!weretis.net!feeder8.news.weretis.net!border2.nntp.ams1.giganews.com!nntp.giganews.com!newsfeed.neostrada.pl!unt-exc-02.news.neostrada.pl!wsisiz.edu.pl!news.icm.edu.pl!newsfeed.pionier.net.pl!pwr.wroc.pl!news.wcss.wroc.pl!not-for-mail
From: antis...@math.uni.wroc.pl
Newsgroups: comp.arch.embedded
Subject: Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on
Date: Sun, 31 Oct 2021 22:54:22 +0000 (UTC)
Organization: Politechnika Wroclawska
Lines: 237
Message-ID: <sln6qu$n86$1@z-news.wcss.wroc.pl>
References: <skvcnd$5dv$1@dont-email.me> <sl3d4h$17d3$1@gioia.aioe.org> <sl3f65$jdl$1@dont-email.me> <sl4dm3$5ut$1@dont-email.me> <sl77p9$6gt$1@z-news.wcss.wroc.pl> <sl7arc$v0i$1@dont-email.me> <sla605$b7m$1@z-news.wcss.wroc.pl> <sla7tl$gqn$1@dont-email.me> <slannf$qg4$1@z-news.wcss.wroc.pl> <slht2f$1kj$1@dont-email.me>
NNTP-Posting-Host: hera.math.uni.wroc.pl
X-Trace: z-news.wcss.wroc.pl 1635720862 23814 156.17.86.1 (31 Oct 2021 22:54:22 GMT)
X-Complaints-To: abuse@news.pwr.wroc.pl
NNTP-Posting-Date: Sun, 31 Oct 2021 22:54:22 +0000 (UTC)
Cancel-Lock: sha1:MKUcLLLGRsXl/XeFmVVpNiVIy5Y=
User-Agent: tin/2.4.3-20181224 ("Glen Mhor") (UNIX) (Linux/4.19.0-10-amd64 (x86_64))
 by: antis...@math.uni.wroc.pl - Sun, 31 Oct 2021 22:54 UTC

Don Y <blockedofcourse@foo.invalid> wrote:
> On 10/26/2021 10:22 PM, antispam@math.uni.wroc.pl wrote:
> >> One wants to be able to move towards the goal of software *components*.
> >> You don't want to have to inspect the design of every *diode* that
> >> you use; you want to look at it's overall specifications and decide
> >> if those fit your needs.
> >
> > Sure, I would love to see really reusable components. But IMHO we
> > are quite far from that.
>
> Do you use the standard libraries?

Yes, I uses libraries when appropriate.

> Aren't THEY components?

Well, some folks expect more from components than from
traditional libraries. Some evan claim to deliver.
However, libraries have limitations and ATM I see nothing
that fundamentally change situation.

> You rely on the compiler to decide how to divide X by Y -- instead
> of writing your own division routine.

Well, normally in C code I relay on compiler provied division.
To say the truth, my MCU code uses division sparingly, only
when I can not avoid it. OTOH I also use languages with
multiprecision integers. In one case I use complier provided
routines, but I am provider of modifed compiler and modification
includes replacement of division routine. In other case I
override compiler supplied division routine by my own (which
in turn sends real work to external library).

> How often do you reimplement
> ?printf() to avoid all of the bloat that typically accompanies it?

I did that once (for OS kernel where standard library would not
work). If needed I can reuse it. On PC-s I am not worried by
bloat due to printf. OTOH, on MCU-s I am not sure if I ever used
printf. Rather, printing was done by specialized routines
either library provided or my own.

> (when was the last time you needed ALL of those format specifiers
> in an application? And modifiers?
>
> > There are some things which are reusable
> > if you accept modest to severe overhead.
>
> What you need is components with varying characteristics.
> You can buy diodes with all sorts of current carrying capacities,
> PIVs, package styles, etc. But, they all still perform the
> same function. Why so many different part numbers? Why not
> just use the biggest, baddest diode in ALL your circuits?

I heard such electronic analogies many times. But they miss
important point: there is no way for me to make my own diode,
I am stuck with what is available on the market. And diode
is logically pretty simple component, yet we need many kinds.

> I.e., we readily accept differences in "standard components"
> in other disciplines; why not when it comes to software
> modules?

Well, software is _much_ more compilcated than physical
engineering artifacts. Physical thing may have 10000 joints,
but if joints are identical, then this is moral equivalent of
simple loop that just iterates fixed number of times.
At software level number of possible pre-composed blocks
is so large that it is infeasible to deliver all of them.
Classic trick it to parametrize. However even if you
parametrize there are hundreds of design decisions going
into relatively small piece of code. If you expose all
design decisions then user as well may write his/her own
code because complexity will be similar. So normaly
parametrization is limited and there will be users who
find hardcoded desion choices inadequate.

Another things is that current tools are rather weak
at supporting parametrization.

> > For example things tends
> > to compose nicely if you dynamically allocate everything and use
> > garbage collection. But performace cost may be substantial.
> > And in embedded setting garbage collection may be unacceptable.
> > In some cases I have found out that I can get much better
> > speed joing things that could be done as composition of library
> > operations into single big routine.
>
> Sure, but now you're tuning a solution to a specific problem.
> I've designed custom chips to solve particular problems.
> But, they ONLY solve those particular problems! OTOH,
> I use lots of OTC components in my designs because those have
> been designed (for the most part) with an eye towards
> meeting a variety of market needs.

Maybe I made wrong impression, I think some explanation is in
place here. I am trying to make my code reusable. For my
problems performance is important part of reusablity: our
capability to solve problem is limited by performance and with
better perfomance users can solve bigger problems. I am
re-using code that I can and I would re-use more if I could
but there there are technical obstacles. Also, while I am
trying to make my code reusable, there are intrusive
design decision which may interfere with your possiobility
and willingness to re-use.

In slightly different spirit: in another thread you wrote
about accessing disc without OS file cache. Here I
normaly depend on OS and OS file caching is big thing.
It is not perfect, but OS (OK, at least Linux) is doing
this resonably well I have no temptation to avoid it.
And I appreciate that with OS cache performance is
usually much better that would be "without cache".
OTOH, I routinly avoid stdio for I/O critical things
(so no printf in I/O critical code).

> > In other cases I fixed
> > bugs by replacing composition of library routines by a single
> > routine: there were interactions making simple composition
> > incorrect. Correct alterantive was single routine.
> >
> > As I wrote my embedded programs are simple and small. But I
> > use almost no external libraries. Trying some existing libraries
> > I have found out that some produce rather large programs, linking
> > in a lot of unneeded stuff.
>
> Because they try to address a variety of solution spaces without
> trying to be "optimal" for any. You trade flexibility/capability
> for speed/performance/etc.

I think that this is more subtle: libraries frequently force some
way of doing things. Which may be good if you try to quickly roll
solution and are within capabilities of library. But if you
need/want different design, then library may be too inflexible
to deliver it.

> > Of course, writing for scratch
> > will not scale to bigger programs. OTOH, I feel that with
> > proper tooling it would be possible to retain efficiency and
> > small code size at least for large class of microntroller
> > programs (but existing tools and libraries do not support this).
>
> Templates are an attempt in this direction. Allowing a class of
> problems to be solved once and then tailored to the specific
> application.

Yes, templates could help. But they also have problems. One
of them is that (among others) I would like to target STM8
and I have no C++ compiler for STM8. My idea is to create
custom "optimizer/generator" for (annotated) C code.
ATM it is vapourware, but I think it is feasible with
reasonable effort.

> But, personal experience is where you win the most. You write
> your second or third UART driver and start realizing that you
> could leverage a previous design if you'd just thought it out
> more fully -- instead of tailoring it to the specific needs
> of the original application.
>
> And, as you EXPECT to be reusing it in other applications (as
> evidenced by the fact that it's your third time writing the same
> piece of code!), you anticipate what those *might* need and
> think about how to implement those features "economically".
>
> It's rare that an application is *so* constrained that it can't
> afford a couple of extra lines of code, here and there. If
> you've considered efficiency in the design of your algorithms,
> then these little bits of inefficiency will be below the noise floor.

Well, I am not talking about "couple of extra lines". Rather
about IMO substantial fixed overhead. As I wrote, one of my
targets is STM8 with 8k flash, another is MSP430 with 16k flash,
another is STM32 with 16k flash (there are also bigger targets).
One of libraries/frameworks for STM32 after activating few featurs
pulled in about 16k code, this is substantial overhead given
how little features I needed. Other folks reported that for
trivial programs vendor supplied frameworks pulled close to 30k
code. That may be fine if you have bigger device and need features,
but for smaller MCU-s it may be difference between not fitting into
device or (without library) having plenty of free space.

When I tried it Free RTOS for STM32 needed about 8k flash. Which
is fine if you need RTOS. But ATM my designs run without RTOS.

I have found libopencm3 to have small overhead. But is routines
are doing so little that direct register access may give simpler
code.

> >> Unlikely that this code will describe itself as "works well enough
> >> SOME of the time..."
> >>
> >> And, when/if you stumble on such faults, good luck explaining to
> >> your customer why it's going to take longer to fix and retest the
> >> *existing* codebase before you can get on with your modifications...
> >
> > Commercial vendors like to say how good their progam are. But
> > market reality is that program my be quite bad and still sell.
>
> The same is true of FOSS -- despite the claim that many eyes (may)
> have looked at it (suggesting that bugs would have been caught!)
>
> From "KLEE: Unassisted and Automatic Generation of High-Coverage
> Tests for Complex Systems Programs":
>
> KLEE finds important errors in heavily-tested code. It
> found ten fatal errors in COREUTILS (including three
> that had escaped detection for 15 years), which account
> for more crashing bugs than were reported in 2006, 2007
> and 2008 combined. It further found 24 bugs in BUSYBOX, 21
> bugs in MINIX, and a security vulnerability in HISTAR? a
> total of 56 serious bugs.
>
> Ooops! I wonder how many FOSS *eyes* missed those errors?


Click here to read the complete article
Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on

<slnndl$a9b$1@dont-email.me>

 copy mid

https://www.novabbs.com/devel/article-flat.php?id=711&group=comp.arch.embedded#711

 copy link   Newsgroups: comp.arch.embedded
Path: i2pn2.org!i2pn.org!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: blockedo...@foo.invalid (Don Y)
Newsgroups: comp.arch.embedded
Subject: Re: How to write a simple driver in bare metal systems: volatile,
memory barrier, critical sections and so on
Date: Sun, 31 Oct 2021 20:37:25 -0700
Organization: A noiseless patient Spider
Lines: 349
Message-ID: <slnndl$a9b$1@dont-email.me>
References: <skvcnd$5dv$1@dont-email.me> <sl3d4h$17d3$1@gioia.aioe.org>
<sl3f65$jdl$1@dont-email.me> <sl4dm3$5ut$1@dont-email.me>
<sl77p9$6gt$1@z-news.wcss.wroc.pl> <sl7arc$v0i$1@dont-email.me>
<sla605$b7m$1@z-news.wcss.wroc.pl> <sla7tl$gqn$1@dont-email.me>
<slannf$qg4$1@z-news.wcss.wroc.pl> <slht2f$1kj$1@dont-email.me>
<sln6qu$n86$1@z-news.wcss.wroc.pl>
Mime-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Mon, 1 Nov 2021 03:37:26 -0000 (UTC)
Injection-Info: reader02.eternal-september.org; posting-host="19911e43b3b7286beabebf0c5f46ccf4";
logging-data="10539"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18WVHka3QT+pPo1+nhkGJn1"
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101
Thunderbird/52.1.1
Cancel-Lock: sha1:YpaPFXjIIHamfLMBJ7wt++nTYxk=
In-Reply-To: <sln6qu$n86$1@z-news.wcss.wroc.pl>
Content-Language: en-US
 by: Don Y - Mon, 1 Nov 2021 03:37 UTC

On 10/31/2021 3:54 PM, antispam@math.uni.wroc.pl wrote:
>> Aren't THEY components?
>
> Well, some folks expect more from components than from
> traditional libraries. Some evan claim to deliver.
> However, libraries have limitations and ATM I see nothing
> that fundamentally change situation.

A component is something that you can use as a black box,
without having to reinvent it. It is the epitome of reuse.

>> How often do you reimplement
>> ?printf() to avoid all of the bloat that typically accompanies it?
>
> I did that once (for OS kernel where standard library would not
> work). If needed I can reuse it. On PC-s I am not worried by
> bloat due to printf. OTOH, on MCU-s I am not sure if I ever used
> printf. Rather, printing was done by specialized routines
> either library provided or my own.

You can also create a ?printf() that you can configure at build time to
support the modifiers and specifiers that you know you will need.

Just like you can configure a UART driver to support a FIFO size defined
at configuration, hardware handshaking, software flowcontrol, the
high and low water marks for each of those (as they can be different),
the character to send to request the remote to stop transmitting,
the character you send to request resumption of transmission, which
character YOU will recognize as requesting your Tx channel to pause,
the character (or condition) you will recognize to resume your Tx,
whether or not you will sample the condition codes in the UART, how
you read/write the data register, how you read/write the status register,
etc.

While these sound like lots of options, they are all relatively
trivial additions to the code.

>> (when was the last time you needed ALL of those format specifiers
>> in an application? And modifiers?
>>
>>> There are some things which are reusable
>>> if you accept modest to severe overhead.
>>
>> What you need is components with varying characteristics.
>> You can buy diodes with all sorts of current carrying capacities,
>> PIVs, package styles, etc. But, they all still perform the
>> same function. Why so many different part numbers? Why not
>> just use the biggest, baddest diode in ALL your circuits?
>
> I heard such electronic analogies many times. But they miss
> important point: there is no way for me to make my own diode,

Sure there is! It is just not an efficient way of spending your
resources when you have so many OTS offerings available.

You can design your own processor. Why do you "settle" for an
OTS device (ANS: because there is so little extra added value
you will typically gain from rolling your own vs. the "inefficiency"
of using a COTS offering)

> I am stuck with what is available on the market. And diode
> is logically pretty simple component, yet we need many kinds.
>
>> I.e., we readily accept differences in "standard components"
>> in other disciplines; why not when it comes to software
>> modules?
>
> Well, software is _much_ more compilcated than physical
> engineering artifacts. Physical thing may have 10000 joints,
> but if joints are identical, then this is moral equivalent of
> simple loop that just iterates fixed number of times.

This is the argument in favor of components. You'd much rather
read a comprehensive specification ("datasheet") for a software
component than have to read through all of the code that implements
it. What if it was implemented in some programming language in
which you aren't expert? What if it was a binary "BLOB" and
couldn't be inspected?

> At software level number of possible pre-composed blocks
> is so large that it is infeasible to deliver all of them.

You don't have to deliver all of them. When you wire a circuit,
you still have to *solder* connections, don't you? The
components don't magically glue themselves together...

> Classic trick it to parametrize. However even if you
> parametrize there are hundreds of design decisions going
> into relatively small piece of code. If you expose all
> design decisions then user as well may write his/her own
> code because complexity will be similar. So normaly
> parametrization is limited and there will be users who
> find hardcoded desion choices inadequate.
>
> Another things is that current tools are rather weak
> at supporting parametrization.

Look at a fleshy UART driver and think about how you would decompose
it into N different variants that could be "compile time configurable".
You'll be surprised as to how easy it is. Even if the actual UART
hardware differs from instance to instance.

>>> For example things tends
>>> to compose nicely if you dynamically allocate everything and use
>>> garbage collection. But performace cost may be substantial.
>>> And in embedded setting garbage collection may be unacceptable.
>>> In some cases I have found out that I can get much better
>>> speed joing things that could be done as composition of library
>>> operations into single big routine.
>>
>> Sure, but now you're tuning a solution to a specific problem.
>> I've designed custom chips to solve particular problems.
>> But, they ONLY solve those particular problems! OTOH,
>> I use lots of OTC components in my designs because those have
>> been designed (for the most part) with an eye towards
>> meeting a variety of market needs.
>
> Maybe I made wrong impression, I think some explanation is in
> place here. I am trying to make my code reusable. For my
> problems performance is important part of reusablity: our
> capability to solve problem is limited by performance and with
> better perfomance users can solve bigger problems. I am
> re-using code that I can and I would re-use more if I could
> but there there are technical obstacles. Also, while I am
> trying to make my code reusable, there are intrusive
> design decision which may interfere with your possiobility
> and willingness to re-use.

If you don't know where the design is headed, then you can't
pick the components that it will need.

I approach a design from the top (down) and bottom (up). This
lets me gauge the types of information that I *may* have
available from the hardware -- so I can sort out how to
approach those limitations from above. E.g., if I can't
control the data rate of a comm channel, then I either have
to ensure I can catch every (complete) message *or* design a
protocol that lets me detect when I've missed something.

There are costs to both approaches. If I dedicate resource to
ensuring I don't miss anything, then some other aspect of the
design will bear that cost. If I rely on detecting missed
messages, then I have to put a figure on their relative
likelihood so my device doesn't fail to provide its desired
functionality (because it is always missing one or two characters
out of EVERY message -- and, thus, sees NO messages).

> In slightly different spirit: in another thread you wrote
> about accessing disc without OS file cache. Here I
> normaly depend on OS and OS file caching is big thing.
> It is not perfect, but OS (OK, at least Linux) is doing
> this resonably well I have no temptation to avoid it.
> And I appreciate that with OS cache performance is
> usually much better that would be "without cache".
> OTOH, I routinly avoid stdio for I/O critical things
> (so no printf in I/O critical code).

My point about the cache was that it is of no value in my case;
I'm not going to revisit a file once I've seen it the first
time (so why hold onto that data?)

>>> In other cases I fixed
>>> bugs by replacing composition of library routines by a single
>>> routine: there were interactions making simple composition
>>> incorrect. Correct alterantive was single routine.
>>>
>>> As I wrote my embedded programs are simple and small. But I
>>> use almost no external libraries. Trying some existing libraries
>>> I have found out that some produce rather large programs, linking
>>> in a lot of unneeded stuff.
>>
>> Because they try to address a variety of solution spaces without
>> trying to be "optimal" for any. You trade flexibility/capability
>> for speed/performance/etc.
>
> I think that this is more subtle: libraries frequently force some
> way of doing things. Which may be good if you try to quickly roll
> solution and are within capabilities of library. But if you
> need/want different design, then library may be too inflexible
> to deliver it.

Use a different diode.

>>> Of course, writing for scratch
>>> will not scale to bigger programs. OTOH, I feel that with
>>> proper tooling it would be possible to retain efficiency and
>>> small code size at least for large class of microntroller
>>> programs (but existing tools and libraries do not support this).
>>
>> Templates are an attempt in this direction. Allowing a class of
>> problems to be solved once and then tailored to the specific
>> application.
>
> Yes, templates could help. But they also have problems. One
> of them is that (among others) I would like to target STM8
> and I have no C++ compiler for STM8. My idea is to create
> custom "optimizer/generator" for (annotated) C code.
> ATM it is vapourware, but I think it is feasible with
> reasonable effort.
>
>> But, personal experience is where you win the most. You write
>> your second or third UART driver and start realizing that you
>> could leverage a previous design if you'd just thought it out
>> more fully -- instead of tailoring it to the specific needs
>> of the original application.
>>
>> And, as you EXPECT to be reusing it in other applications (as
>> evidenced by the fact that it's your third time writing the same
>> piece of code!), you anticipate what those *might* need and
>> think about how to implement those features "economically".
>>
>> It's rare that an application is *so* constrained that it can't
>> afford a couple of extra lines of code, here and there. If
>> you've considered efficiency in the design of your algorithms,
>> then these little bits of inefficiency will be below the noise floor.
>
> Well, I am not talking about "couple of extra lines". Rather
> about IMO substantial fixed overhead. As I wrote, one of my
> targets is STM8 with 8k flash, another is MSP430 with 16k flash,
> another is STM32 with 16k flash (there are also bigger targets).
> One of libraries/frameworks for STM32 after activating few featurs
> pulled in about 16k code, this is substantial overhead given
> how little features I needed. Other folks reported that for
> trivial programs vendor supplied frameworks pulled close to 30k


Click here to read the complete article
Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on

<smi6ft$504$1@z-news.wcss.wroc.pl>

 copy mid

https://www.novabbs.com/devel/article-flat.php?id=713&group=comp.arch.embedded#713

 copy link   Newsgroups: comp.arch.embedded
Path: i2pn2.org!i2pn.org!usenet.goja.nl.eu.org!3.eu.feeder.erje.net!feeder.erje.net!newsfeed.pionier.net.pl!pwr.wroc.pl!news.wcss.wroc.pl!not-for-mail
From: antis...@math.uni.wroc.pl
Newsgroups: comp.arch.embedded
Subject: Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on
Date: Thu, 11 Nov 2021 04:34:05 +0000 (UTC)
Organization: Politechnika Wroclawska
Lines: 472
Message-ID: <smi6ft$504$1@z-news.wcss.wroc.pl>
References: <skvcnd$5dv$1@dont-email.me> <sl3d4h$17d3$1@gioia.aioe.org> <sl3f65$jdl$1@dont-email.me> <sl4dm3$5ut$1@dont-email.me> <sl77p9$6gt$1@z-news.wcss.wroc.pl> <sl7arc$v0i$1@dont-email.me> <sla605$b7m$1@z-news.wcss.wroc.pl> <sla7tl$gqn$1@dont-email.me> <slannf$qg4$1@z-news.wcss.wroc.pl> <slht2f$1kj$1@dont-email.me> <sln6qu$n86$1@z-news.wcss.wroc.pl> <slnndl$a9b$1@dont-email.me>
NNTP-Posting-Host: hera.math.uni.wroc.pl
X-Trace: z-news.wcss.wroc.pl 1636605245 5124 156.17.86.1 (11 Nov 2021 04:34:05 GMT)
X-Complaints-To: abuse@news.pwr.wroc.pl
NNTP-Posting-Date: Thu, 11 Nov 2021 04:34:05 +0000 (UTC)
Cancel-Lock: sha1:wSTroEwSNMRHQLJLNC2fOTLXU1Y=
User-Agent: tin/2.4.3-20181224 ("Glen Mhor") (UNIX) (Linux/4.19.0-10-amd64 (x86_64))
 by: antis...@math.uni.wroc.pl - Thu, 11 Nov 2021 04:34 UTC

Don Y <blockedofcourse@foo.invalid> wrote:
> On 10/31/2021 3:54 PM, antispam@math.uni.wroc.pl wrote:
> >> Aren't THEY components?
> >
> > Well, some folks expect more from components than from
> > traditional libraries. Some evan claim to deliver.
> > However, libraries have limitations and ATM I see nothing
> > that fundamentally change situation.
>
> A component is something that you can use as a black box,
> without having to reinvent it. It is the epitome of reuse.
>
> >> How often do you reimplement
> >> ?printf() to avoid all of the bloat that typically accompanies it?
> >
> > I did that once (for OS kernel where standard library would not
> > work). If needed I can reuse it. On PC-s I am not worried by
> > bloat due to printf. OTOH, on MCU-s I am not sure if I ever used
> > printf. Rather, printing was done by specialized routines
> > either library provided or my own.
>
> You can also create a ?printf() that you can configure at build time to
> support the modifiers and specifiers that you know you will need.
>
> Just like you can configure a UART driver to support a FIFO size defined
> at configuration, hardware handshaking, software flowcontrol, the
> high and low water marks for each of those (as they can be different),
> the character to send to request the remote to stop transmitting,
> the character you send to request resumption of transmission, which
> character YOU will recognize as requesting your Tx channel to pause,
> the character (or condition) you will recognize to resume your Tx,
> whether or not you will sample the condition codes in the UART, how
> you read/write the data register, how you read/write the status register,
> etc.
>
> While these sound like lots of options, they are all relatively
> trivial additions to the code.
>
> >> (when was the last time you needed ALL of those format specifiers
> >> in an application? And modifiers?
> >>
> >>> There are some things which are reusable
> >>> if you accept modest to severe overhead.
> >>
> >> What you need is components with varying characteristics.
> >> You can buy diodes with all sorts of current carrying capacities,
> >> PIVs, package styles, etc. But, they all still perform the
> >> same function. Why so many different part numbers? Why not
> >> just use the biggest, baddest diode in ALL your circuits?
<snip>
> > I am stuck with what is available on the market. And diode
> > is logically pretty simple component, yet we need many kinds.
> >
> >> I.e., we readily accept differences in "standard components"
> >> in other disciplines; why not when it comes to software
> >> modules?
> >
> > Well, software is _much_ more compilcated than physical
> > engineering artifacts. Physical thing may have 10000 joints,
> > but if joints are identical, then this is moral equivalent of
> > simple loop that just iterates fixed number of times.
>
> This is the argument in favor of components. You'd much rather
> read a comprehensive specification ("datasheet") for a software
> component than have to read through all of the code that implements
> it.

Well, if there is simple to use component that performs what
you need, then using it is fine. However, for many tasks
once component is flexible enough to cover both your and
my needs its specification may be longer and more tricky
than code doing task at hand.

> What if it was implemented in some programming language in
> which you aren't expert? What if it was a binary "BLOB" and
> couldn't be inspected?

There are many reasons when existing code can not be reused.
Concerning BLOB-s, I am trying to avoid them and in first
order approximation I am not using them. One (serious IMO)
problem with BLOB-s is that sooner or later they will be
incompatible with other things (OS/other libraries/my code).
Very old source code usually can be run on modern systems
with modest effort. BLOB-s normally would require much
more effort.

> > At software level number of possible pre-composed blocks
> > is so large that it is infeasible to deliver all of them.
>
> You don't have to deliver all of them. When you wire a circuit,
> you still have to *solder* connections, don't you? The
> components don't magically glue themselves together...

Yes, one needs to make connections. In fact, in programming
most work is "making connections". So you want something
which is simple to connect. In other words, you can all
parts of your design to play nicely together. With code
deliverd by other folks that is not always the case.

> > Classic trick it to parametrize. However even if you
> > parametrize there are hundreds of design decisions going
> > into relatively small piece of code. If you expose all
> > design decisions then user as well may write his/her own
> > code because complexity will be similar. So normaly
> > parametrization is limited and there will be users who
> > find hardcoded desion choices inadequate.
> >
> > Another things is that current tools are rather weak
> > at supporting parametrization.
>
> Look at a fleshy UART driver and think about how you would decompose
> it into N different variants that could be "compile time configurable".
> You'll be surprised as to how easy it is. Even if the actual UART
> hardware differs from instance to instance.

UART-s are simple. And yet some things are tricky: in C to have
"compile time configurable" buffer size you need to use macros.
Works, but in a sense UART implementation "leaks" to user code.

> >>> For example things tends
> >>> to compose nicely if you dynamically allocate everything and use
> >>> garbage collection. But performace cost may be substantial.
> >>> And in embedded setting garbage collection may be unacceptable.
> >>> In some cases I have found out that I can get much better
> >>> speed joing things that could be done as composition of library
> >>> operations into single big routine.
> >>
> >> Sure, but now you're tuning a solution to a specific problem.
> >> I've designed custom chips to solve particular problems.
> >> But, they ONLY solve those particular problems! OTOH,
> >> I use lots of OTC components in my designs because those have
> >> been designed (for the most part) with an eye towards
> >> meeting a variety of market needs.
> >
> > Maybe I made wrong impression, I think some explanation is in
> > place here. I am trying to make my code reusable. For my
> > problems performance is important part of reusablity: our
> > capability to solve problem is limited by performance and with
> > better perfomance users can solve bigger problems. I am
> > re-using code that I can and I would re-use more if I could
> > but there there are technical obstacles. Also, while I am
> > trying to make my code reusable, there are intrusive
> > design decision which may interfere with your possiobility
> > and willingness to re-use.
>
> If you don't know where the design is headed, then you can't
> pick the components that it will need.

Well, there are routine tasks, for them it is natural to
re-use existing code. There are new tasks that are "almost"
routine, than one can come with good design at the start.
But in a sense "interesting" tasks are when at start you
have only limited understanding. In such case it is hard
to know "where the design is headed", except that it is
likely to change. Of course, customer may be dissatisfied
if you tell "I will look at the problem and maybe I will
find solution". But lack of understanding is normal
in research (at starting point), and I think that software
houses also do risky projects hoping that big win on succesful
ones will cover losses on failures.

> I approach a design from the top (down) and bottom (up). This
> lets me gauge the types of information that I *may* have
> available from the hardware -- so I can sort out how to
> approach those limitations from above. E.g., if I can't
> control the data rate of a comm channel, then I either have
> to ensure I can catch every (complete) message *or* design a
> protocol that lets me detect when I've missed something.

Well, with UART there will be some fixed transmission rate
(with wrong clock frequency UART would be unable to receive
anything). I would expect MCU to be able to receive all
incoming characters (OK, assuming hardware UART with drivier
using high priority interrupt). So, detecting that you got too
much should not be too hard. OTOH, sensibly handling
excess input is different issue: if characters are coming
faster than you can process them, then either your CPU is
underpowered or there is some failure causing excess transmission.
In either case specific application will dictate what
should be avoided.


Click here to read the complete article
Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on

<sn9bim$r6$3@dont-email.me>

 copy mid

https://www.novabbs.com/devel/article-flat.php?id=732&group=comp.arch.embedded#732

 copy link   Newsgroups: comp.arch.embedded
Path: i2pn2.org!i2pn.org!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: blockedo...@foo.invalid (Don Y)
Newsgroups: comp.arch.embedded
Subject: Re: How to write a simple driver in bare metal systems: volatile,
memory barrier, critical sections and so on
Date: Fri, 19 Nov 2021 16:21:49 -0700
Organization: A noiseless patient Spider
Lines: 326
Message-ID: <sn9bim$r6$3@dont-email.me>
References: <skvcnd$5dv$1@dont-email.me> <sl3d4h$17d3$1@gioia.aioe.org>
<sl3f65$jdl$1@dont-email.me> <sl4dm3$5ut$1@dont-email.me>
<sl77p9$6gt$1@z-news.wcss.wroc.pl> <sl7arc$v0i$1@dont-email.me>
<sla605$b7m$1@z-news.wcss.wroc.pl> <sla7tl$gqn$1@dont-email.me>
<slannf$qg4$1@z-news.wcss.wroc.pl> <slht2f$1kj$1@dont-email.me>
<sln6qu$n86$1@z-news.wcss.wroc.pl> <slnndl$a9b$1@dont-email.me>
<smi6ft$504$1@z-news.wcss.wroc.pl>
Mime-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Fri, 19 Nov 2021 23:21:59 -0000 (UTC)
Injection-Info: reader02.eternal-september.org; posting-host="f1e457d5218ac1e41f1783cf17b5280b";
logging-data="870"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/WUqif0ga/adM1krYo+PzP"
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101
Thunderbird/52.1.1
Cancel-Lock: sha1:hrLpcq/MRgPScxRj8VOveOra40s=
In-Reply-To: <smi6ft$504$1@z-news.wcss.wroc.pl>
Content-Language: en-US
X-Mozilla-News-Host: news://nntp.aioe.org
 by: Don Y - Fri, 19 Nov 2021 23:21 UTC

On 11/10/2021 9:34 PM, antispam@math.uni.wroc.pl wrote:
> Don Y <blockedofcourse@foo.invalid> wrote:

>>> Classic trick it to parametrize. However even if you
>>> parametrize there are hundreds of design decisions going
>>> into relatively small piece of code. If you expose all
>>> design decisions then user as well may write his/her own
>>> code because complexity will be similar. So normaly
>>> parametrization is limited and there will be users who
>>> find hardcoded desion choices inadequate.
>>>
>>> Another things is that current tools are rather weak
>>> at supporting parametrization.
>>
>> Look at a fleshy UART driver and think about how you would decompose
>> it into N different variants that could be "compile time configurable".
>> You'll be surprised as to how easy it is. Even if the actual UART
>> hardware differs from instance to instance.
>
> UART-s are simple. And yet some things are tricky: in C to have
> "compile time configurable" buffer size you need to use macros.
> Works, but in a sense UART implementation "leaks" to user code.

You can configure using manifest constants, conditional compilation,
or even run-time switches. Or, by linking against different
"support" routines. How and where the configuration "leaks"
into user code is a function of the configuration mechanisms that
you decide to employ.

E.g., You'd likely NOT design your network stack to be tightly integrated
with your choice of NIC (all else being equal) -- simply because you'd
want to be able to reuse the stack with some *other* NIC without having
to rewrite it.

OTOH, it's not unexpected to want to isolate the caching of ARP results
in an "application specific" manner as you'll likely know the sorts (and
number!) of clients/services with which the device in question will be
connecting. So, that (sub)module can be replaced with something most
appropriate to the application yet with a "standardized" interface to
the stack itself (*YOU* define that standard)

All of these require decisions up-front; you can't expect to be able to
retrofit an existing piece of code (cheaply) to support a more
modular/configurable implementation in the future.

But, personal experience teaches you what you are likely to need
by way of flexibility/configurability. Most folks tend to eork
in a very narrow set of application domains. Chances are, the
network stack you design for an embedded product will be considerably
different than one for a desktop OS. If you plan to straddle
both domains, then the configurability challenge is greater!

>> There are costs to both approaches. If I dedicate resource to
>> ensuring I don't miss anything, then some other aspect of the
>> design will bear that cost. If I rely on detecting missed
>> messages, then I have to put a figure on their relative
>> likelihood so my device doesn't fail to provide its desired
>> functionality (because it is always missing one or two characters
>> out of EVERY message -- and, thus, sees NO messages).
>
> My thinking goes toward using relatively short messages and
> buffer big enough for two messages.

You can also design with the intent of parsing messages before they are
complete and "reducing" them along the way. This is particularly
important if messages can have varying length *or* there is a possibility
for the ass end of a message to get dropped (how do you know when the
message is complete? Imagine THE USER misconfiguring your device
to expect CRLFs and the traffic only contains newlines; the terminating
CRLF never arrives!)

[At the limit case, a message reduces to a concept -- that is represented
in some application specific manner: "Start the motor", "Clear the screen",
etc.]

Barcodes are messages (character sequences) of a sort. I typically
process a barcode at several *concurrent* levels:
- an ISR that captures the times of transitions (black->white->black)
- a task that reduces the data captured by the ISR into "bar widths"
- a task that aggregates bar widths to form characters
- a task that parses character sequences to determine valid messages
- an application layer interpretation (or discard) of that message
This allows each layer to decide when the data on which it relies
does not represent a valid barcode and discard some (or all) of it...
without waiting for a complete message to be present. So, the
resources that were consumed by that (partial?) message are
freed earlier.

As such, there is never a "start time" nor "end time" for a barcode
message -- because you don't want the user to have to "do something"
to tell you that he is now going to scan a barcode (otherwise, the
efficiency of using barcodes is subverted).

[Think about the sorts of applications that use barcodes; how many
require the user to tell the device "here comes a barcode, please start
your decoder algorithm NOW!"]

As users can abuse the barcode reader (there is nothing preventing them
from continuously scanning barcodes, in violation of any "protocol"
that the product may *intend*), you have to tolerate the case where
the data arrives faster than it can be consumed. *Knowing* where
(in the event stream) you may have "lost" some data (transitions,
widths, characters or messages) lets you resync to a less pathological
event stream later (when the user starts "behaving properly")

> If there is need for
> high speed I would go for continous messages and DMA
> transfers (using break interrupt to discover end of message
> in case of variable length messages). So device should
> be able to get all messages and in case of excess message
> trafic whole message could be dropped (possibly looking
> first for some high priority messages). Of course, there
> may be some externaly mandated message format and/or
> communitation protocal making DMA inappropriate.
> Still, assuming interrupts, all characters should reach
> interrupt handler, causing possibly some extra CPU
> load. The only possiblity of unnoticed loss of characters
> would be blocking interrupts too long. If interrupts can
> be blocked for too long, then I would expect loss of whole
> messages. In such case protocol should have something like
> "dont talk to me for next 100 miliseconds, I will be busy"
> to warn other nodes and request silence. Now, if you
> need to faithfully support sillyness like Modbus RTU timeouts,
> then I hope that you are adequatly paid...

>> IMO, the advantages of writing in a multitasking environment so
>> far outweigh the "costs" of an MTOS that it behooves one to consider
>> how to shoehorn that functionality into EVERY design.
>>
>> When writing in a HLL, there are complications that impose
>> constraints on how the MTOS provides its services. But, for small
>> projects written in ASM, you can gain the benefits of an MTOS
>> for very few bytes of code (and effectively zero RAM).
>
> Well, looking at books and articles I did not find convincing
> argument/example showing that one really need multitasking for
> small systems.

The advantages of multitasking lie in problem decomposition.
Smaller problems are easier to "get right", in isolation.
The *challenge* of multitasking is coordinating the interactions
between these semi-concurrent actors. Experience teaches you how
to partition a "job".

I want to blink a light at 1 Hz and check for a button to be
pressed which will start some action that may be lengthy. I
can move the light blink into an ISR (which GENERALLY is a ridiculous
use of that "resource") to ensure the 1Hz timeliness is maintained
regardless of what the "lengthy" task may be doing, at the time.

Or, I can break the lengthy task into smaller chunks that
are executed sequentially with "peeks" at the "light timer"
between each of those segments.

sequence1 := sequence2 := sequence3 := sequence4 := 0;
while (FOREVER) {
task1:
case sequence1++ {
0 => do_task1_step0;
1 => do_task1_step1;
2 => do_task1_step2;
...
}

do_light;

task2:
case sequence2++ {
0 => do_task2_step0;
1 => do_task2_step1;
2 => do_task2_step2;
...
}

do_light;

task3:
switch sequence3++ {
0 => do_task3_step0;
1 => do_task3_step1;
2 => do_task3_step2;
...
}

do_light;

...
}

When you need to do seven (or fifty) other "lengthy actions"
concurrently (each of which may introduce other "blinking
lights" or timeliness constraints), its easier (less brittle)
to put a structure in place that lets those competing actions
share the processor without requiring the developer to
micromanage at this level.


Click here to read the complete article
Pages:123
server_pubkey.txt

rocksolid light 0.9.7
clearnet tor