Delay

Accurate Blocking Delay

This blocking delay is created using arm-none-eabi-as to produce the machine code which is then INLINED into a Forth Word.

Note

While the delay is being used, the CPU is not available to do anything else.

To see the same thing done using Interactive Assembly see Interactive Assembly Blocking Delay

Why do it this way ?

The reason that the millisecond blocking delay is done this way rather than in pure Forth is because it can be done in about half the binary code size compared to a pure Forth Word. Another reason is that sometimes maximum speed is required and this means using minimal instructions in the Forth Word. The delay example is a great way to demonstrate how to achieve this.

Note

The THUMB Instruction Set is used here

Using Pure Forth Instead

The pure Forth way is certainly much faster to write and debug compared to the alternate methods.

The “delay” Word below uses the common “do-loop”.

: delay
  0 do loop
;

Disassembly

see delay

2000068A: B500  push { lr }
2000068C: B430  push { r4  r5 }
2000068E: 2400  movs r4 #0
20000690: 0035  lsls r5 r6 #0
20000692: CF40  ldmia r7 { r6 }
20000694: 3401  adds r4 #1
20000696: 42AC  cmp r4 r5
20000698: D1FC  bne 20000694
2000069A: BC30  pop { r4  r5 }
2000069C: BD00  pop { pc }

Bytes: 20  ok.

Delay Measurments

Timing measurements were performed using the on chip Systick counter set to a count of 0.1ms using a Interrupt.

Input

Delay

Period

Comments

10000000

6.5359

seconds

uncalibrated

The Method below produces the following delays:

  1. 105.2nS @ 48Mhz

  2. 631.2nS @ 8Mhz

Note

Although very accurate due to the small loop, the accuracy will be affected by many factors such as the cache, interrupts and the stability of the clock. All blocking loop delays are affected by these things, but they are fine for general purpose delays of a known time period such a providing a minimum pulse width for a LCD display, blinking a LED and so on. If greater accuracy is required, consider using a Timer Peripheral instead.

In this example the delay Word is named “105ns” for use on a 48MHz system.

Delay Code

: 105ns  ( u --  )     \ 105.2ns delay @ 48mhz clock
  [
  $3e01 h,    \ subs   r6, #1
  $46c0 h,    \ nop
  $d1fc h,    \ bne.n  8 <loop>
  ] drop
;

Disassembly

see 105ns

20000688: B500  push { lr }
2000068A: 3E01  subs r6 #1
2000068C: 46C0  mov r8 r8
2000068E: D1FC  bne 2000068A
20000690: CF40  ldmia r7 { r6 }
20000692: BD00  pop { pc }

Bytes: 12  ok.

Delay Measurments

Timing measurements were performed using the on chip Systick counter set to a count of 0.1ms using a Interrupt.

This delay should work for a minium delay of 105.2 nS to a maximum delay of 451.86 seconds (7.53 Minutes)

Input

Delay

Period

Comments

1

105.2

ns

CALCULATED (too small to measure with systick)

1000

0.1052

ms

CALCULATED (too small to measure with systick)

1000000

0.1052

seconds

10000000

1.0521

seconds

$00FFFFFF

1.7651

seconds

$0FFFFFFF

28.2415

seconds

$FFFFFFFF

451.8640

seconds

(7.531067 minutes)

Millisecond Delay

The ms Word calls the 105ns Word and is scaled for 1 ms.

: ms ( u  -- )    \ for a 48 Mhz clock
  9505 * 105ns
;

Example usage

This lights the green LED on a Discovery board (clocked at 48MHz) for exactly 1 second.

: green-led-on-1-second ( -- ) green-on 1000 ms green-off ;

How to Inline code

Write the code in Assembler

_images/assembly-delay-gvim.jpg

Compile the code with arm-none-eabi-as

_images/assembly-delay-makefile.jpg

Test the Code in GDB

Note: the code shown here is slightly different to the actual “Delay Code” above because I have inserted a fake “Top Of Stack” line to supply R6 with a delay value of 0x2 for the debugging session. When this code is used with Forth, R6 will already contain a valid number from the user program so the fake TOS isn’t required.

GDB talks to the actual MCU via SWD and single steps thru the program on the actual chip, displaying register contents and following the program flow on the actual chip.

It’s incredible to think that this facility which once used to cost tens of thousands of dollars is available in a MCU costing $0.56 USD and that the GNU software is Free.

_images/assembly-delay-gdb.jpg

Cut and Paste the Machine Code into a Forth Word

The paste must be edited to suit Forth as seen in the “Delay Code” above.

_images/assembly-delay.list.jpg