Skip to content

Instantly share code, notes, and snippets.

@jepler
Created March 2, 2022 16:53
Show Gist options
  • Save jepler/95cd021e60b354f388298b573d725a69 to your computer and use it in GitHub Desktop.
Save jepler/95cd021e60b354f388298b573d725a69 to your computer and use it in GitHub Desktop.
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2022 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
import ulab.numpy as np
buf = np.zeros(80000, dtype=np.uint16)
# On an Adafruit Feather M4 with Floppy Featherwing, do some track-to-track seeking.
import time
import wait_serial
import digitalio
import board
import array
import adafruit_ticks
import microcontroller
import ulab.numpy as np
import adafruit_pioasm
import rp2pio
PHASE_A = board.A2
PHASE_B = board.D13
PHASE_C = board.D12
PHASE_D = board.D11
ENABLE = board.D6
# stepping FORWARD through phases steps OUT towards SMALLER track numbers
# stepping BACKWARD through phases steps IN towards BIGGER track numbers
phases = [
[1, 0, 0, 0],
[1, 1, 0, 0],
[0, 1, 0, 0],
[0, 1, 1, 0],
[0, 0, 1, 0],
[0, 0, 1, 1],
[0, 0, 0, 1],
[1, 0, 0, 1],
]
STEP_OUT_QUARTER = -1
STEP_OUT_HALF = -2
STEP_IN_HALF = 2
STEP_IN_QUARTER = 1
class AppleDrivePositioner:
def __init__(self, a, b, c, d):
self._io = [digitalio.DigitalInOut(p) for p in (a, b, c, d)]
for p in self._io:
p.switch_to_output(False)
self._position = None
def home(self):
self._position = 160
self.step(STEP_OUT_HALF, 80)
@property
def track(self):
if self._position & 3 == 0:
return self._position // 4
return self._position / 4
@track.setter
def track(self, new_position):
if new_position is None:
self._position = None
return
if self._position is None:
self.home()
if new_position >= 40 or new_position < 0:
raise ValueError(f"Invalid track {new_position}")
quarter_track = round(new_position * 4)
diff = quarter_track - self._position
if diff < 0:
# step OUT to SMALLER track numbers
diff = -diff
self.step(STEP_OUT_HALF, diff // 2)
if diff & 1:
self.step(STEP_OUT_QUARTER, 1)
else:
# step IN to BIGGER track numbers
self.step(STEP_IN_HALF, diff // 2)
if diff & 1:
self.step(STEP_IN_QUARTER, 1)
assert self._position == quarter_track, (self._position, quarter_track)
def step(self, delta, n, delay=.016):
print(f"Step by {delta} x {n}")
position = self._position
for i in range(n):
position += delta
phase = position % len(phases)
if phase > len(phases):
phase -= len(phases)
#print(f"set phases to {phase} = {phases[phase]}")
for io, value in zip(self._io, phases[phase]):
io.value = value
time.sleep(delay)
self._position = position
print(f"new position is {position}")
fluxread_program = adafruit_pioasm.Program("""
; Count flux pulses and watch for index pin
; flux input is the 'jmp pin'. index is "pin zero".
; Counts are in units 3 / F_pio, so e.g., at 30MHz 1 count = 0.1us
; Count down while waiting for the counter to go HIGH
; The only counting is down, so C code will just have to negate the count!
; Each 'wait one' loop takes 3 instruction-times
wait_one:
jmp x--, wait_one_next ; acts as a non-conditional decrement of x
wait_one_next:
jmp pin wait_zero
jmp wait_one
; Each 'wait zero' loop takes 3 instruction-times, needing one instruction delay
; (it has to match the 'wait one' timing exactly)
wait_zero:
jmp x--, wait_zero_next ; acts as a non-conditional decrement of x
wait_zero_next:
jmp pin wait_zero [1]
; give 16 bits of 'x'
in x, 16
jmp x--, wait_one
""")
print(fluxread_program.pio_kwargs)
f_CPU = microcontroller.cpu.frequency
frequency = f_CPU // 2
rddatapin = board.D5
def test_fluxread():
with rp2pio.StateMachine(
fluxread_program.assembled,
frequency=frequency,
jmp_pin = rddatapin,
push_threshold = 32,
auto_push = True,
) as sm:
f_pulses = sm.frequency / 3
print(f"sm.frequency={sm.frequency}")
print(f"f_pulses={f_pulses/1e6}MHz")
print(f"1 count = {1e6/f_pulses}us")
sm.readinto(memoryview(buf).cast('L'))
print(min(buf), max(buf))
bins = [0] * 400
o = buf[0]
print(list(buf[:30]))
for i in range(0, len(buf)-1):
n = buf[i]
diff = o - n
if diff < 0: diff += 65536
#if (not (n & 1) and (o & 1)): print(f"falling index @ {i}")
#diff //= 2
diff = min(diff, 399)
bins[diff] += 1
o = n
o = -1
for i, b in enumerate(bins):
if b <= 1:
continue
if i != o+1:
print("---")
o = i
print(f"{i/f_pulses*1e6:7.2} [{i:4}] {b:5}")
if __name__ == '__main__':
enable = digitalio.DigitalInOut(ENABLE)
enable.switch_to_output(False)
positioner = AppleDrivePositioner(PHASE_A, PHASE_B, PHASE_C, PHASE_D)
while True:
positioner.home()
for _ in range(8):
for i in (2, 3, 7, 11, 2, 2.5, 3.75, 5, 6.25, 39, 20, 0):
print(f"**** step to {i}")
positioner.track = i
print()
with digitalio.DigitalInOut(rddatapin) as d:
print(sum(d.value for _ in range(10000)))
test_fluxread()
@jepler
Copy link
Author

jepler commented Mar 2, 2022

Typical flux readings

---
    3.7 [  77]     2
---
    3.8 [  80]    13
    3.9 [  81]   287
    3.9 [  82]  3079
      4 [  83]  6078
      4 [  84]  4999
    4.1 [  85]  5807
    4.1 [  86]  5810
    4.2 [  87]  7116
    4.2 [  88]  5671
    4.3 [  89]  4752
    4.3 [  90]  3893
    4.4 [  91]  2703
    4.4 [  92]   869
    4.5 [  93]   145
    4.5 [  94]    18
---
    4.8 [ 100]     2
---
      6 [ 124]     2
---
    7.7 [ 161]    23
    7.8 [ 162]   230
    7.8 [ 163]  1000
    7.9 [ 164]  2054
    7.9 [ 165]  2600
      8 [ 166]  2384
      8 [ 167]  1950
    8.1 [ 168]  2006
    8.1 [ 169]  2340
    8.2 [ 170]  2338
    8.2 [ 171]  1921
    8.3 [ 172]  1428
    8.3 [ 173]   822
    8.4 [ 174]   248
    8.4 [ 175]    39
    8.4 [ 176]     4
---
    9.5 [ 197]     3
---
     12 [ 244]     5
     12 [ 245]    34
     12 [ 246]   200
     12 [ 247]   468
     12 [ 248]   702
     12 [ 249]   864
     12 [ 250]   768
     12 [ 251]   739
     12 [ 252]   841
     12 [ 253]   782
     12 [ 254]   743
     12 [ 255]   589
     12 [ 256]   332
     12 [ 257]   159
     12 [ 258]    86
     12 [ 259]    23
     12 [ 260]     5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment