Skip to content

Commit 6884e11

Browse files
committed
Added pulseIn implementation
1 parent d20e0d2 commit 6884e11

File tree

4 files changed

+267
-1
lines changed

4 files changed

+267
-1
lines changed

cores/arduino/Arduino.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ void loop( void ) ;
7171
#include "Tone.h"
7272
#include "WMath.h"
7373
#include "HardwareSerial.h"
74-
// #include "wiring_pulse.h"
74+
#include "pulse.h"
7575
#include "delay.h"
7676
#include "Uart.h"
7777
#endif // __cplusplus

cores/arduino/pulse.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
Copyright (c) 2015 Arduino LLC. All right reserved.
3+
4+
This library is free software; you can redistribute it and/or
5+
modify it under the terms of the GNU Lesser General Public
6+
License as published by the Free Software Foundation; either
7+
version 2.1 of the License, or (at your option) any later version.
8+
9+
This library is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
See the GNU Lesser General Public License for more details.
13+
14+
You should have received a copy of the GNU Lesser General Public
15+
License along with this library; if not, write to the Free Software
16+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17+
*/
18+
19+
#include <Arduino.h>
20+
21+
// See pulse_asm.S
22+
extern unsigned long countPulseASM(const volatile uint32_t *port, uint32_t bit, uint32_t stateMask, unsigned long maxloops);
23+
24+
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
25+
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
26+
* to 3 minutes in length, but must be called at least a few dozen microseconds
27+
* before the start of the pulse. */
28+
uint32_t pulseIn(uint32_t pin, uint32_t state, uint32_t timeout)
29+
{
30+
// cache the port and bit of the pin in order to speed up the
31+
// pulse width measuring loop and achieve finer resolution. calling
32+
// digitalRead() instead yields much coarser resolution.
33+
PinDescription p = g_APinDescription[pin];
34+
uint32_t bit = 1 << p.ulPin;
35+
uint32_t stateMask = state ? bit : 0;
36+
37+
// convert the timeout from microseconds to a number of times through
38+
// the initial loop; it takes (roughly) 13 clock cycles per iteration.
39+
uint32_t maxloops = microsecondsToClockCycles(timeout) / 13;
40+
41+
uint32_t width = countPulseASM(&(PORT->Group[p.ulPort].IN.reg), bit, stateMask, maxloops);
42+
43+
// convert the reading to microseconds. The loop has been determined
44+
// to be 13 clock cycles long and have about 16 clocks between the edge
45+
// and the start of the loop. There will be some error introduced by
46+
// the interrupt handlers.
47+
if (width)
48+
return clockCyclesToMicroseconds(width * 13 + 16);
49+
else
50+
return 0;
51+
}
52+

cores/arduino/pulse.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
Copyright (c) 2015 Arduino LLC. All right reserved.
3+
4+
This library is free software; you can redistribute it and/or
5+
modify it under the terms of the GNU Lesser General Public
6+
License as published by the Free Software Foundation; either
7+
version 2.1 of the License, or (at your option) any later version.
8+
9+
This library is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
See the GNU Lesser General Public License for more details.
13+
14+
You should have received a copy of the GNU Lesser General Public
15+
License along with this library; if not, write to the Free Software
16+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17+
*/
18+
19+
#pragma once
20+
21+
#ifdef __cplusplus
22+
extern "C" {
23+
#endif
24+
25+
/*
26+
* \brief Measures the length (in microseconds) of a pulse on the pin; state is HIGH
27+
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
28+
* to 3 minutes in length, but must be called at least a few dozen microseconds
29+
* before the start of the pulse.
30+
*/
31+
uint32_t pulseIn(uint32_t pin, uint32_t state, uint32_t timeout);
32+
33+
#ifdef __cplusplus
34+
// Provides a version of pulseIn with a default argument (C++ only)
35+
uint32_t pulseIn(uint32_t pin, uint32_t state, uint32_t timeout = 1000000L);
36+
37+
} // extern "C"
38+
#endif
39+

cores/arduino/pulse_asm.S

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/*
2+
Copyright (c) 2015 Arduino LLC. All right reserved.
3+
4+
This library is free software; you can redistribute it and/or
5+
modify it under the terms of the GNU Lesser General Public
6+
License as published by the Free Software Foundation; either
7+
version 2.1 of the License, or (at your option) any later version.
8+
9+
This library is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
See the GNU Lesser General Public License for more details.
13+
14+
You should have received a copy of the GNU Lesser General Public
15+
License along with this library; if not, write to the Free Software
16+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17+
*/
18+
19+
/*
20+
21+
The following function has been compiled to ASM with gcc
22+
23+
unsigned long countPulseASM(const volatile uint32_t *port, uint32_t bit, uint32_t stateMask, unsigned long maxloops)
24+
{
25+
unsigned long width = 0;
26+
27+
// wait for any previous pulse to end
28+
while ((*port & bit) == stateMask)
29+
if (--maxloops == 0)
30+
return 0;
31+
32+
// wait for the pulse to start
33+
while ((*port & bit) != stateMask)
34+
if (--maxloops == 0)
35+
return 0;
36+
37+
// wait for the pulse to stop
38+
while ((*port & bit) == stateMask) {
39+
if (++width == maxloops)
40+
return 0;
41+
}
42+
return width;
43+
}
44+
45+
using the command line:
46+
47+
arm-none-eabi-gcc -mcpu=cortex-m0plus -mthumb -c -Os -W -ffunction-sections -fdata-sections \
48+
-nostdlib --param max-inline-insns-single=500 -fno-exceptions -MMD \
49+
-DF_CPU=48000000L -DARDUINO=10602 -DARDUINO_SAMD_ZERO -DARDUINO_ARCH_SAMD \
50+
-D__SAMD21G18A__ -DUSB_VID=0x2341 -DUSB_PID=0x004d -DUSBCON \
51+
-DUSB_MANUFACTURER="Arduino LLC" -DUSB_PRODUCT="Arduino Zero" \
52+
-I/Code/arduino/build/linux/work/hardware/tools/CMSIS/CMSIS/Include/ \
53+
-I/Code/arduino/build/linux/work/hardware/tools/CMSIS/Device/ATMEL/ \
54+
-I/Code/arduino/build/linux/work/hardware/arduino/samd/cores/arduino \
55+
-I/Code/arduino/build/linux/work/hardware/arduino/samd/variants/arduino_zero \
56+
count.c -Wa,-ahlmsd=output.lst -dp -fverbose-asm -S
57+
58+
The result has been slightly edited to increase readability.
59+
60+
*/
61+
62+
.cpu cortex-m0plus
63+
.fpu softvfp
64+
.eabi_attribute 20, 1 @ Tag_ABI_FP_denormal
65+
.eabi_attribute 21, 1 @ Tag_ABI_FP_exceptions
66+
.eabi_attribute 23, 3 @ Tag_ABI_FP_number_model
67+
.eabi_attribute 24, 1 @ Tag_ABI_align8_needed
68+
.eabi_attribute 25, 1 @ Tag_ABI_align8_preserved
69+
.eabi_attribute 26, 1 @ Tag_ABI_enum_size
70+
.eabi_attribute 30, 4 @ Tag_ABI_optimization_goals
71+
.eabi_attribute 34, 0 @ Tag_CPU_unaligned_access
72+
.eabi_attribute 18, 4 @ Tag_ABI_PCS_wchar_t
73+
.file "count.c"
74+
@ GNU C (GNU Tools for ARM Embedded Processors (Arduino build)) version 4.8.3 20140228 (release) [ARM/embedded-4_8-branch revision 208322] (arm-none-eabi)
75+
@ compiled by GNU C version 4.3.2, GMP version 4.3.2, MPFR version 2.4.2, MPC version 0.8.1
76+
@ GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
77+
@ options passed:
78+
@ -I /Code/arduino/build/linux/work/hardware/tools/CMSIS/CMSIS/Include/
79+
@ -I /Code/arduino/build/linux/work/hardware/tools/CMSIS/Device/ATMEL/
80+
@ -I /Code/arduino/build/linux/work/hardware/arduino/samd/cores/arduino
81+
@ -I /Code/arduino/build/linux/work/hardware/arduino/samd/variants/arduino_zero
82+
@ -imultilib armv6-m
83+
@ -iprefix /Code/arduino/build/linux/work/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin/../lib/gcc/arm-none-eabi/4.8.3/
84+
@ -isysroot /Code/arduino/build/linux/work/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin/../arm-none-eabi
85+
@ -MMD count.d -D__USES_INITFINI__ -D F_CPU=48000000L -D ARDUINO=10602
86+
@ -D ARDUINO_SAMD_ZERO -D ARDUINO_ARCH_SAMD -D __SAMD21G18A__
87+
@ -D USB_VID=0x2341 -D USB_PID=0x004d -D USBCON
88+
@ -D USB_MANUFACTURER=Arduino LLC -D USB_PRODUCT=Arduino Zero count.c
89+
@ -mcpu=cortex-m0plus -mthumb -Os -Wextra -ffunction-sections
90+
@ -fdata-sections -fno-exceptions -fverbose-asm
91+
@ --param max-inline-insns-single=500
92+
@ options enabled: -faggressive-loop-optimizations -fauto-inc-dec
93+
@ -fbranch-count-reg -fcaller-saves -fcombine-stack-adjustments -fcommon
94+
@ -fcompare-elim -fcprop-registers -fcrossjumping -fcse-follow-jumps
95+
@ -fdata-sections -fdefer-pop -fdelete-null-pointer-checks -fdevirtualize
96+
@ -fdwarf2-cfi-asm -fearly-inlining -feliminate-unused-debug-types
97+
@ -fexpensive-optimizations -fforward-propagate -ffunction-cse
98+
@ -ffunction-sections -fgcse -fgcse-lm -fgnu-runtime
99+
@ -fguess-branch-probability -fhoist-adjacent-loads -fident -fif-conversion
100+
@ -fif-conversion2 -findirect-inlining -finline -finline-atomics
101+
@ -finline-functions -finline-functions-called-once
102+
@ -finline-small-functions -fipa-cp -fipa-profile -fipa-pure-const
103+
@ -fipa-reference -fipa-sra -fira-hoist-pressure -fira-share-save-slots
104+
@ -fira-share-spill-slots -fivopts -fkeep-static-consts
105+
@ -fleading-underscore -fmath-errno -fmerge-constants -fmerge-debug-strings
106+
@ -fomit-frame-pointer -foptimize-register-move -foptimize-sibling-calls
107+
@ -fpartial-inlining -fpeephole -fpeephole2 -fprefetch-loop-arrays
108+
@ -freg-struct-return -fregmove -freorder-blocks -freorder-functions
109+
@ -frerun-cse-after-loop -fsched-critical-path-heuristic
110+
@ -fsched-dep-count-heuristic -fsched-group-heuristic -fsched-interblock
111+
@ -fsched-last-insn-heuristic -fsched-pressure -fsched-rank-heuristic
112+
@ -fsched-spec -fsched-spec-insn-heuristic -fsched-stalled-insns-dep
113+
@ -fschedule-insns2 -fsection-anchors -fshow-column -fshrink-wrap
114+
@ -fsigned-zeros -fsplit-ivs-in-unroller -fsplit-wide-types
115+
@ -fstrict-aliasing -fstrict-overflow -fstrict-volatile-bitfields
116+
@ -fsync-libcalls -fthread-jumps -ftoplevel-reorder -ftrapping-math
117+
@ -ftree-bit-ccp -ftree-builtin-call-dce -ftree-ccp -ftree-ch
118+
@ -ftree-coalesce-vars -ftree-copy-prop -ftree-copyrename -ftree-cselim
119+
@ -ftree-dce -ftree-dominator-opts -ftree-dse -ftree-forwprop -ftree-fre
120+
@ -ftree-loop-if-convert -ftree-loop-im -ftree-loop-ivcanon
121+
@ -ftree-loop-optimize -ftree-parallelize-loops= -ftree-phiprop -ftree-pre
122+
@ -ftree-pta -ftree-reassoc -ftree-scev-cprop -ftree-sink
123+
@ -ftree-slp-vectorize -ftree-slsr -ftree-sra -ftree-switch-conversion
124+
@ -ftree-tail-merge -ftree-ter -ftree-vect-loop-version -ftree-vrp
125+
@ -funit-at-a-time -fverbose-asm -fzero-initialized-in-bss -mlittle-endian
126+
@ -mpic-data-is-text-relative -msched-prolog -mthumb
127+
@ -mvectorize-with-neon-quad
128+
129+
.section .text.countPulseASM,"ax",%progbits
130+
.align 1
131+
.global countPulseASM
132+
.code 16
133+
.thumb_func
134+
.type countPulseASM, %function
135+
countPulseASM:
136+
push {r4, r5, lr} @ @ 112 *push_multi [length = 2]
137+
.L2:
138+
ldr r4, [r0] @ D.11539, *port_7(D) @ 22 *thumb1_movsi_insn/7 [length = 2]
139+
and r4, r1 @ D.11539, bit @ 24 *thumb1_andsi3_insn [length = 2]
140+
cmp r4, r2 @ D.11539, stateMask @ 25 cbranchsi4_insn/1 [length = 4]
141+
bne .L5 @,
142+
sub r3, r3, #1 @ maxloops, @ 17 *thumb1_addsi3/2 [length = 2]
143+
cmp r3, #0 @ maxloops, @ 18 cbranchsi4_insn/1 [length = 4]
144+
bne .L2 @,
145+
b .L10 @ @ 127 *thumb_jump [length = 2]
146+
.L6:
147+
sub r3, r3, #1 @ maxloops, @ 30 *thumb1_addsi3/2 [length = 2]
148+
cmp r3, #0 @ maxloops, @ 31 cbranchsi4_insn/1 [length = 4]
149+
beq .L10 @,
150+
.L5:
151+
ldr r4, [r0] @ D.11539, *port_7(D) @ 35 *thumb1_movsi_insn/7 [length = 2]
152+
and r4, r1 @ D.11539, bit @ 37 *thumb1_andsi3_insn [length = 2]
153+
cmp r4, r2 @ D.11539, stateMask @ 38 cbranchsi4_insn/1 [length = 4]
154+
bne .L6 @,
155+
mov r4, #0 @ width, @ 7 *thumb1_movsi_insn/2 [length = 2]
156+
.L7:
157+
ldr r5, [r0] @ D.11539, *port_7(D) @ 48 *thumb1_movsi_insn/7 [length = 2]
158+
and r5, r1 @ D.11539, bit @ 50 *thumb1_andsi3_insn [length = 2]
159+
cmp r5, r2 @ D.11539, stateMask @ 51 cbranchsi4_insn/1 [length = 4]
160+
bne .L13 @,
161+
add r4, r4, #1 @ width, @ 43 *thumb1_addsi3/1 [length = 2]
162+
cmp r4, r3 @ width, maxloops @ 44 cbranchsi4_insn/1 [length = 4]
163+
bne .L7 @,
164+
mov r0, #0 @ D.11539, @ 11 *thumb1_movsi_insn/2 [length = 2]
165+
b .L3 @ @ 130 *thumb_jump [length = 2]
166+
.L13:
167+
mov r0, r4 @ D.11539, width @ 9 *thumb1_movsi_insn/1 [length = 2]
168+
b .L3 @ @ 132 *thumb_jump [length = 2]
169+
.L10:
170+
mov r0, r3 @ D.11539, maxloops @ 8 *thumb1_movsi_insn/1 [length = 2]
171+
.L3:
172+
@ sp needed @ @ 115 force_register_use [length = 0]
173+
pop {r4, r5, pc}
174+
.size countPulseASM, .-countPulseASM
175+
.ident "GCC: (GNU Tools for ARM Embedded Processors (Arduino build)) 4.8.3 20140228 (release) [ARM/embedded-4_8-branch revision 208322]"

0 commit comments

Comments
 (0)