Compare commits

..

2 commits

Author SHA1 Message Date
Stephan I. Böttcher
6269048394 flash_alke: update bitfile 2025-10-27 12:57:30 +01:00
Stephan I. Böttcher
934fecf35b leia_stepper: adaptet from chaos.py 2025-10-22 21:21:18 +02:00
2 changed files with 175 additions and 0 deletions

Binary file not shown.

175
leia_stepper.py Normal file
View file

@ -0,0 +1,175 @@
import sys, armlib, struct, math, time
class leia_stepper:
class Stepper_Error(armlib.irena_ifc.IrenaError):
pass
def __init__(self, ifc):
if ifc:
self._connect(ifc)
def _connect(self, ifc):
self.ifc = ifc
self.ifc.cmd("spi/reset/ssel/rate 30")
def _export(self, scope=None, prefix="stepper_"):
"""usage: ..._export(globals())
return a dict with all mames in self that
do not begin with an '_'
and are not all uppercase.
The scope is updated with the dict.
"""
r = {
prefix+k: getattr(self, k)
for k in dir(self)
if k.upper() != k and k[0] != "_"
}
if scope:
scope.update(r)
return r
_verbose = 2
cmd_pref = "spi/step"
def cmd(self, cmd, arg=0, argh=None, Error=False, retry=False, eth_retry=False):
c = ord(cmd[0])
arg2 = 0
if len(cmd)>1:
cc = f"{self.cmd_pref} {cmd!r} 0x{arg:x}"
else:
if isinstance(arg, str):
arg = arg.encode()
if isinstance(arg, bytes):
arg = arg[0]
if len(arg) > 1:
arg2 = arg[1]
if argh is not None:
arg2 = argh
if arg & 0xff00:
cc = f"{self.cmd_pref} {cmd!r} 0x{arg:x}"
else:
cc = f"{self.cmd_pref} {cmd!r} 0x{arg:x} 0x{arg2:x}"
while True:
r = self.ifc.cmd(cc, timeout=1000)
if r is None and eth_retry:
continue
if self._verbose >= 2:
print(cc, r, file=sys.stderr)
if self.ifc.cmdn(r) != 280:
if retry and self.ifc.cmdn(r) == 780 and r.split()[-1] == "130":
continue
raise self.Stepper_Error(r)
rr = r.split()
r1 = int(rr[2],0)
r = int(rr[3],0)
if retry and r1==0x45 and (r==0x5945 or r==0x5745):
# "EEY" interruped action by SPI
# "EEW" watchdog int during command Rx
continue
if r1 != c:
if Error:
r |= r1<<16
else:
raise self.Stepper_Error(f"{chr(r1)} {rr[3]}")
break
return r
def id(self):
n = self.hvc('V', 0xff) >> 8
return "".join([chr(self.hvc('V', i) & 0xff) for i in range(n)])
CONFN = [
"magic",
"version",
"flags",
"period",
"slen",
"lmask",
"lval",
"step",
"enable",
"reset",
"dir",
"n_steps",
"dac",
"dac_ramp",
"dac_step",
"adc_idx",
"adc_incr",
"adc_period",
"pad1", "pad23", "pad45", "pad67",
"adc00", "adc01", "adc02", "adc03",
"adc04", "adc05", "adc06", "adc07",
"adc08", "adc09", "adc10", "adc11",
"adc12", "adc13", "adc14", "adc15",
]
CONFV = (1,)
CONFF = "<HBBHH6B4H4B3H16B"
CONFS = 48
CONFM = b'\x1a\x1e'
def confdict(self, b):
b = struct.unpack(self.CONFF, b)
b = {k:v for k,v in zip(self.CONFN, b)}
return b
def confbytes(self, b, a=0):
"from str, dict, list, or bytes: make conf bytes"
if isinstance(b, str):
b = self.readhex(b, a, unpack=True)
if isinstance(b, dict):
b = [b[k] for k in self.CONFN]
if isinstance(b, list):
b = struct.pack(self.CONFF, *b)
return b
def read_conf(self, unpack=True):
b = []
while True:
r = self.cmd('x', len(b), Error=True)
if r & 0xff0000:
break
b.append(r & 0xff)
time.sleep(0.005)
b = bytes(b)
if unpack and b[:2]==self.CONFM and b[2] in self.CONFV:
return self.confdict(b)
return b
def readhex(self, fn, a=0, unpack=False):
import intelhex
b = bytes(intelhex.IntelHex(fn).tobinarray())[4*a:]
if not unpack:
return b
return self.confdict(b[:self.CONFS])
def verify_conf(self, b, a=0):
f = self.confbytes(b, a)
c = self.read_conf(unpack=False)
return [(4*a+i, b, f[i]) for i, b in enumerate(c) if b != f[i]]
def write_conf(self, b, a=0):
b = self.confbytes(b,a)
n = 0
for i, bb in enumerate(b):
self.cmd('X', i, bb)
n = i+1
return b[:n]
def adc(self, ch=0, what=0, val=0):
return self.cmd('a', val, what<<4 | ch & 0xf);
def dac(self, volt=0.0, dac=None, ramp=True):
if dac is None:
dac = int(volt/3.3*0x10000)
if dac < 0 or dac >= 0x10000:
raise ValueError(f"DAC voltage out of range {volt}, {dac}")
old = self.cmd('D', dac)
if self._verbose >= 2:
print(f"DAC set to 0x{dac:04x}, old value: 0x{old:04x}",
file=sys.stderr)
self._dacvalue = dac