Created
March 2, 2022 16:53
-
-
Save jepler/95cd021e60b354f388298b573d725a69 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Typical flux readings