EmbeddedRelated.com
Forums

Accurate delay routine in assembly for ARM7, CortexM3 and M0

Started by Alexan_e June 7, 2012
Hi

I know that any delay based on a loop can only guarantee a min execution
time and that this will be increased if it is interrupted but I don'
think that this makes a delay routine useless, it is up to the
programmer to evaluate the environment in which the delay is executed
and the possible outcomes.
I have seen several times delay routines using volatile variable loops
to achieve delays , why isn't an accurate (uninterrupted )delay more
usefull than that.

So for example in the delays needed in a LCD text display between
commands or in the initialization , does everyone use a timer delay?

Usually there is a delay library for the majority of 8bit
microcontrollers which provides that functionality based on a hard coded
delay so I can't understand why when we jump to a 32bit platform this
practice is considered useless and replaced by timers.
I believe that timers are very convenient if I want to use an input
polling or repeated execution of code in defined intervals while
executing the rest of the code in between but seem like an overkill
solution and waste of resources when I just want a few us delay and
there is no need to execute any code while delaying.

Alex

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

http://alexan.edaboard.eu/ (Home of ARMwizard, a free tool for peripheral initialization of LPC2xxx/17xx/13xx/11xx microcontrollers )

An Engineer's Guide to the LPC2100 Series

Dos your system not have a systick timer that you can use?, this would be a
lot easier.
> Dos your system not have a systick timer that you can use?, this would be a
> lot easier.

My cortex M0 and M3 mcu do have it but my ARM7TDMI does not.
I'm not referring to a specific project, I 'm just looking for a delay
that I can use in a few libraries that can work in several LPC platforms
without the need to have different versions for different platforms.

The systick is used in the scheduler I have made with an alternative of
using timer 3 when systick is not available (ARM7TDMI) or when systick
is used in another task, I would prefer to use another alternative which
for some reason doesn't seem to exist.
I guess that the only option I have (apart from a timer which I prefer
to avoid) is to use a volatile variable loop in C and try to figure the
delays I get.
Or maybe I can stop being stubborn and use a timer like everyone suggests...

Alex
For GCC; works on CM0, CM3, ARM7, ARM9...


--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
SolderCore running Defender... http://www.vimeo.com/25709426
--- In l..., Alexan_e wrote:
> I have seen several times delay routines using volatile variable loops
> to achieve delays , why isn't an accurate (uninterrupted )delay more
> usefull than that.
>

Define 'accurate'.

e.g. if you want the same delay (measured in units of time) on different targets you will need to take the clock speed of the target it is currently running on into account.

> So for example in the delays needed in a LCD text display between
> commands or in the initialization , does everyone use a timer delay?
>

We do. How else can you guarantee that you are going to get the delay that you need (not too long, not too short) within the required tolerance?

> Usually there is a delay library for the majority of 8bit
> microcontrollers which provides that functionality based on a hard coded
> delay so I can't understand why when we jump to a 32bit platform this
> practice is considered useless and replaced by timers.

If you didn't have a timer on your 8bit microcontroller then obviously you couldn't use one so a hard coded delay might have been the only option. Now you do have a timer it is the easiest way to achieve a predictable result.

Regards,
Chris Burrows
Astrobe v4.2: Oberon for Cortex-M3
http://www.astrobe.com
> For GCC; works on CM0, CM3, ARM7, ARM9...
>
> __attribute__((naked)) static void
> delay_loop(unsigned n)
> {
> __asm volatile ("1: subs r0, r0, #1");
> __asm volatile (" bne 1b");
> __asm volatile (" bx lr");
> }
>
> void
> delay_microseconds(unsigned n)
> {
> // Bogus assumption:
> // Assume 8 cycles/iteration and running at 80MHz
> delay_loop(n / 10);
> }

...bother, engage brain, n * 10. Early in the morning and no coffee yet...

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
SolderCore running Defender... http://www.vimeo.com/25709426
On 06/08/2012 11:14 AM, cfbsoftware1 wrote:
>>Define 'accurate'.
>> e.g. if you want the same delay (measured in units of time) on different targets you will need to take the clock speed of the target it is currently running on into account.

Yes the clock of the core should always be defined in order to make the
delay give the expected results, there is no way to calculate the needed
cpu clocks for a given delay without knowing the delay per cpu clock.
In cortrex it is very easy using the SystemCoreClock variable , for ARM7
there will probably be a define set by the user or maybe I'll figure out
an automatic way to calculate the clock.

By accurate a mean that it should have a min delay accuracy, for example
delay_us(5) should give a delay of 5us if not interrupted or more if for
any reason it is interrupted but it shouldn't give 4.5us in any case.

>>If you didn't have a timer on your 8bit microcontroller then obviously you couldn't use one so a hard coded delay might have been the only option.\ >>Now you do have a timer it is the easiest way to achieve a predictable result.

The AVRs and PICs have at least two or three timers so I don't think
that this was a problem.

On 06/08/2012 11:12 AM, Paul Curtis wrote:
>
>
> For GCC; works on CM0, CM3, ARM7, ARM9...
>
> __attribute__((naked)) static void
> delay_loop(unsigned n)
> {
> __asm volatile ("1: subs r0, r0, #1");
> __asm volatile (" bne 1b");
> __asm volatile (" bx lr");
> }
>
> void
> delay_microseconds(unsigned n)
> {
> // Bogus assumption:
> // Assume 8 cycles/iteration and running at 80MHz
> delay_loop(n / 10);
> }

Thank you Paul but unfortunately in the ARM compiler this giver the same
error I got for the delay routine of the first post in this thread
(#1113: Inline assembler not permitted when generating Thumb code)

I have no idea how to fix that.

Alex
This is by no means an 8-bit specific issue.

There are three reasons for the cycle-burning variety for delay in any mcu, would it be 4, 8, 16, 32 or not-power-of-two-bits one:

1. there is no other means (no timer or no free timer)
2. it's a no-care application and using timer is more laborious than using the cycle-burning (for quick and dirty tests like blinkey)
3. short few-cycle delays to accomodate for slow[ish] [external] peripherals

All of them are valid, occur at times, have their limitations and consequences, etc. That's why it may be nice to have library/framework/whatever to use them.

I thought this all goes without mentioning: this is what I meant by being grown-up in a forum like this... :-)

>Thank you Paul but unfortunately in the ARM compiler this giver the same
>error I got for the delay routine of the first post in this thread
> (#1113: Inline assembler not permitted when generating Thumb code)
>
>I have no idea how to fix that.

I don't know either, but here are ideas:

Use non-inline asm?
Complain at Keil/ARM?

JW
> Thank you Paul but unfortunately in the ARM compiler this giver the same
> error I got for the delay routine of the first post in this thread
> (#1113: Inline assembler not permitted when generating Thumb code)
>
> I have no idea how to fix that.

The code above will run in ARM or Thumb mode it is so basic.

If you are using a toolset that cannot swallow unified assembly language,
use the following:



Alternatively, JUST WRITE IT IN UNIFIED ASSEMBLY LANGUAGE.



I mean, this is just like falling off a log, why make it so difficult?

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
SolderCore running Defender... http://www.vimeo.com/25709426
> There are three reasons for the cycle-burning variety for delay in any
> mcu, would it be 4, 8, 16, 32 or not-power-of-two-bits one:
>
> 1. there is no other means (no timer or no free timer)
> 2. it's a no-care application and using timer is more laborious than
> using the cycle-burning (for quick and dirty tests like blinkey)
> 3. short few-cycle delays to accomodate for slow[ish] [external] peripherals

Add the IMHO most important reason: I want to write a library (let's say
for an HD44780 display) and Iw ant my library to be useable *without
imposing restrictions on the rest of the program* (like: thou shalt not
use TIMER0).

Imagine using 5 libraries in your application that each claim one of the
(3?) available timers :(

--

Wouter van Ooijen

-- -------
Van Ooijen Technische Informatica: www.voti.nl
consultancy, development, PICmicro products
docent Hogeschool van Utrecht: www.voti.nl/hvu
C++ on uC blog: http://www.voti.nl/erblog