Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.arch.embedded > #25852 > unrolled thread

Short blocking delay in Cortex-M0+

Started bypozz <pozzugno@gmail.com>
First post2017-02-23 17:15 +0100
Last post2017-03-25 01:11 +0100
Articles 20 on this page of 24 — 14 participants

Back to article view | Back to comp.arch.embedded


Contents

  Short blocking delay in Cortex-M0+ pozz <pozzugno@gmail.com> - 2017-02-23 17:15 +0100
    Re: Short blocking delay in Cortex-M0+ John Speth <johnspeth@yahoo.com> - 2017-02-23 09:00 -0800
      Re: Short blocking delay in Cortex-M0+ Tim Wescott <tim@seemywebsite.com> - 2017-02-23 13:15 -0600
      Re: Short blocking delay in Cortex-M0+ pozz <pozzugno@gmail.com> - 2017-02-24 09:51 +0100
        Re: Short blocking delay in Cortex-M0+ rickman <gnuarm@gmail.com> - 2017-02-24 04:26 -0500
        Re: Short blocking delay in Cortex-M0+ Tim Wescott <seemywebsite@myfooter.really> - 2017-02-24 14:22 -0600
      Re: Short blocking delay in Cortex-M0+ Jack <jack4747@gmail.com> - 2017-02-24 02:22 -0800
      Re: Short blocking delay in Cortex-M0+ Don Y <blockedofcourse@foo.invalid> - 2017-02-24 10:51 -0700
      Re: Short blocking delay in Cortex-M0+ Stefan Reuther <stefan.news@arcor.de> - 2017-02-24 18:29 +0100
        Re: Short blocking delay in Cortex-M0+ Dave Nadler <drn@nadler.com> - 2017-02-24 13:03 -0800
      Re: Short blocking delay in Cortex-M0+ mrfirmware <mrfirmware@gmail.com> - 2017-03-22 09:29 -0700
        Re: Short blocking delay in Cortex-M0+ mrfirmware <mrfirmware@gmail.com> - 2017-03-22 09:48 -0700
          Re: Short blocking delay in Cortex-M0+ Hans-Bernhard Bröker <HBBroeker@t-online.de> - 2017-03-22 22:02 +0100
          Re: Short blocking delay in Cortex-M0+ David Brown <david.brown@hesbynett.no> - 2017-03-23 10:05 +0100
            Re: Short blocking delay in Cortex-M0+ Tim Wescott <seemywebsite@myfooter.really> - 2017-03-23 12:54 -0500
              Re: Short blocking delay in Cortex-M0+ mrfirmware <mrfirmware@gmail.com> - 2017-03-23 12:52 -0700
    Re: Short blocking delay in Cortex-M0+ Don Y <blockedofcourse@foo.invalid> - 2017-02-23 13:54 -0700
    Re: Short blocking delay in Cortex-M0+ Paul <paul@pcserviceselectronics.co.uk> - 2017-02-24 10:36 +0000
    Re: Short blocking delay in Cortex-M0+ pozz <pozzugno@gmail.com> - 2017-03-24 12:23 +0100
      Re: Short blocking delay in Cortex-M0+ David Brown <david.brown@hesbynett.no> - 2017-03-24 12:57 +0100
        Re: Short blocking delay in Cortex-M0+ pozz <pozzugno@gmail.com> - 2017-03-24 13:54 +0100
          Re: Short blocking delay in Cortex-M0+ David Brown <david.brown@hesbynett.no> - 2017-03-24 15:21 +0100
            Re: Short blocking delay in Cortex-M0+ Tauno Voipio <tauno.voipio@notused.fi.invalid> - 2017-03-24 21:26 +0200
              Re: Short blocking delay in Cortex-M0+ David Brown <david.brown@hesbynett.no> - 2017-03-25 01:11 +0100

Page 1 of 2  [1] 2  Next page →


#25852 — Short blocking delay in Cortex-M0+

Frompozz <pozzugno@gmail.com>
Date2017-02-23 17:15 +0100
SubjectShort blocking delay in Cortex-M0+
Message-ID<o8n1mp$meq$1@dont-email.me>
During startup, I need a short and not precise delay, before configuring 
clocks, timers and other peripherals (at startup the CPU runs with 
internal clock).

What do you suggest?

I think there's a simpler method than configuring a hardware timer.

I need to check the status of an input pin, *after* enabling internal 
pull-up. I'd like to introduce a short delay after enabling internal 
pull-up, otherwise there's a risk I will read a transient level (maybe 0 
or 1).

[toc] | [next] | [standalone]


#25853

FromJohn Speth <johnspeth@yahoo.com>
Date2017-02-23 09:00 -0800
Message-ID<o8n4eq$ccn$1@gioia.aioe.org>
In reply to#25852
On 2/23/2017 8:15 AM, pozz wrote:
> During startup, I need a short and not precise delay, before configuring
> clocks, timers and other peripherals (at startup the CPU runs with
> internal clock).
>
> What do you suggest?
>
> I think there's a simpler method than configuring a hardware timer.
>
> I need to check the status of an input pin, *after* enabling internal
> pull-up. I'd like to introduce a short delay after enabling internal
> pull-up, otherwise there's a risk I will read a transient level (maybe 0
> or 1).

First thing after main() starts, configure your pin and run a spin loop 
based delay, then read the pin.  There's probably no need for a timer at 
that stage of start up.

void delay(void)
{
   // Use volatile so the optimizer will not nullify this code
   volatile int i;
   for(i = 0; i < YOUR_DELAY; i++);
}

JJS

[toc] | [prev] | [next] | [standalone]


#25854

FromTim Wescott <tim@seemywebsite.com>
Date2017-02-23 13:15 -0600
Message-ID<O6SdnawGxb8qqTLFnZ2dnUU7-WWdnZ2d@giganews.com>
In reply to#25853
On Thu, 23 Feb 2017 09:00:11 -0800, John Speth wrote:

> On 2/23/2017 8:15 AM, pozz wrote:
>> During startup, I need a short and not precise delay, before
>> configuring clocks, timers and other peripherals (at startup the CPU
>> runs with internal clock).
>>
>> What do you suggest?
>>
>> I think there's a simpler method than configuring a hardware timer.
>>
>> I need to check the status of an input pin, *after* enabling internal
>> pull-up. I'd like to introduce a short delay after enabling internal
>> pull-up, otherwise there's a risk I will read a transient level (maybe
>> 0 or 1).
> 
> First thing after main() starts, configure your pin and run a spin loop
> based delay, then read the pin.  There's probably no need for a timer at
> that stage of start up.
> 
> void delay(void)
> {
>    // Use volatile so the optimizer will not nullify this code volatile
>    int i;
>    for(i = 0; i < YOUR_DELAY; i++);
> }
> 
> JJS

Exactly!  Short, reliable, and if you're going to do the startup in a 
single thread anyway, no harm done anywhere.

-- 
Tim Wescott
Control systems, embedded software and circuit design
I'm looking for work!  See my website if you're interested
http://www.wescottdesign.com

[toc] | [prev] | [next] | [standalone]


#25860

Frompozz <pozzugno@gmail.com>
Date2017-02-24 09:51 +0100
Message-ID<o8os33$1ah$1@dont-email.me>
In reply to#25853
Il 23/02/2017 18:00, John Speth ha scritto:
> On 2/23/2017 8:15 AM, pozz wrote:
>> During startup, I need a short and not precise delay, before configuring
>> clocks, timers and other peripherals (at startup the CPU runs with
>> internal clock).
>>
>> What do you suggest?
>>
>> I think there's a simpler method than configuring a hardware timer.
>>
>> I need to check the status of an input pin, *after* enabling internal
>> pull-up. I'd like to introduce a short delay after enabling internal
>> pull-up, otherwise there's a risk I will read a transient level (maybe 0
>> or 1).
>
> First thing after main() starts, configure your pin and run a spin loop
> based delay, then read the pin.  There's probably no need for a timer at
> that stage of start up.
>
> void delay(void)
> {
>   // Use volatile so the optimizer will not nullify this code
>   volatile int i;
>   for(i = 0; i < YOUR_DELAY; i++);
> }

Yes, it's a solution. But I haven't ANY idea what is the value of 
YOUR_DELAY based on the real delay.

Considering I'm talking about a precise processor (Cortex-M0+) and 
knowing the core clock at startup (in my case 8MHz), is it possible to 
calculate YOUR_DELAY value based on the delay in microseconds?

[toc] | [prev] | [next] | [standalone]


#25861

Fromrickman <gnuarm@gmail.com>
Date2017-02-24 04:26 -0500
Message-ID<o8ou3v$673$2@dont-email.me>
In reply to#25860
On 2/24/2017 3:51 AM, pozz wrote:
> Il 23/02/2017 18:00, John Speth ha scritto:
>> On 2/23/2017 8:15 AM, pozz wrote:
>>> During startup, I need a short and not precise delay, before configuring
>>> clocks, timers and other peripherals (at startup the CPU runs with
>>> internal clock).
>>>
>>> What do you suggest?
>>>
>>> I think there's a simpler method than configuring a hardware timer.
>>>
>>> I need to check the status of an input pin, *after* enabling internal
>>> pull-up. I'd like to introduce a short delay after enabling internal
>>> pull-up, otherwise there's a risk I will read a transient level (maybe 0
>>> or 1).
>>
>> First thing after main() starts, configure your pin and run a spin loop
>> based delay, then read the pin.  There's probably no need for a timer at
>> that stage of start up.
>>
>> void delay(void)
>> {
>>   // Use volatile so the optimizer will not nullify this code
>>   volatile int i;
>>   for(i = 0; i < YOUR_DELAY; i++);
>> }
>
> Yes, it's a solution. But I haven't ANY idea what is the value of
> YOUR_DELAY based on the real delay.
>
> Considering I'm talking about a precise processor (Cortex-M0+) and
> knowing the core clock at startup (in my case 8MHz), is it possible to
> calculate YOUR_DELAY value based on the delay in microseconds?

Sure, it should be fairly easy to get enough info on the instruction 
timing to figure that out.  But why not just code it up and  measure it? 
   Put an I/O instruction before and after and hang a scope on the I/O? 
Try a few permutations of options on the tools such as debug settings 
and optimizations to see how that impacts it.

After all, you did ask for a "not precise" delay.  What is your concern?

-- 

Rick C

[toc] | [prev] | [next] | [standalone]


#25870

FromTim Wescott <seemywebsite@myfooter.really>
Date2017-02-24 14:22 -0600
Message-ID<wKmdnRkMV4ZuCC3FnZ2dnUU7-eudnZ2d@giganews.com>
In reply to#25860
On Fri, 24 Feb 2017 09:51:31 +0100, pozz wrote:

> Il 23/02/2017 18:00, John Speth ha scritto:
>> On 2/23/2017 8:15 AM, pozz wrote:
>>> During startup, I need a short and not precise delay, before
>>> configuring clocks, timers and other peripherals (at startup the CPU
>>> runs with internal clock).
>>>
>>> What do you suggest?
>>>
>>> I think there's a simpler method than configuring a hardware timer.
>>>
>>> I need to check the status of an input pin, *after* enabling internal
>>> pull-up. I'd like to introduce a short delay after enabling internal
>>> pull-up, otherwise there's a risk I will read a transient level (maybe
>>> 0 or 1).
>>
>> First thing after main() starts, configure your pin and run a spin loop
>> based delay, then read the pin.  There's probably no need for a timer
>> at that stage of start up.
>>
>> void delay(void)
>> {
>>   // Use volatile so the optimizer will not nullify this code volatile
>>   int i;
>>   for(i = 0; i < YOUR_DELAY; i++);
>> }
> 
> Yes, it's a solution. But I haven't ANY idea what is the value of
> YOUR_DELAY based on the real delay.
> 
> Considering I'm talking about a precise processor (Cortex-M0+) and
> knowing the core clock at startup (in my case 8MHz), is it possible to
> calculate YOUR_DELAY value based on the delay in microseconds?

In theory, yes, but there's a huge number of variables having to do not 
only with the core used, but how the manufacturer of the particular part 
has laid out their flash.

If it's just one part, time it, then recalculate YOUR_DELAY.  If that's 
not good enough, then use the core's clock.

-- 

Tim Wescott
Wescott Design Services
http://www.wescottdesign.com

I'm looking for work -- see my website!

[toc] | [prev] | [next] | [standalone]


#25862

FromJack <jack4747@gmail.com>
Date2017-02-24 02:22 -0800
Message-ID<0291c851-d7c9-4fe2-b3da-7a12ed148bd0@googlegroups.com>
In reply to#25853
Il giorno giovedì 23 febbraio 2017 18:00:23 UTC+1, John Speth ha scritto:
> On 2/23/2017 8:15 AM, pozz wrote:
> > During startup, I need a short and not precise delay, before configuring
> > clocks, timers and other peripherals (at startup the CPU runs with
> > internal clock).
> >
> > What do you suggest?
> >
> > I think there's a simpler method than configuring a hardware timer.
> >
> > I need to check the status of an input pin, *after* enabling internal
> > pull-up. I'd like to introduce a short delay after enabling internal
> > pull-up, otherwise there's a risk I will read a transient level (maybe 0
> > or 1).
> 
> First thing after main() starts, configure your pin and run a spin loop 
> based delay, then read the pin.  There's probably no need for a timer at 
> that stage of start up.
> 
> void delay(void)
> {
>    // Use volatile so the optimizer will not nullify this code
>    volatile int i;
>    for(i = 0; i < YOUR_DELAY; i++);
> }
> 
> JJS

I would put a "asm NOP;" (in whathever sintax is needed by your compiler) to better calculate the timing.

BUT: check the library files (the include files) that comes with the toolchain. Usually you have some utility function already defined/implemented, such as enabling/disabling interrupts and also something link us_delay() or ms_delay() (they could be implemented as funtions or macros).

Bye Jack

[toc] | [prev] | [next] | [standalone]


#25865

FromDon Y <blockedofcourse@foo.invalid>
Date2017-02-24 10:51 -0700
Message-ID<o8prng$h5a$1@dont-email.me>
In reply to#25853
On 2/23/2017 10:00 AM, John Speth wrote:
> First thing after main() starts, configure your pin and run a spin loop based
> delay, then read the pin.  There's probably no need for a timer at that stage
> of start up.
>
> void delay(void)
> {
>   // Use volatile so the optimizer will not nullify this code
>   volatile int i;
>   for(i = 0; i < YOUR_DELAY; i++);
> }

The optimizer can still "rewrite" your code in ways that won't
guarantee the delay for YOUR_DELAY=2*N won't be twice the delay
for YOUR_DELAY=N (within the cost of initialization differences).
(think: loop unrolling)

You're stuck having to pick a value, compile and then measure to
VERIFY the actual delay exceeds your requirement.  Then tweek your
value and try again.

You can try to isolate compiler influences by implementing the
routine in ASM (either inline or as a separate ASM function
bound in by the linkage editor).  But, this still leaves you
vulnerable to changes in the processor (family) and application
(i.e., cutting and pasting into other projects or elsewhere in
this project).

[Brief (Solution Systems) was a classic example of how timing
loops could make a piece of software useless in short order.
A command line bogo-parameter was used to drive the timing
loop for the key repeat function.  As processors got faster
and started relying on bigger/integrated caches, it became
impossible to tweek that bogo-value to a point where you could
get your finger off the keyboard fast enough to prevent
multiple keystrokes being synthesized from your *one* keypress]

And, regardless, a different compiler (e.g., a new release of
your EXISTING compiler) can alter the actual delay associated
with a particular value of YOUR_DELAY.

As the OP hasn't put any parameters on the size of his actual
desired delay, a error of 10% -- or 90% -- may be insignificant...
or, disasterous (in terms of the UX).

Use something that has known, predictable TIMING.  Would you use
an *approximation* of an addition operator to SUM two values?

[toc] | [prev] | [next] | [standalone]


#25866

FromStefan Reuther <stefan.news@arcor.de>
Date2017-02-24 18:29 +0100
Message-ID<o8pu1h.2hk.1@stefan.msgid.phost.de>
In reply to#25853
Am 23.02.2017 um 18:00 schrieb John Speth:
> First thing after main() starts, configure your pin and run a spin loop
> based delay, then read the pin.  There's probably no need for a timer at
> that stage of start up.
> 
> void delay(void)
> {
>   // Use volatile so the optimizer will not nullify this code
>   volatile int i;
>   for(i = 0; i < YOUR_DELAY; i++);
> }

If you want a piece of assembly to show up in your binary, write that
piece of assembly (and not some piece of C code that happens to produce
that piece of assembly today). Even with volatile, the compiler is free
to decide between a register or a variable, possibly different increment
and compare instructions, unrolling the loop, etc.

And if you're too lazy to implement parameter passing in assembler to
get a variable delay, it's definitely not hard to write a function that
burns 10000 cycles. Wrap that in a C loop, and if your compiler
generates anything between 1 or 100 cycles for the C code, you'll still
have 1% accuracy.


  Stefan

[toc] | [prev] | [next] | [standalone]


#25871

FromDave Nadler <drn@nadler.com>
Date2017-02-24 13:03 -0800
Message-ID<a2dd07cd-4e77-4ccc-8b22-f2fcac3367bd@googlegroups.com>
In reply to#25866
On Friday, February 24, 2017 at 12:58:26 PM UTC-5, Stefan Reuther wrote:
> If you want a piece of assembly to show up in your binary, write that
> piece of assembly (and not some piece of C code that happens to produce
> that piece of assembly today). Even with volatile, the compiler is free
> to decide between a register or a variable, possibly different increment
> and compare instructions, unrolling the loop, etc.

Even that is not enough; GCC will optimize out assembler NOPs if you're
not careful. For Cortex-M4, NOPs get eaten in the pipeline; can't remember
about M0.

Regardless, if you want a reliable delay: 

1) You MUST check the delay on a scope, in RELEASE build with
the optimization settings you expect for production.

2) You MUST recheck with the scope after any toolchain update or optimization
setting change.

Hope that helps!
Best Regards, Dave

PS: Just last week I had to do a short delay with a volatile iterator
for loop, and check it on the scope ;-)

[toc] | [prev] | [next] | [standalone]


#26151

Frommrfirmware <mrfirmware@gmail.com>
Date2017-03-22 09:29 -0700
Message-ID<e719382c-55af-4d35-ae53-aa3835840f33@googlegroups.com>
In reply to#25853
On Thursday, February 23, 2017 at 12:00:23 PM UTC-5, John Speth wrote:
> On 2/23/2017 8:15 AM, pozz wrote:
> > During startup, I need a short and not precise delay, before configuring
> > clocks, timers and other peripherals (at startup the CPU runs with
> > internal clock).
> >
> > What do you suggest?
> >
> > I think there's a simpler method than configuring a hardware timer.
> >
> > I need to check the status of an input pin, *after* enabling internal
> > pull-up. I'd like to introduce a short delay after enabling internal
> > pull-up, otherwise there's a risk I will read a transient level (maybe 0
> > or 1).
> 
> First thing after main() starts, configure your pin and run a spin loop 
> based delay, then read the pin.  There's probably no need for a timer at 
> that stage of start up.
> 
> void delay(void)
> {
>    // Use volatile so the optimizer will not nullify this code
>    volatile int i;
>    for(i = 0; i < YOUR_DELAY; i++);
> }
> 
> JJS

How is it legal for the compiler to optimize out the iterator? If it does, your compiler is broken. Don't confuse <optimized out> from gdb with "I removed your code." That for loop will execute because you told the compiler to loop for YOUR_DELAY counts. It must emit that code even if 'i' is not visible in the debugger. Volatile is only needed when the compiler cannot see any possible path for the variable to change with in the current scope of execution, e.g. ISR, another thread, or a hardware mapped address.

As for a delay in this case I'd read that GPIO port N times to create the delay. The port read will have a longer execution duration and you may be able to empirically determine how many reads it takes before it stabilizes. Often times port reads can be rather CPU clock independent and depend more on the port peripheral clock so you may even be able to get reliable timing regardless of the CPU clock.

[toc] | [prev] | [next] | [standalone]


#26154

Frommrfirmware <mrfirmware@gmail.com>
Date2017-03-22 09:48 -0700
Message-ID<c573f224-c7df-4fb4-b422-5598146d6eab@googlegroups.com>
In reply to#26151
On Wednesday, March 22, 2017 at 12:29:29 PM UTC-4, mrfirmware wrote:
> On Thursday, February 23, 2017 at 12:00:23 PM UTC-5, John Speth wrote:
> > On 2/23/2017 8:15 AM, pozz wrote:
> > > During startup, I need a short and not precise delay, before configuring
> > > clocks, timers and other peripherals (at startup the CPU runs with
> > > internal clock).
> > >
> > > What do you suggest?
> > >
> > > I think there's a simpler method than configuring a hardware timer.
> > >
> > > I need to check the status of an input pin, *after* enabling internal
> > > pull-up. I'd like to introduce a short delay after enabling internal
> > > pull-up, otherwise there's a risk I will read a transient level (maybe 0
> > > or 1).
> > 
> > First thing after main() starts, configure your pin and run a spin loop 
> > based delay, then read the pin.  There's probably no need for a timer at 
> > that stage of start up.
> > 
> > void delay(void)
> > {
> >    // Use volatile so the optimizer will not nullify this code
> >    volatile int i;
> >    for(i = 0; i < YOUR_DELAY; i++);
> > }
> > 
> > JJS
> 
> How is it legal for the compiler to optimize out the iterator? If it does, your compiler is broken. Don't confuse <optimized out> from gdb with "I removed your code." That for loop will execute because you told the compiler to loop for YOUR_DELAY counts. It must emit that code even if 'i' is not visible in the debugger. Volatile is only needed when the compiler cannot see any possible path for the variable to change with in the current scope of execution, e.g. ISR, another thread, or a hardware mapped address.
> 
> As for a delay in this case I'd read that GPIO port N times to create the delay. The port read will have a longer execution duration and you may be able to empirically determine how many reads it takes before it stabilizes. Often times port reads can be rather CPU clock independent and depend more on the port peripheral clock so you may even be able to get reliable timing regardless of the CPU clock.

Gah! I forgot about optimizers. Yes the -O2 flag will remove the for loop. It's not correct C though to do that. The port read is immune to optimizer magic.

[toc] | [prev] | [next] | [standalone]


#26157

FromHans-Bernhard Bröker <HBBroeker@t-online.de>
Date2017-03-22 22:02 +0100
Message-ID<ejg74fFprikU1@mid.dfncis.de>
In reply to#26154
Am 22.03.2017 um 17:48 schrieb mrfirmware:

> Gah! I forgot about optimizers. Yes the -O2 flag will remove the for
> loop. It's not correct C though to do that.

Actually in the case at hand, it can still be considered correct, 
depending how you interpret some rather involved wording in the standard.

> The port read is immune to optimizer magic.

If there were one in the code under consideration, it might be.  But 
there isn't, so the entire loop is fair game.

[toc] | [prev] | [next] | [standalone]


#26159

FromDavid Brown <david.brown@hesbynett.no>
Date2017-03-23 10:05 +0100
Message-ID<ob0300$3ch$1@dont-email.me>
In reply to#26154
On 22/03/17 17:48, mrfirmware wrote:
> On Wednesday, March 22, 2017 at 12:29:29 PM UTC-4, mrfirmware wrote:
>> On Thursday, February 23, 2017 at 12:00:23 PM UTC-5, John Speth wrote:
>>> On 2/23/2017 8:15 AM, pozz wrote:
>>>> During startup, I need a short and not precise delay, before configuring
>>>> clocks, timers and other peripherals (at startup the CPU runs with
>>>> internal clock).
>>>>
>>>> What do you suggest?
>>>>
>>>> I think there's a simpler method than configuring a hardware timer.
>>>>
>>>> I need to check the status of an input pin, *after* enabling internal
>>>> pull-up. I'd like to introduce a short delay after enabling internal
>>>> pull-up, otherwise there's a risk I will read a transient level (maybe 0
>>>> or 1).
>>>
>>> First thing after main() starts, configure your pin and run a spin loop 
>>> based delay, then read the pin.  There's probably no need for a timer at 
>>> that stage of start up.
>>>
>>> void delay(void)
>>> {
>>>    // Use volatile so the optimizer will not nullify this code
>>>    volatile int i;
>>>    for(i = 0; i < YOUR_DELAY; i++);
>>> }
>>>
>>> JJS
>>
>> How is it legal for the compiler to optimize out the iterator? If it
>> does, your compiler is broken. Don't confuse <optimized out> from gdb
>> with "I removed your code." That for loop will execute because you told
>> the compiler to loop for YOUR_DELAY counts. It must emit that code even
>> if 'i' is not visible in the debugger. Volatile is only needed when the
>> compiler cannot see any possible path for the variable to change with in
>> the current scope of execution, e.g. ISR, another thread, or a hardware
>> mapped address.
>>
>> As for a delay in this case I'd read that GPIO port N times to create
>> the delay. The port read will have a longer execution duration and you
>> may be able to empirically determine how many reads it takes before it
>> stabilizes. Often times port reads can be rather CPU clock independent
>> and depend more on the port peripheral clock so you may even be able to
>> get reliable timing regardless of the CPU clock.
> 
> Gah! I forgot about optimizers. Yes the -O2 flag will remove the for
> loop. It's not correct C though to do that. The port read is immune to
> optimizer magic.
> 

It is /entirely/ correct for the compiler to remove a delay loop like
this if there is no "volatile" involved.  For C, there are certain
"observable behaviours" in a program.  These are:

1. Accesses to volatile objects (reads or writes).  Ordering is
important, but timing is not.
2. Program start and exit.
3. Input and output of "interactive devices" through <stdio.h> functions
like printf(), fread() and fwrite().
4. The data written to files, at program termination.
5. Any function calls where the functions might do one of the above four
things.

The compiler has to generate code that produces the same results with
respect to these "observable behaviours" as the "C abstract machine" does.

And that is /it/.  The compiler is free to do anything it wants, as long
as these rules are followed.

For embedded systems, this usually boils down to just "program start"
and "volatile accesses".  Even when you use "printf", the key point is
that this will eventually use volatile accesses to send data to UART
hardware.  And function calls are considered "observable behaviour" if
the compiler does not know for sure that they involve no volatile accesses.

A loop that simple counts up does not access anything volatile - the
compiler can freely remove it.  The compiler can shuffle things around
any way it wants, as long as it does not break the ordering of volatile
accesses.  It can remove or simplify any code it wants, as long as the
results are that the same data is written out to volatile objects and
the same reads are made of volatile objects.

It can do this regardless of any optimisation settings.  Using -O0 or no
optimisation flags does /not/ turn off optimisations - it merely tells
the compiler not to work too hard on optimising.  Turning on -O2 can
never make correct code (in the C sense) into incorrect code - it just
asks the compiler to work harder to generate more efficient code that
does exactly the same thing as before.

And note that C has no concept of time - there is no way in C to express
a delay, or to suggest that some code has to be faster or slower than
other code.  There is only ordering of volatiles and the expectation
that a decent compiler won't insert extra slow code.


[toc] | [prev] | [next] | [standalone]


#26168

FromTim Wescott <seemywebsite@myfooter.really>
Date2017-03-23 12:54 -0500
Message-ID<LoKdnZcZLbNElknFnZ2dnUU7-Y-dnZ2d@giganews.com>
In reply to#26159
On Thu, 23 Mar 2017 10:05:51 +0100, David Brown wrote:

> Turning on -O2 can never make correct code (in the C sense) into
> incorrect code - it just asks the compiler to work harder to
> generate more efficient code that does exactly the same thing as
> before.

Just wanted to double down on that -- if bumping up the optimization 
level screws the pooch, then your code is at fault.

-- 

Tim Wescott
Wescott Design Services
http://www.wescottdesign.com

I'm looking for work -- see my website!

[toc] | [prev] | [next] | [standalone]


#26175

Frommrfirmware <mrfirmware@gmail.com>
Date2017-03-23 12:52 -0700
Message-ID<7c18b369-1014-4451-83e1-ed187d640db4@googlegroups.com>
In reply to#26168
On Thursday, March 23, 2017 at 1:54:41 PM UTC-4, Tim Wescott wrote:
> On Thu, 23 Mar 2017 10:05:51 +0100, David Brown wrote:
> 
> > Turning on -O2 can never make correct code (in the C sense) into
> > incorrect code - it just asks the compiler to work harder to
> > generate more efficient code that does exactly the same thing as
> > before.
> 
> Just wanted to double down on that -- if bumping up the optimization 
> level screws the pooch, then your code is at fault.
> 
> -- 
> 
> Tim Wescott
> Wescott Design Services
> http://www.wescottdesign.com
> 
> I'm looking for work -- see my website!

Yeah, in retrospect what was I thinking? I guess this is why I just read or write the port pin multiple times to sample reliably/create a pulse. Or snapshot a free running hw timer and wait for it to exceed some offset from the snapshot time.

[toc] | [prev] | [next] | [standalone]


#25855

FromDon Y <blockedofcourse@foo.invalid>
Date2017-02-23 13:54 -0700
Message-ID<o8ni27$mkq$1@dont-email.me>
In reply to#25852
On 2/23/2017 9:15 AM, pozz wrote:
> During startup, I need a short and not precise delay, before configuring

"Short" can mean lots of different things to different people.

> clocks, timers and other peripherals (at startup the CPU runs with internal
> clock).

*Must* the delay expire before these configurations are *begun*?  I.e.,
can you factor the time required to perform these configuration actions
INTO the delay -- esp given that you don't care about its precision
(presumably, the delay is expressed as "at least X" and not "at least
X but not exceeding Y" or "exactly X".

> What do you suggest?

I like to have timing services running just after I know I have a working
stack.  So, I'd simply use those services.

In your case, just spin in a loop immediately prior to reading the pin.
The problem with spin loops is knowing how long each iteration of the loop
WILL take to execute in light of hardware changes (XTAL freq, introduction
of cache, etc.), software evolution (i.e., lifting that code section and
reusing it in another design -- or, elsewhere in the same design), etc.
So, you want to #define the constants governing the loop iteration in
terms of actual hardware characteristics (XTAL_FREQ, CLOCK_MULTIPLIER,
CYCLES_PER_ITERATION, DESIRED_DELAY, etc.) to document the desired
goal *and* its derivation in a manner that makes it less dependant on the
particulars of the design.

But, "serializing" delays in this manner means that NOTHING happens while
the processor is twiddling its thumbs.  You'll likely repeat the practice
somewhere else in the startup code -- or, rationalize that you can use it
for larger "short" delays, etc.

This is akin to lame code like:
     show_startup_banner()
     delay(FOR_USER_TO_VIEW_BANNER)
     do_rest_of_real_work()

A more "performant" approach is to use the expected time of some other activity
to serve double-duty as your delay.  This allows "work to get done" while the
delay is being satisfied.  E.g.,
     do_whatever()   // at start of delay interval
     clear_memory()  // eats up time
     etc()
     do_followup()   // after delay has passed
The risk with this approach is that it decouples the "delay" as a prerequisite
for the "do_followup()" that relies on the delay.  I.e., someone changing the
ACTIONS that implement the delay AS A SIDE-EFFECT can alter the delay in ways
that aren't obvious to the do_followup() invocation.

Timing services allow you to make the delay and the things that depend on it
more explicit:
     start_timer(INITIALIZATION_TIMER, INITIALIZATION_DELAY)
     do_some_stuff()
     wait_timer(INITIALIZATION_TIMER)
     do_followup()     // requires INITIALIZATION_DELAY to have expired

> I think there's a simpler method than configuring a hardware timer.
>
> I need to check the status of an input pin, *after* enabling internal pull-up.

So, you need to know the worst-case time-constant for <whatever> is dangling
on the pin (C) fed by the internal pullup.  Is that <whatever> likely to subtly
change during manufacture (e.g., if you are sensing a switch closure on a
cable that might get lengthened -- perhaps by the user after the sale?) or
with different versions of your design?

> I'd like to introduce a short delay after enabling internal pull-up, otherwise
> there's a risk I will read a transient level (maybe 0 or 1).

Postpone the time at which you *need* to know the pin state to a point where
you have more of the system (and its services) available for use.  Even if you
end up having "done" things that are now determined to have been unnecessary
(based on your observation of the pin state), it hasn't COST you anything as
you would have otherwise spent that time twiddling your thumbs.

If you opt to use a spin-loop, put it (and other hardware specific things) in
a separate module (mach.c/mach.s) so you make the hardware dependencies very
obvious to future developers.

[toc] | [prev] | [next] | [standalone]


#25863

FromPaul <paul@pcserviceselectronics.co.uk>
Date2017-02-24 10:36 +0000
Message-ID<MPG.331a1d0770408a0298981c@172.16.0.1>
In reply to#25852
In article <o8n1mp$meq$1@dont-email.me>, pozzugno@gmail.com says...
> 
> During startup, I need a short and not precise delay, before configuring 
> clocks, timers and other peripherals (at startup the CPU runs with 
> internal clock).
> 
> What do you suggest?
> 
> I think there's a simpler method than configuring a hardware timer.
> 
> I need to check the status of an input pin, *after* enabling internal 
> pull-up. I'd like to introduce a short delay after enabling internal 
> pull-up, otherwise there's a risk I will read a transient level (maybe 0 
> or 1).

1/ If in startup surely other things need setting up or blocks of memory 
   initialised or similar to be put in waiting to start stage, do those
   first. Then do some form of delay if needed

2/ Does you processor have some form of SYS TICK hardware counter?
   If so once you know that is stable take a reading of SYS TICK
	after everything else than can be initialised 
	take another reading of SYS TICK
	Wait till SYS TICK has reached some threshold value.

-- 
Paul Carpenter          | paul@pcserviceselectronics.co.uk
<http://www.pcserviceselectronics.co.uk/>    PC Services
<http://www.pcserviceselectronics.co.uk/LogicCell/>   Logic Gates 
Education 
<http://www.pcserviceselectronics.co.uk/pi/>  Raspberry Pi Add-ons
<http://www.pcserviceselectronics.co.uk/fonts/> Timing Diagram Font
<http://www.badweb.org.uk/> For those web sites you hate

[toc] | [prev] | [next] | [standalone]


#26202

Frompozz <pozzugno@gmail.com>
Date2017-03-24 12:23 +0100
Message-ID<ob2vem$37q$1@dont-email.me>
In reply to#25852
Il 23/02/2017 17:15, pozz ha scritto:
> During startup, I need a short and not precise delay, before configuring
> clocks, timers and other peripherals (at startup the CPU runs with
> internal clock).
>
> What do you suggest?
>
> I think there's a simpler method than configuring a hardware timer.
>
> I need to check the status of an input pin, *after* enabling internal
> pull-up. I'd like to introduce a short delay after enabling internal
> pull-up, otherwise there's a risk I will read a transient level (maybe 0
> or 1).

I found some interesting code in Atmel Software Framework. It is based 
on the following function defined in delay.c file:

__attribute__((optimize("-Os")))
__attribute__ ((section(".ramfunc")))
void portable_delay_cycles(unsigned long n)
{
     (void)n;

     __asm (
         "loop: DMB	\n"
         "SUB r0, r0, #1 \n"
         "CMP r0, #0  \n"
         "BNE loop         "
     );
}


In delay.h there are some macros:

void portable_delay_cycles(unsigned long n);

#define cpu_ms_2_cy(ms, f_cpu)  \
         (((uint64_t)(ms) * (f_cpu) + (uint64_t)(7e3-1ul)) / (uint64_t)7e3)
#define cpu_us_2_cy(us, f_cpu)  \
         (((uint64_t)(us) * (f_cpu) + (uint64_t)(7e6-1ul)) / (uint64_t)7e6)

#define delay_cycles               portable_delay_cycles

#define cpu_delay_s(delay) delay_cycles(cpu_ms_2_cy(1000 * delay, F_CPU))
#define cpu_delay_ms(delay) delay_cycles(cpu_ms_2_cy(delay, F_CPU))
#define cpu_delay_us(delay) delay_cycles(cpu_us_2_cy(delay, F_CPU))


However I didn't measure how precise are the delays generated by those 
functions.

[toc] | [prev] | [next] | [standalone]


#26203

FromDavid Brown <david.brown@hesbynett.no>
Date2017-03-24 12:57 +0100
Message-ID<ob31ei$9k7$1@dont-email.me>
In reply to#26202
On 24/03/17 12:23, pozz wrote:
> Il 23/02/2017 17:15, pozz ha scritto:
>> During startup, I need a short and not precise delay, before configuring
>> clocks, timers and other peripherals (at startup the CPU runs with
>> internal clock).
>>
>> What do you suggest?
>>
>> I think there's a simpler method than configuring a hardware timer.
>>
>> I need to check the status of an input pin, *after* enabling internal
>> pull-up. I'd like to introduce a short delay after enabling internal
>> pull-up, otherwise there's a risk I will read a transient level (maybe 0
>> or 1).
> 
> I found some interesting code in Atmel Software Framework. It is based
> on the following function defined in delay.c file:
> 
> __attribute__((optimize("-Os")))
> __attribute__ ((section(".ramfunc")))
> void portable_delay_cycles(unsigned long n)
> {
>     (void)n;
> 
>     __asm (
>         "loop: DMB    \n"
>         "SUB r0, r0, #1 \n"
>         "CMP r0, #0  \n"
>         "BNE loop         "
>     );
> }
> 

Someone should teach the Atmel folk about gcc inline assembly...

They might also realise that "written in AVR32 assembly" and "portable"
don't really go together!

> 
> In delay.h there are some macros:
> 
> void portable_delay_cycles(unsigned long n);
> 
> #define cpu_ms_2_cy(ms, f_cpu)  \
>         (((uint64_t)(ms) * (f_cpu) + (uint64_t)(7e3-1ul)) / (uint64_t)7e3)
> #define cpu_us_2_cy(us, f_cpu)  \
>         (((uint64_t)(us) * (f_cpu) + (uint64_t)(7e6-1ul)) / (uint64_t)7e6)
> 
> #define delay_cycles               portable_delay_cycles
> 
> #define cpu_delay_s(delay) delay_cycles(cpu_ms_2_cy(1000 * delay, F_CPU))
> #define cpu_delay_ms(delay) delay_cycles(cpu_ms_2_cy(delay, F_CPU))
> #define cpu_delay_us(delay) delay_cycles(cpu_us_2_cy(delay, F_CPU))
> 
> 
> However I didn't measure how precise are the delays generated by those
> functions.

For a multi-MHz cpu clock, they should certainly be better than µs
precision.  The point of the function is to put the code in ram, so that
its timing is not dependent on things like flash access delays.

Of course, if interrupts are enabled, it's a different matter.

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.arch.embedded


csiph-web