EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

Short blocking delay in Cortex-M0+

Started by pozz February 23, 2017
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).
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
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
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.
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?
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
Il giorno gioved&igrave; 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
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
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?
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!

The 2024 Embedded Online Conference