Skip to content

Commit d93b18f

Browse files
committed
pulseIn: add ASM implementation for Due
1 parent a8af250 commit d93b18f

File tree

4 files changed

+185
-25
lines changed

4 files changed

+185
-25
lines changed

hardware/arduino/sam/cores/arduino/wiring_pulse.cpp

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,39 +23,27 @@
2323
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
2424
* to 3 minutes in length, but must be called at least a few dozen microseconds
2525
* before the start of the pulse. */
26-
extern uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout )
26+
uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout )
2727
{
2828
// cache the port and bit of the pin in order to speed up the
2929
// pulse width measuring loop and achieve finer resolution. calling
3030
// digitalRead() instead yields much coarser resolution.
3131
PinDescription p = g_APinDescription[pin];
32-
uint32_t width = 0; // keep initialization out of time critical area
32+
uint32_t bit = p.ulPin;
33+
uint32_t stateMask = state ? bit : 0;
3334

3435
// convert the timeout from microseconds to a number of times through
35-
// the initial loop; it takes 22 clock cycles per iteration.
36-
uint32_t numloops = 0;
37-
uint32_t maxloops = microsecondsToClockCycles(timeout) / 22;
38-
39-
// wait for any previous pulse to end
40-
while (PIO_Get(p.pPort, PIO_INPUT, p.ulPin) == state)
41-
if (numloops++ == maxloops)
42-
return 0;
43-
44-
// wait for the pulse to start
45-
while (PIO_Get(p.pPort, PIO_INPUT, p.ulPin) != state)
46-
if (numloops++ == maxloops)
47-
return 0;
48-
49-
// wait for the pulse to stop
50-
while (PIO_Get(p.pPort, PIO_INPUT, p.ulPin) == state) {
51-
if (numloops++ == maxloops)
52-
return 0;
53-
width++;
54-
}
36+
// the initial loop; it takes (roughly) 18 clock cycles per iteration.
37+
uint32_t maxloops = microsecondsToClockCycles(timeout) / 18;
38+
39+
uint32_t width = countPulseASM(&(p.pPort->PIO_PDSR), bit, stateMask, maxloops);
5540

5641
// convert the reading to microseconds. The loop has been determined
57-
// to be 52 clock cycles long and have about 16 clocks between the edge
42+
// to be 18 clock cycles long and have about 16 clocks between the edge
5843
// and the start of the loop. There will be some error introduced by
5944
// the interrupt handlers.
60-
return clockCyclesToMicroseconds(width * 52 + 16);
45+
if (width)
46+
return clockCyclesToMicroseconds(width * 18 + 16);
47+
else
48+
return 0;
6149
}

hardware/arduino/sam/cores/arduino/wiring_pulse.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
extern "C" {
2424
#endif
2525

26+
unsigned long countPulseASM(const volatile uint32_t *port, uint32_t bit, uint32_t stateMask, unsigned long maxloops);
2627
/*
2728
* \brief Measures the length (in microseconds) of a pulse on the pin; state is HIGH
2829
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
Copyright (c) 2015 Arduino LLC. All right reserved.
3+
This library is free software; you can redistribute it and/or
4+
modify it under the terms of the GNU Lesser General Public
5+
License as published by the Free Software Foundation; either
6+
version 2.1 of the License, or (at your option) any later version.
7+
This library is distributed in the hope that it will be useful,
8+
but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10+
See the GNU Lesser General Public License for more details.
11+
You should have received a copy of the GNU Lesser General Public
12+
License along with this library; if not, write to the Free Software
13+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
14+
*/
15+
16+
/*
17+
The following function has been compiled to ASM with gcc
18+
unsigned long countPulseASM(const volatile uint32_t *port, uint32_t bit, uint32_t stateMask, unsigned long maxloops)
19+
{
20+
unsigned long width = 0;
21+
// wait for any previous pulse to end
22+
while ((*port & bit) == stateMask)
23+
if (--maxloops == 0)
24+
return 0;
25+
// wait for the pulse to start
26+
while ((*port & bit) != stateMask)
27+
if (--maxloops == 0)
28+
return 0;
29+
// wait for the pulse to stop
30+
while ((*port & bit) == stateMask) {
31+
if (++width == maxloops)
32+
return 0;
33+
}
34+
return width;
35+
}
36+
37+
using the command line:
38+
39+
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -c -O2 -W -ffunction-sections -fdata-sections -nostdlib \
40+
countPulseASM.c -Wa,-ahlmsd=output.lst -dp -fverbose-asm -S \
41+
-I.arduino15/packages/arduino/hardware/sam/1.6.3/cores/arduino \
42+
-I.arduino15/packages/arduino/hardware/sam/1.6.3/system/CMSIS/CMSIS/Include \
43+
-I.arduino15/packages/arduino/hardware/sam/1.6.3/system/CMSIS/Device/ATMEL \
44+
-I.arduino15/packages/arduino/hardware/sam/1.6.3/system/libsam/include \
45+
-I.arduino15/packages/arduino/hardware/sam/1.6.3/variants/arduino_due_x
46+
47+
The result has been slightly edited to increase readability.
48+
*/
49+
50+
.syntax unified
51+
.cpu cortex-m3
52+
.fpu softvfp
53+
.eabi_attribute 20, 1 @ Tag_ABI_FP_denormal
54+
.eabi_attribute 21, 1 @ Tag_ABI_FP_exceptions
55+
.eabi_attribute 23, 3 @ Tag_ABI_FP_number_model
56+
.eabi_attribute 24, 1 @ Tag_ABI_align8_needed
57+
.eabi_attribute 25, 1 @ Tag_ABI_align8_preserved
58+
.eabi_attribute 26, 1 @ Tag_ABI_enum_size
59+
.eabi_attribute 30, 2 @ Tag_ABI_optimization_goals
60+
.eabi_attribute 34, 1 @ Tag_CPU_unaligned_access
61+
.eabi_attribute 18, 4 @ Tag_ABI_PCS_wchar_t
62+
.file "countPulseASM.c"
63+
@ GNU C (GNU Tools for ARM Embedded Processors) version 4.9.3 20150303 (release) [ARM/embedded-4_9-branch revision 221220] (arm-none-eabi)
64+
@ compiled by GNU C version 4.7.4, GMP version 4.3.2, MPFR version 2.4.2, MPC version 0.8.1
65+
@ GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
66+
@ options passed:
67+
@ -I .arduino15/packages/arduino/hardware/sam/1.6.3/cores/arduino
68+
@ -I .arduino15/packages/arduino/hardware/sam/1.6.3/system/CMSIS/CMSIS/Include
69+
@ -I .arduino15/packages/arduino/hardware/sam/1.6.3/system/CMSIS/Device/ATMEL
70+
@ -I .arduino15/packages/arduino/hardware/sam/1.6.3/system/libsam/include
71+
@ -I .arduino15/packages/arduino/hardware/sam/1.6.3/variants/arduino_due_x
72+
@ -imultilib armv7-m -iprefix /usr/bin/../lib/gcc/arm-none-eabi/4.9.3/
73+
@ -isysroot /usr/bin/../arm-none-eabi -D__USES_INITFINI__ countPulseASM.c
74+
@ -mcpu=cortex-m3 -mthumb -O2 -Wextra -ffunction-sections -fdata-sections
75+
@ -fverbose-asm
76+
@ options enabled: -faggressive-loop-optimizations -fauto-inc-dec
77+
@ -fbranch-count-reg -fcaller-saves -fcombine-stack-adjustments -fcommon
78+
@ -fcompare-elim -fcprop-registers -fcrossjumping -fcse-follow-jumps
79+
@ -fdata-sections -fdefer-pop -fdelete-null-pointer-checks -fdevirtualize
80+
@ -fdevirtualize-speculatively -fdwarf2-cfi-asm -fearly-inlining
81+
@ -feliminate-unused-debug-types -fexpensive-optimizations
82+
@ -fforward-propagate -ffunction-cse -ffunction-sections -fgcse -fgcse-lm
83+
@ -fgnu-runtime -fgnu-unique -fguess-branch-probability
84+
@ -fhoist-adjacent-loads -fident -fif-conversion -fif-conversion2
85+
@ -findirect-inlining -finline -finline-atomics
86+
@ -finline-functions-called-once -finline-small-functions -fipa-cp
87+
@ -fipa-profile -fipa-pure-const -fipa-reference -fipa-sra
88+
@ -fira-hoist-pressure -fira-share-save-slots -fira-share-spill-slots
89+
@ -fisolate-erroneous-paths-dereference -fivopts -fkeep-static-consts
90+
@ -fleading-underscore -flifetime-dse -fmath-errno -fmerge-constants
91+
@ -fmerge-debug-strings -fmove-loop-invariants -fomit-frame-pointer
92+
@ -foptimize-sibling-calls -foptimize-strlen -fpartial-inlining -fpeephole
93+
@ -fpeephole2 -fprefetch-loop-arrays -freg-struct-return -freorder-blocks
94+
@ -freorder-functions -frerun-cse-after-loop
95+
@ -fsched-critical-path-heuristic -fsched-dep-count-heuristic
96+
@ -fsched-group-heuristic -fsched-interblock -fsched-last-insn-heuristic
97+
@ -fsched-pressure -fsched-rank-heuristic -fsched-spec
98+
@ -fsched-spec-insn-heuristic -fsched-stalled-insns-dep -fschedule-insns
99+
@ -fschedule-insns2 -fsection-anchors -fshow-column -fshrink-wrap
100+
@ -fsigned-zeros -fsplit-ivs-in-unroller -fsplit-wide-types
101+
@ -fstrict-aliasing -fstrict-overflow -fstrict-volatile-bitfields
102+
@ -fsync-libcalls -fthread-jumps -ftoplevel-reorder -ftrapping-math
103+
@ -ftree-bit-ccp -ftree-builtin-call-dce -ftree-ccp -ftree-ch
104+
@ -ftree-coalesce-vars -ftree-copy-prop -ftree-copyrename -ftree-cselim
105+
@ -ftree-dce -ftree-dominator-opts -ftree-dse -ftree-forwprop -ftree-fre
106+
@ -ftree-loop-if-convert -ftree-loop-im -ftree-loop-ivcanon
107+
@ -ftree-loop-optimize -ftree-parallelize-loops= -ftree-phiprop -ftree-pre
108+
@ -ftree-pta -ftree-reassoc -ftree-scev-cprop -ftree-sink -ftree-slsr
109+
@ -ftree-sra -ftree-switch-conversion -ftree-tail-merge -ftree-ter
110+
@ -ftree-vrp -funit-at-a-time -fverbose-asm -fzero-initialized-in-bss
111+
@ -mfix-cortex-m3-ldrd -mlittle-endian -mlra -mpic-data-is-text-relative
112+
@ -msched-prolog -mthumb -munaligned-access -mvectorize-with-neon-quad
113+
114+
.section .text.countPulseASM,"ax",%progbits
115+
.align 2
116+
.global countPulseASM
117+
.thumb
118+
.thumb_func
119+
.type countPulseASM, %function
120+
countPulseASM:
121+
@ args = 0, pretend = 0, frame = 0
122+
@ frame_needed = 0, uses_anonymous_args = 0
123+
@ link register save eliminated.
124+
push {r4, r5} @ @ 132 *push_multi [length = 2]
125+
b .L2 @ @ 178 *arm_jump [length = 2]
126+
.L4:
127+
subs r3, r3, #1 @ maxloops, maxloops, @ 18 thumb2_addsi3_compare0/1 [length = 2]
128+
beq .L12 @, @ 19 arm_cond_branch [length = 2]
129+
.L2:
130+
ldr r4, [r0] @ D.4169, *port_7(D) @ 22 *thumb2_movsi_insn/6 [length = 4]
131+
ands r4, r4, r1 @, D.4169, D.4169, bit @ 24 *thumb2_alusi3_short [length = 2]
132+
cmp r4, r2 @ D.4169, stateMask @ 25 *arm_cmpsi_insn/2 [length = 2]
133+
beq .L4 @, @ 26 arm_cond_branch [length = 2]
134+
b .L6 @ @ 181 *arm_jump [length = 2]
135+
.L7:
136+
subs r3, r3, #1 @ maxloops, maxloops, @ 32 thumb2_addsi3_compare0/1 [length = 2]
137+
beq .L12 @, @ 33 arm_cond_branch [length = 2]
138+
.L6:
139+
ldr r4, [r0] @ D.4169, *port_7(D) @ 41 *thumb2_movsi_insn/6 [length = 4]
140+
ands r4, r4, r1 @, D.4169, D.4169, bit @ 43 *thumb2_alusi3_short [length = 2]
141+
cmp r4, r2 @ D.4169, stateMask @ 44 *arm_cmpsi_insn/2 [length = 2]
142+
bne .L7 @, @ 45 arm_cond_branch [length = 2]
143+
movs r5, #0 @ width, @ 7 *thumb2_movsi_shortim [length = 2]
144+
b .L9 @ @ 183 *arm_jump [length = 2]
145+
.L10:
146+
adds r5, r5, #1 @ width, width, @ 50 *thumb2_addsi_short/1 [length = 2]
147+
cmp r3, r5 @ maxloops, width @ 51 *arm_cmpsi_insn/2 [length = 2]
148+
beq .L22 @, @ 52 arm_cond_branch [length = 2]
149+
.L9:
150+
ldr r4, [r0] @ D.4169, *port_7(D) @ 60 *thumb2_movsi_insn/6 [length = 4]
151+
ands r4, r4, r1 @, D.4169, D.4169, bit @ 62 *thumb2_alusi3_short [length = 2]
152+
cmp r4, r2 @ D.4169, stateMask @ 63 *arm_cmpsi_insn/2 [length = 2]
153+
beq .L10 @, @ 64 arm_cond_branch [length = 2]
154+
mov r0, r5 @ D.4169, width @ 9 *thumb2_movsi_insn/1 [length = 2]
155+
pop {r4, r5} @ @ 165 *load_multiple_with_writeback [length = 4]
156+
bx lr @ @ 166 *thumb2_return [length = 4]
157+
.L12:
158+
mov r0, r3 @ D.4169, maxloops @ 8 *thumb2_movsi_insn/1 [length = 2]
159+
pop {r4, r5} @ @ 137 *load_multiple_with_writeback [length = 4]
160+
bx lr @ @ 138 *thumb2_return [length = 4]
161+
.L22:
162+
movs r0, #0 @ D.4169, @ 11 *thumb2_movsi_shortim [length = 2]
163+
pop {r4, r5} @ @ 173 *load_multiple_with_writeback [length = 4]
164+
bx lr @ @ 174 *thumb2_return [length = 4]
165+
.size countPulseASM, .-countPulseASM
166+
.ident "GCC: (GNU Tools for ARM Embedded Processors) 4.9.3 20150303 (release) [ARM/embedded-4_9-branch revision 221220]"

hardware/arduino/sam/platform.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ compiler.c.cmd=arm-none-eabi-gcc
2222
compiler.c.flags=-c -g -Os {compiler.warning_flags} -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -Dprintf=iprintf -MMD
2323
compiler.c.elf.cmd=arm-none-eabi-gcc
2424
compiler.c.elf.flags=-Os -Wl,--gc-sections
25-
compiler.S.flags=-c -g -x assembler-with-cpp
25+
compiler.S.cmd=arm-none-eabi-gcc
26+
compiler.S.flags=-c -g -x assembler-with-cpp -mthumb
2627
compiler.cpp.cmd=arm-none-eabi-g++
2728
compiler.cpp.flags=-c -g -Os {compiler.warning_flags} -ffunction-sections -fdata-sections -nostdlib -fno-threadsafe-statics --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -Dprintf=iprintf -MMD
2829
compiler.ar.cmd=arm-none-eabi-ar
@@ -42,6 +43,7 @@ build.extra_flags=
4243
compiler.c.extra_flags=
4344
compiler.c.elf.extra_flags=
4445
compiler.cpp.extra_flags=
46+
compiler.S.extra_flags=
4547
compiler.ar.extra_flags=
4648
compiler.elf2hex.extra_flags=
4749

@@ -66,6 +68,9 @@ recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -mcpu={b
6668
## Compile c++ files
6769
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {compiler.libsam.c.flags} {includes} "{source_file}" -o "{object_file}"
6870

71+
## Compile S files
72+
recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {compiler.libsam.c.flags} {includes} "{source_file}" -o "{object_file}"
73+
6974
## Create archives
7075
recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{build.path}/{archive_file}" "{object_file}"
7176

0 commit comments

Comments
 (0)