-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathPIO_4Intervals_Timer.py
More file actions
155 lines (123 loc) · 4.71 KB
/
PIO_4Intervals_Timer.py
File metadata and controls
155 lines (123 loc) · 4.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
'''
Measure time intervals on input pulses, using PIO state machine hardware
RP2040 CPU clock at 250 MHz
J.Beale 15-March-2021
'''
import utime
import rp2
from rp2 import PIO, asm_pio
from machine import Pin
'''
______ _____ _____
pin 1 _______/ \_____/ \____/
A B C D E
Time A-B, A-C, A-D, and A-E intervals:
Start counting on rising edge A
report timer values at edges B, C, D, and E
'''
# Assembly code for RP2040 PIO hardware state machine
@asm_pio()
def PULSE_LOW_DELTA():
# Initialize x to be -1
set(x,0)
jmp(x_dec,'START')
label('START')
# Syntax: wait(Polarity,Source,Index)
# https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf#section_pio
wait(0,pin,0) # wait for pin1 to be low (if isn't already)
wait(1,pin,0) # wait for pin1 to be high: first rising edge
# Here, just had rising edge; pin1 is high
# Now, dec x while pin1 remains high
label('loop')
jmp(x_dec,'continue') # decrement X, jump if zero
label('continue')
jmp(pin, 'loop') # jump when 'pin' (config as pin1=GPIO16) is high
mov(isr,x) # transfer X to input shift register
push() # transfer shift register to FIFO
# here, just had falling edge. pin1 is low
# dec x until pin1 goes high
label('loop2')
jmp(pin, 'exit') # jump when 'pin' (config as pin1=GPIO16) is high
jmp(x_dec,'loop2') # decrement X, jump if zero
label('exit')
mov(isr,x) # transfer X to input shift register
push() # transfer shift register to FIFO
# Here, just had 2nd rising edge; pin1 is high
# Now, dec x while pin1 remains high
label('loop3')
jmp(x_dec,'cont2') # decrement X, jump if zero
label('cont2')
jmp(pin, 'loop3') # jump when 'pin' (config as pin1=GPIO16) is high
mov(isr,x) # transfer X to input shift register
push() # transfer shift register to FIFO
# here, just had 2nd falling edge; pin1 is low
# dec x until pin1 goes high
label('loop4')
jmp(pin, 'exit2') # jump when 'pin' (config as pin1=GPIO16) is high
jmp(x_dec,'loop4') # decrement X, jump if zero
label('exit2')
# Now report value to CPU via FIFO, with push
mov(isr,x) # transfer X to input shift register
push() # transfer shift register to FIFO
label('End')
jmp('End') # stop everything
# regular Python code follows
class pulsedelay:
def __init__(self,pin1,pin2, stateMachine=0):
self.pin1 = pin1
self.pin2 = pin2
self.sm= rp2.StateMachine(stateMachine)
def get(self):
self.sm.init(PULSE_LOW_DELTA,freq=250000000,
in_base=(self.pin1),
jmp_pin=(self.pin2))
''' in_base declare the first Pin offset
jmp_pin declare the pin to use for jmp (this is not an offset)
'''
self.sm.active(1)
return (0xffffffff - self.sm.get()) # units of raw counter ticks, T = 1/freq
def read_blocking(self, n):
self.sm.init(PULSE_LOW_DELTA,freq=250000000,
in_base=(self.pin1),
jmp_pin=(self.pin2))
''' in_base declare the first Pin offset
jmp_pin declare the pin to use for jmp (this is not an offset)
'''
self.sm.active(1)
data = []
for i in range(n):
data.append(0xffffffff - self.sm.get() )
return data
# -----------------------------------------
if __name__ == "__main__":
import machine as m
m.freq(250000000) # overclock to 250 MHz. Wheee!
#m.freq(125000000) # standard clock speed
# nominal timings from 1-PPS, 10% duty pulse
nomInt = (12500000, 125000000, 137500000, 250000000)
p1 = m.Pin(16,m.Pin.IN, m.Pin.PULL_UP) # Channel A input
led1 = m.Pin(25, m.Pin.OUT) # set pin 25 (driving onboard LED) to output
led2 = m.Pin(22, m.Pin.OUT) # set external output pin (driving offboard LED) to output
led1.off()
led2.off()
pulsein = pulsedelay(p1,p1)
rSum = 0 # running sum of interval deltas
while True:
newVals = pulsein.read_blocking(4) # get interval times
i = 0
for n in newVals:
delta = nomInt[i] - (n+i) # +i correction due to mov,push overhead
print("%d" % delta,end="")
if i < 3:
i += 1
print(", ",end="")
print()
led1.toggle()
# Note: Timer Period = 2/(250 MHz) so time in microseconds = newVal / (125)
# Sample output with 1-PPS 10% duty cycle input:
# -1, 3, 1, 5
# -1, 3, 1, 6
# -1, 3, 2, 6
# -1, 3, 2, 6
# -1, 3, 1, 6
# -1, 3, 2, 6