Compare commits
33 commits
master
...
turbo_dose
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33d120cf80 | ||
|
|
18f6ba9c2f | ||
|
|
cce9ded5a2 | ||
|
|
8a56b61f79 | ||
|
|
e5af295232 | ||
|
|
2aab85975a | ||
|
|
13407292dd | ||
|
|
873a2ba93a | ||
|
|
6fcdb271d3 | ||
|
|
302b6bb8d7 | ||
|
|
d1e6a031ab | ||
|
|
0fa9cdbc14 | ||
|
|
899798defa | ||
|
|
26e39e219e | ||
|
|
0248c1dab2 | ||
|
|
60abd1ab89 | ||
|
|
0e878a6fa4 | ||
|
|
977af7648b | ||
|
|
133f55edf6 | ||
|
|
65d615407c | ||
|
|
bd0238bb2d | ||
|
|
f0945b9227 | ||
|
|
97d00bc908 | ||
|
|
90aaf8d48e | ||
|
|
46809f6fac | ||
|
|
bf73d2b586 | ||
|
|
429a0bf530 | ||
|
|
867b705561 | ||
|
|
210779c074 | ||
|
|
94625ffdc8 | ||
|
|
45a055527e | ||
|
|
7575ad5cda | ||
|
|
f3e6b2ebf7 |
62 changed files with 5494 additions and 2575 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -22,3 +22,9 @@ src/mul
|
|||
*.eeprom
|
||||
*.elf
|
||||
src/data
|
||||
BCH-Codes/
|
||||
*.odt
|
||||
*.userrow
|
||||
*.m
|
||||
src/data
|
||||
galois
|
||||
|
|
|
|||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "src/bch4369"]
|
||||
path = src/bch4369
|
||||
url = git@codeberg.org:SiB64/bch4369
|
||||
510
dose.py
Normal file
510
dose.py
Normal file
|
|
@ -0,0 +1,510 @@
|
|||
#! /usr/bin/ipython3 --profile=turbo_dose
|
||||
|
||||
import sys, time, getopt, fileinput, struct, csv, os, contextlib
|
||||
import uart
|
||||
from base85 import base85_encode, base85_decode
|
||||
from map import memmap
|
||||
from iotn424 import SFR
|
||||
import flash as flash_cmd
|
||||
flash_cmd = flash_cmd.flash_cmd()
|
||||
sys.path[1:1] = ["./bch4369"]
|
||||
from bch4369 import bch
|
||||
|
||||
options, files = getopt.gnu_getopt(sys.argv[1:], "F:o:M:", ["debug", "tty=", "output=", "map=", "galois"])
|
||||
|
||||
tty = None
|
||||
baud = 115200
|
||||
out = None
|
||||
debug = None
|
||||
map_fn = "hallo.map"
|
||||
|
||||
def Debug(e, *a):
|
||||
if debug:
|
||||
import traceback
|
||||
sys.stdout.flush()
|
||||
print("xdebug", a, repr(e), file=sys.stderr)
|
||||
traceback.print_exception(e, limit=-2, file=sys.stderr)
|
||||
|
||||
for o,v in options:
|
||||
|
||||
if o == "--debug":
|
||||
debug = True
|
||||
|
||||
if o in "-F --tty":
|
||||
tty = v
|
||||
v = v.split(",", 1)
|
||||
if v[1:]:
|
||||
tty = v[0]
|
||||
baud = int(v[1])
|
||||
do_clock = True
|
||||
|
||||
if o in "--output":
|
||||
if out:
|
||||
raise ValueError("cannot have multiple --outputs")
|
||||
if v=="-":
|
||||
out = sys.stdout
|
||||
elif v=="--":
|
||||
out = sys.stderr
|
||||
else:
|
||||
out = open(v, "a")
|
||||
|
||||
if o in "-M --map":
|
||||
map_fn = v
|
||||
|
||||
if o == "--galois":
|
||||
bch.load_galois()
|
||||
|
||||
if not out:
|
||||
out = sys.stdout
|
||||
|
||||
if len(files)==1:
|
||||
if "/dev/tty" in files[0]:
|
||||
tty = files[0]
|
||||
files = []
|
||||
|
||||
mmap = memmap(map_fn)
|
||||
|
||||
class dose_cmd(uart.uart):
|
||||
|
||||
def cmd(self, c, d=None, timeout=0.2):
|
||||
if not isinstance(c, bytes):
|
||||
c = c.encode()
|
||||
if d:
|
||||
c += b" " + base85_encode(d)
|
||||
self.flush()
|
||||
self.ucmd(c)
|
||||
r = self.resp(timeout)
|
||||
while r and (r[0] != b'#'[0] or r[1] != c[0]):
|
||||
r = self.resp(timeout)
|
||||
d = None
|
||||
if not r:
|
||||
return r, d
|
||||
r = r.split()
|
||||
e = int(r[-1], 16)
|
||||
if len(r)==3:
|
||||
d = base85_decode(r[1])
|
||||
if self._verbose:
|
||||
print(f"{r[0]}[{r[2]}] {"".join([f"{b:02x}" for b in d])}", file=sys.stderr)
|
||||
self.last_cmd = c[0:1]
|
||||
return r[0], e, d
|
||||
|
||||
def poke(self, a, d, s=None, ccp=0):
|
||||
return self.peek(a, s=s, d=d, ccp=ccp)
|
||||
|
||||
def peek(self, a=None, s=None, d=None, ccp=0):
|
||||
name = None
|
||||
if a in SFR:
|
||||
name = a
|
||||
a, ss = SFR[a]
|
||||
if s is None:
|
||||
s = ss
|
||||
if a in mmap:
|
||||
a, ss = mmap[a]
|
||||
if ss and s is None:
|
||||
s = ss
|
||||
if isinstance(a, str):
|
||||
print(f"PEEK: unknown addr {a}", file=sys.stderr)
|
||||
for k in mmap.keys():
|
||||
if a in k:
|
||||
print(f"PEEK: in RAM we have {k}", file=sys.stderr)
|
||||
for k in SFR.keys():
|
||||
if a in k:
|
||||
print(f"PEEK: IO SFR we have {k}", file=sys.stderr)
|
||||
raise ValueError(a)
|
||||
FF = {1: "B", 2: "H", 4:"I"}
|
||||
if a is None:
|
||||
cc, nn, dd = self.cmd(b"M=")
|
||||
else:
|
||||
if d is None:
|
||||
c = b"M"
|
||||
d = b''
|
||||
if s is None:
|
||||
s = 12
|
||||
else:
|
||||
c = b'M!'
|
||||
if isinstance(d, int) and s in FF:
|
||||
d = struct.pack(f"<{FF[s]}", d)
|
||||
else:
|
||||
d = bytes(d)
|
||||
if s is None:
|
||||
s = len(d)
|
||||
d = struct.pack("<HBB", a,s,ccp) + d + b'\0\0\0\0\0\0\0\0\0\0\0\0'
|
||||
cc, nn, dd = self.cmd(c, d[:16])
|
||||
if dd and nn:
|
||||
aa,ss,cc = struct.unpack("<HBB", dd[:4])
|
||||
print(f"PEEK: {aa-nn:04x}[{nn}+{ss}]: {b2hex(dd[4:4+nn])}", file=sys.stderr)
|
||||
if name is not None and nn in FF:
|
||||
d = struct.unpack(f"<{FF[nn]}", dd[4:4+nn])
|
||||
print(f"{name}: {d[0]:#x}", file=sys.stderr)
|
||||
return name, d
|
||||
return cc, nn, dd
|
||||
|
||||
def more(self, flags=b''):
|
||||
return self.cmd(self.last_cmd + b'=' + flags)
|
||||
|
||||
def read_mem(self, a, s=None):
|
||||
cc, nn, dd = self.peek(a=a, s=s)
|
||||
r = dd[4:4+nn]
|
||||
while dd[2]:
|
||||
cc, nn, dd = self.more()
|
||||
r += dd[4:4+nn]
|
||||
return r
|
||||
|
||||
_adc_conf = None
|
||||
_sigrow = None
|
||||
|
||||
ADC_MUX = {
|
||||
0: "GND",
|
||||
6: "Gate",
|
||||
7: "Drain1",
|
||||
10: "Drain2",
|
||||
0x30: "GND",
|
||||
0x31: ("Vdd", 10, 0, 0),
|
||||
0x32: "T",
|
||||
0x33: "DACREF",
|
||||
}
|
||||
ADC_REF = {
|
||||
0: (3.3, "VDD"),
|
||||
4: (1.024,),
|
||||
5: (2.048,),
|
||||
6: (2.5,),
|
||||
7: (4.096,),
|
||||
}
|
||||
|
||||
def adc(self, start=False, read_conf=False):
|
||||
if not self._adc_conf or read_conf:
|
||||
self._adc_conf = self.read_mem("adc_conf")
|
||||
self._sigrow = self.read_mem(0x1100, 0x24)
|
||||
g = self._sigrow[0x20]
|
||||
o = self._sigrow[0x21]
|
||||
if o & 0x80:
|
||||
o -= 0x100
|
||||
o <<= 6
|
||||
g /= 1 << 14
|
||||
self.ADC_MUX[0x32] = ("T°C", g, o, 273)
|
||||
c = "A!<" if start else "A<"
|
||||
cc, nn, dd = self.cmd(c)
|
||||
dd = struct.unpack("<8H", dd)
|
||||
r = []
|
||||
for i in range(nn):
|
||||
pos = self._adc_conf[4*i+2] & 0x3f
|
||||
ref = self._adc_conf[4*i+1] & 0x07
|
||||
if ref in self.ADC_REF:
|
||||
ref = self.ADC_REF[ref]
|
||||
else:
|
||||
ref = (1,)
|
||||
a = dd[i]
|
||||
if pos != 0x32:
|
||||
a *= ref[0]/0x10000
|
||||
if pos in self.ADC_MUX:
|
||||
pos = self.ADC_MUX[pos]
|
||||
else:
|
||||
pos = f"Ain{pos}"
|
||||
if isinstance(pos, tuple):
|
||||
a = (a - pos[2])*pos[1] - pos[3]
|
||||
pos = pos[0]
|
||||
r.append((a, pos, ref))
|
||||
print(f"{i} {pos:6s} {a:.4f} {ref!r}", file=sys.stderr)
|
||||
return r
|
||||
|
||||
def nfet_scan(self, t=1, dcs=(0x1000,)):
|
||||
r = []
|
||||
for dc in range(*dcs):
|
||||
self.poke("TCA0_SINGLE_CMP0", dc)
|
||||
time.sleep(t)
|
||||
self.cmd("A!")
|
||||
time.sleep(1)
|
||||
r.append((dc, self.adc()))
|
||||
return r
|
||||
|
||||
def fet_temp_log(self, fn="fet_temp_log.csv",
|
||||
dc_start=0, dc_stop=0x1000, dc_step=0x40,
|
||||
settle=0.5, adc_settle=0.5,
|
||||
duration=None, sweeps=None, interval=0.0,
|
||||
idle_dc=0, gate="TCA0_SINGLE_CMP0",
|
||||
quiet=True, append=False):
|
||||
|
||||
"""
|
||||
Records FET characteristic curve with temperature over time to a CSV.
|
||||
"""
|
||||
|
||||
if dc_step == 0:
|
||||
raise ValueError("dc_step must not be 0")
|
||||
if (dc_stop - dc_start) * dc_step <= 0:
|
||||
raise ValueError(
|
||||
f"dc_step sign does not move {dc_start:#x} -> {dc_stop:#x}")
|
||||
if sweeps is not None and sweeps <= 0:
|
||||
raise ValueError("Sweeps must be positive or None")
|
||||
if sweeps is None and duration is None:
|
||||
sweeps = 1
|
||||
|
||||
def clamp_dc(x):
|
||||
x = int(round(x))
|
||||
return 0 if x < 0 else 0xffff if x > 0xffff else x
|
||||
|
||||
dcs = []
|
||||
dc = dc_start
|
||||
while (dc < dc_stop) if dc_step > 0 else (dc > dc_stop):
|
||||
dcs.append(clamp_dc(dc))
|
||||
dc += dc_step
|
||||
if not dcs:
|
||||
raise ValueError("Empty sweep. Check dc_start/dc_stop/dc_step")
|
||||
|
||||
devnull = open(os.devnull, "w") if quiet else None
|
||||
def reader():
|
||||
return contextlib.redirect_stderr(devnull) if quiet \
|
||||
else contextlib.nullcontext()
|
||||
|
||||
def row_channels(adc_rows):
|
||||
d = {}
|
||||
for val, pos, _ref in adc_rows:
|
||||
name = str(pos)
|
||||
if name in d:
|
||||
k = 2
|
||||
while f"{name}#{k}" in d:
|
||||
k += 1
|
||||
name = f"{name}#{k}"
|
||||
d[name] = val
|
||||
return d
|
||||
|
||||
with reader():
|
||||
first = self.adc(start=True, read_conf=True)
|
||||
chan_names = list(row_channels(first).keys())
|
||||
temp_chan = next((c for c in chan_names if c.startswith("T")), None)
|
||||
header = ["iso_time", "epoch", "t_s", "sweep", "point", "dc"] + chan_names
|
||||
|
||||
write_header = True
|
||||
if append:
|
||||
try:
|
||||
write_header = os.path.getsize(fn) == 0
|
||||
except OSError:
|
||||
write_header = True
|
||||
f = open(fn, "a" if append else "w", newline="")
|
||||
w = csv.writer(f)
|
||||
if write_header:
|
||||
w.writerow(header)
|
||||
f.flush()
|
||||
|
||||
print(f"fet_temp_log: {len(dcs)} points/sweep, dc "
|
||||
f"{dc_start:#x}..{dc_stop:#x} step {dc_step:#x}; channels "
|
||||
f"{chan_names}; temp={temp_chan or 'NONE'} -> {fn}",
|
||||
file=sys.stderr)
|
||||
if temp_chan is None:
|
||||
print("fet_temp_log: No temperature channel in the ADC "
|
||||
"Only the I-V curve will be logged.",
|
||||
file=sys.stderr)
|
||||
|
||||
all_sweeps = []
|
||||
t0 = time.time()
|
||||
n = 0
|
||||
try:
|
||||
while True:
|
||||
if sweeps is not None and n >= sweeps:
|
||||
break
|
||||
if duration is not None and (time.time() - t0) >= duration:
|
||||
break
|
||||
|
||||
sweep_rows = []
|
||||
for point, dc in enumerate(dcs):
|
||||
self.poke(gate, dc)
|
||||
time.sleep(settle)
|
||||
self.cmd("A!")
|
||||
time.sleep(adc_settle)
|
||||
with reader():
|
||||
adc_rows = self.adc(start=False)
|
||||
now = time.time()
|
||||
chans = row_channels(adc_rows)
|
||||
w.writerow([
|
||||
time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(now)),
|
||||
f"{now:.3f}", f"{now - t0:.3f}", n, point, dc,
|
||||
] + [chans.get(name, "") for name in chan_names])
|
||||
f.flush()
|
||||
sweep_rows.append(dict(epoch=now, t_s=now - t0, sweep=n,
|
||||
point=point, dc=dc, channels=chans))
|
||||
drain = chans.get("Drain1", chans.get("Drain2", "?"))
|
||||
temp = chans.get(temp_chan, "?") if temp_chan else "n/a"
|
||||
print(f" sweep {n} pt {point:3d} dc={dc:#06x} "
|
||||
f"gate={chans.get('Gate', '?')} drain={drain} "
|
||||
f"T={temp}", file=sys.stderr)
|
||||
|
||||
all_sweeps.append(sweep_rows)
|
||||
n += 1
|
||||
self.poke(gate, clamp_dc(idle_dc))
|
||||
|
||||
if sweeps is not None and n >= sweeps:
|
||||
break
|
||||
if duration is not None and (time.time() - t0) >= duration:
|
||||
break
|
||||
if interval > 0:
|
||||
time.sleep(interval)
|
||||
except KeyboardInterrupt:
|
||||
print("\nfet_temp_log: Interrupted. Closing file.", file=sys.stderr)
|
||||
finally:
|
||||
self.poke(gate, clamp_dc(idle_dc))
|
||||
f.flush()
|
||||
f.close()
|
||||
if devnull is not None:
|
||||
devnull.close()
|
||||
|
||||
print(f"fet_temp_log: Wrote {sum(len(s) for s in all_sweeps)} rows in "
|
||||
f"{len(all_sweeps)} sweep(s) to {fn}", file=sys.stderr)
|
||||
return all_sweeps
|
||||
|
||||
"""
|
||||
|
||||
Usage example: fet_temp_log("data.csv", dc_step=0x40, duration=3600, interval=60)
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def flash(self, op=None, abort=False, buf=False, **aa):
|
||||
if op is None:
|
||||
c = "F"
|
||||
if abort:
|
||||
c = "F!"
|
||||
if buf:
|
||||
c += "<"
|
||||
return self.cmd(c)
|
||||
r = self.cmd("F", flash_cmd.cmd_buffer(op, **aa))
|
||||
if r[1]:
|
||||
raise flash_cmd.Flash_Error(op)
|
||||
return r
|
||||
|
||||
def write2fbuffer(self, d, op="WriteBuffer2"):
|
||||
for i in range(0, 512, 16):
|
||||
b = i>>4
|
||||
if not b:
|
||||
c = "B0@%@"
|
||||
elif not (b&3):
|
||||
c = "B0@%"
|
||||
elif b==31:
|
||||
c = "B3%!"
|
||||
else:
|
||||
c = f"B{b&3}%"
|
||||
self.cmd(c, d=d[i:i+16])
|
||||
if (b&3) == 3:
|
||||
if b==31:
|
||||
s = 80
|
||||
else:
|
||||
s = 64
|
||||
self.flash(op, byte=i & 0x1c0, size=s)[1]
|
||||
self.wait_for_spi()
|
||||
|
||||
def wait_for_spi(self):
|
||||
while True:
|
||||
r = self.cmd("F")[1]
|
||||
if not r:
|
||||
break
|
||||
print(f"SPI busy {r:02x}", file=sys.stderr)
|
||||
|
||||
def readfbuffer(self, op="ReadBuffer2"):
|
||||
d = b''
|
||||
for i in range(0, 512, 16):
|
||||
b = i>>4
|
||||
if (b&3) == 0:
|
||||
if b==28:
|
||||
s = 80
|
||||
else:
|
||||
s = 64
|
||||
self.flash(op, byte=i, size=s)
|
||||
self.wait_for_spi()
|
||||
d += self.cmd(f"B{b&3}<!")[2]
|
||||
d += self.cmd(f"B4<!")[2]
|
||||
self._last_page = d
|
||||
if min(d) == 255:
|
||||
print(f"FLASH: page is erased")
|
||||
elif bch.check_page(d):
|
||||
if not bch.galois:
|
||||
raise bch.BCHError("galois module not loaded for Parity Error correction")
|
||||
d = bch.fix_page(d)
|
||||
return d[:512]
|
||||
|
||||
def read_flash(self, page):
|
||||
print(f"FLASH: reading from {page=}")
|
||||
self.flash("Transfer2", page=page)
|
||||
self.flash_status(True)
|
||||
return self.readfbuffer()
|
||||
|
||||
def read_flash2file(self, fn, page, n):
|
||||
with open(fn, "wb") as f:
|
||||
while n > 0:
|
||||
f.write(self.read_flash(page))
|
||||
page += 1
|
||||
n -= 1
|
||||
|
||||
def flash_status(self, blocking=False):
|
||||
r = (0,0,bytes(2))
|
||||
while not r[2][0] & 0x80:
|
||||
self.flash("Status", what="cmdbuf")
|
||||
r = self.cmd("F<")
|
||||
while r[1]:
|
||||
r = self.cmd("F<")
|
||||
if not blocking:
|
||||
break
|
||||
return tuple(r[2][:2])
|
||||
|
||||
def write_flash(self, page, d):
|
||||
print(f"FLASH: writing to {page=}")
|
||||
self.write2fbuffer(d)
|
||||
self.flash("Program2", page=page)
|
||||
self.flash_status(True)
|
||||
|
||||
def write_file2flash(self, page, fn):
|
||||
n = 0
|
||||
with open(fn, "rb") as f:
|
||||
while True:
|
||||
b =f.read(512)
|
||||
if not b:
|
||||
break
|
||||
if len(b)<512:
|
||||
b += bytes(512-len(b))
|
||||
self.write_flash(page+n, b)
|
||||
n += 1
|
||||
return n
|
||||
|
||||
def erase_flash_sector(self, page, op="EraseSector"):
|
||||
"""
|
||||
op="EraseSector" (default)
|
||||
page=0: pages 0 … 7
|
||||
page=8: pages 8 … 0xff
|
||||
page=0x100: pages 0x100 … 0x1ff
|
||||
…
|
||||
op="ErasePage", page=n
|
||||
op="EraseBlock", page=n [n&~7 … n|7]
|
||||
op="EraseChip"
|
||||
"""
|
||||
self.flash(op, page=page)
|
||||
self.flash_status(True)
|
||||
|
||||
def flash_power(self, on=True):
|
||||
op = "PowerUp" if on else "PowerDown"
|
||||
self.flash(op)
|
||||
|
||||
def flash_Id(self):
|
||||
self.flash("Id", what="cmdbuf")
|
||||
while True:
|
||||
r = self.cmd("F<")
|
||||
if not r[1]:
|
||||
break
|
||||
i = r[2][:5]
|
||||
print(f"FLASH chip {b2hex(i)}", file=sys.stderr)
|
||||
return i
|
||||
|
||||
def memsetfbuffer(self, byte=0, what=0xff, size=528, op=0x0887):
|
||||
for i in range(byte, byte+size, 255):
|
||||
s = byte+size - i
|
||||
if s > 255:
|
||||
s = 255
|
||||
self.flash(op, size=s, what=what, byte=i)
|
||||
self.wait_for_spi()
|
||||
|
||||
if tty:
|
||||
tty = dose_cmd(tty, baud)
|
||||
tty._export(globals())
|
||||
tty._verbose = False
|
||||
|
||||
uart.set_prompt("TurboD")
|
||||
|
||||
def b2hex(b, sep=" "):
|
||||
return sep.join([f"{x:02x}" for x in b])
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
Element["" "SIL_100_3" "U?" "unknown" 0 0 0 0 0 50 ""] (
|
||||
Pin[0mil -100mil 70mil 20mil 76mil 30mil "" "1" ""]
|
||||
Pin[0mil 0mil 70mil 20mil 76mil 30mil "" "2" ""]
|
||||
Pin[0mil 100mil 70mil 20mil 76mil 30mil "" "3" ""]
|
||||
Pin[0mil -100mil 70mil 20mil 76mil 38mil "" "1" ""]
|
||||
Pin[0mil 0mil 70mil 20mil 76mil 38mil "" "2" ""]
|
||||
Pin[0mil 100mil 70mil 20mil 76mil 38mil "" "3" ""]
|
||||
ElementLine[50mil -150mil 50mil 150mil 5mil]
|
||||
ElementLine[50mil 150mil -50mil 150mil 5mil]
|
||||
ElementLine[-50mil 150mil -50mil -150mil 5mil]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
Element["" "SIL_100_4" "U?" "unknown" 0 0 0 0 0 50 ""] (
|
||||
Pin[0mil -150mil 70mil 20mil 76mil 30mil "" "1" ""]
|
||||
Pin[0mil -50mil 70mil 20mil 76mil 30mil "" "2" ""]
|
||||
Pin[0mil 50mil 70mil 20mil 76mil 30mil "" "3" ""]
|
||||
Pin[0mil 150mil 70mil 20mil 76mil 30mil "" "4" ""]
|
||||
Pin[0mil -150mil 70mil 20mil 76mil 38mil "" "1" ""]
|
||||
Pin[0mil -50mil 70mil 20mil 76mil 38mil "" "2" ""]
|
||||
Pin[0mil 50mil 70mil 20mil 76mil 38mil "" "3" ""]
|
||||
Pin[0mil 150mil 70mil 20mil 76mil 38mil "" "4" ""]
|
||||
ElementLine[50mil -200mil 50mil 200mil 5mil]
|
||||
ElementLine[50mil 200mil -50mil 200mil 5mil]
|
||||
ElementLine[-50mil 200mil -50mil -200mil 5mil]
|
||||
|
|
|
|||
15
fp/SOIC_150_8.fp
Normal file
15
fp/SOIC_150_8.fp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
Element["" "SOIC_150_8" "U?" "unknown" 0 0 0 0 0 50 ""] (
|
||||
Pad[-87.5mil -75mil -122.5mil -75mil 25mil 20mil 31mil "" "1" "square"]
|
||||
Pad[-87.5mil -25mil -122.5mil -25mil 25mil 20mil 31mil "" "2" "square"]
|
||||
Pad[-87.5mil 25mil -122.5mil 25mil 25mil 20mil 31mil "" "3" "square"]
|
||||
Pad[-87.5mil 75mil -122.5mil 75mil 25mil 20mil 31mil "" "4" "square"]
|
||||
Pad[87.5mil 75mil 122.5mil 75mil 25mil 20mil 31mil "" "5" "square"]
|
||||
Pad[87.5mil 25mil 122.5mil 25mil 25mil 20mil 31mil "" "6" "square"]
|
||||
Pad[87.5mil -25mil 122.5mil -25mil 25mil 20mil 31mil "" "7" "square"]
|
||||
Pad[87.5mil -75mil 122.5mil -75mil 25mil 20mil 31mil "" "8" "square"]
|
||||
ElementLine[-87.5mil -100mil -87.5mil 100mil 5mil]
|
||||
ElementLine[-87.5mil 100mil 87.5mil 100mil 5mil]
|
||||
ElementLine[87.5mil 100mil 87.5mil -100mil 5mil]
|
||||
ElementLine[87.5mil -100mil -87.5mil -100mil 5mil]
|
||||
ElementLine[-70mil -100mil -70mil 100mil 5mil]
|
||||
)
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
|
||||
PROJ = turbo
|
||||
SUBPROJ = _dose
|
||||
SPROJ=$(PROJ)$(SUBPROJ)
|
||||
|
||||
VERSION = v01
|
||||
|
||||
GERBERS = $(PROJ).plated-drill.cnc
|
||||
|
|
@ -13,9 +16,9 @@ png: $(patsubst %.gvp, %.png, $(wildcard $(PROJ)*.gvp))
|
|||
%.png: %.gvp $(GERBERS)
|
||||
$(GVP2MAKE) -o $@ $< -w -B0 -w --background=#ffffff -A group=1.0 -X $(GV_OPT)
|
||||
|
||||
zip: $(PROJ)_$(VERSION).zip
|
||||
zip: $(SPROJ)_$(VERSION).zip
|
||||
|
||||
%_$(VERSION).zip: %.README %.plated-drill.cnc
|
||||
%$(SUBPROJ)_$(VERSION).zip: %.README %.plated-drill.cnc
|
||||
rm -fv $@
|
||||
awk '/: *$*/{print $$2}' $< | xargs make
|
||||
zip $@ $< `awk '/: *$*/{print $$2}' $<`
|
||||
|
|
@ -23,9 +26,9 @@ zip: $(PROJ)_$(VERSION).zip
|
|||
%.plated-drill.cnc: ../%.pcb
|
||||
pcb -x gerber --gerberfile $* --name-style single $<
|
||||
|
||||
bom: $(PROJ)_bom.pdf
|
||||
bom: $(SPROJ)_bom.pdf
|
||||
|
||||
%.bom: ../%.pcb
|
||||
%$(SUBPROJ).bom: ../%.pcb
|
||||
pcb -x bom --bomfile $@ $<
|
||||
|
||||
%_bom.txt: %.bom
|
||||
|
|
|
|||
|
|
@ -1,36 +1,36 @@
|
|||
(gerbv-file-version! "2.0A")
|
||||
(define-layer! 9 (cons 'filename "turbo.bottommask.gbr")
|
||||
(define-layer! 10 (cons 'filename "turbo.bottompaste.gbr")
|
||||
(cons 'visible #t)
|
||||
(cons 'color #(17973 10705 61411))
|
||||
)
|
||||
(define-layer! 9 (cons 'filename "turbo.bottom.gbr")
|
||||
(cons 'visible #t)
|
||||
(cons 'color #(45177 46748 64893))
|
||||
)
|
||||
(define-layer! 8 (cons 'filename "turbo.bottommask.gbr")
|
||||
(cons 'inverted #t)
|
||||
(cons 'visible #f)
|
||||
(cons 'color #(0 57568 6070))
|
||||
(cons 'alpha #(21588))
|
||||
)
|
||||
(define-layer! 8 (cons 'filename "turbo.bottom.gbr")
|
||||
(cons 'visible #t)
|
||||
(cons 'color #(45177 46748 64893))
|
||||
)
|
||||
(define-layer! 7 (cons 'filename "turbo.bottomsilk.gbr")
|
||||
(cons 'visible #t)
|
||||
(cons 'color #(0 0 0))
|
||||
)
|
||||
(define-layer! 6 (cons 'filename "turbo.top.gbr")
|
||||
(define-layer! 7 (cons 'filename "turbo.top.gbr")
|
||||
(cons 'visible #f)
|
||||
(cons 'color #(65535 29244 28836))
|
||||
(cons 'alpha #(42662))
|
||||
)
|
||||
(define-layer! 5 (cons 'filename "turbo.toppaste.gbr")
|
||||
(define-layer! 6 (cons 'filename "turbo.toppaste.gbr")
|
||||
(cons 'visible #f)
|
||||
(cons 'color #(65535 0 6760))
|
||||
)
|
||||
(define-layer! 4 (cons 'filename "turbo.topmask.gbr")
|
||||
(define-layer! 5 (cons 'filename "turbo.topmask.gbr")
|
||||
(cons 'inverted #t)
|
||||
(cons 'visible #f)
|
||||
(cons 'color #(0 64984 7760))
|
||||
(cons 'alpha #(13364))
|
||||
)
|
||||
(define-layer! 3 (cons 'filename "turbo.plated-drill.cnc")
|
||||
(define-layer! 4 (cons 'filename "turbo.plated-drill.cnc")
|
||||
(cons 'visible #t)
|
||||
(cons 'color #(61307 61307 61307))
|
||||
(cons 'color #(65535 65535 65535))
|
||||
(cons 'alpha #(65535))
|
||||
(cons 'attribs (list
|
||||
(list 'autodetect 'Boolean 1)
|
||||
|
|
@ -39,6 +39,10 @@
|
|||
(list 'digits 'Integer 4)
|
||||
))
|
||||
)
|
||||
(define-layer! 3 (cons 'filename "turbo.bottomsilk.gbr")
|
||||
(cons 'visible #t)
|
||||
(cons 'color #(0 0 0))
|
||||
)
|
||||
(define-layer! 2 (cons 'filename "turbo.topsilk.gbr")
|
||||
(cons 'visible #f)
|
||||
(cons 'color #(0 0 0))
|
||||
|
|
@ -54,7 +58,7 @@
|
|||
(cons 'color #(0 0 0))
|
||||
(cons 'alpha #(65535))
|
||||
)
|
||||
(define-layer! -1 (cons 'filename "/home/falbala/stephan/eda/turbo_weather/gerber")
|
||||
(cons 'color #(65535 65535 65535))
|
||||
(define-layer! -1 (cons 'filename "/home/blaulicht/stephan/eda/turbo_weather/gerber")
|
||||
(cons 'color #(51265 51265 51265))
|
||||
)
|
||||
(set-render-type! 3)
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 31 KiB |
BIN
gerber/turbo.png
BIN
gerber/turbo.png
Binary file not shown.
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
|
@ -1,30 +1,26 @@
|
|||
# PcbBOM Version 1.0
|
||||
# Date: So 21 Apr 2024 10:57:09 GMT UTC
|
||||
# Author:
|
||||
# Date: Di 09 Jun 2026 08:58:28 GMT UTC
|
||||
# Author: Stephan Boettcher
|
||||
# Title: TURBO - PCB BOM
|
||||
# Quantity, Description, Value, RefDes
|
||||
# --------------------------------------------
|
||||
C0603 -BYP_100nF 1/1 C4
|
||||
C0603 100nF 6/6 C1 C10 C11 C12 C2 C3
|
||||
C0603 100nF 6/6 C11 C12 C30 C32 C33 C34
|
||||
C0603 SMD-LED 1/1 D1
|
||||
C0603.fp -SD:_10kΩ 1/1 R13
|
||||
C0603.fp 10MΩ 1/1 R9
|
||||
C0603.fp 10kΩ 4/4 R11 R5 R7 R8
|
||||
C0603.fp 10kΩ_NTC 1/1 R6
|
||||
C0603.fp 1MΩ 1/1 R10
|
||||
C0603.fp 100kΩ 7/7 R30 R31 R32 R33 R34 R35 R36
|
||||
C0603.fp 10kΩ 1/1 R11
|
||||
C0603.fp 2.2MΩ 1/1 R4
|
||||
C0603.fp 220kΩ 1/1 R2
|
||||
C0603.fp 3.3MΩ 1/1 R3
|
||||
C0603.fp 330kΩ 1/1 R1
|
||||
C0603.fp ∞Ω 1/1 R12
|
||||
C0603.fp ∞Ω/0Ω 1/1 R10
|
||||
KEYSTONE-1025-7 6V 1/1 B1
|
||||
MS5534C MS5534C 1/1 U2
|
||||
P1206 10µF 11/11 C20 C21 C22 C23 C24 C25 C26 C27 C28 C29
|
||||
C30
|
||||
P1206 10µF 4/4 C20 C26 C29 C31
|
||||
SIL_100_3 HE_100_1×3 1/1 J1
|
||||
SIL_100_4 WRL-10534 1/1 U3
|
||||
SIL_100_4 SIL4 1/1 U3
|
||||
SOIC_150_14 ATtiny4x4SS 1/1 U1
|
||||
SOT23_5 LT1761-SD 1/1 U4
|
||||
SOIC_150_8 AT45DB161E 1/1 U2
|
||||
SOT23_3 2N7002 2/2 Q1 Q2
|
||||
SOT23_5 LT1761-SD_/_-BYP 1/1 U5
|
||||
SUBD9_PINS D9_pigtail 1/1 CONN1
|
||||
gseboard turbo 1/1 BOARD
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
from fp import *
|
||||
|
||||
make(SIL, (3,4))
|
||||
make(SOIC, (14,))
|
||||
make(SOIC, (8, 14))
|
||||
make(HEADER, (2, 10,))
|
||||
make(SOT, (3,5))
|
||||
make(SOD, ("C0603", "P1206"))
|
||||
|
|
|
|||
128
src/Makefile
128
src/Makefile
|
|
@ -1,19 +1,34 @@
|
|||
|
||||
PROJ=bate
|
||||
PROJ=hallo
|
||||
|
||||
PATH:=/usr/local/bin:$(PATH)
|
||||
VPATH=.:bch4369
|
||||
|
||||
default: all
|
||||
all: $(PROJ).hex
|
||||
all: $(PROJ).hex $(PROJ)_all
|
||||
|
||||
SN_bate = 1
|
||||
MCU_bate = attiny424
|
||||
C_FILES_bate = uart.c rtc.c spi.c adc.c calib.c mul.c cmd.c
|
||||
S_FILES_bate = uart_tx.S
|
||||
hallo_all: hallo.eeprom
|
||||
CFLAGS_hallo = -Ibch4369 -DHAVE_nFETs -DSEND_HEX -DHALLO
|
||||
MCU_hallo = attiny424
|
||||
SN_hallo = 1
|
||||
C_FILES_hallo = config.c uart.c cmd.c base85.c rtc.c adc.c pwm.c spi.c flash.c bch4369.c
|
||||
S_FILES_hallo = uart_tx.S base85a.S
|
||||
|
||||
dose_all: dose.eeprom dose.userrow
|
||||
SN_dose = 1
|
||||
MCU_dose = $(MCU_$(VAR))
|
||||
MCU_nFETs = attiny424
|
||||
MCU_FPGA = attiny3224
|
||||
|
||||
VAR=nFETs
|
||||
C_FILES_nFETs =
|
||||
C_FILES_FPGA = fpga.c
|
||||
CFLAGS_dose = -DHAVE_$(VAR)
|
||||
C_FILES_dose = config.c rtc.c adc.c pwm.c $(C_FILES_$(VAR)) uart.c cmd.c pipe.c base85.c bch4369.c spi.c flash.c
|
||||
S_FILES_dose = uart_tx.S base85a.S
|
||||
|
||||
MCU = $(MCU_$(PROJ))
|
||||
# When flash gets tight, use `OPT=-Os`, or use more assembler :-)
|
||||
OPT = -O2
|
||||
OPT = -Os
|
||||
|
||||
CC=avr-gcc -Wall -Wno-parentheses -MMD -std=c99 $(OPT) \
|
||||
-mmcu=$(MCU) \
|
||||
|
|
@ -22,24 +37,26 @@ CC=avr-gcc -Wall -Wno-parentheses -MMD -std=c99 $(OPT) \
|
|||
-fpack-struct \
|
||||
-fshort-enums \
|
||||
-mtiny-stack \
|
||||
-mint8 \
|
||||
-fverbose-asm
|
||||
-mint8
|
||||
|
||||
SN = $(SN_$(PROJ))
|
||||
CFLAGS = $($*_CFLAGS) $(DEBUG) -I. -DSN="$(SN)"
|
||||
CFLAGS = $(CFLAGS_$(PROJ)) $(DEBUG) -I. -DSN="$(SN)"
|
||||
|
||||
C_FILES = $(C_FILES_$(PROJ))
|
||||
S_FILES = $(S_FILES_$(PROJ))
|
||||
OBJS = $(patsubst %.c, %.o, $(C_FILES)) $(patsubst %.S, %.o, $(S_FILES))
|
||||
|
||||
%.s: %.c %.o
|
||||
%.s: %.c
|
||||
$(CC) $(CFLAGS) -S $<
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -g $(CFLAGS) -c $<
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
%.o: %.S
|
||||
$(CC) -g $(CFLAGS) -c $<
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
%.m: %.S
|
||||
$(CC) $(CFLAGS) -E -dM $< > $@
|
||||
|
||||
-include *.d
|
||||
|
||||
|
|
@ -51,41 +68,36 @@ LDFLAGS = -Teeprom.ld
|
|||
OBJCOPY = avr-objcopy
|
||||
|
||||
%.hex: %.elf
|
||||
$(OBJCOPY) -O ihex -R .eeprom -R .eemap $< $@
|
||||
$(OBJCOPY) -O ihex -R .eeprom -R .eemap -R .userrow -R .uumap $< $@
|
||||
|
||||
%.eeprom: %.elf
|
||||
$(OBJCOPY) -O ihex -j .eemap --change-section-lma .eemap=0 $< $@
|
||||
|
||||
%.userrow: %.elf
|
||||
$(OBJCOPY) -O ihex -j .uumap --change-section-lma .uumap=0 $< $@
|
||||
|
||||
|
||||
pMCU-attiny424 = t424
|
||||
|
||||
#
|
||||
#avrdude> dump fuses
|
||||
#>>> dump fuses 0x0 0x9
|
||||
#
|
||||
#Reading | ################################################## | 100% 0.13 s
|
||||
#
|
||||
#0000 00 00 7e ff ff f6 ff 00 00 |..~...... |
|
||||
#
|
||||
#avrdude>
|
||||
pMCU-attiny824 = t824
|
||||
pMCU-attiny824 = t3224
|
||||
|
||||
# WDT
|
||||
fuse0_bate= 0x00
|
||||
fuse0_dose= 0x00
|
||||
# BOD
|
||||
fuse1_bate= 0x00
|
||||
fuse1_dose= 0x00
|
||||
# OSC, 20 MHz
|
||||
fuse2_bate= 0x7e
|
||||
fuse2_dose= 0x7e
|
||||
# ???
|
||||
fuse4_bate= 0xff
|
||||
fuse4_dose= 0xff
|
||||
# SYS0 (default 0xf6) RESET, EEPROM erase
|
||||
fuse5_bate= 0xf7
|
||||
fuse5_dose= 0xf7
|
||||
# SYS1 startup time (64ms)
|
||||
fuse6_bate= 0xff
|
||||
fuse6_dose= 0xff
|
||||
# APPEND
|
||||
fuse7_bate= 0x00
|
||||
fuse7_dose= 0x00
|
||||
# BOOTEND
|
||||
fuse8_bate= 0x00
|
||||
fuses_bate =$(patsubst %, 0x%, 00 00 7e ff ff f7 ff 00 00)
|
||||
fuse8_dose= 0x00
|
||||
fuses_dose =$(patsubst %, 0x%, 00 00 7e ff ff f7 ff 00 00)
|
||||
|
||||
AVRDUDEPROG = avrdude
|
||||
AVRDUDE = $(AVRDUDEPROG)
|
||||
|
|
@ -94,7 +106,8 @@ AVRDUDE_PORT = /dev/ttyUSB1
|
|||
|
||||
AD = $(AVRDUDE) -p $(pMCU-$(MCU)) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
|
||||
|
||||
sig_bate = 0x1e 0x92 0x2c
|
||||
sig_dose = 0x1e 0x92 0x2c
|
||||
sig_hallo = 0x1e 0x92 0x2c
|
||||
|
||||
id: $(PROJ).id
|
||||
%.id:
|
||||
|
|
@ -104,12 +117,12 @@ ad: $(PROJ).ad
|
|||
%.ad:
|
||||
$(AD) -v -t
|
||||
|
||||
%.burn: %.hex
|
||||
%.burn: %.hex %.id
|
||||
$(AD) -U flash:v:$< || $(AD) -U flash:w:$<
|
||||
|
||||
%.verify: %.hex %.eeprom
|
||||
%.verify: %.hex %.eeprom %.userrow
|
||||
-$(AD) -qq -U fuses:v:"$(fuses_$*)":m
|
||||
-$(AD) -qq -U userrow:v:"$(BATE_CONFIG)":m
|
||||
-$(AD) -qq -U userrow:v:$(word 3, $^)
|
||||
-$(AD) -qq -U eeprom:v:$(word 2, $^)
|
||||
-$(AD) -qq -U flash:v:$<
|
||||
|
||||
|
|
@ -119,41 +132,10 @@ fuse: $(PROJ).fuse$F
|
|||
echo "$*: fuse$F = $(fuse$F_$*)"
|
||||
[ -n "$(fuse$F_$*)" ] && $(AD) -B 5 -U fuse$F:w:$(fuse$F_$*):m
|
||||
|
||||
# see bate.c: Configuration in USERROW
|
||||
BC_MAGIC = 0xba
|
||||
BC_VERS = 9
|
||||
BC_TRIG = 0x29
|
||||
BC_SEND = 0x59
|
||||
BC_PWR = 0xfc
|
||||
BC_TEST = 0
|
||||
BC_SPI = 4
|
||||
BC_MDEL = 2
|
||||
BC_PER = 9
|
||||
BC_CPER = 30
|
||||
|
||||
BC_CLK = 1
|
||||
BC_MCLK = 0
|
||||
BC_BAUD = 0 0
|
||||
BC_UART = 0xd0
|
||||
BC_PIT = 0xff
|
||||
BC_IMM = 5
|
||||
BC_PAD = 0 0 0 0 0 0 0
|
||||
BC_PRE = 0xff 0xff 0xff 0xff 0xff 0x55 0x0a 0
|
||||
|
||||
BATE_CONFIG = $(BC_MAGIC) $(BC_VERS) \
|
||||
$(BC_TRIG) $(BC_SEND) $(BC_PWR) $(BC_TEST) \
|
||||
$(BC_SPI) $(BC_MDEL) $(BC_PER) $(BC_CPER) \
|
||||
$(BC_CLK) $(BC_MCLK) $(BC_BAUD) $(BC_UART) \
|
||||
$(BC_PIT) $(BC_IMM) $(BC_PAD) $(BC_PRE)
|
||||
|
||||
bate.config:
|
||||
$(AD) -U userrow:v:"$(BATE_CONFIG)":m \
|
||||
|| $(AD) -U userrow:w:"$(BATE_CONFIG)":m
|
||||
|
||||
clean:
|
||||
rm -f *.hex *.o *.s *.map *.elf *.d
|
||||
|
||||
bate.hex: bate.eeprom
|
||||
# $(PROJ).hex: $(PROJ).eeprom $(PROJ).userrow
|
||||
|
||||
.PHONY: eeprom.eeprom
|
||||
eeprom.eeprom:
|
||||
|
|
@ -161,7 +143,5 @@ eeprom.eeprom:
|
|||
%.eeprom.burn: %.eeprom
|
||||
$(AD) -U eeprom:v:$< || $(AD) -U eeprom:w:$<
|
||||
|
||||
calib: calib.c mul.c
|
||||
gcc -DCALIB_DEBUG -o $@ $<
|
||||
mul: mul.c
|
||||
gcc -DMUL_TEST -o $@ $<
|
||||
%.userrow.burn: %.userrow
|
||||
$(AD) -U userrow:v:$< || $(AD) -U userrow:w:$<
|
||||
|
|
|
|||
270
src/adc.c
270
src/adc.c
|
|
@ -2,81 +2,77 @@
|
|||
// adc.c
|
||||
//
|
||||
|
||||
#include "config.h"
|
||||
#include "adc.h"
|
||||
#include "bate.h"
|
||||
#include "mul.h"
|
||||
#include "eeprom.h"
|
||||
#include <avr/interrupt.h>
|
||||
#include "pwm.h"
|
||||
#include "rtc.h"
|
||||
|
||||
#ifdef ADC_IMMEDIATE
|
||||
# define ADC_TRIGGER ADC_MODE_BURST_SCALING_gc | ADC_START_IMMEDIATE_gc
|
||||
#else
|
||||
# define ADC_TRIGGER ADC_MODE_SERIES_SCALING_gc | ADC_START_EVENT_TRIGGER_gc
|
||||
#endif
|
||||
|
||||
enum adc_conf_parameter {
|
||||
INP = ADC_VIA_ADC_gc,
|
||||
INN = ADC_VIA_ADC_gc,
|
||||
REF = 10 << ADC_TIMEBASE_gp,
|
||||
MODE = ADC_MODE_BURST_SCALING_gc | ADC_START_IMMEDIATE_gc,
|
||||
MODE_DIFF = ADC_MODE_BURST_SCALING_gc | ADC_START_IMMEDIATE_gc | ADC_DIFF_bm,
|
||||
V_RFP = ADC_MUXPOS_AIN4_gc,
|
||||
V_NTC = ADC_MUXPOS_AIN6_gc,
|
||||
V_BAT = ADC_MUXPOS_AIN7_gc,
|
||||
MODE = ADC_TRIGGER,
|
||||
MODE_DIFF = ADC_TRIGGER | ADC_DIFF_bm,
|
||||
};
|
||||
|
||||
struct adc_conf adc_conf[N_ADC] ADC_CONF_ADDR = {
|
||||
{ // Internal Temperature
|
||||
.mode = MODE,
|
||||
.ref = REF | ADC_REFSEL_1024MV_gc,
|
||||
.inp = INP | ADC_MUXPOS_TEMPSENSE_gc,
|
||||
.calib = 80 * 256,
|
||||
.shifts = 1,
|
||||
},
|
||||
__attribute__((section(".eeprom1")))
|
||||
struct adc_conf adc_conf[N_ADC] = {
|
||||
{ // V_CC / 10
|
||||
.mode = MODE,
|
||||
.ref = REF | ADC_REFSEL_1024MV_gc,
|
||||
.inp = INP | ADC_MUXPOS_VDDDIV10_gc,
|
||||
.calib = 1024 * 10,
|
||||
.shifts = 3, // V [×10]
|
||||
},
|
||||
{ // Batterie Voltage / 11
|
||||
{ // Internal Temperature
|
||||
.mode = MODE,
|
||||
.ref = REF | ADC_REFSEL_1024MV_gc,
|
||||
.inp = INP | V_BAT,
|
||||
.calib = 1024 * 11,
|
||||
.shifts = 3, // V [×11]
|
||||
.inp = INP | ADC_MUXPOS_TEMPSENSE_gc,
|
||||
},
|
||||
{ // NTC biased by V_RF
|
||||
.mode = MODE_DIFF,
|
||||
#ifdef HAVE_nFETs
|
||||
{ // VD1
|
||||
.mode = MODE,
|
||||
.ref = REF | ADC_REFSEL_1024MV_gc,
|
||||
.inp = INP | V_NTC,
|
||||
.inn = INP | V_RFP,
|
||||
.calib = 2048 * 10,
|
||||
.shifts = 1, // mV
|
||||
.inp = INP | ADC_D1,
|
||||
},
|
||||
{ // NTC biased by V_RF
|
||||
{ // VD2
|
||||
.mode = MODE,
|
||||
.ref = REF | ADC_REFSEL_1024MV_gc,
|
||||
.inp = INP | ADC_D2,
|
||||
},
|
||||
{ // VD1
|
||||
.mode = MODE,
|
||||
.ref = REF | ADC_REFSEL_2500MV_gc,
|
||||
.inp = INP | V_NTC,
|
||||
.calib = 2500 * 10,
|
||||
.shifts = 1,
|
||||
.inp = INP | ADC_D1,
|
||||
},
|
||||
{ // NTC biased by V_RF
|
||||
.mode = MODE,
|
||||
.ref = REF | ADC_REFSEL_VDD_gc,
|
||||
.inp = INP | V_NTC,
|
||||
},
|
||||
{ // Transmitter power
|
||||
{ // VD2
|
||||
.mode = MODE,
|
||||
.ref = REF | ADC_REFSEL_2500MV_gc,
|
||||
.inp = INP | V_RFP,
|
||||
.calib = 2500 * 10,
|
||||
.shifts = 1,
|
||||
.inp = INP | ADC_D2,
|
||||
},
|
||||
{ // Transmitter power
|
||||
{ // VDG
|
||||
.mode = MODE,
|
||||
.ref = REF | ADC_REFSEL_2500MV_gc,
|
||||
.inp = INP | ADC_G,
|
||||
},
|
||||
{ // VDG
|
||||
.mode = MODE,
|
||||
.ref = REF | ADC_REFSEL_VDD_gc,
|
||||
.inp = INP | V_RFP,
|
||||
.inp = INP | ADC_G,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
uint16_t adc_readings[N_ADC];
|
||||
uint8_t adc_current = 0xff;
|
||||
section_status(adc.n) uint8_t adc_current;
|
||||
section_status(adc.r) uint16_t adc_readings[N_ADC];
|
||||
#ifdef HAVE_nFETs
|
||||
section_status(pwm) uint16_t pwm_dutycycle;
|
||||
#endif
|
||||
|
||||
static inline
|
||||
void start_conversion(const struct adc_conf *c)
|
||||
|
|
@ -87,47 +83,42 @@ void start_conversion(const struct adc_conf *c)
|
|||
ADC.COMMAND = c->mode;
|
||||
}
|
||||
|
||||
void init_adc()
|
||||
{
|
||||
PORTA.PIN4CTRL |= PORT_ISC_INPUT_DISABLE_gc;
|
||||
PORTA.PIN6CTRL |= PORT_ISC_INPUT_DISABLE_gc;
|
||||
PORTA.PIN7CTRL |= PORT_ISC_INPUT_DISABLE_gc;
|
||||
}
|
||||
struct_ioconf(adc_config) = {
|
||||
conf_prefix(ADC),
|
||||
conf_io(ADC.CTRLA, ADC_ENABLE_bm),
|
||||
conf_io(ADC.CTRLB, ADC_PRESC_DIV10_gc),
|
||||
conf_io(ADC.CTRLE, 250),
|
||||
conf_io(ADC.CTRLF, ADC_SAMPNUM_ACC256_gc | ADC_LEFTADJ_bm),
|
||||
conf_io(ADC.INTCTRL, ADC_RESRDY_bm),
|
||||
conf_prefix(EVSYS),
|
||||
conf_io(EVSYS.CHANNEL0, EVSYS_CHANNEL0_TCA0_CMP1_LCMP1_gc),
|
||||
conf_io(EVSYS.USERADC0START, 1),
|
||||
};
|
||||
|
||||
void start_adc()
|
||||
{
|
||||
if (!adc_conf->mode)
|
||||
return;
|
||||
ADC.CTRLA = ADC_ENABLE_bm | ADC_RUNSTDBY_bm;
|
||||
ADC.COMMAND = 0;
|
||||
ADC.CTRLB = ADC_PRESC_DIV10_gc;
|
||||
ADC.CTRLE = 32 << ADC_SAMPDUR_gp;
|
||||
ADC.CTRLF = ADC_SAMPNUM_ACC64_gc | ADC_LEFTADJ_bm;
|
||||
adc_current = 0;
|
||||
ADC.INTFLAGS = 0xff;
|
||||
ADC.INTCTRL = ADC_RESRDY_bm;
|
||||
start_conversion(adc_conf);
|
||||
}
|
||||
|
||||
#if 0
|
||||
ISR(ADC0_RESRDY_vect)
|
||||
{
|
||||
DEBUG_COUNTER(adc_irqs);
|
||||
|
||||
uint8_t i = adc_current;
|
||||
if (i >= N_ADC)
|
||||
goto stop;
|
||||
adc_readings[i] = *(volatile uint16_t *) &ADC.RESULT;
|
||||
if (++i < N_ADC) {
|
||||
while (++i < N_ADC) {
|
||||
const struct adc_conf *c = adc_conf + i;
|
||||
if (c->mode || c->mode == 0xff)
|
||||
goto stop;
|
||||
adc_current = i;
|
||||
start_conversion(c);
|
||||
return;
|
||||
if (c->mode) {
|
||||
start_conversion(c);
|
||||
adc_current = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
stop:
|
||||
ADC.CTRLA = 0;
|
||||
ADC.COMMAND = 0;
|
||||
adc_current = N_ADC;
|
||||
}
|
||||
|
||||
|
|
@ -149,7 +140,7 @@ ISR(ADC0_RESRDY_vect, ISR_NAKED)
|
|||
"push r31" "\n\t"
|
||||
"lds r24, adc_current" "\n\t"
|
||||
"cpi r24, %[NADC]" "\n\t"
|
||||
"brsh 3f" "\n\t"
|
||||
"brcc 2f" "\n\t"
|
||||
"mov r30, r24" "\n\t"
|
||||
"ldi r31, 0" "\n\t"
|
||||
"lsl r30" "\n\t"
|
||||
|
|
@ -158,22 +149,19 @@ ISR(ADC0_RESRDY_vect, ISR_NAKED)
|
|||
"lds r25, %[RESULT]" "\n\t"
|
||||
"st Z, r25" "\n\t"
|
||||
"lds r25, %[RESULT]+1" "\n\t"
|
||||
"std Z+1, r25" "\n\t"
|
||||
"cpi r24, %[NADC]-1" "\n\t"
|
||||
"brsh 3f" "\n\t"
|
||||
"subi r24, 0xff" "\n\t"
|
||||
"std Z+1, r25" "\n"
|
||||
"1:" "\n\t"
|
||||
"subi r24, -1" "\n\t"
|
||||
"cpi r24, %[NADC]" "\n"
|
||||
"2:" "\n\t"
|
||||
"clr r25" "\n\t"
|
||||
"brcc 3f" "\n\t"
|
||||
"mov r30, r24" "\n\t"
|
||||
"ldi r31, 0" "\n\t"
|
||||
"lsl r30" "\n\t"
|
||||
"lsl r30" "\n\t"
|
||||
"lsl r30" "\n\t"
|
||||
"subi r30, lo8(-(adc_conf))" "\n\t"
|
||||
"sbci r31, hi8(-(adc_conf))" "\n"
|
||||
"1:" "\n\t"
|
||||
"ld r25, Z" "\n\t"
|
||||
"subi r25, 1" "\n\t"
|
||||
"cpi r25, 0xfe" "\n\t"
|
||||
"brsh 3f" "\n\t"
|
||||
"sbci r31, hi8(-(adc_conf))" "\n\t"
|
||||
"ldd r25, Z+1" "\n\t"
|
||||
"sts %[CTRLC], r25" "\n\t"
|
||||
"ldd r25, Z+3" "\n\t"
|
||||
|
|
@ -181,8 +169,10 @@ ISR(ADC0_RESRDY_vect, ISR_NAKED)
|
|||
"ldd r25, Z+2" "\n\t"
|
||||
"sts %[MUXPOS], r25" "\n\t"
|
||||
"ld r25, Z" "\n\t"
|
||||
"sts %[COMMAND], r25" "\n"
|
||||
"2:" "\n\t"
|
||||
"tst r25" "\n\t"
|
||||
"breq 1b" "\n"
|
||||
"3:" "\n\t"
|
||||
"sts %[COMMAND], r25" "\n\t"
|
||||
"sts adc_current, r24" "\n\t"
|
||||
"pop r31" "\n\t"
|
||||
"pop r30" "\n\t"
|
||||
|
|
@ -191,15 +181,9 @@ ISR(ADC0_RESRDY_vect, ISR_NAKED)
|
|||
"out __SREG__, r24" "\n\t"
|
||||
"pop r24" "\n\t"
|
||||
"reti" "\n"
|
||||
"3:" "\n\t"
|
||||
"clr r24" "\n\t"
|
||||
"sts %[CTRLA], r24" "\n\t"
|
||||
"ldi r24, %[NADC]" "\n\t"
|
||||
"rjmp 2b" "\n"
|
||||
: :
|
||||
[NADC] "n" (N_ADC),
|
||||
[RESULT] "n" (&ADC.RESULT),
|
||||
[CTRLA] "n" (&ADC.CTRLA),
|
||||
[CTRLC] "n" (&ADC.CTRLC),
|
||||
[MUXPOS] "n" (&ADC.MUXPOS),
|
||||
[MUXNEG] "n" (&ADC.MUXNEG),
|
||||
|
|
@ -208,97 +192,31 @@ ISR(ADC0_RESRDY_vect, ISR_NAKED)
|
|||
}
|
||||
#endif
|
||||
|
||||
static inline
|
||||
int16_t calib_temp(uint16_t a)
|
||||
void adc_start_stream(uint8_t flag)
|
||||
{
|
||||
uint16_t calib = SIGROW.TEMPSENSE0;
|
||||
int16_t offset = (int8_t) SIGROW.TEMPSENSE1;
|
||||
a >>= 1;
|
||||
a -= offset << 5;
|
||||
a = mul16sun(calib, a, 8);
|
||||
a -= 8741;
|
||||
// [K × 32]
|
||||
return a;
|
||||
#ifdef HAVE_nFETs
|
||||
if (flag & ADC_PWM)
|
||||
pwm_set(config.pwm_min, 1);
|
||||
#endif
|
||||
start_adc();
|
||||
}
|
||||
|
||||
// saturating addition, signed + signed
|
||||
|
||||
static inline
|
||||
int16_t saddss(int16_t a, int16_t o)
|
||||
uint8_t adc_poll(uint8_t flags)
|
||||
{
|
||||
__asm__(
|
||||
" add %A[a], %A[o] \n"
|
||||
" adc %B[a], %B[o] \n"
|
||||
" brvc 1f \n"
|
||||
" ldi %A[a], 0xff \n"
|
||||
" ldi %B[a], 0x7f \n"
|
||||
" brmi 1f \n"
|
||||
" adiw %[a], 1 \n"
|
||||
"1: \n"
|
||||
: [a] "+w" (a)
|
||||
: [o] "r" (o)
|
||||
);
|
||||
return a;
|
||||
}
|
||||
|
||||
// saturating addition, unsigned + signed
|
||||
|
||||
static inline
|
||||
uint16_t saddus(uint16_t a, int16_t o)
|
||||
{
|
||||
__asm__(
|
||||
" add %A[a], %A[o] \n"
|
||||
" adc %B[a], %B[o] \n"
|
||||
" tst %B[o] \n"
|
||||
" brmi 1f \n"
|
||||
" brcc 3f \n"
|
||||
" rjmp 2f \n"
|
||||
"1: \n"
|
||||
" brcs 3f \n"
|
||||
"2: \n"
|
||||
" ldi %A[a], 0xff \n"
|
||||
" ldi %B[a], 0xff \n"
|
||||
" brcs 3f \n"
|
||||
" adiw %[a], 1 \n"
|
||||
"3: \n"
|
||||
: [a] "+w" (a)
|
||||
: [o] "r" (o)
|
||||
);
|
||||
return a;
|
||||
}
|
||||
|
||||
void send_calib_adc(uint8_t i)
|
||||
{
|
||||
struct adc_conf *conf = adc_conf + i;
|
||||
uint8_t sgnd = conf->mode & ADC_DIFF_bm;
|
||||
int16_t offset = (int16_t)conf->offset;
|
||||
uint16_t calib = conf->calib;
|
||||
uint16_t a = adc_readings[i];
|
||||
|
||||
if (conf->inp == ADC_MUXPOS_TEMPSENSE_gc) {
|
||||
a = calib_temp(a);
|
||||
sgnd = 1;
|
||||
time(); // fill `clock`
|
||||
uint8_t r = adc_busy();
|
||||
if (r)
|
||||
return r;
|
||||
if (flags) {
|
||||
if (flags & ADC_RTC && !rtc_cnt_tick())
|
||||
return 1;
|
||||
#ifdef HAVE_nFETs
|
||||
if (flags & ADC_PWM)
|
||||
pwm_step(config.pwm_max);
|
||||
pwm_dutycycle = PWM.CMP0;
|
||||
if (pwm_busy() || flags & ADC_CONV)
|
||||
#endif
|
||||
start_adc();
|
||||
}
|
||||
|
||||
if (sgnd)
|
||||
a = saddss(a, offset);
|
||||
else
|
||||
a = saddus(a, offset);
|
||||
|
||||
if (!calib) {
|
||||
send_str(" 0x");
|
||||
send_hex_word(a);
|
||||
return;
|
||||
}
|
||||
uint16_t c;
|
||||
if (sgnd)
|
||||
c = calib;
|
||||
else {
|
||||
c = a;
|
||||
a = calib;
|
||||
}
|
||||
a = mul16sun(a, c, conf->shifts >> 4);
|
||||
|
||||
send_char(' ');
|
||||
send_str(decimal_str(a, conf->shifts & 3));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
30
src/adc.h
30
src/adc.h
|
|
@ -10,18 +10,36 @@ struct adc_conf {
|
|||
uint8_t ref;
|
||||
uint8_t inp;
|
||||
uint8_t inn;
|
||||
int8_t offset;
|
||||
uint8_t shifts;
|
||||
uint16_t calib;
|
||||
};
|
||||
|
||||
#define N_ADC (64/sizeof(struct adc_conf))
|
||||
#ifdef HAVE_nFETs
|
||||
#define N_ADC 8
|
||||
#define ADC_D1 7
|
||||
#define ADC_D1_PINCTRL PORTA.PIN7CTRL
|
||||
#define ADC_D2 10
|
||||
#define ADC_D2_PINCTRL PORTB.PIN1CTRL
|
||||
#define ADC_G 6
|
||||
#define ADC_G_PINCTRL PORTA.PIN6CTRL
|
||||
#else
|
||||
#define N_ADC 2
|
||||
#endif
|
||||
|
||||
extern uint16_t adc_readings[N_ADC];
|
||||
extern uint8_t adc_current;
|
||||
|
||||
void start_adc();
|
||||
void init_adc();
|
||||
static inline uint8_t adc_busy() { return ADC.STATUS & 1; }
|
||||
static inline uint8_t adc_busy() { return ADC.COMMAND; }
|
||||
extern struct adc_conf adc_conf[N_ADC];
|
||||
void send_calib_adc(uint8_t i);
|
||||
uint8_t adc_poll(uint8_t flag);
|
||||
void adc_start_stream(uint8_t flag);
|
||||
|
||||
enum adc_flags {
|
||||
ADC_CONV = 1,
|
||||
ADC_PWM = 2,
|
||||
ADC_SIZE = 0x70, // opencoded in pipe.c
|
||||
ADC_16 = 0x10,
|
||||
ADC_32 = 0x20,
|
||||
ADC_64 = 0x40,
|
||||
ADC_RTC = 0x80,
|
||||
};
|
||||
|
|
|
|||
43
src/base85.c
Normal file
43
src/base85.c
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <base85.h>
|
||||
|
||||
uint32_t divmod85(uint32_t u, uint8_t *m);
|
||||
uint32_t mul85(uint32_t u, uint8_t m);
|
||||
uint8_t base85_error;
|
||||
|
||||
#ifdef BASE85C
|
||||
|
||||
int base85_encode(uint32_t u, uint8_t *s)
|
||||
{
|
||||
s += 5;
|
||||
*s = 0;
|
||||
u = divmod85(u, --s);
|
||||
u = divmod85(u, --s);
|
||||
u = divmod85(u, --s);
|
||||
u = divmod85(u, --s);
|
||||
*--s = (u>>24) + 33;
|
||||
return 5;
|
||||
}
|
||||
|
||||
const uint8_t *base85_decode(const uint8_t *s, uint32_t *u)
|
||||
{
|
||||
uint32_t uu = 0;
|
||||
uint8_t c;
|
||||
for (int i=0; i<5; i++) {
|
||||
while (1) {
|
||||
c = *s++ - 33;
|
||||
if (c >= 85)
|
||||
goto error;
|
||||
uu = mul85(uu, c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
c = 0;
|
||||
error:
|
||||
base85_error = c;
|
||||
*u = uu;
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif
|
||||
4
src/base85.h
Normal file
4
src/base85.h
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
extern uint8_t base85_error;
|
||||
int base85_encode(uint32_t u, uint8_t *s);
|
||||
const uint8_t *base85_decode(const uint8_t *s, uint32_t *u);
|
||||
25
src/base85.py
Normal file
25
src/base85.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
import struct
|
||||
|
||||
def base85_encode(b):
|
||||
uu = list(struct.unpack(f">{len(b)//4}I", b))
|
||||
uu.reverse()
|
||||
r = []
|
||||
for u in uu:
|
||||
for i in range(5):
|
||||
r[0:0] = [u % 85 + 33]
|
||||
u //= 85
|
||||
return bytes(r)
|
||||
|
||||
def base85_decode(s):
|
||||
uu = [];
|
||||
for j in range(0,len(s),5):
|
||||
u = 0
|
||||
for i in range(5):
|
||||
m = ord(s[j+i:j+i+1]) - 33;
|
||||
if m < 0 or m >= 85:
|
||||
raise ValueError(f"invalid base85 char {s}[{i}]")
|
||||
u *= 85
|
||||
u += m
|
||||
uu.append(u)
|
||||
return struct.pack(f">{len(uu)}I", *uu)
|
||||
132
src/base85_test.c
Normal file
132
src/base85_test.c
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t m;
|
||||
uint64_t f;
|
||||
|
||||
static inline
|
||||
uint32_t divmod85(uint32_t u)
|
||||
{
|
||||
uint64_t uu = u;
|
||||
uu += uu << 1;
|
||||
uu += 1;
|
||||
// f = (uu << 16) + (uu << 8) + uu + (uu >> 8) + (uu >> 16) + (uu >> 24);
|
||||
f = (uu << 16) + (uu << 8) + uu + (uu >> 8) + (uu >> 16) + (uu >> 24) + (uu>>32);
|
||||
f >>= 16;
|
||||
m = ((f & 0xff) * 85 + 0x80) >> 8;
|
||||
return f >> 8;
|
||||
}
|
||||
|
||||
int d = 0;
|
||||
|
||||
typedef uint8_t r;
|
||||
uint32_t divmod85avr(uint32_t u)
|
||||
{
|
||||
|
||||
#define D(_m) if(d) printf("%-8s c=%x r0=%02x r1=%02x r18=%02x r19=%02x r20=%02x r21=%02x " \
|
||||
"r22=%02x r23=%02x r24=%02x r25=%02x r30=%02x r31=%02x\n", \
|
||||
_m, c, r0, r1, r18, r19, r20, r21, r23, r23, r24, r25, r30, r31)
|
||||
|
||||
#define ADD(_x, _y) { _c = (_x + _y) >>8; _x += _y; c = _c & 1; D("ADD "#_x);}
|
||||
#define ADC(_x, _y) { _c = (_x + _y + c) >>8; _x += _y + c; c = _c & 1; D("ADC "#_x);}
|
||||
#define SUB(_x, _y) { _c = (_x - _y) >>8; _x -= _y; c = _c & 1; D("SUB "#_x);}
|
||||
#define SBC(_x, _y) { _c = (_x - _y - c) >>8; _x -= _y + c; c = _c & 1; D("SBC "#_x);}
|
||||
#define LSL(_x) { c = _x >> 7; _x <<= 1; D("LSL "#_x);}
|
||||
#define ROL(_x) { _c = _x >> 7; _x <<= 1; _x |= c; c = _c; D("ROL "#_x);}
|
||||
#define CLR(_x) { _x = 0; D("CLR "#_x);}
|
||||
#define MOV(_x, _y) { _x = _y; D("MOV "#_x);}
|
||||
#define MOVW(_x, _xh, _y, _yh) { _x = _y; _xh = _yh; D("MOVW "#_x);}
|
||||
#define SEC {c=1; D("SEC");}
|
||||
#define LDI(_x, _n) { _x = _n; D("LDI "#_x);}
|
||||
#define MUL(_x, _y) { r0 = _x * _y; r1 = (_x * _y) >> 8; D("MUL "#_x);}
|
||||
|
||||
r c, _c, r0, r18, r19, r20, r21, r30, r31;
|
||||
r r1 = 0;
|
||||
r r22 = u>>24;
|
||||
r r23 = u>>16;
|
||||
r r24 = u>>8;
|
||||
r r25 = u;
|
||||
|
||||
MOVW(r18,r19, r22,r23);
|
||||
MOVW(r20,r21, r24,r25);
|
||||
LSL(r21);
|
||||
ROL(r20);
|
||||
ROL(r19);
|
||||
ROL(r18);
|
||||
CLR(r0);
|
||||
ROL(r0);
|
||||
SEC;
|
||||
ADC(r21, r25);
|
||||
ADC(r20, r24);
|
||||
ADC(r19, r23);
|
||||
ADC(r18, r22);
|
||||
ADC(r0, r1);
|
||||
|
||||
MOV(r30, r21);
|
||||
ADD(r30, r20);
|
||||
CLR(r31);
|
||||
ROL(r31);
|
||||
ADD(r30, r19);
|
||||
ADC(r31, r1);
|
||||
ADD(r30, r18);
|
||||
ADC(r31, r1);
|
||||
ADD(r30, r0);
|
||||
ADC(r31, r1);
|
||||
|
||||
MOV(r22, r31);
|
||||
ADD(r22, r30);
|
||||
MOV(r18, r31);
|
||||
ADC(r18, r30);
|
||||
MOV(r25, r31);
|
||||
ADC(r25, r1);
|
||||
|
||||
SUB(r30, r21);
|
||||
SBC(r31, r1);
|
||||
ADD(r25, r30);
|
||||
MOV(r24, r31);
|
||||
ADC(r24, r1);
|
||||
|
||||
SUB(r30, r20);
|
||||
SBC(r31, r1);
|
||||
ADD(r24, r30);
|
||||
MOV(r23, r31);
|
||||
ADC(r23, r1);
|
||||
|
||||
SUB(r30, r19);
|
||||
SBC(r31, r1);
|
||||
ADD(r23, r30);
|
||||
MOV(r22, r31);
|
||||
ADC(r22, r0);
|
||||
|
||||
LDI(r19, 85);
|
||||
MUL(r18, r19);
|
||||
LSL(r0);
|
||||
LDI(r19, 0)
|
||||
ADC(r1, r19);
|
||||
m = r1;
|
||||
CLR(r1);
|
||||
return (r22<<24) | (r23<<16) | (r24<<8) | r25;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
uint32_t u = 0;
|
||||
int did_d = 0;
|
||||
do {
|
||||
if (!(u & 0xffff))
|
||||
fprintf(stderr, "%08x\r", u);
|
||||
uint32_t nn = u / 85;
|
||||
uint8_t mm = u % 85;
|
||||
uint32_t n = divmod85avr(u);
|
||||
if (nn != n || mm != m) {
|
||||
printf("%08x = %08x × 85 + %02x : %08x %02x : %014lx\n",
|
||||
u, nn, mm, n, m, f);
|
||||
if (!did_d) {
|
||||
did_d = d = 1;
|
||||
divmod85avr(u);
|
||||
d = 0;
|
||||
}
|
||||
}
|
||||
} while (++u);
|
||||
}
|
||||
175
src/base85a.S
Normal file
175
src/base85a.S
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
|
||||
|
||||
;uint32_t divmod85(uint32_t u)
|
||||
;{
|
||||
; uint64_t uu = u;
|
||||
; f = (uu << 16) + (uu << 8) + uu + (uu >> 8) + (uu >> 16) + (uu >> 24);
|
||||
; f += 0x0100;
|
||||
; f &= 0xffffffffffff00LL;
|
||||
; f += f << 1;
|
||||
; m = (((f >> 16) & 0xff) * 85 + 0x80) >> 8;
|
||||
; return f >> 24;
|
||||
;}
|
||||
;
|
||||
; E,A,B,C,D = 3 × (r25,r24,r23,r22 big endian)
|
||||
; 3*(A+B+C+D+E) = r30, r31
|
||||
;
|
||||
; E D C B A
|
||||
; E D C B A
|
||||
; E D C B A
|
||||
; E D C B
|
||||
; E D C
|
||||
; E D
|
||||
; E
|
||||
; =============
|
||||
; u u u u r -
|
||||
|
||||
#ifdef BASE85C
|
||||
.global divmod85
|
||||
divmod85:
|
||||
movw r26, r20
|
||||
#endif
|
||||
;; ! C-ABI: m=X
|
||||
_divmod85: ; r25,r24,r23,r22 = A,B,C,D
|
||||
movw r18, r22
|
||||
movw r20, r24
|
||||
lsl r21
|
||||
rol r20
|
||||
rol r19
|
||||
rol r18
|
||||
clr r0
|
||||
rol r0
|
||||
sec
|
||||
adc r21, r25
|
||||
adc r20, r24
|
||||
adc r19, r23
|
||||
adc r18, r22
|
||||
adc r0, r1 ; r21,r20,r19,r18,r0 = 3u + 1
|
||||
|
||||
mov r30, r21
|
||||
add r30, r20
|
||||
clr r31
|
||||
rol r31
|
||||
add r30, r19
|
||||
adc r31, r1
|
||||
add r30, r18
|
||||
adc r31, r1
|
||||
add r30, r0
|
||||
adc r31, r1 ; r30,r31 = A+B+C+D+E
|
||||
|
||||
mov r22, r31 ;
|
||||
add r22, r30 ; just for the carry bit
|
||||
mov r18, r31
|
||||
adc r18, r30 ; r18 = r
|
||||
mov r25, r31
|
||||
adc r25, r1
|
||||
|
||||
sub r30, r21
|
||||
sbc r31, r1 ; r30,r31 = B+C+D+E
|
||||
add r25, r30
|
||||
mov r24, r31
|
||||
adc r24, r1
|
||||
|
||||
sub r30, r20
|
||||
sbc r31, r1 ; r30,r31 = C+D+E
|
||||
add r24, r30
|
||||
mov r23, r31
|
||||
adc r23, r1
|
||||
|
||||
sub r30, r19
|
||||
sbc r31, r1 ; r30,r31 = D+E
|
||||
add r23, r30
|
||||
mov r22, r31
|
||||
adc r22, r0
|
||||
|
||||
ldi r19, 85
|
||||
mul r18, r19
|
||||
lsl r0
|
||||
ldi r19, '!'
|
||||
adc r1, r19
|
||||
st -X, r1
|
||||
clr r1
|
||||
ret
|
||||
|
||||
#ifndef BASE85C
|
||||
.global base85_encode
|
||||
base85_encode:
|
||||
movw r26, r20
|
||||
adiw r26, 5
|
||||
st X, r1
|
||||
rcall _divmod85
|
||||
rcall _divmod85
|
||||
rcall _divmod85
|
||||
rcall _divmod85
|
||||
subi r25, -'!'
|
||||
st -X, r25
|
||||
ret
|
||||
#endif
|
||||
|
||||
; uint32_t mul85(uint32_t u, uint8_t m);
|
||||
|
||||
#ifdef BASE85C
|
||||
.global mul85
|
||||
mul85:
|
||||
#endif
|
||||
;; TODO for SPACE: inline this
|
||||
|
||||
;; big endian r22/r23/r24/r25 *= 85; … += r20
|
||||
_mul85:
|
||||
ldi r21, 85
|
||||
mul r25, r21
|
||||
movw r18, r0
|
||||
mul r24, r21
|
||||
movw r24, r0
|
||||
mul r23, r21
|
||||
movw r30, r0
|
||||
mul r22, r21
|
||||
add r18, r20
|
||||
adc r24, r19
|
||||
adc r30, r25
|
||||
adc r31, r0
|
||||
mov r25, r18
|
||||
mov r23, r30
|
||||
mov r22, r31
|
||||
#ifdef BASE85C
|
||||
clr r1
|
||||
#endif
|
||||
ret
|
||||
|
||||
#ifndef BASE85C
|
||||
|
||||
.global base85_decode
|
||||
base85_decode:
|
||||
push r17
|
||||
push r22
|
||||
push r23
|
||||
movw r26, r24
|
||||
clr r25
|
||||
clr r24
|
||||
clr r23
|
||||
clr r22
|
||||
ldi r17, 5
|
||||
1:
|
||||
ld r20, X+
|
||||
subi r20, '!'
|
||||
brcs 2f
|
||||
cpi r20, 85
|
||||
brcc 2f
|
||||
rcall _mul85
|
||||
subi r17, 1
|
||||
brne 1b
|
||||
clr r20
|
||||
2:
|
||||
sts base85_error, r20
|
||||
pop r31
|
||||
pop r30
|
||||
st Z, r22
|
||||
std Z+1, r23
|
||||
std Z+2, r24
|
||||
std Z+3, r25
|
||||
movw r24, r26
|
||||
pop r17
|
||||
clr r1
|
||||
ret
|
||||
|
||||
#endif
|
||||
1
src/bch4369
Submodule
1
src/bch4369
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit eebd4bb43039a2ecf63aa7c2fdbe1c4edf469393
|
||||
98
src/calib.c
98
src/calib.c
|
|
@ -1,98 +0,0 @@
|
|||
//
|
||||
// calib.c
|
||||
//
|
||||
|
||||
// MS5534-CM.pdf
|
||||
// https://media.digikey.com/pdf/Data%20Sheets/Measurement%20Specialties%20PDFs/MS5534-CM.pdf
|
||||
|
||||
#ifdef CALIB_DEBUG
|
||||
# include <stdio.h>
|
||||
# define TESTDATA_ADDR
|
||||
#else
|
||||
# include "eeprom.h"
|
||||
#endif
|
||||
|
||||
#include "calib.h"
|
||||
#include "mul.h"
|
||||
|
||||
void bate_calib(const union bate *bate, struct pressure *pt)
|
||||
{
|
||||
uint16_t C1 = bate->W1 >> 1;
|
||||
uint16_t C5 = (bate->W1 & 1) << 13 | (bate->W2 & 0xffc0) >> 3;
|
||||
uint8_t C6 = bate->W2 & 0x3f;
|
||||
uint16_t C4 = bate->W3 >> 6;
|
||||
uint16_t C3 = bate->W4 & 0xffc0;
|
||||
uint16_t C2 = (bate->W3 & 0x3f) << 6 | bate->W4 & 0x3f;
|
||||
|
||||
uint16_t D1 = bate->D1;
|
||||
uint16_t D2 = bate->D2;
|
||||
|
||||
uint16_t UT1 = C5 + 20224;
|
||||
uint16_t dT = D2 - UT1;
|
||||
|
||||
uint16_t TEMPSENS = C6 + 50;
|
||||
int16_t TEMP = mul16sun(dT, TEMPSENS, 6) + 200;
|
||||
|
||||
int16_t TCO = C4 - 512;
|
||||
uint16_t OFFT1 = C2 << 2;
|
||||
// fails when TCO < 0
|
||||
uint16_t OFF = OFFT1 + mul16sun(dT, TCO, 4);
|
||||
|
||||
uint16_t SENST1 = C1 + 24576;
|
||||
uint16_t TCS = C3;
|
||||
uint16_t SENS = SENST1 + mul16sun(dT, TCS, 0);
|
||||
|
||||
int16_t X = mul16sun(D1 - 7168, SENS, 2) - OFF;
|
||||
int16_t P = mul16sun(X, 80, 8) + 2500;
|
||||
|
||||
pt->T = TEMP + 2732;
|
||||
pt->p = P;
|
||||
|
||||
#ifdef CALIB_DEBUG
|
||||
|
||||
printf("W1 0x%04x\n", bate->W1);
|
||||
printf("W2 0x%04x\n", bate->W2);
|
||||
printf("W3 0x%04x\n", bate->W3);
|
||||
printf("W4 0x%04x\n", bate->W4);
|
||||
printf("D1 0x%04x %6d\n", D1, D1 - 7168);
|
||||
printf("D2 0x%04x\n", D2);
|
||||
printf("C1 %5u\n", C1);
|
||||
printf("C2 %5u\n", C2);
|
||||
printf("C3 %5d %5d\n", C3>>6, C3);
|
||||
printf("C4 %5d\n", C4);
|
||||
printf("C5 %5u %5u\n", C5>>3, C5);
|
||||
printf("C6 %5u\n", C6);
|
||||
printf("UT1 %5u\n", UT1);
|
||||
printf("dT %5d\n", dT);
|
||||
printf("TEMPSENS %5u\n", TEMPSENS);
|
||||
printf("TEMP %5d\n", TEMP);
|
||||
printf("TCO %5d\n", TCO);
|
||||
printf("OFFT1 %5u\n", OFFT1);
|
||||
printf("OFF %5u\n", OFF);
|
||||
printf("SENST1 %5u\n", SENST1);
|
||||
printf("TCS %5u %5u\n", TCS>>6, TCS);
|
||||
printf("SENS %5u\n", SENS);
|
||||
printf("X %5d\n", X);
|
||||
printf("P %5d\n", P);
|
||||
printf(" %.1f °C %.1f mbar\n\n", TEMP/10., P/10.);
|
||||
}
|
||||
|
||||
#define MUL_DEBUG
|
||||
#include "mul.c"
|
||||
|
||||
int main()
|
||||
{
|
||||
struct pressure pt;
|
||||
for (int i=0; i<5; i++)
|
||||
bate_calib(testdata+i, &pt);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
const union bate testdata[] TESTDATA_ADDR = {
|
||||
{ .w = { 0xA691, 0x0A97, 0x989F, 0xAF28, 0x4896, 0x71F4 }, },
|
||||
{ .W = { 0xabaf, 0x3c99, 0xa31a, 0xb589}, .D = { 0x470c, 0x773f }, }, // 21.2 °C, 1021.7 mbar
|
||||
{ .W = { 0xabaf, 0x3c99, 0xa31a, 0xb589}, .D = { 0x1a51, 0x6fed }, }, // 7.5 °C, 5.4 mbar
|
||||
{ .W = { 0xaa3d, 0x35d9, 0xcbe5, 0xb736}, .D = { 0x4bb7, 0x7487 }, }, // 17.7 °C, 1023.0 mbar
|
||||
{ .W = { 0xaa3d, 0x35d9, 0xcbe5, 0xb736}, .D = { 0x1e25, 0x650a }, }, // -11.3 °C, 2.4 mbar
|
||||
};
|
||||
29
src/calib.h
29
src/calib.h
|
|
@ -1,29 +0,0 @@
|
|||
|
||||
#include <stdint.h>
|
||||
// !!! int = int8_t
|
||||
|
||||
union bate {
|
||||
uint8_t b[12];
|
||||
uint16_t w[6];
|
||||
struct {
|
||||
uint16_t W[4];
|
||||
uint16_t D[2];
|
||||
};
|
||||
struct {
|
||||
uint16_t W1;
|
||||
uint16_t W2;
|
||||
uint16_t W3;
|
||||
uint16_t W4;
|
||||
uint16_t D1;
|
||||
uint16_t D2;
|
||||
};
|
||||
};
|
||||
|
||||
struct pressure {
|
||||
uint16_t T;
|
||||
uint16_t p;
|
||||
};
|
||||
|
||||
#define N_TESTDATA (64/sizeof(union bate))
|
||||
void bate_calib(const union bate *bate, struct pressure *pt);
|
||||
extern const union bate testdata[N_TESTDATA];
|
||||
448
src/cmd.c
448
src/cmd.c
|
|
@ -2,215 +2,279 @@
|
|||
// cmd.c
|
||||
//
|
||||
|
||||
#include "bate.h"
|
||||
#include "rtc.h"
|
||||
#include <string.h>
|
||||
#include "cmd.h"
|
||||
#include "adc.h"
|
||||
#include "flash.h"
|
||||
#include "bch4369.h"
|
||||
#include "base85.h"
|
||||
#include "uart.h"
|
||||
#include "pipe.h"
|
||||
|
||||
#ifdef NOCMD
|
||||
// no space for this
|
||||
void parse_command(uint8_t *s, uint8_t n) {}
|
||||
#else
|
||||
#ifdef HAVE_FPGA
|
||||
#include "fpga.h"
|
||||
#endif
|
||||
|
||||
uint8_t rx_params[8];
|
||||
uint8_t cmd_buffer[16];
|
||||
uint8_t base85_str[6];
|
||||
|
||||
#if 0
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
uint8_t parse_hex_nibble(uint8_t c)
|
||||
void base85_send(const uint32_t *v)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 0x0a;
|
||||
return 0xf0;
|
||||
base85_encode(*v, base85_str);
|
||||
send_str((const char *)base85_str);
|
||||
}
|
||||
|
||||
static inline
|
||||
uint8_t parse_rx_params(uint8_t *s, uint8_t n)
|
||||
void base85_send_buffer(const uint8_t *buf)
|
||||
{
|
||||
uint8_t p;
|
||||
p = 0;
|
||||
while (n) {
|
||||
while (n) {
|
||||
if (*s != ' ')
|
||||
break;
|
||||
n--;
|
||||
s++;
|
||||
}
|
||||
if (!n || p >= sizeof(rx_params))
|
||||
break;
|
||||
uint8_t d = parse_hex_nibble(*s);
|
||||
if (d==0xf0)
|
||||
break;
|
||||
n--;
|
||||
s++;
|
||||
if (n) {
|
||||
uint8_t h = 0;
|
||||
h = parse_hex_nibble(*s);
|
||||
if (h != 0xf0) {
|
||||
n--;
|
||||
s++;
|
||||
d <<= 4;
|
||||
d |= h;
|
||||
}
|
||||
}
|
||||
rx_params[p++] = d;
|
||||
DEBUG_POKE(rxhex, d);
|
||||
}
|
||||
if (!n || *s != '\n')
|
||||
p = 0;
|
||||
DEBUG_POKE(rxpar, p);
|
||||
return p;
|
||||
base85_send((void*)(buf+0));
|
||||
base85_send((void*)(buf+4));
|
||||
base85_send((void*)(buf+8));
|
||||
base85_send((void*)(buf+12));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline
|
||||
uint8_t parse_rx_params(uint8_t *s, uint8_t n)
|
||||
__attribute__((naked))
|
||||
void base85_send_buffer(const uint8_t *buf)
|
||||
{
|
||||
uint8_t p;
|
||||
__asm__("\n"
|
||||
"1: \n"
|
||||
" clr %[p] \n"
|
||||
" tst %[n] \n"
|
||||
" breq 8f \n"
|
||||
" ldi r26, lo8(rx_params) \n"
|
||||
" ldi r27, hi8(rx_params) \n"
|
||||
"2: \n"
|
||||
" ld r21, Z+ \n"
|
||||
" cpi r21, ' ' \n"
|
||||
" breq 6f \n"
|
||||
" cpi r21, '\\n' \n"
|
||||
" breq 8f \n"
|
||||
" rcall nibble \n"
|
||||
" brcc 7f \n"
|
||||
" mov r25, r21 \n"
|
||||
" subi %[n], 1 \n"
|
||||
" breq 7f \n"
|
||||
" ld r21, Z \n"
|
||||
" rcall nibble \n"
|
||||
" brcc 5f \n"
|
||||
" subi %[n], 1 \n"
|
||||
" breq 7f \n"
|
||||
" adiw r30, 1 \n"
|
||||
" swap r25 \n"
|
||||
" or r25, r21 \n"
|
||||
"5: \n"
|
||||
" cpi %[p], 8 ; sz rx_params \n"
|
||||
" brcc 7f \n"
|
||||
" subi %[p], -1 \n"
|
||||
" st X+, r25 \n"
|
||||
#ifdef DEBUG
|
||||
" sts debug_data + 6, r25 \n"
|
||||
" sts debug_data + 9, %[p] \n"
|
||||
#endif
|
||||
" rjmp 2b \n"
|
||||
" \n"
|
||||
"nibble: \n"
|
||||
" subi r21, '0' \n"
|
||||
" cpi r21, 10 \n"
|
||||
" brcs 9f \n"
|
||||
" subi r21, 'a'-'0' \n"
|
||||
" cpi r21, 6 \n"
|
||||
" brcc 9f \n"
|
||||
" subi r21, -10 \n"
|
||||
" sec \n"
|
||||
"9: ret \n"
|
||||
" \n"
|
||||
"6: \n"
|
||||
" subi %[n], 1 \n"
|
||||
" brne 2b \n"
|
||||
"7: \n"
|
||||
" clr %[p] \n"
|
||||
"8: \n"
|
||||
: [p] "=a" (p), // r24 (r16…)
|
||||
[s] "+z" (s), // r30,r31
|
||||
[n] "+a" (n) // r22 (r16…)
|
||||
: : "r21", "r25", "r26", "r27"
|
||||
);
|
||||
DEBUG_POKE(rxpar, p);
|
||||
return p;
|
||||
// send_str26 does not gobble r18, r20, r21, r24.
|
||||
__asm__(
|
||||
""
|
||||
"push r28" "\n\t"
|
||||
"push r29" "\n\t"
|
||||
"movw r28, r24" "\n\t"
|
||||
"rcall _base85_send28" "\n\t"
|
||||
"rcall _base85_send28" "\n\t"
|
||||
"rcall _base85_send28" "\n\t"
|
||||
"rcall _base85_send28" "\n\t"
|
||||
"pop r29" "\n\t"
|
||||
"pop r28" "\n\t"
|
||||
"ret" "\n"
|
||||
"_base85_send28:" "\n\t"
|
||||
"ld r22, Y+" "\n\t"
|
||||
"ld r23, Y+" "\n\t"
|
||||
"ld r24, Y+" "\n\t"
|
||||
"ld r25, Y+" "\n\t"
|
||||
"ldi r20, lo8(base85_str)" "\n\t"
|
||||
"ldi r21, hi8(base85_str)" "\n\t"
|
||||
"rcall base85_encode" "\n\t"
|
||||
"rjmp _send_str26" "\n"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
void parse_command(uint8_t *s, uint8_t n)
|
||||
|
||||
static inline
|
||||
const uint8_t *base85_fill_buffer(const uint8_t *s) {
|
||||
base85_error = 0;
|
||||
for (int i=0; !base85_error && i<16; i+=4)
|
||||
s = base85_decode(s, (uint32_t *)(cmd_buffer + i));
|
||||
return s;
|
||||
}
|
||||
|
||||
struct peak_poke {
|
||||
uint8_t *addr;
|
||||
uint8_t size;
|
||||
uint8_t ccp;
|
||||
uint8_t data[12];
|
||||
};
|
||||
|
||||
static inline
|
||||
uint8_t poke(struct peak_poke *p, uint8_t poke)
|
||||
{
|
||||
if (!n || n >= 15)
|
||||
goto fail;
|
||||
|
||||
uint8_t cmd = *s++;
|
||||
uint8_t p = parse_rx_params(s, n-1);
|
||||
uint8_t *pp = rx_params;
|
||||
|
||||
uint8_t *a = (uint8_t *)(((uint16_t)pp[0] << 8) | pp[1]);
|
||||
|
||||
if (cmd == 'R' && p==1)
|
||||
__asm__("\n"
|
||||
" ldi r18, 1 \n"
|
||||
" out %[ccp], %[p] \n"
|
||||
" sts %[swrr], r18 \n"
|
||||
:
|
||||
: [p] "r" (pp[0]),
|
||||
[ccp] "n" (_SFR_IO_ADDR(CCP)),
|
||||
[swrr] "n" (&RSTCTRL.SWRR)
|
||||
: "r18"
|
||||
);
|
||||
|
||||
if (p >= 3 && p < 8 && (
|
||||
cmd == 'C' && pp[0]==0xba
|
||||
|| cmd == 'E'
|
||||
|| cmd == 'U')) {
|
||||
uint8_t *e = (uint8_t*) &config;
|
||||
if (cmd=='E')
|
||||
e = (uint8_t*) EEPROM_START;
|
||||
if (cmd=='U')
|
||||
e = (uint8_t*) &USERROW;
|
||||
e += pp[1];
|
||||
pp[p] = *e;
|
||||
memcpy(e, pp+2, p-2);
|
||||
if (cmd != 'C')
|
||||
__asm__("\n"
|
||||
" ldi r24, %[erwp] \n"
|
||||
" out %[ccp], %[p] \n"
|
||||
" sts %[ctrl], r24 \n"
|
||||
:
|
||||
: [p] "r" (pp[0]),
|
||||
[ccp] "n" (_SFR_IO_ADDR(CCP)),
|
||||
[ctrl] "n" (&NVMCTRL.CTRLA),
|
||||
[erwp] "n" (NVMCTRL_CMD_PAGEERASEWRITE_gc)
|
||||
: "r24"
|
||||
uint8_t s = p->size;
|
||||
uint8_t *a = p->addr;
|
||||
uint8_t n = s;
|
||||
if (n > 12)
|
||||
n = 12;
|
||||
p->size = s - n;
|
||||
p->addr = a + n;
|
||||
if (!n)
|
||||
return 0;
|
||||
if (poke) {
|
||||
uint8_t ccp = p->ccp;
|
||||
if (ccp)
|
||||
__asm__(
|
||||
"out __CCP__, %[key] \n\t"
|
||||
"sts %[ctrla], %[cmd] \n"
|
||||
::
|
||||
[ctrla] "n" (&NVMCTRL.CTRLA),
|
||||
[key] "r" (ccp),
|
||||
[cmd] "r" (NVMCTRL_CMD_PAGEBUFCLR_gc)
|
||||
: "memory"
|
||||
);
|
||||
_memcopy(a, p->data, n);
|
||||
if (ccp && !(0x8000 & (uint16_t)a))
|
||||
__asm__(
|
||||
"out __CCP__, %[key] \n\t"
|
||||
"sts %[ctrla], %[cmd] \n"
|
||||
::
|
||||
[ctrla] "n" (&NVMCTRL.CTRLA),
|
||||
[key] "r" (ccp),
|
||||
[cmd] "r" (NVMCTRL_CMD_PAGEERASEWRITE_gc)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
else if (cmd == 'T' && p==1) {
|
||||
immediate += pp[0];
|
||||
pp[1] = immediate;
|
||||
}
|
||||
else if (cmd == 'M' && p==2) {
|
||||
pp[2] = *a;
|
||||
}
|
||||
else if (cmd == 'W' && p==3) {
|
||||
pp[3] = *a;
|
||||
*a = pp[2];
|
||||
}
|
||||
else if (cmd == 'K' && p==4) {
|
||||
cli();
|
||||
pp[4] = clock_tick;
|
||||
clock = *(uint32_t*)pp;
|
||||
sei();
|
||||
}
|
||||
else if (cmd == 'D' && p==1) {
|
||||
pp[1] = test_calib;
|
||||
test_calib = pp[0];
|
||||
}
|
||||
else
|
||||
goto fail;
|
||||
|
||||
send_char('R');
|
||||
send_char('!');
|
||||
send_hex(cmd, pp, p+1, 1);
|
||||
return;
|
||||
fail:
|
||||
send_str("R?\n");
|
||||
_memcopy(p->data, a, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
const uint8_t *cmd_flags;
|
||||
#if 0
|
||||
static __attribute__((noinline))
|
||||
uint8_t cmd_flag(uint8_t f)
|
||||
{
|
||||
if (*cmd_flags == f) {
|
||||
cmd_flags++;
|
||||
send_char(f);
|
||||
return f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static __attribute__((noinline, naked))
|
||||
uint8_t cmd_flag(uint8_t f)
|
||||
{
|
||||
// _send_char22 does not gobble r24.
|
||||
__asm__(
|
||||
""
|
||||
"lds r30, cmd_flags" "\n\t"
|
||||
"lds r31, cmd_flags+1" "\n\t"
|
||||
"ld r22, Z+" "\n\t"
|
||||
"cp r22, r24" "\n\t"
|
||||
"mov r24, r1" "\n\t"
|
||||
"breq 1f" "\n\t"
|
||||
"ret" "\n"
|
||||
"1:" "\n\t"
|
||||
"mov r24, r22" "\n\t"
|
||||
"sts cmd_flags, r30" "\n\t"
|
||||
"sts cmd_flags+1, r31" "\n\t"
|
||||
"rjmp _send_char22" "\n"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t cmd_pending;
|
||||
|
||||
void parse_command(const uint8_t *s, uint8_t n)
|
||||
{
|
||||
// ^[A-Z][!-@]+( [!-u]{20}])?$
|
||||
// cmd flags ␣base85
|
||||
|
||||
uint8_t r = 0;
|
||||
uint8_t cmd = *s++;
|
||||
if (cmd < 'A' || cmd > 'Z')
|
||||
return;
|
||||
send_char('#');
|
||||
send_char(cmd);
|
||||
uint8_t bflg = *s - '0';
|
||||
uint8_t *bptr = cmd_buffer;
|
||||
if (bflg <= 5) {
|
||||
bptr = flash_buffer + 16*bflg;
|
||||
bflg = 1<<bflg;
|
||||
send_char(*s++);
|
||||
}
|
||||
else
|
||||
bflg = 0;
|
||||
cmd_flags = s;
|
||||
while (*s > ' ' && *s < 'A')
|
||||
s++;
|
||||
uint8_t have_b = 0;
|
||||
if (*s==' ') {
|
||||
cmd_pending = 0;
|
||||
s = base85_fill_buffer(s+1);
|
||||
r = base85_error;
|
||||
if (r)
|
||||
goto error;
|
||||
have_b = 1;
|
||||
cmd_pending = cmd;
|
||||
}
|
||||
else if (cmd_flag('='))
|
||||
have_b = cmd_pending == cmd;
|
||||
if (*s != '\n')
|
||||
goto error;
|
||||
switch(cmd) {
|
||||
case 'A':
|
||||
r = adc_current;
|
||||
if (cmd_flag('!'))
|
||||
start_adc();
|
||||
if (cmd_flag('<')) {
|
||||
bptr = (void*)adc_readings;
|
||||
goto send_buffer;
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
if (cmd_flag('@'))
|
||||
pipe.valid = 0;
|
||||
r = pipe.valid;
|
||||
if (have_b) {
|
||||
if (cmd_flag('!') || ~r & bflg) {
|
||||
memcpy(bptr, cmd_buffer, 16);
|
||||
r = pipe.valid |= bflg;
|
||||
}
|
||||
else
|
||||
goto error;
|
||||
}
|
||||
if (cmd_flag('%')) {
|
||||
if (cmd_flag('@'))
|
||||
bch4369_init(config.bch_salt);
|
||||
bch4369_str(bptr, 16);
|
||||
if (cmd_flag('!')) {
|
||||
bch4369_fini();
|
||||
memcpy(flash_buffer+64, bch_parity, 16);
|
||||
r = pipe.valid |= 0x10;
|
||||
}
|
||||
}
|
||||
if (cmd_flag('<')) {
|
||||
if (cmd_flag('!')) goto send_buffer;
|
||||
if (~r & bflg)
|
||||
goto error;
|
||||
pipe.valid &=~ bflg;
|
||||
goto send_buffer;
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
flash_find_free();
|
||||
bptr = (void*)&fs;
|
||||
goto send_buffer;
|
||||
case 'F':
|
||||
if (have_b)
|
||||
r = flash_submit_command(cmd_buffer);
|
||||
else
|
||||
r = spi_busy_p();
|
||||
if (cmd_flag('<'))
|
||||
goto send_buffer;
|
||||
break;
|
||||
#ifndef HALLO
|
||||
case 'P':
|
||||
if (have_b)
|
||||
pipe_config((void*)cmd_buffer);
|
||||
else
|
||||
r = pipe_poll();
|
||||
break;
|
||||
goto send_buffer;
|
||||
break;
|
||||
#ifdef HAVE_FPGA
|
||||
case 'C':
|
||||
if (cmd_flag('@')) {
|
||||
fpga_reset();
|
||||
break;
|
||||
}
|
||||
if (!have_b)
|
||||
goto error;
|
||||
fpga_cmd((void*)cmd_buffer);
|
||||
goto send_buffer;
|
||||
#endif
|
||||
#endif // HALLO
|
||||
case 'M':
|
||||
if (!have_b)
|
||||
goto error;
|
||||
r = poke((void*)cmd_buffer, cmd_flag('!'));
|
||||
send_buffer:
|
||||
send_char(' ');
|
||||
base85_send_buffer(bptr);
|
||||
break;
|
||||
default:
|
||||
error:
|
||||
send_char('?');
|
||||
}
|
||||
send_hex_byte_eol(r);
|
||||
}
|
||||
|
|
|
|||
6
src/cmd.h
Normal file
6
src/cmd.h
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
extern uint8_t base85_error;
|
||||
void parse_command(const uint8_t *s, uint8_t n);
|
||||
extern uint8_t cmd_buffer[16];
|
||||
67
src/config.c
Normal file
67
src/config.c
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
#include "config.h"
|
||||
#include "flash.h"
|
||||
#include "adc.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Configuration in USERROW
|
||||
|
||||
__attribute__((section(".userrow")))
|
||||
const struct config config = {
|
||||
.magic = MAGIC,
|
||||
.version = VERSION,
|
||||
.cpu_clk = CLKCTRL_PDIV_2X_gc | 1, // 10MHz (max @ 3V)
|
||||
.flash_page_size = FM_528 >> 8,
|
||||
.bch_salt = 1,
|
||||
.burn_page = 0x88, // Buffer 1 Page Program w/o Erase
|
||||
.write_buffer = 0x84 | FM_WRITE, // Buffer 1 Write
|
||||
.read_array = 0x03 | FM_READ, // Continuous Array Read (Low-Frequency)
|
||||
.read_buffer = {
|
||||
[0] = 0xd1 | FM_READ, // Buffer 1 Read (Low-Frequency)
|
||||
[1] = 0xd3 | FM_READ, // Buffer 2 Read (Low-Frequency)
|
||||
},
|
||||
.page_start = 0x0800,
|
||||
.page_end = 0x1000,
|
||||
#ifdef HAVE_nFETs
|
||||
.pwm_min = 0x0000,
|
||||
.pwm_max = 0xffff,
|
||||
#endif
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Configuration in EEPROM
|
||||
|
||||
|
||||
struct_ioconf(port_config) = {
|
||||
conf_prefix(PORTA),
|
||||
conf_io(RxD_PINCTRL, PORT_PULLUPEN_bm),
|
||||
#ifdef HAVE_nFETs
|
||||
conf_io(ADC_D1_PINCTRL, PORT_ISC_INPUT_DISABLE_gc),
|
||||
conf_io(ADC_D2_PINCTRL, PORT_ISC_INPUT_DISABLE_gc),
|
||||
conf_io(ADC_G_PINCTRL, PORT_ISC_INPUT_DISABLE_gc),
|
||||
#endif
|
||||
#ifdef HAVE_FPGA
|
||||
conf_io(nSTATUS_PINCTRL, PORT_PULLUPEN_bm),
|
||||
conf_io(CRCERR_PINCTRL, PORT_PULLUPEN_bm),
|
||||
#endif
|
||||
conf_io(PORTA.OUT, Bit(SSEL_PIN)),
|
||||
conf_io(PORTA.DIR, Bit(SSEL_PIN) | Bit(MOSI_PIN) | Bit(SCK_PIN)
|
||||
#ifdef HAVE_nFETs
|
||||
| Bit(DRAIN_PIN)
|
||||
#endif
|
||||
#ifdef HAVE_FPGA
|
||||
| Bit(nCONFIG_PIN) | Bit(TxE_PIN)
|
||||
#endif
|
||||
),
|
||||
conf_io(PORTB.OUT, Bit(TxD_PIN)),
|
||||
conf_io(PORTB.DIR, Bit(TxD_PIN)
|
||||
#ifdef HAVE_nFETs
|
||||
| Bit(PWM_PIN)
|
||||
#endif
|
||||
#ifdef HAVE_FPGA
|
||||
| Bit(TxE_PIN) | Bit(PEN_PIN)
|
||||
#endif
|
||||
),
|
||||
};
|
||||
198
src/config.h
Normal file
198
src/config.h
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
#include <avr/io.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// USERROW
|
||||
|
||||
struct config {
|
||||
uint8_t magic;
|
||||
uint8_t version;
|
||||
uint8_t cpu_clk;
|
||||
uint8_t cron;
|
||||
uint8_t flash_page_size;
|
||||
uint8_t bch_salt;
|
||||
uint16_t burn_page;
|
||||
uint16_t write_buffer;
|
||||
uint16_t read_array;
|
||||
uint16_t read_buffer[2];
|
||||
uint16_t page_start;
|
||||
uint16_t page_end;
|
||||
#ifdef HAVE_nFETs
|
||||
uint16_t pwm_min;
|
||||
uint16_t pwm_max;
|
||||
#endif
|
||||
};
|
||||
|
||||
enum magic_flags {
|
||||
#ifdef HAVE_nFETs
|
||||
MAGIC = 0xD0,
|
||||
VERSION = 0x00,
|
||||
#endif
|
||||
#ifdef HAVE_FPGA
|
||||
MAGIC = 0xC5,
|
||||
VERSION = 0x01,
|
||||
#endif
|
||||
};
|
||||
|
||||
extern const struct config config;
|
||||
|
||||
// EEPROM
|
||||
|
||||
struct io_config {
|
||||
uint8_t addr;
|
||||
uint8_t val;
|
||||
};
|
||||
|
||||
#define struct_ioconf(_n) struct io_config _n[] \
|
||||
__attribute__((section(".eeprom9"), aligned(2)))
|
||||
|
||||
#define conf_prefix(_io) { 0xff, (uint16_t)&(_io) >> 8 }
|
||||
#define conf_io(_io, _v) { (uint16_t)&(_io) & 0xff, (_v) }
|
||||
#define conf_ioo(_io, _o, _v) { (uint16_t)&(_io) + _o & 0xff, (_v) }
|
||||
#define conf_iow(_io, _v) conf_io(_io, (_v) & 0xff), conf_ioo(_io, 1, (uint16_t)(_v) >> 8)
|
||||
|
||||
extern struct io_config ee9_start[], ee9_end[];
|
||||
|
||||
#define Bit(x) (1<<(x))
|
||||
|
||||
#define SPI_VPORT VPORTA
|
||||
#define SPI_PORT PORTA
|
||||
#define MOSI_PIN 1
|
||||
#define MISO_PIN 2
|
||||
#define SCK_PIN 3
|
||||
|
||||
#define UART_VPORT VPORTB
|
||||
#define UART_PORT PORTB
|
||||
#define TxE_PIN 1
|
||||
#define TxD_PIN 2
|
||||
#define RxD_PIN 3
|
||||
#define RxD_PINCTRL UART_PORT.PIN3CTRL
|
||||
|
||||
#ifdef HAVE_FPGA
|
||||
#define SSEL_VPORT VPORTA
|
||||
#define SSEL_PORT PORTA
|
||||
#define SSEL_PIN 7
|
||||
#define nCONFIG_VPORT VPORTA
|
||||
#define nCONFIG_PORT PORTA
|
||||
#define nCONFIG_PIN 6
|
||||
#define nSTATUS_VPORT VPORTA
|
||||
#define nSTATUS_PORT PORTA
|
||||
#define nSTATUS_PIN 4
|
||||
#define nSTATUS_PINCTRL nSTATUS_PORT.PIN4CTRL
|
||||
#define CRCERR_VPORT VPORTA
|
||||
#define CRCERR_PORT PORTA
|
||||
#define CRCERR_PIN 5
|
||||
#define CRCERR_PINCTRL CRCERR_PORT.PIN5CTRL
|
||||
#define PEN_VPORT VPORTB
|
||||
#define PEN_PORT PORTB
|
||||
#define PEN_PIN 1
|
||||
#else
|
||||
#define SSEL_VPORT VPORTA
|
||||
#define SSEL_PORT PORTA
|
||||
#define SSEL_PIN 4
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_nFETs
|
||||
#define DRAIN_VPORT VPORTA
|
||||
#define DRAIN_PORT PORTA
|
||||
#define DRAIN_PIN 5
|
||||
#define PWM_VPORT VPORTB
|
||||
#define PWM_PORT PORTB
|
||||
#define PWM_PIN 0
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
|
||||
static inline
|
||||
void apply_config()
|
||||
{
|
||||
uint8_t n = ee_end - ee_start;
|
||||
struct io_config = ee_start;
|
||||
uint8_t prefix = 0;
|
||||
while (n--) {
|
||||
const struct io_config *io = c++;
|
||||
if (io->addr == 0xff)
|
||||
prefix = io->val;
|
||||
else {
|
||||
uint8_t *p = (uint8_t*)((uint16_t)prefix << 8 | io->addr);
|
||||
*p = io->val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline
|
||||
void apply_config()
|
||||
{
|
||||
__asm__ volatile(
|
||||
"ldi r30, lo8(ee9_start)" "\n\t"
|
||||
"ldi r31, hi8(ee9_start)" "\n\t"
|
||||
"ldi r24, lo8(ee9_size)" "\n\t"
|
||||
"clr r25" "\n"
|
||||
"1:" "\n\t"
|
||||
"mov r27, r25" "\n\t"
|
||||
"subi r24, 2" "\n\t"
|
||||
"brcs 3f" "\n"
|
||||
"2:" "\n\t"
|
||||
"ld r26, Z+" "\n\t"
|
||||
"ld r25, Z+" "\n\t"
|
||||
"cpi r26, 0xff" "\n\t"
|
||||
"breq 1b" "\n\t"
|
||||
"st X, r25" "\n\t"
|
||||
"subi r24, 2" "\n\t"
|
||||
"brcc 2b" "\n"
|
||||
"3:" "\n\t"
|
||||
::: "r24", "r25", "r26", "r27", "r30", "r31");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define section_status(_n) __attribute__((section(".bss."#_n)))
|
||||
extern struct magic {
|
||||
uint8_t magic;
|
||||
uint8_t reset_source;
|
||||
} magic;
|
||||
|
||||
#if 0
|
||||
#define _memcopy memcpy
|
||||
#define _memcopyyz memcpy
|
||||
#else
|
||||
// avoid the avr-libc memcpy.
|
||||
// ¡ n must not be zero !
|
||||
static inline
|
||||
void _memcopy(uint8_t *d, uint8_t *s, uint8_t n)
|
||||
{
|
||||
__asm__ volatile ("\n"
|
||||
"1:" "\n\t"
|
||||
"ld r0, Z+" "\n\t"
|
||||
"st X+, r0" "\n\t"
|
||||
"dec %[N]" "\n\t"
|
||||
"brne 1b" "\n"
|
||||
: [D] "+x" (d),
|
||||
[S] "+z" (s),
|
||||
[N] "+r" (n)
|
||||
:: "r0", "memory");
|
||||
}
|
||||
|
||||
static inline
|
||||
void _memcopyyz(uint8_t *d, uint8_t *s, uint8_t n)
|
||||
{
|
||||
__asm__ volatile ("\n"
|
||||
"1:" "\n\t"
|
||||
"ld r0, Z+" "\n\t"
|
||||
"st Y+, r0" "\n\t"
|
||||
"dec %[N]" "\n\t"
|
||||
"brne 1b" "\n"
|
||||
: [D] "+y" (d),
|
||||
[S] "+z" (s),
|
||||
[N] "+r" (n)
|
||||
:: "r0", "memory");
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _CONFIG_H
|
||||
75
src/dose.c
Normal file
75
src/dose.c
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// dose.c
|
||||
//
|
||||
|
||||
// !!! int = int8_t
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/sleep.h>
|
||||
#include <avr/wdt.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "dose.h"
|
||||
#include "pipe.h"
|
||||
#include "uart.h"
|
||||
#include "rtc.h"
|
||||
#include "cmd.h"
|
||||
#include "adc.h"
|
||||
#include "pwm.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// main()
|
||||
|
||||
section_status(main) struct magic magic;
|
||||
|
||||
struct pipe_config cron_job[1] =
|
||||
{
|
||||
[0] = {
|
||||
.pipe = {
|
||||
.source = pipe_adc,
|
||||
.dest = pipe_cmd,
|
||||
.status = PS_OUT | PS_BCH,
|
||||
.valid = 0,
|
||||
.adc = ADC_64 | ADC_PWM | ADC_RTC,
|
||||
},
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
while (CLKCTRL.MCLKCTRLB != config.cpu_clk) {
|
||||
CCP = CCP_IOREG_gc;
|
||||
CLKCTRL.MCLKCTRLB = config.cpu_clk;
|
||||
}
|
||||
|
||||
sleep_enable();
|
||||
magic.magic = config.magic;
|
||||
while (magic.magic != MAGIC)
|
||||
sleep_cpu();
|
||||
|
||||
apply_config();
|
||||
|
||||
magic.reset_source = RSTCTRL.RSTFR;
|
||||
RSTCTRL.RSTFR = magic.reset_source;
|
||||
send_str("\nV Turbo Dose V0.0");
|
||||
send_hex_byte_eol(magic.reset_source);
|
||||
|
||||
// cron_job[0].page = flash_find_free();
|
||||
// cron_job[0].npages = config.page_end - cron_job[0].page;
|
||||
// if (config.cron & 1)
|
||||
// pipe_config(cron_job);
|
||||
|
||||
while (1) {
|
||||
sei();
|
||||
sleep_cpu();
|
||||
command();
|
||||
// pipe_poll();
|
||||
// if (config.cron & 2 && rtc_cnt_tick())
|
||||
// pipe_config(cron_job);
|
||||
}
|
||||
}
|
||||
11
src/dose.h
Normal file
11
src/dose.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// dose.h
|
||||
//
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Configuration
|
||||
|
||||
#include <stdint.h>
|
||||
#include <avr/io.h>
|
||||
|
||||
370
src/dose.py
Executable file
370
src/dose.py
Executable file
|
|
@ -0,0 +1,370 @@
|
|||
#! /usr/bin/ipython3 --profile=turbo_dose
|
||||
|
||||
import sys, time, getopt, fileinput, struct
|
||||
import uart
|
||||
from base85 import base85_encode, base85_decode
|
||||
from map import memmap
|
||||
from iotn424 import SFR
|
||||
import flash as flash_cmd
|
||||
flash_cmd = flash_cmd.flash_cmd()
|
||||
sys.path[1:1] = ["./bch4369"]
|
||||
from bch4369 import bch
|
||||
|
||||
options, files = getopt.gnu_getopt(sys.argv[1:], "F:o:M:", ["debug", "tty=", "output=", "map=", "galois"])
|
||||
|
||||
tty = None
|
||||
baud = 115200
|
||||
out = None
|
||||
debug = None
|
||||
map_fn = "hallo.map"
|
||||
|
||||
def Debug(e, *a):
|
||||
if debug:
|
||||
import traceback
|
||||
sys.stdout.flush()
|
||||
print("xdebug", a, repr(e), file=sys.stderr)
|
||||
traceback.print_exception(e, limit=-2, file=sys.stderr)
|
||||
|
||||
for o,v in options:
|
||||
|
||||
if o == "--debug":
|
||||
debug = True
|
||||
|
||||
if o in "-F --tty":
|
||||
tty = v
|
||||
v = v.split(",", 1)
|
||||
if v[1:]:
|
||||
tty = v[0]
|
||||
baud = int(v[1])
|
||||
do_clock = True
|
||||
|
||||
if o in "--output":
|
||||
if out:
|
||||
raise ValueError("cannot have multiple --outputs")
|
||||
if v=="-":
|
||||
out = sys.stdout
|
||||
elif v=="--":
|
||||
out = sys.stderr
|
||||
else:
|
||||
out = open(v, "a")
|
||||
|
||||
if o in "-M --map":
|
||||
map_fn = v
|
||||
|
||||
if o == "--galois":
|
||||
bch.load_galois()
|
||||
|
||||
if not out:
|
||||
out = sys.stdout
|
||||
|
||||
if len(files)==1:
|
||||
if "/dev/tty" in files[0]:
|
||||
tty = files[0]
|
||||
files = []
|
||||
|
||||
mmap = memmap(map_fn)
|
||||
|
||||
class dose_cmd(uart.uart):
|
||||
|
||||
def cmd(self, c, d=None, timeout=0.2):
|
||||
if not isinstance(c, bytes):
|
||||
c = c.encode()
|
||||
if d:
|
||||
c += b" " + base85_encode(d)
|
||||
self.flush()
|
||||
self.ucmd(c)
|
||||
r = self.resp(timeout)
|
||||
while r and (r[0] != b'#'[0] or r[1] != c[0]):
|
||||
r = self.resp(timeout)
|
||||
d = None
|
||||
if not r:
|
||||
return r, d
|
||||
r = r.split()
|
||||
e = int(r[-1], 16)
|
||||
if len(r)==3:
|
||||
d = base85_decode(r[1])
|
||||
if self._verbose:
|
||||
print(f"{r[0]}[{r[2]}] {"".join([f"{b:02x}" for b in d])}", file=sys.stderr)
|
||||
self.last_cmd = c[0:1]
|
||||
return r[0], e, d
|
||||
|
||||
def poke(self, a, d, s=None, ccp=0):
|
||||
return self.peek(a, s=s, d=d, ccp=ccp)
|
||||
|
||||
def peek(self, a=None, s=None, d=None, ccp=0):
|
||||
name = None
|
||||
if a in SFR:
|
||||
name = a
|
||||
a, ss = SFR[a]
|
||||
if s is None:
|
||||
s = ss
|
||||
if a in mmap:
|
||||
a, ss = mmap[a]
|
||||
if ss and s is None:
|
||||
s = ss
|
||||
if isinstance(a, str):
|
||||
print(f"PEEK: unknown addr {a}", file=sys.stderr)
|
||||
for k in mmap.keys():
|
||||
if a in k:
|
||||
print(f"PEEK: in RAM we have {k}", file=sys.stderr)
|
||||
for k in SFR.keys():
|
||||
if a in k:
|
||||
print(f"PEEK: IO SFR we have {k}", file=sys.stderr)
|
||||
raise ValueError(a)
|
||||
FF = {1: "B", 2: "H", 4:"I"}
|
||||
if a is None:
|
||||
cc, nn, dd = self.cmd(b"M=")
|
||||
else:
|
||||
if d is None:
|
||||
c = b"M"
|
||||
d = b''
|
||||
if s is None:
|
||||
s = 12
|
||||
else:
|
||||
c = b'M!'
|
||||
if isinstance(d, int) and s in FF:
|
||||
d = struct.pack(f"<{FF[s]}", d)
|
||||
else:
|
||||
d = bytes(d)
|
||||
if s is None:
|
||||
s = len(d)
|
||||
d = struct.pack("<HBB", a,s,ccp) + d + b'\0\0\0\0\0\0\0\0\0\0\0\0'
|
||||
cc, nn, dd = self.cmd(c, d[:16])
|
||||
if dd and nn:
|
||||
aa,ss,cc = struct.unpack("<HBB", dd[:4])
|
||||
print(f"PEEK: {aa-nn:04x}[{nn}+{ss}]: {b2hex(dd[4:4+nn])}", file=sys.stderr)
|
||||
if name is not None and nn in FF:
|
||||
d = struct.unpack(f"<{FF[nn]}", dd[4:4+nn])
|
||||
print(f"{name}: {d[0]:#x}", file=sys.stderr)
|
||||
return name, d
|
||||
return cc, nn, dd
|
||||
|
||||
def more(self, flags=b''):
|
||||
return self.cmd(self.last_cmd + b'=' + flags)
|
||||
|
||||
def read_mem(self, a, s=None):
|
||||
cc, nn, dd = self.peek(a=a, s=s)
|
||||
r = dd[4:4+nn]
|
||||
while dd[2]:
|
||||
cc, nn, dd = self.more()
|
||||
r += dd[4:4+nn]
|
||||
return r
|
||||
|
||||
_adc_conf = None
|
||||
_sigrow = None
|
||||
|
||||
ADC_MUX = {
|
||||
0: "GND",
|
||||
6: "Gate",
|
||||
7: "Drain1",
|
||||
10: "Drain2",
|
||||
0x30: "GND",
|
||||
0x31: ("Vdd", 10, 0, 0),
|
||||
0x32: "T",
|
||||
0x33: "DACREF",
|
||||
}
|
||||
ADC_REF = {
|
||||
0: (3.3, "VDD"),
|
||||
4: (1.024,),
|
||||
5: (2.048,),
|
||||
6: (2.5,),
|
||||
7: (4.096,),
|
||||
}
|
||||
|
||||
def adc(self, start=False, read_conf=False):
|
||||
if not self._adc_conf or read_conf:
|
||||
self._adc_conf = self.read_mem("adc_conf")
|
||||
self._sigrow = self.read_mem(0x1100, 0x24)
|
||||
g = self._sigrow[0x20]
|
||||
o = self._sigrow[0x21]
|
||||
if o & 0x80:
|
||||
o -= 0x100
|
||||
o <<= 6
|
||||
g /= 1 << 14
|
||||
self.ADC_MUX[0x32] = ("T°C", g, o, 273)
|
||||
c = "A!<" if start else "A<"
|
||||
cc, nn, dd = self.cmd(c)
|
||||
dd = struct.unpack("<8H", dd)
|
||||
r = []
|
||||
for i in range(nn):
|
||||
pos = self._adc_conf[4*i+2] & 0x3f
|
||||
ref = self._adc_conf[4*i+1] & 0x07
|
||||
if ref in self.ADC_REF:
|
||||
ref = self.ADC_REF[ref]
|
||||
else:
|
||||
ref = (1,)
|
||||
a = dd[i]
|
||||
if pos != 0x32:
|
||||
a *= ref[0]/0x10000
|
||||
if pos in self.ADC_MUX:
|
||||
pos = self.ADC_MUX[pos]
|
||||
else:
|
||||
pos = f"Ain{pos}"
|
||||
if isinstance(pos, tuple):
|
||||
a = (a - pos[2])*pos[1] - pos[3]
|
||||
pos = pos[0]
|
||||
r.append((a, pos, ref))
|
||||
print(f"{i} {pos:6s} {a:.4f} {ref!r}", file=sys.stderr)
|
||||
return r
|
||||
|
||||
def nfet_scan(self, t=1, dcs=(0x1000,)):
|
||||
r = []
|
||||
for dc in range(*dcs):
|
||||
self.poke("TCA0_SINGLE_CMP0", dc)
|
||||
time.sleep(t)
|
||||
self.cmd("A!")
|
||||
time.sleep(1)
|
||||
r.append((dc, self.adc()))
|
||||
return r
|
||||
|
||||
def flash(self, op=None, abort=False, buf=False, **aa):
|
||||
if op is None:
|
||||
c = "F"
|
||||
if abort:
|
||||
c = "F!"
|
||||
if buf:
|
||||
c += "<"
|
||||
return self.cmd(c)
|
||||
r = self.cmd("F", flash_cmd.cmd_buffer(op, **aa))
|
||||
if r[1]:
|
||||
raise flash_cmd.Flash_Error(op)
|
||||
return r
|
||||
|
||||
def write2fbuffer(self, d, op="WriteBuffer2"):
|
||||
for i in range(0, 512, 16):
|
||||
b = i>>4
|
||||
if not b:
|
||||
c = "B0@%@"
|
||||
elif not (b&3):
|
||||
c = "B0@%"
|
||||
elif b==31:
|
||||
c = "B3%!"
|
||||
else:
|
||||
c = f"B{b&3}%"
|
||||
self.cmd(c, d=d[i:i+16])
|
||||
if (b&3) == 3:
|
||||
if b==31:
|
||||
s = 80
|
||||
else:
|
||||
s = 64
|
||||
self.flash(op, byte=i & 0x1c0, size=s)[1]
|
||||
self.wait_for_spi()
|
||||
|
||||
def wait_for_spi(self):
|
||||
while True:
|
||||
r = self.cmd("F")[1]
|
||||
if not r:
|
||||
break
|
||||
print(f"SPI busy {r:02x}", file=sys.stderr)
|
||||
|
||||
def readfbuffer(self, op="ReadBuffer2"):
|
||||
d = b''
|
||||
for i in range(0, 512, 16):
|
||||
b = i>>4
|
||||
if (b&3) == 0:
|
||||
if b==28:
|
||||
s = 80
|
||||
else:
|
||||
s = 64
|
||||
self.flash(op, byte=i, size=s)
|
||||
self.wait_for_spi()
|
||||
d += self.cmd(f"B{b&3}<!")[2]
|
||||
d += self.cmd(f"B4<!")[2]
|
||||
self._last_page = d
|
||||
if min(d) == 255:
|
||||
print(f"FLASH: page is erased")
|
||||
elif bch.check_page(d):
|
||||
if not bch.galois:
|
||||
raise bch.BCHError("galois module not loaded for Parity Error correction")
|
||||
d = bch.fix_page(d)
|
||||
return d[:512]
|
||||
|
||||
def read_flash(self, page):
|
||||
print(f"FLASH: reading from {page=}")
|
||||
self.flash("Transfer2", page=page)
|
||||
self.flash_status(True)
|
||||
return self.readfbuffer()
|
||||
|
||||
def read_flash2file(self, fn, page, n):
|
||||
with open(fn, "wb") as f:
|
||||
while n > 0:
|
||||
f.write(self.read_flash(page))
|
||||
page += 1
|
||||
n -= 1
|
||||
|
||||
def flash_status(self, blocking=False):
|
||||
r = (0,0,bytes(2))
|
||||
while not r[2][0] & 0x80:
|
||||
self.flash("Status", what="cmdbuf")
|
||||
r = self.cmd("F<")
|
||||
while r[1]:
|
||||
r = self.cmd("F<")
|
||||
if not blocking:
|
||||
break
|
||||
return tuple(r[2][:2])
|
||||
|
||||
def write_flash(self, page, d):
|
||||
print(f"FLASH: writing to {page=}")
|
||||
self.write2fbuffer(d)
|
||||
self.flash("Program2", page=page)
|
||||
self.flash_status(True)
|
||||
|
||||
def write_file2flash(self, page, fn):
|
||||
n = 0
|
||||
with open(fn, "rb") as f:
|
||||
while True:
|
||||
b =f.read(512)
|
||||
if not b:
|
||||
break
|
||||
if len(b)<512:
|
||||
b += bytes(512-len(b))
|
||||
self.write_flash(page+n, b)
|
||||
n += 1
|
||||
return n
|
||||
|
||||
def erase_flash_sector(self, page, op="EraseSector"):
|
||||
"""
|
||||
op="EraseSector" (default)
|
||||
page=0: pages 0 … 7
|
||||
page=8: pages 8 … 0xff
|
||||
page=0x100: pages 0x100 … 0x1ff
|
||||
…
|
||||
op="ErasePage", page=n
|
||||
op="EraseBlock", page=n [n&~7 … n|7]
|
||||
op="EraseChip"
|
||||
"""
|
||||
self.flash(op, page=page)
|
||||
self.flash_status(True)
|
||||
|
||||
def flash_power(self, on=True):
|
||||
op = "PowerUp" if on else "PowerDown"
|
||||
self.flash(op)
|
||||
|
||||
def flash_Id(self):
|
||||
self.flash("Id", what="cmdbuf")
|
||||
while True:
|
||||
r = self.cmd("F<")
|
||||
if not r[1]:
|
||||
break
|
||||
i = r[2][:5]
|
||||
print(f"FLASH chip {b2hex(i)}", file=sys.stderr)
|
||||
return i
|
||||
|
||||
def memsetfbuffer(self, byte=0, what=0xff, size=528, op=0x0887):
|
||||
for i in range(byte, byte+size, 255):
|
||||
s = byte+size - i
|
||||
if s > 255:
|
||||
s = 255
|
||||
self.flash(op, size=s, what=what, byte=i)
|
||||
self.wait_for_spi()
|
||||
|
||||
if tty:
|
||||
tty = dose_cmd(tty, baud)
|
||||
tty._export(globals())
|
||||
tty._verbose = False
|
||||
|
||||
uart.set_prompt("TurboD")
|
||||
|
||||
def b2hex(b, sep=" "):
|
||||
return sep.join([f"{x:02x}" for x in b])
|
||||
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
|
||||
#define ADC_CONF_ADDR __attribute__((__section__(".eeprom")))
|
||||
#define TESTDATA_ADDR __attribute__((__section__(".eeprom")))
|
||||
|
|
@ -6,12 +6,25 @@ MEMORY
|
|||
{
|
||||
eemap : ORIGIN = 0x1400, LENGTH = 0x80
|
||||
eedef : ORIGIN = 0x810000, LENGTH = 0x80
|
||||
uumap : ORIGIN = 0x1300, LENGTH = 0x20
|
||||
uudef : ORIGIN = 0x850000, LENGTH = 0x20
|
||||
}
|
||||
SECTIONS
|
||||
{
|
||||
.eemap 0x1400:
|
||||
{
|
||||
ee1_start = .;
|
||||
*(.eeprom1)
|
||||
ee1_end = .;
|
||||
*(.eeprom)
|
||||
ee9_start = .;
|
||||
*(.eeprom9)
|
||||
ee9_end = .;
|
||||
ee9_size = ee9_end - ee9_start;
|
||||
} >eemap AT >eedef
|
||||
.uumap 0x1300:
|
||||
{
|
||||
*(.userrow)
|
||||
} >uumap AT >uudef
|
||||
}
|
||||
INSERT BEFORE .eeprom
|
||||
|
|
|
|||
364
src/flash.c
Normal file
364
src/flash.c
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
/******************************************************
|
||||
|
||||
- opcode (hex)
|
||||
- address
|
||||
- pb page and byte address
|
||||
- xb byte address
|
||||
- px page address
|
||||
- kx block address
|
||||
- sx sector address
|
||||
- xxx don't care
|
||||
- padding
|
||||
- 0 1 byte
|
||||
- 00 2 bytes
|
||||
- 0000 4 bytes
|
||||
- data
|
||||
- … data bytes
|
||||
- | no data bytes
|
||||
|
||||
|
||||
read commands
|
||||
|
||||
- Main Memory Page Read D2 pb 0000 …
|
||||
- Continuous Array Read (Low-Power Mode) 01 pb …
|
||||
- Continuous Array Read (Low-Frequency) 03 pb …
|
||||
- Continuous Array Read (High-Frequency) 0B pb 0 …
|
||||
- Continuous Array Read (High-Frequency) 1B pb 00 …
|
||||
- Continuous Array Read (Legacy Command) E8 pb 0000 …
|
||||
- Buffer 1 Read (Low-Frequency) D1 xb …
|
||||
- Buffer 2 Read (Low-Frequency) D3 xb …
|
||||
- Buffer 1 Read (High-Frequency) D4 xb 0 …
|
||||
- Buffer 2 Read (High-Frequency) D6 xb 0 …
|
||||
|
||||
write commands
|
||||
|
||||
- Buffer 1 Write 84 xb …
|
||||
- Buffer 2 Write 87 xb …
|
||||
- Buffer 1 Page Program with Erase 83 px |
|
||||
- Buffer 2 Page Program with Erase 86 px |
|
||||
- Buffer 1 Page Program w/o Erase 88 px |
|
||||
- Buffer 2 Page Program w/o Erase 89 px |
|
||||
- Page through Buffer 1 with Erase 82 pb …
|
||||
- Page through Buffer 2 with Erase 85 pb …
|
||||
- Byte/Page through Buffer 1 w/o Erase 02 pb …
|
||||
- Page Erase 81 px |
|
||||
- Block Erase 50 kx |
|
||||
- Sector Erase 7C sx |
|
||||
- Chip Erase C7_94_80_9A |
|
||||
- Program/Erase Suspend B0 |
|
||||
- Program/Erase Resume D0 |
|
||||
- Read-Modify-Write through Buffer 1 58 pbx …
|
||||
- Read-Modify-Write through Buffer 2 59 pbx …
|
||||
|
||||
security commands
|
||||
|
||||
- Enable Sector Protection 3D_2A_7F_A9 |
|
||||
- Disable Sector Protection 3D_2A_7F_9A |
|
||||
- Erase Sector Protection Register 3D_2A_7F_CF |
|
||||
- Program Sector Protection Register 3D_2A_7F_FC …
|
||||
- Read Sector Protection Register 32 xxx …
|
||||
- Sector Lockdown 3D_2A_7F_30 …
|
||||
- Read Sector Lockdown Register 35 xxx …
|
||||
- Freeze Sector Lockdown 34_55_AA_40 |
|
||||
- Program Security Register 9B_00_00_00 …
|
||||
- Read Security Register 77 xxx …
|
||||
|
||||
miscellanious
|
||||
|
||||
- Main Memory Page to Buffer 1 Transfer 53 px |
|
||||
- Main Memory Page to Buffer 2 Transfer 55 px |
|
||||
- Main Memory Page to Buffer 1 Compare 60 px |
|
||||
- Main Memory Page to Buffer 2 Compare 61 px |
|
||||
- Auto Page Rewrite through Buffer 1 58 px |
|
||||
- Auto Page Rewrite through Buffer 2 59 px |
|
||||
- Deep Power-Down B9 |
|
||||
- Resume from Deep Power-Down AB |
|
||||
- Ultra-Deep Power-Down 79 |
|
||||
- Status Register Read D7 …
|
||||
- Manufacturer and Device ID Read 9F …
|
||||
- “Power of 2” (Binary) Page Size 3D_2A_80_A6 |
|
||||
- Standard DataFlash Page Size 3D_2A_80_A7 |
|
||||
- Software Reset F0_00_00_00 |
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "flash.h"
|
||||
#include "cmd.h"
|
||||
|
||||
section_status(flash) uint8_t flash_cmd_buffer[4];
|
||||
section_status(flash) uint8_t flash_status_bytes[2];
|
||||
uint8_t flash_buffer[FB_SIZE];
|
||||
|
||||
uint8_t flash_cmd_na(uint16_t mode, uint16_t what)
|
||||
{
|
||||
return flash_cmd(mode, what, 0, 0);
|
||||
}
|
||||
|
||||
uint8_t flash_cmd(uint16_t mode, uint16_t what, uint16_t page, uint16_t byte)
|
||||
{
|
||||
uint8_t spi_mode = SPI_FLASH | mode & FM_SPI;
|
||||
uint8_t op = mode;
|
||||
uint8_t size = what;
|
||||
what >>= 8;
|
||||
uint8_t s = spi_select(spi_mode);
|
||||
if (s)
|
||||
return s;
|
||||
uint8_t *b = flash_cmd_buffer;
|
||||
*b++ = op ;
|
||||
switch (mode & FM_ADDR) {
|
||||
case FM_528:
|
||||
page <<= 1;
|
||||
case FM_512:
|
||||
byte |= page << 9;
|
||||
page >>= 7;
|
||||
case FM_SEC:
|
||||
*b++ = page;
|
||||
*b++ = byte>>8;
|
||||
*b++ = byte;
|
||||
}
|
||||
uint8_t csize = b - flash_cmd_buffer;
|
||||
uint8_t pads = 0;
|
||||
switch (mode & FM_PAD) {
|
||||
case FM_PAD4: pads = 2;
|
||||
case FM_PAD2: pads += 1;
|
||||
case FM_PAD1: pads += 1;
|
||||
}
|
||||
if (!(mode & FM_START)) {
|
||||
spi.zsize = pads + size;
|
||||
spi.zero = what;
|
||||
spi_start_cmd(csize, flash_cmd_buffer);
|
||||
return 0;
|
||||
}
|
||||
if (size > 80) {
|
||||
// for read of the security register
|
||||
pads += size-64;
|
||||
size = 64;
|
||||
}
|
||||
spi.zsize = pads;
|
||||
if (what + size <= 80)
|
||||
b = flash_buffer + what;
|
||||
else if (what>=96 && what+size <= 112)
|
||||
b = cmd_buffer + (what-96);
|
||||
else if (size <= 2)
|
||||
b = flash_status_bytes;
|
||||
switch (mode & FM_START) {
|
||||
case FM_WRITE:
|
||||
spi_start_write(csize, flash_cmd_buffer, size, b);
|
||||
break;
|
||||
case FM_READ:
|
||||
spi_start_read(csize, flash_cmd_buffer, size, b);
|
||||
break;
|
||||
case FM_WAIT:
|
||||
spi.mask = 0x80;
|
||||
spi_start_read(csize, flash_cmd_buffer, 2, b);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct flash_cmd {
|
||||
uint16_t mode, what, page, byte;
|
||||
};
|
||||
|
||||
uint8_t flash_submit_command(uint8_t *cmd)
|
||||
{
|
||||
struct flash_cmd *c = (void*)cmd;
|
||||
return flash_cmd(c->mode, c->what, c->page, c->byte);
|
||||
}
|
||||
struct flash_stream fs;
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
uint8_t flash_stream_submit(uint16_t mode, uint8_t size)
|
||||
{
|
||||
uint8_t b = fs.block;
|
||||
uint16_t p = fs.page;
|
||||
uint8_t r = fs.status & ~FS_Ready;
|
||||
mode |= (uint16_t)config.flash_page_size << 8;
|
||||
if (size) {
|
||||
if (b & 8) {
|
||||
b = 0;
|
||||
fs.page = ++p;
|
||||
fs.npages--;
|
||||
}
|
||||
else if (b==7 && r & FS_528)
|
||||
size |= 16;
|
||||
}
|
||||
else if ((r & FS_Dir) == FS_Erase) {
|
||||
fs.page += (uint16_t) b + 1;
|
||||
fs.npages -= (uint16_t) b + 1;
|
||||
b = 8;
|
||||
}
|
||||
fs.block = b+1;
|
||||
|
||||
uint8_t e = flash_cmd(mode, size, p, (uint16_t)(b&7) << 6);
|
||||
if (e)
|
||||
r |= FS_Ready; // FS_Error
|
||||
r |= FS_Busy;
|
||||
fs.status = r;
|
||||
return e;
|
||||
}
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
uint8_t flash_stream_done()
|
||||
{
|
||||
uint8_t r = fs.status & FS_Error;
|
||||
if (!r || r == FS_Error)
|
||||
return 1;
|
||||
if (fs.npages || !(fs.block & 8))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline
|
||||
uint8_t flash_write_next_block()
|
||||
{
|
||||
return flash_stream_submit(config.write_buffer, 64);
|
||||
}
|
||||
|
||||
static inline
|
||||
uint8_t flash_read_next_block()
|
||||
{
|
||||
uint16_t mode;
|
||||
if (fs.page & 0x1000)
|
||||
mode = config.read_buffer[fs.page&1];
|
||||
else
|
||||
mode = config.read_array;
|
||||
return flash_stream_submit(mode, 64);
|
||||
}
|
||||
|
||||
static inline
|
||||
uint8_t flash_erase_next_page()
|
||||
{
|
||||
uint16_t mode = 0x81; // Page Erase
|
||||
uint8_t n = 0;
|
||||
if (fs.page && !(fs.page & 0xff) && fs.npages & 0xff00) {
|
||||
mode = 0x7c; // Sector 1…15 Erase
|
||||
n = 0xff;
|
||||
}
|
||||
else if (!(fs.page & 7) && fs.npages >= 8) {
|
||||
mode = 0x50; // Block Erase
|
||||
n = 7;
|
||||
}
|
||||
fs.block = n;
|
||||
return flash_stream_submit(mode, 0);
|
||||
}
|
||||
|
||||
static inline
|
||||
uint8_t flash_burn_page()
|
||||
{
|
||||
return flash_stream_submit(config.burn_page, 0);
|
||||
}
|
||||
|
||||
uint8_t flash_poll(uint8_t rr)
|
||||
{
|
||||
uint8_t r = fs.status;
|
||||
if (spi_busy_p())
|
||||
return r;
|
||||
if ((r & FS_Error) == FS_Error)
|
||||
return r;
|
||||
if (r & FS_StBsy) {
|
||||
// status bytes arrived
|
||||
if (~flash_status_bytes[0] & 0x80)
|
||||
// flash is still busy burning
|
||||
goto rd_status;
|
||||
// not busy any more, move Bsy → Rdy
|
||||
if (r & FS_Busy)
|
||||
r |= FS_Ready;
|
||||
goto ready;
|
||||
}
|
||||
if (!(r & FS_Busy))
|
||||
goto ready;
|
||||
if (rr) {
|
||||
r |= FS_Error;
|
||||
fs.status = r;
|
||||
return r;
|
||||
}
|
||||
if (r & FS_Write) {
|
||||
if (fs.block == 9) {
|
||||
rd_status:
|
||||
// request status bytes for pending Write or Error
|
||||
r |= FS_StBsy;
|
||||
fs.status = r;
|
||||
flash_cmd_na(0xd7 | FM_READ, 0xf002);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
ready:
|
||||
r &= ~(FS_Busy | FS_StBsy);
|
||||
if (rr)
|
||||
r |= FS_Ack;
|
||||
fs.status = r;
|
||||
if (r & FS_Dir == FS_Write && fs.block == 8)
|
||||
flash_burn_page();
|
||||
else if (!flash_stream_done()) {
|
||||
if (r & (FS_Dir|FS_Ack) == (FS_Read|FS_Ack))
|
||||
flash_read_next_block();
|
||||
else if (r & (FS_Dir|FS_Ack) == (FS_Write|FS_Ack))
|
||||
flash_write_next_block();
|
||||
else if (r & FS_Dir == FS_Erase)
|
||||
flash_erase_next_page();
|
||||
fs.status &=~ FS_Ack;
|
||||
}
|
||||
return fs.status;
|
||||
}
|
||||
|
||||
uint8_t flash_start_stream(uint16_t page, uint16_t npages, uint8_t flags)
|
||||
{
|
||||
uint8_t r = flash_poll(0);
|
||||
if ((r & FS_Error) == FS_Busy)
|
||||
return FS_Error;
|
||||
r = flags | FS_Ready;
|
||||
if (config.flash_page_size != FM_528)
|
||||
r &=~ FS_528;
|
||||
fs.page = page;
|
||||
fs.block = 0;
|
||||
fs.npages = npages;
|
||||
fs.status = r;
|
||||
flash_status_bytes[0] = 0xff;
|
||||
return flash_poll(0);
|
||||
}
|
||||
|
||||
static inline
|
||||
uint8_t flash_memset_buffer2()
|
||||
{
|
||||
for (uint16_t i=0; i<528; i += 176) {
|
||||
uint8_t r = flash_cmd((uint16_t)config.flash_page_size << 8 | 0x87, 176|0xff00, 0, i);
|
||||
if (r)
|
||||
return r;
|
||||
while (spi_busy_p()) ;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
uint8_t flash_compare_buffer2(uint16_t p)
|
||||
{
|
||||
uint8_t r;
|
||||
r = flash_cmd((uint16_t)config.flash_page_size << 8 | 0x61, 0, p, 0);
|
||||
if (r)
|
||||
return r;
|
||||
while (spi_busy_p()) ;
|
||||
r = flash_cmd_na(0xd7 | FM_WAIT, 0xf002);
|
||||
if (r)
|
||||
return r;
|
||||
while (spi_busy_p()) ;
|
||||
return (flash_status_bytes[0] | flash_status_bytes[1]) & 0x40;
|
||||
}
|
||||
|
||||
uint16_t flash_find_free()
|
||||
{
|
||||
flash_memset_buffer2();
|
||||
uint16_t a = config.page_start;
|
||||
uint16_t e = config.page_end;
|
||||
while (e > a) {
|
||||
uint16_t p = (a+e)>>1;
|
||||
if (flash_compare_buffer2(p))
|
||||
a = p+1;
|
||||
else
|
||||
e = p;
|
||||
}
|
||||
fs.free = a;
|
||||
return a;
|
||||
}
|
||||
56
src/flash.h
Normal file
56
src/flash.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
#ifndef _FLASH_H
|
||||
#define _FLASH_H
|
||||
|
||||
#include "spi.h"
|
||||
|
||||
enum flash_mode_bits {
|
||||
FM_PAD1 = 0x0100,
|
||||
FM_PAD2 = 0x0200,
|
||||
FM_PAD4 = 0x0300,
|
||||
FM_PAD = 0x0300,
|
||||
FM_512 = 0x0400,
|
||||
FM_528 = 0x0800,
|
||||
FM_SEC = 0x0c00,
|
||||
FM_ADDR = 0x0c00,
|
||||
FM_WRITE = 0x1000,
|
||||
FM_READ = 0x2000,
|
||||
FM_WAIT = 0x3000,
|
||||
FM_START = 0x3000,
|
||||
FM_CONT = (uint16_t)SPI_CONT << 8,
|
||||
FM_SPI = FM_CONT,
|
||||
FM_NSTR = 0x8000,
|
||||
};
|
||||
|
||||
uint8_t flash_cmd_na(uint16_t mode, uint16_t what);
|
||||
uint8_t flash_cmd(uint16_t mode, uint16_t what, uint16_t page, uint16_t byte);
|
||||
#define FB_SIZE 80
|
||||
extern uint8_t flash_buffer[FB_SIZE];
|
||||
uint8_t flash_submit_command(uint8_t *cmd);
|
||||
uint8_t flash_start_stream(uint16_t page, uint16_t npages, uint8_t flags);
|
||||
uint8_t flash_poll(uint8_t rr);
|
||||
uint16_t flash_find_free();
|
||||
|
||||
extern
|
||||
struct flash_stream {
|
||||
uint16_t free; // first free page
|
||||
uint16_t page; // page address of buffer number
|
||||
uint16_t npages; // more pages to read
|
||||
uint8_t block; // next block to read 0…9
|
||||
uint8_t status; // FS_… flags
|
||||
} fs;
|
||||
|
||||
enum {
|
||||
FS_Ready = 1, // ready for the next buffer
|
||||
FS_Busy = 2, // processing …
|
||||
FS_Error = 3, // Aborted
|
||||
FS_Read = 4, // array read
|
||||
FS_Write = 8, // buffer write and burn
|
||||
FS_Erase = 12, // Erase
|
||||
FS_Dir = 12, // Mask for the last three
|
||||
FS_Ack = 32, // Next buffer is provided, continue …
|
||||
FS_StBsy = 64, // Waiting to Flash status register
|
||||
FS_528 = 128, // do 528 byte pages.
|
||||
};
|
||||
|
||||
#endif
|
||||
113
src/flash.py
Normal file
113
src/flash.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
|
||||
import struct
|
||||
|
||||
class flash_cmd:
|
||||
|
||||
class Flash_Error(IOError):
|
||||
pass
|
||||
|
||||
M = {
|
||||
0: 0x0000,
|
||||
1: 0x0100,
|
||||
2: 0x0200,
|
||||
4: 0x0300,
|
||||
512: 0x0400,
|
||||
528: 0x0800,
|
||||
"addr": 0x0c00,
|
||||
"secure": 0x0c00,
|
||||
"write": 0x1000,
|
||||
"read": 0x2000,
|
||||
"wait": 0x3000,
|
||||
"start": 0x3000,
|
||||
}
|
||||
|
||||
def __init__(self, pagesize=528):
|
||||
self.set_pagesize(pagesize)
|
||||
|
||||
def set_pagesize(self, pagesize):
|
||||
self.pagesize = pagesize
|
||||
M = self.M
|
||||
A = M[pagesize]
|
||||
self.A = A
|
||||
self.OP = {
|
||||
"ReadPage": (0xd2 | A | M["read"] | M[4],),
|
||||
"ReadLPower": (0x01 | A | M["read"] | M[0],),
|
||||
"Read": (0x03 | A | M["read"] | M[0],),
|
||||
"ReadHFreq1": (0x0b | A | M["read"] | M[1],),
|
||||
"ReadHFreq2": (0x1b | A | M["read"] | M[2],),
|
||||
"ReadLegacy": (0xe8 | A | M["read"] | M[4],),
|
||||
"ReadBuffer1": (0xd1 | A | M["read"] | M[0],),
|
||||
"ReadBuffer2": (0xd3 | A | M["read"] | M[0],),
|
||||
"ReadBufHF1": (0xd4 | A | M["read"] | M[1],),
|
||||
"ReadBufHF2": (0xd6 | A | M["read"] | M[1],),
|
||||
"WriteBuffer1": (0x84 | A | M["write"],),
|
||||
"WriteBuffer2": (0x87 | A | M["write"],),
|
||||
"ProgErase1": (0x83 | A,),
|
||||
"ProgErase2": (0x86 | A,),
|
||||
"Program1": (0x88 | A,),
|
||||
"Program2": (0x89 | A,),
|
||||
"Transfer1": (0x53 | A,),
|
||||
"Transfer2": (0x55 | A,),
|
||||
"Compare1": (0x60 | A,),
|
||||
"Compare2": (0x61 | A,),
|
||||
"ErasePage": (0x81 | A,),
|
||||
"EraseBlock": (0x50 | A,),
|
||||
"EraseSector": (0x7c | A,),
|
||||
"EraseChip": (0xc7 | M["secure"], 0x9a8094),
|
||||
"Status": (0xd7 | M["read"], 2),
|
||||
"PowerDown": (0xb9,),
|
||||
"PowerUp": (0xab,),
|
||||
"Id": (0x9f | M["read"], 5),
|
||||
"PageSize512": (0x3d | M["secure"], 0xa6802a),
|
||||
"PageSize528": (0x3d | M["secure"], 0xa7802a),
|
||||
"Reset": (0xf0 | M["secure"], 0x0),
|
||||
}
|
||||
|
||||
WHAT = {
|
||||
"buffer": 0,
|
||||
"cmdbuf": 96,
|
||||
"cmd": 96+8,
|
||||
"status": 128,
|
||||
}
|
||||
|
||||
def cmd_buffer(self, op, mode=0, size=None, page=0, byte=0, what=0, data=None):
|
||||
if op in self.OP:
|
||||
opp = self.OP[op]
|
||||
op = opp[0]
|
||||
if len(opp) > 1:
|
||||
if (op & self.M["addr"]) == self.M["secure"]:
|
||||
page = opp[1] >> 16
|
||||
byte = opp[1] & 0xffff;
|
||||
elif op & self.M["read"] and size is None:
|
||||
size = opp[1]
|
||||
if mode:
|
||||
op = op & 0xff | mode & 0xff00
|
||||
if what in self.WHAT:
|
||||
what = self.WHAT[what]
|
||||
if size is None:
|
||||
size = 0
|
||||
if op & self.M["start"]:
|
||||
if what >=112:
|
||||
size = 2
|
||||
elif what >= 96:
|
||||
size = 112 - what
|
||||
elif what < 80:
|
||||
if byte == 448 and self.pagesize == 528:
|
||||
size = 80
|
||||
else:
|
||||
size = 64
|
||||
if size + byte > self.pagesize:
|
||||
size = self.pagesize - byte
|
||||
if what+size > 80:
|
||||
size = 80 - what
|
||||
elif data is not None and not what and size <= 8:
|
||||
what = self.WHAT["cmd"]
|
||||
if data is None:
|
||||
data = 0
|
||||
size |= what << 8;
|
||||
if self.verbose:
|
||||
from sys import stderr
|
||||
print("Flash cmd", *map(hex,(op, size, page, byte, data)), file=stderr)
|
||||
return struct.pack("<4HQ", op, size, page, byte, data)
|
||||
|
||||
verbose = False
|
||||
68
src/fpga.c
Normal file
68
src/fpga.c
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
|
||||
#include "pipe.h"
|
||||
#include "fpga.h"
|
||||
#include "spi.h"
|
||||
|
||||
void fpga_cmd(struct fpga_cmd *c)
|
||||
{
|
||||
if (fpga_reset_poll()) {
|
||||
c->n |= 0x20; // busy flag
|
||||
return;
|
||||
}
|
||||
if (c->n & 1 && spi_abort()) {
|
||||
c->n |= 0x10; // aborted flag
|
||||
return;
|
||||
}
|
||||
else if (spi_busy_p()) {
|
||||
c->n |= 0x20; // busy flag
|
||||
return;
|
||||
}
|
||||
c->n &=~ 0x10; // not busy
|
||||
if (c->n & 0x40)
|
||||
return;
|
||||
c->n |= 0x40; // submitted flag
|
||||
uint8_t n = c->n & 0x0e; // send up to seven cmd words
|
||||
uint8_t z = c->z & 0x7e; // and up to 63 zeros
|
||||
spi_select(0);
|
||||
spi.zero = c->n & 0x80; // send nop: 0x8080 (please), or zeros
|
||||
spi.csize = n;
|
||||
spi.cmd = c->d;
|
||||
spi.rdata = c->d;
|
||||
if (c->z & 0x80) {
|
||||
spi.isize = n + z>>3 & 0x0e; // ignore cmd ± (z[6:4])
|
||||
spi.zsize = spi.rsize = z & 0x0e; // read x[3:1] words
|
||||
spi.mask = 0xff; // start reading at the first nonzero byte after cmd
|
||||
}
|
||||
else {
|
||||
spi.zsize = z; // send z zeros/nop after cmd
|
||||
spi.rsize = 14; // save the last 7 words returned
|
||||
if (n + z > 14)
|
||||
spi.isize = n + z - 14;
|
||||
else
|
||||
spi.isize = 0;
|
||||
}
|
||||
spi_start();
|
||||
}
|
||||
|
||||
void fpga_start(uint8_t write)
|
||||
{
|
||||
uint8_t mode = 0;
|
||||
if (pipe.fpga.zero == SPI_CONFIG)
|
||||
mode = SPI_CONFIG;
|
||||
spi_select(mode);
|
||||
_memcopy(&spi.csize, &pipe.fpga.csize, 6);
|
||||
spi.cmd = pipe.fpga.cmd;
|
||||
spi.wdata = flash_buffer;
|
||||
spi.rdata = flash_buffer;
|
||||
uint8_t n = 64;
|
||||
if (n > pipe.fpga.size)
|
||||
n = pipe.fpga.size;
|
||||
pipe.fpga.size -= n;
|
||||
if (!n)
|
||||
return;
|
||||
if (write)
|
||||
spi.wsize = n;
|
||||
else
|
||||
spi.rsize = n;
|
||||
spi_start();
|
||||
}
|
||||
27
src/fpga.h
Normal file
27
src/fpga.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
struct fpga_cmd {
|
||||
uint8_t n;
|
||||
uint8_t z;
|
||||
uint8_t d[14];
|
||||
};
|
||||
|
||||
static inline
|
||||
void fpga_reset()
|
||||
{
|
||||
nCONFIG_VPORT.OUT |= (1<<nCONFIG_PIN);
|
||||
}
|
||||
|
||||
static inline
|
||||
uint8_t fpga_reset_poll()
|
||||
{
|
||||
uint8_t r = !(nSTATUS_VPORT.IN & (1 << nSTATUS_PIN));
|
||||
if (r)
|
||||
nCONFIG_VPORT.OUT |= 1 << nCONFIG_PIN;
|
||||
return r;
|
||||
}
|
||||
|
||||
void fpga_cmd(struct fpga_cmd *c);
|
||||
|
||||
void fpga_start(uint8_t write);
|
||||
48
src/hallo.c
Normal file
48
src/hallo.c
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
//
|
||||
// hallo.c
|
||||
//
|
||||
|
||||
// int = int8_t
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/sleep.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "uart.h"
|
||||
#include "pipe.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// main()
|
||||
|
||||
section_status(pipe) struct pipe pipe;
|
||||
section_status(main) struct magic magic;
|
||||
|
||||
int main()
|
||||
{
|
||||
while (CLKCTRL.MCLKCTRLB != config.cpu_clk) {
|
||||
CCP = CCP_IOREG_gc;
|
||||
CLKCTRL.MCLKCTRLB = config.cpu_clk;
|
||||
}
|
||||
|
||||
sleep_enable();
|
||||
magic.magic = config.magic;
|
||||
while (magic.magic != MAGIC || config.version != VERSION)
|
||||
sleep_cpu();
|
||||
|
||||
apply_config();
|
||||
magic.reset_source = RSTCTRL.RSTFR;
|
||||
|
||||
RSTCTRL.RSTFR = magic.reset_source;
|
||||
send_str("\nV Turbo Hallo V0.0");
|
||||
send_hex_byte_eol(magic.reset_source);
|
||||
|
||||
while (1) {
|
||||
sei();
|
||||
sleep_cpu();
|
||||
command();
|
||||
}
|
||||
}
|
||||
1
src/io.S
Normal file
1
src/io.S
Normal file
|
|
@ -0,0 +1 @@
|
|||
#include <avr/io.h>
|
||||
443
src/iotn424.py
Normal file
443
src/iotn424.py
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
|
||||
SFR = {
|
||||
"USART0_TXDATAL": (0x0802, 1),
|
||||
"PORTB_PIN0CTRL": (0x0430, 1),
|
||||
"ADC0_WINHTH": (0x061F, 1),
|
||||
"ADC0_WINHTL": (0x061E, 1),
|
||||
"RTC_PITCTRLA": (0x0150, 1),
|
||||
"USERROW_USERROW13": (0x130D, 1),
|
||||
"USART0_RXDATAH": (0x0801, 1),
|
||||
"USART0_RXDATAL": (0x0800, 1),
|
||||
"USERROW_USERROW17": (0x1311, 1),
|
||||
"TCA0_SPLIT_LCMP0": (0x0A28, 1),
|
||||
"PORTB_DIRCLR": (0x0422, 1),
|
||||
"TCA0_SINGLE_CMP1H": (0x0A2B, 1),
|
||||
"USERROW_USERROW19": (0x1313, 1),
|
||||
"PORTB_OUTSET": (0x0425, 1),
|
||||
"USART0_BAUDH": (0x0809, 1),
|
||||
"USART0_BAUDL": (0x0808, 1),
|
||||
"TCA0_SPLIT_LCNT": (0x0A20, 1),
|
||||
"TWI0_SCTRLB": (0x08AA, 1),
|
||||
"PORTC_PORTCTRL": (0x044A, 1),
|
||||
"PORTB_INTFLAGS": (0x0429, 1),
|
||||
"CCL_LUT0CTRLA": (0x01C8, 1),
|
||||
"CCL_LUT0CTRLB": (0x01C9, 1),
|
||||
"CCL_LUT0CTRLC": (0x01CA, 1),
|
||||
"TCA0_SPLIT_CTRLECLR": (0x0A04, 1),
|
||||
"NVMCTRL_INTFLAGS": (0x1004, 1),
|
||||
"CPUINT_CTRLA": (0x0110, 1),
|
||||
"EVSYS_USERTCB1COUNT": (0x01B3, 1),
|
||||
"VPORTA_OUT": (0x0001, 1),
|
||||
"BOD_INTFLAGS": (0x008A, 1),
|
||||
"ADC0_PGACTRL": (0x060B, 1),
|
||||
"CLKCTRL_OSC20MCALIBA": (0x0071, 1),
|
||||
"BOD_VLMCTRLA": (0x0088, 1),
|
||||
"TCA0_SPLIT_LPER": (0x0A26, 1),
|
||||
"USERROW_USERROW21": (0x1315, 1),
|
||||
"USERROW_USERROW25": (0x1319, 1),
|
||||
"PORTC_OUTSET": (0x0445, 1),
|
||||
"USERROW_USERROW29": (0x131D, 1),
|
||||
"EVSYS_USERTCB1CAPT": (0x01B2, 1),
|
||||
"SLPCTRL_CTRLA": (0x0050, 1),
|
||||
"ADC0_WINLTL": (0x061C, 1),
|
||||
"TCA0_SPLIT_CTRLB": (0x0A01, 1),
|
||||
"TCA0_SPLIT_CTRLD": (0x0A03, 1),
|
||||
"TCA0_SINGLE_CMP0H": (0x0A29, 1),
|
||||
"TCA0_SINGLE_CMP0L": (0x0A28, 1),
|
||||
"PORTC_DIR": (0x0440, 1),
|
||||
"TCA0_SINGLE_CMP1L": (0x0A2A, 1),
|
||||
"ADC0_INTFLAGS": (0x0605, 1),
|
||||
"USERROW_USERROW2": (0x1302, 1),
|
||||
"USART1_DBGCTRL": (0x082B, 1),
|
||||
"TWI0_MDATA": (0x08A8, 1),
|
||||
"CCL_TRUTH0": (0x01CB, 1),
|
||||
"PORTB_PIN3CTRL": (0x0433, 1),
|
||||
"TCA0_SINGLE_CMP2H": (0x0A2D, 1),
|
||||
"PORTA_PIN0CTRL": (0x0410, 1),
|
||||
"TCA0_SINGLE_CMP2L": (0x0A2C, 1),
|
||||
"CCL_LUT1CTRLA": (0x01CC, 1),
|
||||
"CCL_LUT1CTRLC": (0x01CE, 1),
|
||||
"SIGROW_SERNUM0": (0x1103, 1),
|
||||
"SIGROW_SERNUM1": (0x1104, 1),
|
||||
"SIGROW_SERNUM2": (0x1105, 1),
|
||||
"SIGROW_SERNUM3": (0x1106, 1),
|
||||
"SIGROW_SERNUM4": (0x1107, 1),
|
||||
"SIGROW_SERNUM5": (0x1108, 1),
|
||||
"SIGROW_SERNUM6": (0x1109, 1),
|
||||
"SIGROW_SERNUM7": (0x110A, 1),
|
||||
"SIGROW_SERNUM8": (0x110B, 1),
|
||||
"SIGROW_SERNUM9": (0x110C, 1),
|
||||
"TCA0_SINGLE_PERBUFH": (0x0A37, 1),
|
||||
"TCA0_SINGLE_PERBUFL": (0x0A36, 1),
|
||||
"USERROW_USERROW31": (0x131F, 1),
|
||||
"TCB0_CTRLA": (0x0A80, 1),
|
||||
"TCB0_CTRLB": (0x0A81, 1),
|
||||
"CPUINT_LVL0PRI": (0x0112, 1),
|
||||
"VPORTA_IN": (0x0002, 1),
|
||||
"EVSYS_USERTCB0CAPT": (0x01B0, 1),
|
||||
"PORTC_OUT": (0x0444, 1),
|
||||
"RTC_PITINTCTRL": (0x0152, 1),
|
||||
"PORTB_IN": (0x0428, 1),
|
||||
"TCA0_SINGLE_CTRLB": (0x0A01, 1),
|
||||
"ADC0_TEMP0": (0x0618, 1),
|
||||
"PORTB_DIR": (0x0420, 1),
|
||||
"ADC0_TEMP2": (0x061A, 1),
|
||||
"GPIO0": (0x001C, 1),
|
||||
"GPIO1": (0x001D, 1),
|
||||
"GPIO3": (0x001F, 1),
|
||||
"RTC_CNTH": (0x0149, 1),
|
||||
"EVSYS_CHANNEL0": (0x0190, 1),
|
||||
"EVSYS_CHANNEL1": (0x0191, 1),
|
||||
"EVSYS_CHANNEL2": (0x0192, 1),
|
||||
"EVSYS_CHANNEL3": (0x0193, 1),
|
||||
"EVSYS_CHANNEL4": (0x0194, 1),
|
||||
"EVSYS_CHANNEL5": (0x0195, 1),
|
||||
"PORTC_DIRSET": (0x0441, 1),
|
||||
"CCL_LUT3CTRLA": (0x01D4, 1),
|
||||
"TWI0_SADDRMASK": (0x08AE, 1),
|
||||
"TCA0_SINGLE_CTRLECLR": (0x0A04, 1),
|
||||
"PORTA_DIRCLR": (0x0402, 1),
|
||||
"PORTC_PIN2CTRL": (0x0452, 1),
|
||||
"CCP": (0x0034, 1),
|
||||
"CLKCTRL_OSC20MCALIBB": (0x0072, 1),
|
||||
"USART0_CTRLA": (0x0805, 1),
|
||||
"TWI0_SCTRLA": (0x08A9, 1),
|
||||
"TCB1_CCMPL": (0x0A9C, 1),
|
||||
"PORTC_IN": (0x0448, 1),
|
||||
"SIGROW_DEVICEID2": (0x1102, 1),
|
||||
"TCB1_INTCTRL": (0x0A95, 1),
|
||||
"USART0_TXPLCTRL": (0x080D, 1),
|
||||
"FUSE_WDTCFG": (0x1280, 1),
|
||||
"CCL_LUT2CTRLB": (0x01D1, 1),
|
||||
"CCL_LUT2CTRLC": (0x01D2, 1),
|
||||
"PORTB_OUT": (0x0424, 1),
|
||||
"PORTMUX_USARTROUTEA": (0x05E2, 1),
|
||||
"CLKCTRL_OSC32KCTRLA": (0x0078, 1),
|
||||
"TWI0_SDATA": (0x08AD, 1),
|
||||
"PORTA_DIR": (0x0400, 1),
|
||||
"PORTA_IN": (0x0408, 1),
|
||||
"ADC0_DBGCTRL": (0x0607, 1),
|
||||
"TCB1_CNTL": (0x0A9A, 1),
|
||||
"PORTA_PIN1CTRL": (0x0411, 1),
|
||||
"TCB0_TEMP": (0x0A89, 1),
|
||||
"TCA0_SINGLE_CTRLA": (0x0A00, 1),
|
||||
"TCA0_SINGLE_CTRLC": (0x0A02, 1),
|
||||
"TCA0_SINGLE_CTRLD": (0x0A03, 1),
|
||||
"ADC0_MUXPOS": (0x060C, 1),
|
||||
"TCB1_INTFLAGS": (0x0A96, 1),
|
||||
"EVSYS_USERADC0START": (0x01A8, 1),
|
||||
"NVMCTRL_ADDRH": (0x1009, 1),
|
||||
"NVMCTRL_ADDRL": (0x1008, 1),
|
||||
"TWI0_DBGCTRL": (0x08A2, 1),
|
||||
"RTC_PITDBGCTRL": (0x0155, 1),
|
||||
"SIGROW_OSCCAL20M1": (0x111B, 1),
|
||||
"VREF_CTRLA": (0x00A0, 1),
|
||||
"TCA0_SPLIT_INTCTRL": (0x0A0A, 1),
|
||||
"TCA0_SINGLE_CMP0BUFH": (0x0A39, 1),
|
||||
"AC0_INTCTRL": (0x0686, 1),
|
||||
"TCA0_SINGLE_CNTL": (0x0A20, 1),
|
||||
"TCA0_SPLIT_HCMP0": (0x0A29, 1),
|
||||
"TCA0_SPLIT_HCMP1": (0x0A2B, 1),
|
||||
"TCA0_SPLIT_HCMP2": (0x0A2D, 1),
|
||||
"TCA0_SINGLE_CMP2BUFH": (0x0A3D, 1),
|
||||
"TCA0_SINGLE_CMP2BUFL": (0x0A3C, 1),
|
||||
"USART1_TXPLCTRL": (0x082D, 1),
|
||||
"PORTA_OUT": (0x0404, 1),
|
||||
"CLKCTRL_MCLKSTATUS": (0x0063, 1),
|
||||
"PORTC_PIN4CTRL": (0x0454, 1),
|
||||
"PORTC_OUTCLR": (0x0446, 1),
|
||||
"CCL_LUT3CTRLB": (0x01D5, 1),
|
||||
"WDT_CTRLA": (0x0100, 1),
|
||||
"SIGROW_DEVICEID0": (0x1100, 1),
|
||||
"SIGROW_DEVICEID1": (0x1101, 1),
|
||||
"TCB0_CNTL": (0x0A8A, 1),
|
||||
"USERROW_USERROW1": (0x1301, 1),
|
||||
"PORTMUX_CCLROUTEA": (0x05E1, 1),
|
||||
"PORTC_PIN7CTRL": (0x0457, 1),
|
||||
"ADC0_CTRLB": (0x0601, 1),
|
||||
"ADC0_CTRLC": (0x0602, 1),
|
||||
"ADC0_CTRLD": (0x0603, 1),
|
||||
"ADC0_CTRLE": (0x0608, 1),
|
||||
"ADC0_CTRLF": (0x0609, 1),
|
||||
"RTC_INTCTRL": (0x0142, 1),
|
||||
"RTC_PERL": (0x014A, 1),
|
||||
"GPIO2": (0x001E, 1),
|
||||
"PORTA_PIN7CTRL": (0x0417, 1),
|
||||
"LOCKBIT_LOCKBIT": (0x128A, 1),
|
||||
"SIGROW_OSCCAL20M0": (0x111A, 1),
|
||||
"TCB1_TEMP": (0x0A99, 1),
|
||||
"FUSE_SYSCFG1": (0x1286, 1),
|
||||
"PORTB_DIRSET": (0x0421, 1),
|
||||
"PORTC_OUTTGL": (0x0447, 1),
|
||||
"ADC0_CTRLA": (0x0600, 1),
|
||||
"TCA0_SPLIT_LCMP1": (0x0A2A, 1),
|
||||
"TCA0_SPLIT_LCMP2": (0x0A2C, 1),
|
||||
"TCA0_SINGLE_CMP1BUFH": (0x0A3B, 1),
|
||||
"TCA0_SINGLE_CMP1BUFL": (0x0A3A, 1),
|
||||
"USART1_TXDATAL": (0x0822, 1),
|
||||
"ADC0_TEMP1": (0x0619, 1),
|
||||
"TCA0_SPLIT_INTFLAGS": (0x0A0B, 1),
|
||||
"PORTMUX_SPIROUTEA": (0x05E3, 1),
|
||||
"TCA0_SPLIT_CTRLESET": (0x0A05, 1),
|
||||
"TCA0_SINGLE_CTRLFSET": (0x0A07, 1),
|
||||
"SPI0_INTCTRL": (0x08C2, 1),
|
||||
"PORTC_PIN6CTRL": (0x0456, 1),
|
||||
"NVMCTRL_STATUS": (0x1002, 1),
|
||||
"CCL_TRUTH1": (0x01CF, 1),
|
||||
"CCL_TRUTH2": (0x01D3, 1),
|
||||
"CLKCTRL_MCLKLOCK": (0x0062, 1),
|
||||
"SYSCFG_REVID": (0x0F01, 1),
|
||||
"USERROW_USERROW10": (0x130A, 1),
|
||||
"USERROW_USERROW11": (0x130B, 1),
|
||||
"USERROW_USERROW12": (0x130C, 1),
|
||||
"USERROW_USERROW14": (0x130E, 1),
|
||||
"USERROW_USERROW15": (0x130F, 1),
|
||||
"USERROW_USERROW16": (0x1310, 1),
|
||||
"USERROW_USERROW18": (0x1312, 1),
|
||||
"USART1_CTRLA": (0x0825, 1),
|
||||
"USART1_CTRLB": (0x0826, 1),
|
||||
"USART1_CTRLC": (0x0827, 1),
|
||||
"USART1_CTRLD": (0x082A, 1),
|
||||
"USERROW_USERROW20": (0x1314, 1),
|
||||
"USERROW_USERROW22": (0x1316, 1),
|
||||
"USERROW_USERROW23": (0x1317, 1),
|
||||
"USERROW_USERROW24": (0x1318, 1),
|
||||
"USERROW_USERROW26": (0x131A, 1),
|
||||
"USERROW_USERROW27": (0x131B, 1),
|
||||
"USERROW_USERROW28": (0x131C, 1),
|
||||
"VPORTC_OUT": (0x0009, 1),
|
||||
"CCL_LUT2CTRLA": (0x01D0, 1),
|
||||
"USERROW_USERROW30": (0x131E, 1),
|
||||
"TCA0_SINGLE_CMP0BUFL": (0x0A38, 1),
|
||||
"PORTA_OUTSET": (0x0405, 1),
|
||||
"FUSE_OSCCFG": (0x1282, 1),
|
||||
"ADC0_STATUS": (0x0606, 1),
|
||||
"CPU_SREG": (0x003F, 1),
|
||||
"AC0_CTRLA": (0x0680, 1),
|
||||
"TCA0_SINGLE_PERH": (0x0A27, 1),
|
||||
"EVSYS_USEREVSYSEVOUTA": (0x01A9, 1),
|
||||
"EVSYS_USEREVSYSEVOUTB": (0x01AA, 1),
|
||||
"TCA0_SINGLE_PERL": (0x0A26, 1),
|
||||
"TCA0_SPLIT_DBGCTRL": (0x0A0E, 1),
|
||||
"PORTB_PIN7CTRL": (0x0437, 1),
|
||||
"TCB0_INTCTRL": (0x0A85, 1),
|
||||
"PORTC_PIN5CTRL": (0x0455, 1),
|
||||
"AC0_STATUS": (0x0687, 1),
|
||||
"CLKCTRL_OSC20MCTRLA": (0x0070, 1),
|
||||
"TCB0_INTFLAGS": (0x0A86, 1),
|
||||
"ADC0_SAMPLEL": (0x0614, 1),
|
||||
"RTC_DBGCTRL": (0x0145, 1),
|
||||
"CLKCTRL_MCLKCTRLA": (0x0060, 1),
|
||||
"CLKCTRL_MCLKCTRLB": (0x0061, 1),
|
||||
"USART1_BAUDH": (0x0829, 1),
|
||||
"USART1_BAUDL": (0x0828, 1),
|
||||
"VPORTB_IN": (0x0006, 1),
|
||||
"GPIO_GPIOR0": (0x001C, 1),
|
||||
"GPIO_GPIOR1": (0x001D, 1),
|
||||
"GPIO_GPIOR2": (0x001E, 1),
|
||||
"GPIO_GPIOR3": (0x001F, 1),
|
||||
"BOD_INTCTRL": (0x0089, 1),
|
||||
"CPU_SPH": (0x003E, 1),
|
||||
"CPU_SPL": (0x003D, 1),
|
||||
"SIGROW_TEMPSENSE0": (0x1120, 1),
|
||||
"SIGROW_TEMPSENSE1": (0x1121, 1),
|
||||
"CLKCTRL_XOSC32KCTRLA": (0x007C, 1),
|
||||
"AC0_DACREF": (0x0684, 1),
|
||||
"ADC0_SAMPLEH": (0x0615, 1),
|
||||
"CRCSCAN_STATUS": (0x0122, 1),
|
||||
"RTC_PERH": (0x014B, 1),
|
||||
"TCA0_SINGLE_CTRLESET": (0x0A05, 1),
|
||||
"TCA0_SINGLE_CTRLFCLR": (0x0A06, 1),
|
||||
"PORTC_INTFLAGS": (0x0449, 1),
|
||||
"PORTA_DIRSET": (0x0401, 1),
|
||||
"PORTB_OUTTGL": (0x0427, 1),
|
||||
"TCB0_STATUS": (0x0A87, 1),
|
||||
"PORTB_PIN6CTRL": (0x0436, 1),
|
||||
"TCA0_SINGLE_CNTH": (0x0A21, 1),
|
||||
"USERROW_USERROW0": (0x1300, 1),
|
||||
"USERROW_USERROW3": (0x1303, 1),
|
||||
"USERROW_USERROW4": (0x1304, 1),
|
||||
"USERROW_USERROW5": (0x1305, 1),
|
||||
"USERROW_USERROW7": (0x1307, 1),
|
||||
"USERROW_USERROW8": (0x1308, 1),
|
||||
"USERROW_USERROW9": (0x1309, 1),
|
||||
"TCB1_EVCTRL": (0x0A94, 1),
|
||||
"TCB1_DBGCTRL": (0x0A98, 1),
|
||||
"SIGROW_OSCCAL16M0": (0x1118, 1),
|
||||
"SIGROW_OSCCAL16M1": (0x1119, 1),
|
||||
"EVSYS_USERUSART1IRDA": (0x01AD, 1),
|
||||
"RTC_CLKSEL": (0x0147, 1),
|
||||
"TCA0_SINGLE_INTCTRL": (0x0A0A, 1),
|
||||
"USART0_DBGCTRL": (0x080B, 1),
|
||||
"TCA0_SPLIT_HCNT": (0x0A21, 1),
|
||||
"WDT_STATUS": (0x0101, 1),
|
||||
"PORTMUX_TCAROUTEA": (0x05E4, 1),
|
||||
"USART1_STATUS": (0x0824, 1),
|
||||
"GPIOR0": (0x001C, 1),
|
||||
"GPIOR1": (0x001D, 1),
|
||||
"GPIOR2": (0x001E, 1),
|
||||
"GPIOR3": (0x001F, 1),
|
||||
"TCA0_SPLIT_HPER": (0x0A27, 1),
|
||||
"RSTCTRL_RSTFR": (0x0040, 1),
|
||||
"CCL_INTFLAGS": (0x01C7, 1),
|
||||
"PORTB_OUTCLR": (0x0426, 1),
|
||||
"TWI0_SSTATUS": (0x08AB, 1),
|
||||
"BOD_STATUS": (0x008B, 1),
|
||||
"VPORTC_INTFLAGS": (0x000B, 1),
|
||||
"PORTB_PIN5CTRL": (0x0435, 1),
|
||||
"SPH": (0x003E, 1),
|
||||
"SPL": (0x003D, 1),
|
||||
"PORTC_PIN3CTRL": (0x0453, 1),
|
||||
"TCB1_CTRLA": (0x0A90, 1),
|
||||
"EVSYS_USERTCA0CNTA": (0x01AE, 1),
|
||||
"EVSYS_USERTCA0CNTB": (0x01AF, 1),
|
||||
"NVMCTRL_INTCTRL": (0x1003, 1),
|
||||
"CRCSCAN_CTRLA": (0x0120, 1),
|
||||
"PORTB_DIRTGL": (0x0423, 1),
|
||||
"ADC0_MUXNEG": (0x060D, 1),
|
||||
"NVMCTRL_CTRLA": (0x1000, 1),
|
||||
"NVMCTRL_CTRLB": (0x1001, 1),
|
||||
"USART1_EVCTRL": (0x082C, 1),
|
||||
"PORTC_DIRTGL": (0x0443, 1),
|
||||
"CCL_CTRLA": (0x01C0, 1),
|
||||
"USART1_RXPLCTRL": (0x082E, 1),
|
||||
"RTC_INTFLAGS": (0x0143, 1),
|
||||
"FUSE_SYSCFG0": (0x1285, 1),
|
||||
"AC0_MUXCTRLA": (0x0682, 1),
|
||||
"TWI0_MSTATUS": (0x08A5, 1),
|
||||
"SPI0_CTRLA": (0x08C0, 1),
|
||||
"SPI0_CTRLB": (0x08C1, 1),
|
||||
"TCB0_CNTH": (0x0A8B, 1),
|
||||
"PORTB_PORTCTRL": (0x042A, 1),
|
||||
"EVSYS_USERCCLLUT0A": (0x01A0, 1),
|
||||
"EVSYS_SWEVENTA": (0x0180, 1),
|
||||
"PORTA_PIN6CTRL": (0x0416, 1),
|
||||
"EVSYS_USERCCLLUT0B": (0x01A1, 1),
|
||||
"CCL_LUT1CTRLB": (0x01CD, 1),
|
||||
"EVSYS_USERCCLLUT1A": (0x01A2, 1),
|
||||
"EVSYS_USERCCLLUT1B": (0x01A3, 1),
|
||||
"PORTB_PIN4CTRL": (0x0434, 1),
|
||||
"EVSYS_USERCCLLUT2A": (0x01A4, 1),
|
||||
"EVSYS_USERCCLLUT2B": (0x01A5, 1),
|
||||
"EVSYS_USERCCLLUT3A": (0x01A6, 1),
|
||||
"EVSYS_USERCCLLUT3B": (0x01A7, 1),
|
||||
"RTC_PITSTATUS": (0x0151, 1),
|
||||
"TCA0_SINGLE_INTFLAGS": (0x0A0B, 1),
|
||||
"TWI0_MBAUD": (0x08A6, 1),
|
||||
"TCB0_EVCTRL": (0x0A84, 1),
|
||||
"TCB1_CTRLB": (0x0A91, 1),
|
||||
"TCB0_CCMPH": (0x0A8D, 1),
|
||||
"TCB0_CCMPL": (0x0A8C, 1),
|
||||
"PORTA_OUTTGL": (0x0407, 1),
|
||||
"USART1_TXDATAH": (0x0823, 1),
|
||||
"TCA0_SINGLE_EVCTRL": (0x0A09, 1),
|
||||
"TCA0_SINGLE_DBGCTRL": (0x0A0E, 1),
|
||||
"BOD_CTRLA": (0x0080, 1),
|
||||
"USART1_RXDATAH": (0x0821, 1),
|
||||
"USART1_RXDATAL": (0x0820, 1),
|
||||
"TWI0_CTRLA": (0x08A0, 1),
|
||||
"VPORTB_OUT": (0x0005, 1),
|
||||
"RTC_TEMP": (0x0144, 1),
|
||||
"PORTB_PIN1CTRL": (0x0431, 1),
|
||||
"VPORTB_INTFLAGS": (0x0007, 1),
|
||||
"ADC0_RESULT0": (0x0610, 1),
|
||||
"ADC0_RESULT1": (0x0611, 1),
|
||||
"ADC0_RESULT2": (0x0612, 1),
|
||||
"PORTA_PIN5CTRL": (0x0415, 1),
|
||||
"CCL_TRUTH3": (0x01D7, 1),
|
||||
"CPUINT_LVL1VEC": (0x0113, 1),
|
||||
"CCL_INTCTRL0": (0x01C5, 1),
|
||||
"TCB1_CNTH": (0x0A9B, 1),
|
||||
"PORTC_PIN1CTRL": (0x0451, 1),
|
||||
"SPI0_DATA": (0x08C4, 1),
|
||||
"USART0_STATUS": (0x0804, 1),
|
||||
"CPU_CCP": (0x0034, 1),
|
||||
"RTC_CTRLA": (0x0140, 1),
|
||||
"RTC_STATUS": (0x0141, 1),
|
||||
"PORTA_INTFLAGS": (0x0409, 1),
|
||||
"CPUINT_STATUS": (0x0111, 1),
|
||||
"BOD_CTRLB": (0x0081, 1),
|
||||
"USART0_RXPLCTRL": (0x080E, 1),
|
||||
"CRCSCAN_CTRLB": (0x0121, 1),
|
||||
"PORTA_PORTCTRL": (0x040A, 1),
|
||||
"TCB0_DBGCTRL": (0x0A88, 1),
|
||||
"RTC_PITINTFLAGS": (0x0153, 1),
|
||||
"PORTC_DIRCLR": (0x0442, 1),
|
||||
"PORTA_DIRTGL": (0x0403, 1),
|
||||
"CCL_SEQCTRL0": (0x01C1, 1),
|
||||
"CCL_SEQCTRL1": (0x01C2, 1),
|
||||
"PORTA_PIN4CTRL": (0x0414, 1),
|
||||
"VPORTC_DIR": (0x0008, 1),
|
||||
"TCB1_STATUS": (0x0A97, 1),
|
||||
"FUSE_BODCFG": (0x1281, 1),
|
||||
"PORTB_PIN2CTRL": (0x0432, 1),
|
||||
"TWI0_MADDR": (0x08A7, 1),
|
||||
"FUSE_BOOTEND": (0x1288, 1),
|
||||
"EVSYS_USERUSART0IRDA": (0x01AC, 1),
|
||||
"RTC_CALIB": (0x0146, 1),
|
||||
"TWI0_MCTRLA": (0x08A3, 1),
|
||||
"TWI0_MCTRLB": (0x08A4, 1),
|
||||
"PORTC_PIN0CTRL": (0x0450, 1),
|
||||
"ADC0_WINLTH": (0x061D, 1),
|
||||
"RSTCTRL_SWRR": (0x0041, 1),
|
||||
"PORTMUX_TCBROUTEA": (0x05E5, 1),
|
||||
"VPORTC_IN": (0x000A, 1),
|
||||
"TCA0_SINGLE_TEMP": (0x0A0F, 1),
|
||||
"TCA0_SPLIT_CTRLA": (0x0A00, 1),
|
||||
"FUSE_APPEND": (0x1287, 1),
|
||||
"RTC_CMPH": (0x014D, 1),
|
||||
"RTC_CMPL": (0x014C, 1),
|
||||
"TCA0_SPLIT_CTRLC": (0x0A02, 1),
|
||||
"CCL_LUT3CTRLC": (0x01D6, 1),
|
||||
"RTC_CNTL": (0x0148, 1),
|
||||
"USERROW_USERROW6": (0x1306, 1),
|
||||
"VPORTA_INTFLAGS": (0x0003, 1),
|
||||
"PORTA_OUTCLR": (0x0406, 1),
|
||||
"PORTMUX_EVSYSROUTEA": (0x05E0, 1),
|
||||
"PORTA_PIN3CTRL": (0x0413, 1),
|
||||
"VPORTB_DIR": (0x0004, 1),
|
||||
"ADC0_INTCTRL": (0x0604, 1),
|
||||
"NVMCTRL_DATAH": (0x1007, 1),
|
||||
"VPORTA_DIR": (0x0000, 1),
|
||||
"VREF_CTRLB": (0x00A1, 1),
|
||||
"NVMCTRL_DATAL": (0x1006, 1),
|
||||
"TWI0_SADDR": (0x08AC, 1),
|
||||
"USART0_CTRLB": (0x0806, 1),
|
||||
"USART0_CTRLC": (0x0807, 1),
|
||||
"USART0_CTRLD": (0x080A, 1),
|
||||
"EVSYS_USERTCB0COUNT": (0x01B1, 1),
|
||||
"TCB1_CCMPH": (0x0A9D, 1),
|
||||
"SPI0_INTFLAGS": (0x08C3, 1),
|
||||
"ADC0_COMMAND": (0x060A, 1),
|
||||
"ADC0_RESULT3": (0x0613, 1),
|
||||
"SREG": (0x003F, 1),
|
||||
"PORTA_PIN2CTRL": (0x0412, 1),
|
||||
"USART0_EVCTRL": (0x080C, 1),
|
||||
"USART0_TXDATAH": (0x0803, 1),
|
||||
"ADC0_SAMPLE": (0x0614, 2),
|
||||
"TCA0_SINGLE_CMP0": (0x0A28, 2),
|
||||
"TCA0_SINGLE_CMP1": (0x0A2A, 2),
|
||||
"TCA0_SINGLE_CNT": (0x0A20, 2),
|
||||
"RTC_CMP": (0x014C, 2),
|
||||
"RTC_CNT": (0x0148, 2),
|
||||
"CPU_SP": (0x003D, 2),
|
||||
"TCA0_SINGLE_CMP2": (0x0A2C, 2),
|
||||
"TCA0_SINGLE_CMP2BUF": (0x0A3C, 2),
|
||||
"NVMCTRL_DATA": (0x1006, 2),
|
||||
"TCA0_SINGLE_CMP1BUF": (0x0A3A, 2),
|
||||
"NVMCTRL_ADDR": (0x1008, 2),
|
||||
"USART0_BAUD": (0x0808, 2),
|
||||
"TCA0_SINGLE_CMP0BUF": (0x0A38, 2),
|
||||
"TCB0_CCMP": (0x0A8C, 2),
|
||||
"RTC_PER": (0x014A, 2),
|
||||
"TCB1_CNT": (0x0A9A, 2),
|
||||
"TCB1_CCMP": (0x0A9C, 2),
|
||||
"USART1_BAUD": (0x0828, 2),
|
||||
"TCB0_CNT": (0x0A8A, 2),
|
||||
"ADC0_WINHT": (0x061E, 2),
|
||||
"ADC0_WINLT": (0x061C, 2),
|
||||
"SP": (0x003D, 2),
|
||||
"TCA0_SINGLE_PERBUF": (0x0A36, 2),
|
||||
"TCA0_SINGLE_PER": (0x0A26, 2),
|
||||
"ADC0_RESULT": (0x0610, 4),
|
||||
}
|
||||
33
src/map.py
Normal file
33
src/map.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
class memmap(dict):
|
||||
|
||||
def __init__(self, fn="hallo.map"):
|
||||
self.parsemap(fn)
|
||||
|
||||
def parsemap(self, fn):
|
||||
with open(fn) as f:
|
||||
laddr = None
|
||||
for l in f:
|
||||
try:
|
||||
ll = l.split()
|
||||
if l[:1] == "." and len(ll) >= 3:
|
||||
section = ll[0]
|
||||
saddr = int(ll[1], 0) & 0xffff
|
||||
slen = int(ll[2], 0)
|
||||
self[section] = (saddr, slen)
|
||||
laddr = saddr
|
||||
last = None
|
||||
continue
|
||||
if l[:1] != " ":
|
||||
continue
|
||||
if len(ll)==2 and ll[0][:2] == "0x" or len(ll)==4 and ll[2]=="=" and ll[3]==".":
|
||||
cur = ll[1]
|
||||
addr = int(ll[0],0) & 0xffff
|
||||
self[cur] = (addr,0)
|
||||
if last is not None:
|
||||
self[last] = (self[last][0], addr-laddr)
|
||||
last = cur
|
||||
laddr = addr
|
||||
except Exception as e:
|
||||
from sys import stderr
|
||||
print(f"{repr(e)}\n{l}", file=stderr)
|
||||
284
src/mul.c
284
src/mul.c
|
|
@ -1,284 +0,0 @@
|
|||
//
|
||||
// mul.c
|
||||
//
|
||||
// To save space in ATtinys.
|
||||
// 16bit × 16bit → 16bit multiplication for AVR w/ `mul`, `muls`, `mulsu`,
|
||||
// returning the high bits, not the low bits.
|
||||
//
|
||||
// Also provides a variant for printing decimal numbers.
|
||||
|
||||
#include "mul.h"
|
||||
|
||||
// To save space, omit what is not needed. Use -D when needed.
|
||||
|
||||
#ifndef MUL_NONE
|
||||
# define MUL16SUN
|
||||
# define MUL_DECIMAL_STR
|
||||
# ifdef MUL_ALL
|
||||
# define MUL16SU
|
||||
# define MUL16SS
|
||||
# define MUL16UU
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef MUL_TEST
|
||||
#define MUL_DEBUG
|
||||
#include <stdio.h>
|
||||
int main()
|
||||
{
|
||||
int16_t tests[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
|
||||
89, 99, 100, 101, 102, 0xff, 0x100, 0x101,
|
||||
999, 1000, 1001, 9999, 10000, 10001,
|
||||
0x7ffe, 0x7fff
|
||||
};
|
||||
|
||||
for (uint8_t dec = 0; dec < 5; dec++)
|
||||
for (int i=0; i < sizeof(tests)/sizeof(*tests); i++)
|
||||
for (int s=0; s<2; s++) {
|
||||
int16_t n = tests[i];
|
||||
if (s)
|
||||
n = -n;
|
||||
printf("%u 0x%04x %+d %s\n",
|
||||
dec, n & 0xffff, n,
|
||||
decimal_str(n, dec));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef MUL_DEBUG
|
||||
|
||||
#ifdef MUL16SU
|
||||
int16_t mul16su(int16_t s, uint16_t u)
|
||||
{
|
||||
__asm__(
|
||||
"movw r18, %[s]" "\n\t"
|
||||
"mul r18, %A[u]" "\n\t"
|
||||
"mov r20, r1" "\n\t"
|
||||
"mulsu r19, %B[u]" "\n\t"
|
||||
"movw %[s], r0" "\n\t"
|
||||
"mul r18, %B[u]" "\n\t"
|
||||
"clr r18" "\n\t"
|
||||
"add r20, r0" "\n\t"
|
||||
"adc %A[s], r1" "\n\t"
|
||||
"adc %B[s], r18" "\n\t"
|
||||
"mulsu r19, %A[u]" "\n\t"
|
||||
"sbc %B[s], r18" "\n\t"
|
||||
"add r20, r0" "\n\t"
|
||||
"adc %A[s], r1" "\n\t"
|
||||
"adc %B[s], r18" "\n\t"
|
||||
"clr r1" "\n\t"
|
||||
: [s] "+r" (s)
|
||||
: [u] "a" (u)
|
||||
: "r0", "r1", "r18", "r19", "r20"
|
||||
);
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MUL16SUN
|
||||
int16_t mul16sun(int16_t s, uint16_t u, uint8_t n)
|
||||
{
|
||||
// n = 0 … 8
|
||||
__asm__(
|
||||
"movw r18, %[s]" "\n\t"
|
||||
"mul r18, %A[u]" "\n\t"
|
||||
"mov r21, r1" "\n\t"
|
||||
"mulsu r19, %B[u]" "\n\t"
|
||||
"movw %[s], r0" "\n\t"
|
||||
"mul r18, %B[u]" "\n\t"
|
||||
"clr r18" "\n\t"
|
||||
"add r21, r0" "\n\t"
|
||||
"adc %A[s], r1" "\n\t"
|
||||
"adc %B[s], r18" "\n\t"
|
||||
"mulsu r19, %A[u]" "\n\t"
|
||||
"sbc %B[s], r18" "\n\t"
|
||||
"add r21, r0" "\n\t"
|
||||
"adc %A[s], r1" "\n\t"
|
||||
"adc %B[s], r18" "\n\t"
|
||||
"cpi %[n], 0" "\n\t"
|
||||
"breq 3f" "\n\t"
|
||||
"sbrs %[n], 3" "\n\t"
|
||||
"rjmp 2f" "\n\t"
|
||||
"mov %B[s], %A[s]" "\n\t"
|
||||
"mov %A[s], r21" "\n\t"
|
||||
"rjmp 3f" "\n"
|
||||
"1:" "\t"
|
||||
"lsl r21" "\n\t"
|
||||
"rol %A[s]" "\n\t"
|
||||
"rol %B[s]" "\n\t"
|
||||
"2:" "\t"
|
||||
"dec %[n]" "\n\t"
|
||||
"brpl 1b" "\n"
|
||||
"3:" "\t"
|
||||
"clr r1" "\n\t"
|
||||
: [s] "+r" (s)
|
||||
: [u] "a" (u),
|
||||
[n] "r" (n)
|
||||
: "r0", "r1", "r18", "r19", "r21"
|
||||
);
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MUL16SS
|
||||
int16_t mul16ss(int16_t a, int16_t b)
|
||||
{
|
||||
// ((int32_t)a*b) >> 16
|
||||
__asm__(
|
||||
"movw r18, %[a]" "\n\t"
|
||||
"mul r18, %A[b]" "\n\t"
|
||||
"mov r20, r1" "\n\t"
|
||||
"muls r19, %B[b]" "\n\t"
|
||||
"movw %[a], r0" "\n\t"
|
||||
"mulsu %B[b], r18" "\n\t"
|
||||
"clr r18" "\n\t"
|
||||
"sbc %B[a], r18" "\n\t"
|
||||
"add r20, r0" "\n\t"
|
||||
"adc %A[a], r1" "\n\t"
|
||||
"adc %B[a], r18" "\n\t"
|
||||
"mulsu r19, %A[b]" "\n\t"
|
||||
"sbc %B[a], r18" "\n\t"
|
||||
"add r20, r0" "\n\t"
|
||||
"adc %A[a], r1" "\n\t"
|
||||
"adc %B[a], r18" "\n\t"
|
||||
"clr r1" "\n\t"
|
||||
: [a] "+r" (a)
|
||||
: [b] "a" (b)
|
||||
: "r0", "r1", "r18", "r19", "r20"
|
||||
);
|
||||
return a;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MUL16UU
|
||||
int16_t mul16uu(uint16_t a, uint16_t b)
|
||||
{
|
||||
// ((uint32_t)a*(uint32_t)b) >> 16
|
||||
__asm__(
|
||||
"movw r18, %[a]" "\n\t"
|
||||
"mul r18, %A[b]" "\n\t"
|
||||
"mov r20, r1" "\n\t"
|
||||
"mul r19, %B[b]" "\n\t"
|
||||
"movw %[a], r0" "\n\t"
|
||||
"mul %B[b], r18" "\n\t"
|
||||
"clr r18" "\n\t"
|
||||
"add r20, r0" "\n\t"
|
||||
"adc %A[a], r1" "\n\t"
|
||||
"adc %B[a], r18" "\n\t"
|
||||
"mul r19, %A[b]" "\n\t"
|
||||
"add r20, r0" "\n\t"
|
||||
"adc %A[a], r1" "\n\t"
|
||||
"adc %B[a], r18" "\n\t"
|
||||
"clr r1" "\n\t"
|
||||
: [a] "+r" (a)
|
||||
: [b] "a" (b)
|
||||
: "r0", "r1", "r18", "r19", "r20"
|
||||
);
|
||||
return a;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MUL_DIVMOD10) || defined(MUL_DECIMAL_STR)
|
||||
#ifndef MUL_DIVMOD10
|
||||
static inline
|
||||
#endif
|
||||
uint16_t divmod10(uint16_t u, uint8_t *mod)
|
||||
{
|
||||
uint16_t r;
|
||||
uint8_t d;
|
||||
__asm__(
|
||||
"ldi r18, lo8(6554)" "\n\t"
|
||||
"ldi r19, hi8(6554)" "\n\t"
|
||||
"mul r18, %A[u]" "\n\t"
|
||||
"mov r20, r1" "\n\t"
|
||||
"mul r19, %B[u]" "\n\t"
|
||||
"movw %[r], r0" "\n\t"
|
||||
"mul r19, %A[u]" "\n\t"
|
||||
"clr r19" "\n\t"
|
||||
"add r20, r0" "\n\t"
|
||||
"adc %A[r], r1" "\n\t"
|
||||
"adc %B[r], r19" "\n\t"
|
||||
"mul r18, %B[u]" "\n\t"
|
||||
"add r20, r0" "\n\t"
|
||||
"adc %A[r], r1" "\n\t"
|
||||
"adc %B[r], r19" "\n\t"
|
||||
"ldi r19, 10" "\n\t"
|
||||
"inc r20" "\n\t"
|
||||
"mul r19, r20" "\n\t"
|
||||
"mov %[d], r1" "\n\t"
|
||||
"clr r1" "\n\t"
|
||||
: [r] "=&r" (r),
|
||||
[d] "=r" (d)
|
||||
: [u] "d" (u)
|
||||
: "r0", "r1", "r18", "r19", "r20"
|
||||
);
|
||||
*mod = d;
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
#else // MUL_DEBUG
|
||||
|
||||
// Models for what the assembly is supposed to do.
|
||||
// Also usefull for testing in non-AVR hosts.
|
||||
|
||||
int16_t mul16su(int16_t s, uint16_t u)
|
||||
{
|
||||
uint32_t r = (int32_t)s * (int32_t)u;
|
||||
return r >> 16;
|
||||
}
|
||||
int16_t mul16sun(int16_t s, uint16_t u, uint8_t n)
|
||||
{
|
||||
// n = 0 … 8
|
||||
uint32_t r = (int32_t)s * (int32_t)u;
|
||||
return r >> (16-n);
|
||||
}
|
||||
int16_t mul16ss(int16_t a, int16_t b)
|
||||
{
|
||||
uint32_t r = (int32_t)a * (int32_t)b;
|
||||
return r >> 16;
|
||||
}
|
||||
int16_t mul16uu(uint16_t a, uint16_t b)
|
||||
{
|
||||
uint32_t r = (int32_t)a * (int32_t)b;
|
||||
return r >> 16;
|
||||
}
|
||||
uint16_t divmod10(uint16_t u, uint8_t *mod)
|
||||
{
|
||||
uint32_t r = (uint32_t)u * (uint32_t)6554;
|
||||
*mod = (((r & 0xff00)+0x100)*10) >> 16;
|
||||
return r >> 16;
|
||||
}
|
||||
|
||||
#endif // MUL_DEBUG
|
||||
|
||||
#ifdef MUL_DECIMAL_STR
|
||||
static uint8_t decimals[8];
|
||||
char *decimal_str(int16_t b, uint8_t dec)
|
||||
{
|
||||
uint8_t s = 0;
|
||||
if (b<0) {
|
||||
s = 1;
|
||||
b = -b;
|
||||
}
|
||||
uint8_t *c = decimals+6;
|
||||
uint8_t n = 0;
|
||||
while ((b || n < dec) && n<7) {
|
||||
b = divmod10(b, c);
|
||||
*c-- += '0';
|
||||
if (++n==dec) {
|
||||
*c-- = '.';
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (!n)
|
||||
*c = '0';
|
||||
else if (s)
|
||||
*c = '-';
|
||||
else
|
||||
*c = '+';
|
||||
return (char *)c;
|
||||
}
|
||||
#endif
|
||||
15
src/mul.h
15
src/mul.h
|
|
@ -1,15 +0,0 @@
|
|||
//
|
||||
// mul.h
|
||||
//
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int16_t mul16su(int16_t s, uint16_t u);
|
||||
int16_t mul16ss(int16_t a, int16_t b);
|
||||
int16_t mul16uu(uint16_t a, uint16_t b);
|
||||
int16_t mul16sun(int16_t s, uint16_t u, uint8_t n);
|
||||
char *decimal_str(int16_t b, uint8_t dec);
|
||||
|
||||
#if defined(MUL_DIVMOD10) || defined(MUL_ALL)
|
||||
uint16_t divmod10(uint16_t u, uint8_t *mod);
|
||||
#endif
|
||||
132
src/pipe.c
Normal file
132
src/pipe.c
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
|
||||
#include "pipe.h"
|
||||
#include "bch4369.h"
|
||||
#include "adc.h"
|
||||
|
||||
#ifdef HAVE_FPGA
|
||||
#include "fpga.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
section_status(pipe) struct pipe pipe;
|
||||
|
||||
uint8_t pipe_poll()
|
||||
{
|
||||
uint8_t r = pipe.status;
|
||||
uint8_t fl = flash_poll(0);
|
||||
if (spi_busy_p() || fl & FS_Busy || adc_poll(0))
|
||||
goto done;
|
||||
#ifdef HAVE_FPGA
|
||||
if (fpga_reset_poll())
|
||||
goto done;
|
||||
#endif
|
||||
if (r & PS_OUT) {
|
||||
if (pipe.dest & pipe_cmd && pipe.valid & 0x1f)
|
||||
// cmd did not drain the buffer, yet
|
||||
goto done;
|
||||
if (pipe.dest & pipe_flash && !(fl & FS_Ready))
|
||||
// flash did not finish successfully
|
||||
goto done;
|
||||
if (pipe.source & pipe_adc && !adc_poll(pipe.adc))
|
||||
goto done;
|
||||
|
||||
// fpga is OUT when the spi is ready.
|
||||
// We are done with this buffer
|
||||
pipe.valid = 0;
|
||||
if (pipe.source & pipe_flash)
|
||||
flash_poll(1);
|
||||
#ifdef HAVE_FPGA
|
||||
else if (pipe.source & pipe_fpga)
|
||||
fpga_start(0);
|
||||
#endif
|
||||
r &=~ (PS_OUT|4);
|
||||
r++;
|
||||
goto done;
|
||||
}
|
||||
|
||||
uint8_t bflgs = 0x0f;
|
||||
if ((r & PS_5) == PS_5)
|
||||
bflgs = 0x1f;
|
||||
|
||||
if (pipe.source & pipe_adc) {
|
||||
uint8_t n = pipe.adc & 0x70;
|
||||
if (!n)
|
||||
goto adc_done;
|
||||
uint8_t f = n-1;
|
||||
uint8_t o = -16;
|
||||
uint8_t v = pipe.valid;
|
||||
#if 0
|
||||
uint8_t c;
|
||||
do {
|
||||
o += 16;
|
||||
f <<= 1;
|
||||
c = v & 1;
|
||||
v >>= 1;
|
||||
} while (c); // please use the carry bit!
|
||||
#else
|
||||
// saves one instruction
|
||||
__asm__ volatile
|
||||
("\n"
|
||||
"1: \n\t"
|
||||
"subi %[O], -16 \n\t"
|
||||
"lsl %[F] \n\t"
|
||||
"lsr %[V] \n\t"
|
||||
"brcs 1b \n"
|
||||
: [O] "+r" (o),
|
||||
[F] "+r" (f),
|
||||
[V] "+r" (v)
|
||||
);
|
||||
#endif
|
||||
if (o > 48)
|
||||
goto adc_done;
|
||||
if (o + n >= 64) {
|
||||
f = 0xff;
|
||||
n = 64-o;
|
||||
}
|
||||
pipe.valid |= f>>4;
|
||||
_memcopy(flash_buffer+o, (void*)&magic, n);
|
||||
}
|
||||
adc_done:
|
||||
|
||||
if (pipe.source & pipe_flash && fl & FS_Ready)
|
||||
pipe.valid = bflgs;
|
||||
#ifdef HAVE_FPGA
|
||||
else if (pipe.source & pipe_fpga)
|
||||
pipe.valid = 0x0f;
|
||||
#endif
|
||||
if (~pipe.valid & 0x0f)
|
||||
goto done;
|
||||
if (r & PS_BCH) {
|
||||
if (!(r&3))
|
||||
bch4369_init();
|
||||
uint8_t *bend = bch4369_stri(flash_buffer, 64);
|
||||
if (!(~r & 3)) {
|
||||
// reuse Y=bend
|
||||
_memcopyyz(bend, bch_parity, 16);
|
||||
pipe.valid = 0x01f;
|
||||
}
|
||||
}
|
||||
if (~pipe.valid & bflgs)
|
||||
goto done;
|
||||
|
||||
#ifdef HAVE_FPGA
|
||||
if (pipe.dest & pipe_fpga)
|
||||
fpga_start(1);
|
||||
#endif
|
||||
|
||||
r |= PS_OUT;
|
||||
done:
|
||||
pipe.status = r;
|
||||
return r;
|
||||
}
|
||||
|
||||
void pipe_config(const struct pipe_config *c)
|
||||
{
|
||||
pipe = c->pipe;
|
||||
if ((pipe.source | pipe.dest) & pipe_flash)
|
||||
flash_start_stream(c->page, c->npages, c->flash);
|
||||
if (pipe.source & pipe_adc)
|
||||
adc_start_stream(pipe.adc);
|
||||
}
|
||||
|
||||
47
src/pipe.h
Normal file
47
src/pipe.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
#include "flash.h"
|
||||
|
||||
enum pipe_ports {
|
||||
pipe_cmd = 1,
|
||||
pipe_adc = 2,
|
||||
pipe_flash = 4,
|
||||
pipe_fpga = 8,
|
||||
|
||||
PS_OUT = 0x80,
|
||||
PS_BCH = 0x10,
|
||||
PS_528 = 0x08,
|
||||
PS_BLK = 0x03,
|
||||
PS_5 = PS_BLK | PS_528, // need 16 bytes more
|
||||
};
|
||||
|
||||
extern
|
||||
struct pipe {
|
||||
uint8_t source;
|
||||
uint8_t dest;
|
||||
uint8_t status;
|
||||
uint8_t valid;
|
||||
uint8_t adc;
|
||||
#ifdef HAVE_FPGA
|
||||
struct {
|
||||
uint16_t size;
|
||||
uint8_t cmd[4];
|
||||
uint8_t csize;
|
||||
uint8_t zsize;
|
||||
uint8_t isize;
|
||||
uint8_t zero;
|
||||
uint8_t wait;
|
||||
uint8_t mask;
|
||||
} fpga;
|
||||
#endif
|
||||
} pipe;
|
||||
|
||||
struct pipe_config {
|
||||
struct pipe pipe;
|
||||
uint16_t page;
|
||||
uint16_t npages;
|
||||
uint8_t flash;
|
||||
};
|
||||
|
||||
uint8_t pipe_poll();
|
||||
void pipe_cron();
|
||||
void pipe_config(const struct pipe_config *c);
|
||||
20
src/prompt.py
Normal file
20
src/prompt.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import sys
|
||||
|
||||
def set_prompt(prompt):
|
||||
sys.ps1 = prompt + "> "
|
||||
sys.ps2 = prompt + ". "
|
||||
try:
|
||||
ip=get_ipython()
|
||||
from IPython.terminal.prompts import Prompts, Token
|
||||
class myprompts(Prompts):
|
||||
def in_prompt_tokens(self, *wtf):
|
||||
return [(Token, prompt+'> ')]
|
||||
def continuation_prompt_tokens(self, *wtf):
|
||||
return [(Token, prompt+'. ')]
|
||||
def out_prompt_tokens(self, *wtf):
|
||||
return [(Token, prompt+'= ')]
|
||||
def rewrite_prompt_tokens(self, *wtf):
|
||||
return [(Token, prompt+'- ')]
|
||||
ip.prompts=myprompts(ip)
|
||||
except:
|
||||
pass
|
||||
17
src/pwm.c
Normal file
17
src/pwm.c
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
// pwm.c
|
||||
|
||||
#include "pwm.h"
|
||||
|
||||
struct_ioconf(pwm_config) = {
|
||||
conf_prefix(PWM),
|
||||
#ifdef HAVE_nFETs
|
||||
conf_io(PWM.CTRLB, TCA_SINGLE_WGMODE_SINGLESLOPE_gc | TCA_SINGLE_CMP0EN_bm),
|
||||
#else
|
||||
conf_io(PWM.CTRLB, TCA_SINGLE_WGMODE_SINGLESLOPE_gc),
|
||||
#endif
|
||||
conf_iow(PWM.PER, 0x0fff),
|
||||
conf_iow(PWM.CMP0, 0xffff),
|
||||
conf_iow(PWM.CMP1, 0x00ff),
|
||||
conf_io(PWM.CTRLA, TCA_SINGLE_ENABLE_bm),
|
||||
};
|
||||
40
src/pwm.h
Normal file
40
src/pwm.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#define PWM TCA0.SINGLE
|
||||
|
||||
#ifdef HAVE_nFETs
|
||||
|
||||
static inline
|
||||
void pwm_set(uint16_t dc, uint8_t d)
|
||||
{
|
||||
PWM.CMP0 = dc;
|
||||
if (d)
|
||||
DRAIN_VPORT.OUT |= 1 << DRAIN_PIN;
|
||||
else
|
||||
DRAIN_VPORT.OUT &=~ (1 << DRAIN_PIN);
|
||||
}
|
||||
|
||||
static inline
|
||||
void pwm_bias()
|
||||
{
|
||||
pwm_set(0xffff, 0);
|
||||
}
|
||||
|
||||
static inline
|
||||
void pwm_step(uint16_t max)
|
||||
{
|
||||
uint16_t c = PWM.CMP0+1;
|
||||
if (c > max)
|
||||
pwm_bias();
|
||||
else
|
||||
pwm_set(c, 1);
|
||||
}
|
||||
|
||||
static inline
|
||||
uint8_t pwm_busy()
|
||||
{
|
||||
return DRAIN_VPORT.OUT & (1 << DRAIN_PIN);
|
||||
}
|
||||
|
||||
#endif
|
||||
177
src/rtc.c
177
src/rtc.c
|
|
@ -4,69 +4,154 @@
|
|||
|
||||
// !!! int = int8_t
|
||||
|
||||
#include "bate.h"
|
||||
#include "config.h"
|
||||
#include "rtc.h"
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/sleep.h>
|
||||
|
||||
#define Bit(x) (1<<(x))
|
||||
|
||||
volatile uint32_t clock;
|
||||
volatile uint8_t clock_tick;
|
||||
section_status(rtc) uint32_t clock;
|
||||
volatile uint16_t clockh;
|
||||
volatile uint8_t pit_tick;
|
||||
volatile uint8_t rtc_tick;
|
||||
|
||||
void init_rtc(uint8_t p)
|
||||
uint8_t rtc_cnt_tick()
|
||||
{
|
||||
if (p>=16)
|
||||
p = RTC_PERIOD_CYC1024_gc;
|
||||
RTC.CLKSEL = RTC_CLKSEL_INT1K_gc;
|
||||
RTC.PITINTCTRL = 1;
|
||||
RTC.PITCTRLA = p;
|
||||
while (RTC.PITSTATUS & 1) ;
|
||||
RTC.PITCTRLA = p | 1;
|
||||
cli();
|
||||
uint8_t r = rtc_tick;
|
||||
rtc_tick = 0;
|
||||
sei();
|
||||
return r;
|
||||
}
|
||||
|
||||
struct_ioconf(rtc_config) = {
|
||||
conf_prefix(RTC),
|
||||
conf_iow(RTC.CMP, 10), // rtc_cnt_tick() period [s]
|
||||
conf_io(RTC.CLKSEL, RTC_CLKSEL_INT1K_gc),
|
||||
conf_io(RTC.PITINTCTRL, 1),
|
||||
conf_io(RTC.PITCTRLA, RTC_PERIOD_CYC1024_gc | RTC_PITEN_bm),
|
||||
conf_iow(RTC.PER, 0xffff),
|
||||
conf_io(RTC.CTRLA, RTC_PRESCALER_DIV1024_gc | RTC_RUNSTDBY_bm | RTC_RTCEN_bm),
|
||||
conf_io(RTC.INTCTRL, RTC_CMP_bm | RTC_OVF_bm),
|
||||
};
|
||||
|
||||
#if 1
|
||||
|
||||
ISR(RTC_PIT_vect, ISR_NAKED)
|
||||
{
|
||||
__asm__ ("push r24" "\n\t"
|
||||
"in r24, __SREG__" "\n\t"
|
||||
"push r24" "\n\t"
|
||||
#ifdef DEBUG
|
||||
"lds r24, debug_data+9" "\n\t"
|
||||
"subi r24, -1" "\n\t"
|
||||
"sts debug_data+9, r24" "\n\t"
|
||||
#endif
|
||||
"ldi r24,1" "\n\t"
|
||||
"sts %[flag], r24" "\n\t"
|
||||
"sts %[tick], r24" "\n\t"
|
||||
"lds r24, %[clock]" "\n\t"
|
||||
"subi r24, -1" "\n\t"
|
||||
"sts %[clock], r24" "\n\t"
|
||||
"lds r24, %[clock]+1" "\n\t"
|
||||
"sbci r24, -1" "\n\t"
|
||||
"sts %[clock]+1, r24" "\n\t"
|
||||
"lds r24, %[clock]+2" "\n\t"
|
||||
"sbci r24, -1" "\n\t"
|
||||
"sts %[clock]+2, r24" "\n\t"
|
||||
"lds r24, %[clock]+3" "\n\t"
|
||||
"sbci r24, -1" "\n\t"
|
||||
"sts %[clock]+3, r24" "\n\t"
|
||||
"pop r24" "\n\t"
|
||||
"out __SREG__, r24" "\n\t"
|
||||
"pop r24" "\n\t"
|
||||
"reti" "\n"
|
||||
:[tick] "+m" (clock_tick),
|
||||
[clock] "+m" (clock)
|
||||
:[flag] "n" (&RTC.PITINTFLAGS)
|
||||
__asm__ (
|
||||
"push r24" "\n\t"
|
||||
"ldi r24, 1" "\n\t"
|
||||
"sts %[flag], r24" "\n\t"
|
||||
"sts pit_tick, r24" "\n\t"
|
||||
"pop r24" "\n\t"
|
||||
"reti" "\n"
|
||||
::[flag] "n" (&RTC.PITINTFLAGS)
|
||||
);
|
||||
}
|
||||
|
||||
ISR(RTC_CNT_vect, ISR_NAKED)
|
||||
{
|
||||
__asm__ (
|
||||
"push r24" "\n\t"
|
||||
"in r24, __SREG__" "\n\t"
|
||||
"push r24" "\n\t"
|
||||
"lds r24, %[flag]" "\n\t"
|
||||
"sts %[flag], r24" "\n\t"
|
||||
"sts rtc_tick, r24" "\n\t"
|
||||
"sbrs r24, 1" "\n\t"
|
||||
"rjmp 1f" "\n\t"
|
||||
"push r24" "\n\t"
|
||||
"push r25" "\n\t"
|
||||
"push r26" "\n\t"
|
||||
"lds r24, %[CMPL]" "\n\t"
|
||||
"lds r25, %[CMPH]" "\n\t"
|
||||
"lds r26, rtc_config+3" "\n\t"
|
||||
"add r24, r26" "\n\t"
|
||||
"sts %[CMPL], r24" "\n\t"
|
||||
"lds r26, rtc_config+5" "\n\t"
|
||||
"adc r25, r26" "\n\t"
|
||||
"sts %[CMPH], r25" "\n\t"
|
||||
"pop r26" "\n\t"
|
||||
"pop r25" "\n\t"
|
||||
"pop r24" "\n"
|
||||
"1:" "\n\t"
|
||||
"sbrs r24, 0" "\n\t"
|
||||
"rjmp 2f" "\n\t"
|
||||
"lds r24, clockh" "\n\t"
|
||||
"subi r24, -1" "\n\t"
|
||||
"sts clockh, r24" "\n\t"
|
||||
"lds r24, clockh+1" "\n\t"
|
||||
"sbci r24, -1" "\n\t"
|
||||
"sts clockh+1, r24" "\n\t"
|
||||
"2:" "\n\t"
|
||||
"pop r24" "\n\t"
|
||||
"out __SREG__, r24" "\n"
|
||||
"pop r24" "\n\t"
|
||||
"reti" "\n"
|
||||
::
|
||||
[flag] "n" (&RTC.INTFLAGS),
|
||||
[CMPL] "n" (&RTC.CMP),
|
||||
[CMPH] "n" (&RTC.CMP+1)
|
||||
);
|
||||
}
|
||||
|
||||
#else
|
||||
ISR(RTC_PIT_vect)
|
||||
{
|
||||
clock_tick = 1;
|
||||
RTC.PITINTFLAGS = 1;
|
||||
clock++;
|
||||
}
|
||||
ISR(RTC_CNT_vect)
|
||||
{
|
||||
uint8_t flag = RTC.INTFLAGS;
|
||||
RTC.INTFLAGS = flag;
|
||||
rtc_tick = flag;
|
||||
if (flag & RTC_CNT_bm)
|
||||
RTC.CMP += rtc_config[1].val | rtc_config[2].val << 8;
|
||||
if (flag & RTC_OVF_bm)
|
||||
clock += 1;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
uint32_t time()
|
||||
{
|
||||
uint16_t cl, ch;
|
||||
do {
|
||||
cli();
|
||||
cl = RTC.CNT;
|
||||
ch = clockh;
|
||||
sei();
|
||||
} while (cl != RTC.CMP);
|
||||
return clock = cl | (uint32_t)ch << 16;
|
||||
}
|
||||
#else
|
||||
__attribute__((naked))
|
||||
uint32_t time()
|
||||
{
|
||||
__asm__ volatile("\n"
|
||||
"1:" "\n\t"
|
||||
"cli" "\n\t"
|
||||
"lds r22, %[CNT]" "\n\t"
|
||||
"lds r23, %[CNT]+1" "\n\t"
|
||||
"lds r24, clockh" "\n\t"
|
||||
"lds r25, clockh+1" "\n\t"
|
||||
"sei" "\n\t"
|
||||
"lds r18, %[CNT]" "\n\t"
|
||||
"lds r19, %[CNT]+1" "\n\t"
|
||||
"cp r18, r22" "\n\t"
|
||||
"cpc r19, r23" "\n\t"
|
||||
"brne 1b" "\n\t"
|
||||
"ldi r30, lo8(clock)" "\n\t"
|
||||
"ldi r31, hi8(clock)" "\n\t"
|
||||
"st Z+, r22" "\n\t"
|
||||
"st Z+, r23" "\n\t"
|
||||
"st Z+, r24" "\n\t"
|
||||
"st Z+, r25" "\n\t"
|
||||
"ret" "\n"
|
||||
:: [CNT] "n" (&RTC.CNT)
|
||||
: "r18", "r19", "r30", "r31", "memory"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
11
src/rtc.h
11
src/rtc.h
|
|
@ -3,7 +3,12 @@
|
|||
//
|
||||
|
||||
#include <stdint.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
volatile extern uint32_t clock;
|
||||
volatile extern uint8_t clock_tick;
|
||||
void init_rtc(uint8_t p);
|
||||
extern uint32_t clock;
|
||||
volatile extern uint16_t clockh;
|
||||
volatile extern uint8_t pit_tick;
|
||||
volatile extern uint8_t rtc_tick;
|
||||
uint32_t time();
|
||||
|
||||
uint8_t rtc_cnt_tick();
|
||||
|
|
|
|||
299
src/spi.c
299
src/spi.c
|
|
@ -2,67 +2,266 @@
|
|||
// spi.c
|
||||
//
|
||||
|
||||
// !!! int = int8_t
|
||||
// ! int = int8_t
|
||||
|
||||
#include "spi.h"
|
||||
#include "bate.h"
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/sleep.h>
|
||||
#include <string.h>
|
||||
|
||||
volatile uint8_t spi_tick;
|
||||
section_status(spi) struct spi_job spi;
|
||||
|
||||
// The Pressure sensor samples on the rising edge, MODE = 0
|
||||
static const uint8_t SPI_Mode_Write = SPI_SSD_bm | SPI_BUFEN_bm;
|
||||
struct_ioconf(spi_config) = {
|
||||
conf_prefix(SPI),
|
||||
conf_io(SPI.CTRLB, SPI_SSD_bm | SPI_BUFEN_bm),
|
||||
conf_io(SPI.CTRLA, SPI_MASTER_bm | SPI_ENABLE_bm | SPI_SPEED),
|
||||
};
|
||||
|
||||
// The Pressure sensor delivers on the rising edge, MODE = 1
|
||||
static const uint8_t SPI_Mode_Read = SPI_SSD_bm | SPI_BUFEN_bm | SPI_MODE_0_bm;
|
||||
|
||||
void init_spi(uint8_t div)
|
||||
#if 0
|
||||
ISR(SPI0_INT_vect)
|
||||
{
|
||||
if (div & ~SPI_PRESC_gm)
|
||||
div = SPI_PRESC_DIV64_gc;
|
||||
SPI.CTRLB = SPI_Mode_Write;
|
||||
SPI.CTRLA = SPI_MASTER_bm | SPI_ENABLE_bm | div;
|
||||
SPI.DATA;
|
||||
SPI.DATA;
|
||||
SPI.INTFLAGS = 0xff;
|
||||
SPI.INTCTRL = SPI_TXCIE_bm;
|
||||
}
|
||||
|
||||
uint16_t spi_frame(uint16_t d)
|
||||
{
|
||||
if (d)
|
||||
SPI.CTRLB = SPI_Mode_Write;
|
||||
else
|
||||
SPI.CTRLB = SPI_Mode_Read;
|
||||
SPI.DATA;
|
||||
SPI.DATA;
|
||||
SPI.INTFLAGS = 0xff;
|
||||
spi_tick = 0;
|
||||
SPI.DATA = d >> 8;
|
||||
SPI.DATA = d;
|
||||
uint8_t timeout = 20; // 20×15µs = 300µs
|
||||
sei();
|
||||
while (!spi_tick) {
|
||||
sleep_cpu();
|
||||
if (!--timeout) {
|
||||
DEBUG_COUNTER(spi_timeout);
|
||||
break;
|
||||
uint8_t d;
|
||||
uint8_t ifg = SPI.INTFLAGS;
|
||||
if (ifg & SPI_DREIF_bm) {
|
||||
repeat:
|
||||
if (spi.csize) {
|
||||
spi.csize--;
|
||||
d = *spi.cmd++;
|
||||
}
|
||||
else if (spi.zsize) {
|
||||
spi.zsize--;
|
||||
d = spi.zero;
|
||||
}
|
||||
else if (spi.wsize) {
|
||||
spi.wsize--;
|
||||
d = *spi.wdata++;
|
||||
}
|
||||
else {
|
||||
SPI.INTCTRL = SPI_TXCIF_bm | SPI_RXCIF_bm;
|
||||
goto done_write;
|
||||
}
|
||||
SPI.DATA = d;
|
||||
// clear a stray TXCIF, at high SCK rate
|
||||
SPI.INTFLAGS = SPI_TXCIF_bm;
|
||||
SPI.INTCTRL = SPI_TXCIF_bm | SPI_DREIF_bm | SPI_RXCIF_bm;
|
||||
done_write:
|
||||
ifg = SPI.INTFLAGS;
|
||||
}
|
||||
if (ifg & SPI_RXCIF_bm) {
|
||||
d = SPI.DATA; // clears the IF flag
|
||||
if (spi.isize)
|
||||
spi.isize --;
|
||||
else {
|
||||
if (spi.mask) {
|
||||
if ((d & spi.mask) == spi.wait) {
|
||||
spi.zsize++;
|
||||
goto cont;
|
||||
}
|
||||
spi.mask = 0;
|
||||
}
|
||||
if (spi.rsize) {
|
||||
spi.rsize--;
|
||||
*spi.rdata++ = d;
|
||||
}
|
||||
}
|
||||
cont:
|
||||
ifg = SPI.INTFLAGS;
|
||||
if (ifg & SPI_DREIF_bm)
|
||||
// This may prevent this ISR to terminate
|
||||
// before the job is done at high clock rate.
|
||||
// DRE is kept set when all bytes were sent.
|
||||
// With just the right clock rate, we may send
|
||||
// two bytes per interrupt.
|
||||
goto repeat;
|
||||
}
|
||||
if (ifg & SPI_TXCIF_bm) {
|
||||
if (!(spi.mode & SPI_CONT))
|
||||
SSEL_VPORT.OUT |= 1 << SSEL_PIN;
|
||||
SPI.INTCTRL = SPI_RXCIF_bm;
|
||||
}
|
||||
uint16_t b = SPI.DATA;
|
||||
return (b<<8) | SPI.DATA;
|
||||
}
|
||||
|
||||
#else
|
||||
ISR(SPI0_INT_vect, ISR_NAKED)
|
||||
{
|
||||
__asm__ ("push r24" "\n\t"
|
||||
"lds r24, %[flag]" "\n\t"
|
||||
"sts %[flag], r24" "\n\t"
|
||||
"sts spi_tick, r24" "\n\t"
|
||||
"pop r24" "\n\t"
|
||||
"reti" "\n"
|
||||
: : [flag] "n" (&SPI.INTFLAGS)
|
||||
__asm__ volatile(
|
||||
"push r24" "\n\t"
|
||||
"in r24, __SREG__" "\n\t"
|
||||
"push r24" "\n\t"
|
||||
"push r25" "\n\t"
|
||||
"push r26" "\n\t"
|
||||
"push r30" "\n\t"
|
||||
"push r31" "\n\t"
|
||||
"lds r24, %[IFLGS]" "\n\t"
|
||||
"sbrs r24, %[DRE]" "\n\t"
|
||||
"rjmp 3f" "\n"
|
||||
|
||||
"5:" "\n"
|
||||
"lds r25, %[CSZ]" "\n\t"
|
||||
"subi r25, 1" "\n\t"
|
||||
"brcs 1f" "\n\t"
|
||||
"sts %[CSZ], r25" "\n\t"
|
||||
"lds r30, %[CMD]" "\n\t"
|
||||
"lds r31, %[CMD]+1" "\n\t"
|
||||
"ld r25, Z+" "\n\t"
|
||||
"sts %[CMD], r30" "\n\t"
|
||||
"sts %[CMD]+1, r31" "\n\t"
|
||||
"rjmp 2f" "\n"
|
||||
|
||||
"1:" "\n\t"
|
||||
"lds r25, %[ZSZ]" "\n\t"
|
||||
"subi r25, 1" "\n\t"
|
||||
"brcs 1f" "\n\t"
|
||||
"sts %[ZSZ], r25" "\n\t"
|
||||
"lds r25, %[ZERO]" "\n\t"
|
||||
"rjmp 2f" "\n"
|
||||
|
||||
"1:" "\n\t"
|
||||
"lds r25, %[WSZ]" "\n\t"
|
||||
"subi r25, 1" "\n\t"
|
||||
"ldi r26, %[RIFLGS]" "\n\t"
|
||||
"brcs 1f" "\n\t"
|
||||
"sts %[WSZ], r25" "\n\t"
|
||||
"lds r30, %[WD]" "\n\t"
|
||||
"lds r31, %[WD]+1" "\n\t"
|
||||
"ld r25, Z+" "\n\t"
|
||||
"sts %[WD], r30" "\n\t"
|
||||
"sts %[WD]+1, r31" "\n"
|
||||
|
||||
"2:" "\n\t"
|
||||
"sts %[DATA], r25" "\n\t"
|
||||
"ldi r25, 1<<%[TXC]" "\n\t"
|
||||
"sts %[IFLGS], r25" "\n\t"
|
||||
"ldi r26, %[AIFLGS]" "\n"
|
||||
|
||||
"1:" "\n\t"
|
||||
"sts %[ICTRL], r26" "\n\t"
|
||||
"lds r24, %[IFLGS]" "\n"
|
||||
"3:" "\n\t"
|
||||
"sbrs r24, %[RXC]" "\n\t"
|
||||
"rjmp 3f" "\n\t"
|
||||
"lds r25, %[DATA]" "\n\t"
|
||||
"lds r26, %[ISZ]" "\n\t"
|
||||
"subi r26, 1" "\n\t"
|
||||
"brcs 1f " "\n\t"
|
||||
"sts %[ISZ], r26" "\n\t"
|
||||
"rjmp 4f" "\n"
|
||||
|
||||
"1:" "\n\t"
|
||||
"lds r26, %[MASK]" "\n\t"
|
||||
"cpi r26, 0" "\n\t"
|
||||
"breq 1f" "\n\t"
|
||||
"and r26, r25" "\n\t"
|
||||
"lds r24, %[WAIT]" "\n\t"
|
||||
"cp r24, r26" "\n\t"
|
||||
"brne 2f" "\n\t"
|
||||
"lds r25, %[ZSZ]" "\n\t"
|
||||
"subi r25, -1" "\n\t"
|
||||
"sts %[ZSZ], r25" "\n\t"
|
||||
"rjmp 4f" "\n"
|
||||
|
||||
"2:" "\n\t"
|
||||
"clr r26" "\n\t"
|
||||
"sts %[MASK], r26" "\n"
|
||||
|
||||
"1:" "\n\t"
|
||||
"lds r26, %[RSZ]" "\n\t"
|
||||
"subi r26, 1" "\n\t"
|
||||
"brcs 4f" "\n\t"
|
||||
"sts %[RSZ], r26" "\n\t"
|
||||
"lds r30, %[RD]" "\n\t"
|
||||
"lds r31, %[RD]+1" "\n\t"
|
||||
"st Z+, r25" "\n\t"
|
||||
"sts %[RD], r30" "\n\t"
|
||||
"sts %[RD]+1, r31" "\n"
|
||||
|
||||
"4:" "\n\t"
|
||||
"lds r24, %[IFLGS]" "\n\t"
|
||||
"sbrc r24, %[DRE]" "\n\t"
|
||||
"rjmp 5b" "\n\t"
|
||||
|
||||
"3:" "\n\t"
|
||||
"sbrs r24, %[TXC]" "\n\t"
|
||||
"rjmp 3f" "\n\t"
|
||||
"lds r25, %[MODE]" "\n\t"
|
||||
"sbrs r25, 7" "\n\t"
|
||||
"sbi %[SPORT], %[SSEL]" "\n\t"
|
||||
"ldi r25, 1<<%[RXC]" "\n\t"
|
||||
"sts %[ICTRL], r25" "\n"
|
||||
|
||||
"3:" "\n\t"
|
||||
"pop r31" "\n\t"
|
||||
"pop r30" "\n\t"
|
||||
"pop r26" "\n\t"
|
||||
"pop r25" "\n\t"
|
||||
"pop r24" "\n\t"
|
||||
"out __SREG__, r24" "\n\t"
|
||||
"pop r24" "\n\t"
|
||||
"reti" "\n"
|
||||
::
|
||||
[CSZ] "m" (spi.csize),
|
||||
[ZSZ] "m" (spi.zsize),
|
||||
[WSZ] "m" (spi.wsize),
|
||||
[ISZ] "m" (spi.isize),
|
||||
[RSZ] "m" (spi.rsize),
|
||||
[CMD] "m" (spi.cmd),
|
||||
[ZERO] "m" (spi.zero),
|
||||
[WD] "m" (spi.wdata),
|
||||
[RD] "m" (spi.rdata),
|
||||
[MODE] "m" (spi.mode),
|
||||
[MASK] "m" (spi.mask),
|
||||
[WAIT] "m" (spi.wait),
|
||||
[IFLGS] "n" (&SPI.INTFLAGS),
|
||||
[TXC] "n" (SPI_TXCIF_bp),
|
||||
[DRE] "n" (SPI_DREIF_bp),
|
||||
[RXC] "n" (SPI_RXCIF_bp),
|
||||
[RIFLGS] "n" (SPI_TXCIF_bm | SPI_RXCIF_bm),
|
||||
[AIFLGS] "n" (SPI_TXCIF_bm | SPI_RXCIF_bm | SPI_DREIF_bm),
|
||||
[ICTRL] "n" (&SPI.INTCTRL),
|
||||
[DATA] "n" (&SPI.DATA),
|
||||
[SPORT] "n" (_SFR_IO_ADDR(SSEL_VPORT.OUT)),
|
||||
[SSEL] "n" (SSEL_PIN)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t spi_select(uint8_t mode)
|
||||
{
|
||||
uint8_t s = spi_busy_p();
|
||||
if (s)
|
||||
return s;
|
||||
memset(&spi, 0, sizeof(spi));
|
||||
spi.mode = mode;
|
||||
if (mode & SPI_FLASH)
|
||||
SSEL_VPORT.OUT &=~ (1 << SSEL_PIN);
|
||||
else
|
||||
SSEL_VPORT.OUT |= 1 << SSEL_PIN;
|
||||
if (mode & SPI_CONFIG)
|
||||
SPI.CTRLA |= SPI_DORD_bm;
|
||||
else
|
||||
SPI.CTRLA &=~ SPI_DORD_bm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spi_start_cmd(uint8_t csize, uint8_t *cmd)
|
||||
{
|
||||
spi.cmd = cmd;
|
||||
barrier();
|
||||
spi.csize = csize;
|
||||
spi_start();
|
||||
}
|
||||
|
||||
void spi_start_write(uint8_t csize, uint8_t *cmd, uint8_t wsize, uint8_t *wdata)
|
||||
{
|
||||
spi.wdata = wdata;
|
||||
barrier();
|
||||
spi.wsize = wsize;
|
||||
spi_start_cmd(csize, cmd);
|
||||
}
|
||||
|
||||
void spi_start_read(uint8_t csize, uint8_t *cmd, uint8_t rsize, uint8_t *rdata)
|
||||
{
|
||||
spi.rdata = rdata;
|
||||
spi.isize = csize + spi.zsize;
|
||||
barrier();
|
||||
spi.zsize += rsize;
|
||||
spi.rsize = rsize;
|
||||
spi_start_cmd(csize, cmd);
|
||||
}
|
||||
|
|
|
|||
64
src/spi.h
64
src/spi.h
|
|
@ -2,12 +2,64 @@
|
|||
// spi.h
|
||||
//
|
||||
|
||||
#include <stdint.h>
|
||||
#include <avr/io.h>
|
||||
#ifndef _SPI_H
|
||||
#define _SPI_H
|
||||
|
||||
#include "config.h"
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#define SPI SPI0
|
||||
#define SPI_SPEED (SPI_CLK2X_bm | SPI_PRESC_DIV4_gc)
|
||||
|
||||
extern volatile uint8_t spi_tick;
|
||||
uint16_t spi_frame(uint16_t d);
|
||||
void init_spi(uint8_t div);
|
||||
static inline void spi_off() { SPI.INTCTRL = SPI.CTRLA = 0; }
|
||||
extern
|
||||
struct spi_job {
|
||||
uint8_t mode;
|
||||
uint8_t csize; // pipe.fpga.…
|
||||
uint8_t zsize; //
|
||||
uint8_t isize; //
|
||||
uint8_t zero; //
|
||||
uint8_t wait; //
|
||||
uint8_t mask; //
|
||||
uint8_t rsize;
|
||||
uint8_t wsize;
|
||||
const uint8_t *cmd;
|
||||
const uint8_t *wdata;
|
||||
uint8_t *rdata;
|
||||
} spi;
|
||||
|
||||
enum spi_mode_bits {
|
||||
SPI_FLASH = 0x01,
|
||||
SPI_CONFIG = 0x02,
|
||||
SPI_CONT = 0x80,
|
||||
};
|
||||
|
||||
static inline
|
||||
uint8_t spi_abort()
|
||||
{
|
||||
cli();
|
||||
uint8_t f = SPI.INTFLAGS;
|
||||
SPI.INTFLAGS = 0;
|
||||
sei();
|
||||
return f;
|
||||
}
|
||||
|
||||
static inline
|
||||
uint8_t spi_busy_p()
|
||||
{
|
||||
return SPI.INTCTRL & SPI_TXCIF_bm;
|
||||
}
|
||||
|
||||
static inline
|
||||
void spi_start()
|
||||
{
|
||||
SPI.INTCTRL = SPI_DREIF_bm | SPI_TXCIF_bm| SPI_RXCIF_bm;
|
||||
}
|
||||
|
||||
static inline void barrier() { __asm__("":::"memory"); }
|
||||
void init_spi(uint8_t spi_div);
|
||||
uint8_t spi_select(uint8_t mode);
|
||||
void spi_start_cmd(uint8_t csize, uint8_t *cmd);
|
||||
void spi_start_write(uint8_t csize, uint8_t *cmd, uint8_t wsize, uint8_t *wdata);
|
||||
void spi_start_read(uint8_t csize, uint8_t *cmd, uint8_t rsize, uint8_t *rdata);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
355
src/uart.c
355
src/uart.c
|
|
@ -4,99 +4,41 @@
|
|||
|
||||
// !!! int = int8_t
|
||||
|
||||
#include "bate.h"
|
||||
#include "mul.h"
|
||||
|
||||
#include <avr/io.h>
|
||||
#include "uart.h"
|
||||
#include <avr/sleep.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#define Bit(x) (1<<(x))
|
||||
|
||||
// 10 MHz / 2400 / 16 * 64
|
||||
#define UART_DIV 16667
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
void init_uart(uint16_t div, uint8_t mode)
|
||||
{
|
||||
if (mode==0xff)
|
||||
mode = USART_TXEN_bm;
|
||||
mode |= USART_TXEN_bm;
|
||||
if (div<64)
|
||||
div = UART_DIV;
|
||||
USART0.BAUD = div;
|
||||
PORTB.DIRSET = Bit(2);
|
||||
USART0.CTRLB = mode;
|
||||
if (mode & USART_RXEN_bm)
|
||||
USART0.CTRLA = USART_RXCIE_bm;
|
||||
// `BOTHEDGES` should wake from power down sleep()
|
||||
PORTB.PIN3CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
|
||||
}
|
||||
|
||||
volatile uint8_t rx_tick;
|
||||
|
||||
ISR(PORTB_PORT_vect, ISR_NAKED)
|
||||
{
|
||||
__asm__ ("push r24" "\n\t"
|
||||
"lds r24, %[stat]" "\n\t"
|
||||
"sts %[stat], r24" "\n\t"
|
||||
"sts rx_tick, r24" "\n\t"
|
||||
"pop r24" "\n\t"
|
||||
"reti" "\n"
|
||||
: : [stat] "n" (&VPORTB.INTFLAGS)
|
||||
);
|
||||
}
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
uint8_t uart_tick()
|
||||
{
|
||||
cli();
|
||||
uint8_t r = rx_tick;
|
||||
rx_tick = 0;
|
||||
sei();
|
||||
return r;
|
||||
}
|
||||
struct_ioconf(uart_config) = {
|
||||
conf_prefix(USART0),
|
||||
conf_iow(USART0.BAUD, 40000000/115200), // 115200 baud
|
||||
conf_io(USART0.CTRLC, USART_CHSIZE_8BIT_gc),
|
||||
conf_io(USART0.CTRLB, USART_TXEN_bm | USART_RXEN_bm),
|
||||
conf_io(USART0.CTRLA, USART_RXCIE_bm),
|
||||
};
|
||||
|
||||
// `uart_tx` buffer size must be a power of 2, max 256.
|
||||
// Fix `tx()` and `put_char()` / `put_char:`
|
||||
// when the size changes.
|
||||
// For now, we can afford half of the available RAM,
|
||||
// and still have 128 bytes for the stack
|
||||
#ifdef UART_TX_SMALL
|
||||
uint8_t uart_tx[128];
|
||||
#else
|
||||
uint8_t uart_tx[256];
|
||||
#endif
|
||||
uint8_t uart_tx[32];
|
||||
|
||||
#define uart_tx_m (sizeof(uart_tx) - 1)
|
||||
volatile uint8_t uart_tx_w;
|
||||
volatile uint8_t uart_tx_r;
|
||||
volatile uint8_t uart_tx_busy;
|
||||
uint8_t uart_cks;
|
||||
|
||||
#if 0
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
void tx()
|
||||
{
|
||||
// interrupts must be disabled
|
||||
if (USART0.STATUS & USART_TXCIF_bm) {
|
||||
USART0.STATUS = USART_TXCIF_bm;
|
||||
uart_tx_busy = 0;
|
||||
}
|
||||
// read volatile memory once, for speed
|
||||
uint8_t r = uart_tx_r;
|
||||
uint8_t w = uart_tx_w;
|
||||
while (w - r) {
|
||||
uart_tx_busy = w - r;
|
||||
if (!(USART0.STATUS & USART_DREIF_bm)) {
|
||||
USART0.CTRLA |= USART_DREIE_bm | USART_TXCIE_bm;
|
||||
USART0.CTRLA |= USART_DREIE_bm;
|
||||
uart_tx_r = r;
|
||||
return;
|
||||
}
|
||||
USART0.TXDATAL = uart_tx[r++ & uart_tx_m];
|
||||
// race? TXC while we were looping? Drop it.
|
||||
USART0.STATUS = USART_TXCIF_bm;
|
||||
USART0.STATUS |= USART_TXCIF_bm
|
||||
}
|
||||
uart_tx_r = r;
|
||||
USART0.CTRLA &=~ USART_DREIE_bm;
|
||||
|
|
@ -104,100 +46,71 @@ void tx()
|
|||
|
||||
ISR(USART0_DRE_vect)
|
||||
{
|
||||
DEBUG_COUNTER(tx_irqs);
|
||||
tx();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
__attribute__ ((noinline, naked))
|
||||
void tx()
|
||||
{
|
||||
// This uses only six registers, to save stack in the ISR.
|
||||
// r0 and r1 need not be saved
|
||||
// Avoids unlikely branches.
|
||||
// [STATUS] is prepared in advance, to avoid two branches and one memory load,
|
||||
// at the cost of one register on the ISR stack (r25)
|
||||
// This uses only three registers, to save stack in the ISR.
|
||||
__asm__("\n"
|
||||
" lds r21, uart_tx_r \n"
|
||||
" lds r19, uart_tx_w \n"
|
||||
" lds r25, %[CTRLA] \n"
|
||||
" andi r25, ~0x20 ; clr DREIE \n"
|
||||
" lds r30, %[STATUS] \n"
|
||||
" ldi r24, 0x40 \n"
|
||||
" and r30, r24 ; TXCIF \n"
|
||||
" breq 2f \n"
|
||||
" sts %[STATUS], r24 ; clr TXCIF \n"
|
||||
" ldi r31, 0 \n"
|
||||
" sts uart_tx_busy, r31 \n"
|
||||
" andi r25, ~(1<<%[DRE]) \n"
|
||||
" rjmp 2f \n"
|
||||
" \n"
|
||||
"1: \n"
|
||||
" mov r30, r21 ; \n"
|
||||
" subi r21, 0xff ; r++ & uart_tx_m \n"
|
||||
#ifdef UART_TX_SMALL
|
||||
" andi r30, 0x7f ; \n"
|
||||
#endif
|
||||
" ldi r31, 0 \n"
|
||||
" mov r31, r30 ; \n"
|
||||
" subi r31, 0xff ; r++ & uart_tx_m \n"
|
||||
" sts uart_tx_r, r31 \n"
|
||||
" andi r30, 0x1f ; \n"
|
||||
" clr r31 \n"
|
||||
" subi r30, lo8(-(uart_tx)) \n"
|
||||
" sbci r31, hi8(-(uart_tx)) \n"
|
||||
" ld r24, Z \n"
|
||||
" sts %[TXDATA], r24 \n"
|
||||
" ldi r24, 0x40 \n"
|
||||
" sts %[STATUS], r24 ; clr TXCIF \n"
|
||||
" ld r30, Z \n"
|
||||
" sts %[TXDATA], r30 \n"
|
||||
" ldi r30, 1<<%[TXC] \n"
|
||||
" sts %[STATUS], r30 \n"
|
||||
"2: \n"
|
||||
" cp r21, r19 \n"
|
||||
" lds r30, uart_tx_r \n"
|
||||
" lds r31, uart_tx_w \n"
|
||||
" cp r30, r31 \n"
|
||||
" breq 3f \n"
|
||||
" sts uart_tx_busy, r24 ; =0x40 \n"
|
||||
" lds r24, %[STATUS] \n"
|
||||
" sbrc r24, 5 ; DREIF \n"
|
||||
" lds r31, %[STATUS] \n"
|
||||
" sbrc r31, %[DRE] \n"
|
||||
" rjmp 1b \n"
|
||||
" ori r25, 0x60 ; set DREIE TXCIE \n"
|
||||
" ori r25, 1<<%[DRE] \n"
|
||||
"3: \n"
|
||||
" sts %[CTRLA], r25 \n"
|
||||
" sts uart_tx_r, r21 \n"
|
||||
" ret \n"
|
||||
:
|
||||
: [STATUS] "n" (&USART0.STATUS),
|
||||
[CTRLA] "n" (&USART0.CTRLA),
|
||||
[TXDATA] "n" (&USART0.TXDATAL)
|
||||
: "r19", "r21",
|
||||
"r24", "r25",
|
||||
"r30", "r31",
|
||||
"memory"
|
||||
:
|
||||
[TXC] "n" (USART_TXCIF_bp),
|
||||
[DRE] "n" (USART_DREIF_bp),
|
||||
[CTRLA] "n" (&USART0.CTRLA),
|
||||
[STATUS] "n" (&USART0.STATUS),
|
||||
[TXDATA] "n" (&USART0.TXDATAL)
|
||||
: "r25", "r30", "r31", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
ISR(USART0_DRE_vect, ISR_NAKED)
|
||||
{
|
||||
// Doing this naked is a bit dangerous,
|
||||
// but saves five instructions and two bytes stack (r0, r1).
|
||||
// This saves five instructions and two bytes stack (r0, r1).
|
||||
// OTOH, the C implementation of tx() is not bad either,
|
||||
// if we are doing this asm, then we do it agressively.
|
||||
__asm__("\n"
|
||||
" push r24 \n"
|
||||
" in r24, __SREG__ \n"
|
||||
" push r24 \n"
|
||||
" push r25 \n"
|
||||
" push r19 \n"
|
||||
" push r21 \n"
|
||||
" in r25, __SREG__ \n"
|
||||
" push r25 \n"
|
||||
" push r30 \n"
|
||||
" push r31 \n"
|
||||
" \n"
|
||||
#ifdef DEBUG
|
||||
" lds r24, debug_data + 3 \n"
|
||||
" subi r24, 0xff \n"
|
||||
" sts debug_data + 3, r24 \n"
|
||||
#endif
|
||||
" rcall tx \n"
|
||||
" \n"
|
||||
" pop r31 \n"
|
||||
" pop r30 \n"
|
||||
" pop r21 \n"
|
||||
" pop r19 \n"
|
||||
" pop r25 \n"
|
||||
" pop r24 \n"
|
||||
" out __SREG__, r24 \n"
|
||||
" pop r24 \n"
|
||||
" out __SREG__, r25 \n"
|
||||
" pop r25 \n"
|
||||
" reti \n"
|
||||
);
|
||||
}
|
||||
|
|
@ -206,26 +119,28 @@ ISR(USART0_DRE_vect, ISR_NAKED)
|
|||
|
||||
ISR(USART0_TXC_vect, ISR_ALIASOF(USART0_DRE_vect));
|
||||
|
||||
uint8_t uart_rx[16];
|
||||
uint8_t uart_rx[32];
|
||||
#define uart_rx_m (sizeof(uart_rx) - 1)
|
||||
|
||||
volatile uint8_t uart_rx_w;
|
||||
volatile uint8_t uart_rx_mes;
|
||||
section_status(uart.w) volatile uint8_t uart_rx_w;
|
||||
section_status(uart.h) volatile uint8_t uart_rx_s;
|
||||
section_status(uart.m) volatile uint8_t uart_rx_mes;
|
||||
section_status(uart.e) uint8_t uart_rx_err;
|
||||
section_status(uart.ee) uint8_t uart_rx_errors;
|
||||
|
||||
#if 0
|
||||
ISR(USART0_RXC_vect)
|
||||
{
|
||||
DEBUG_COUNTER(rx_irqs);
|
||||
// s/while/if/ !
|
||||
if (USART0.STATUS & USART_RXCIF_bm) {
|
||||
uint8_t c = USART0.RXDATAL;
|
||||
DEBUG_POKE(rx_char, c);
|
||||
uart_rx_s |= USART0.RXDATAH;
|
||||
uint8_t w = uart_rx_w;
|
||||
uart_rx[w] = c;
|
||||
if (w < uart_rx_m)
|
||||
uart_rx_w = ++w;
|
||||
if (!uart_rx_mes && c=='\n')
|
||||
uart_rx_mes = w;
|
||||
if (w<=uart_rx_m) {
|
||||
uint8_t c = USART0.RXDATAL;
|
||||
uart_rx[w++] = c;
|
||||
if (!uart_rx_mes && c=='\n')
|
||||
uart_rx_mes = w;
|
||||
uart_rx_w = w;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
|
@ -246,23 +161,19 @@ ISR(USART0_RXC_vect, ISR_NAKED)
|
|||
" push r24 \n"
|
||||
" push r30 \n"
|
||||
" push r31 \n"
|
||||
#ifdef DEBUG
|
||||
" lds r24, debug_data + 4 \n"
|
||||
" subi r24, -1 \n"
|
||||
" sts debug_data + 4, r24 \n"
|
||||
#endif
|
||||
" lds r24, %[RXDATA] \n"
|
||||
" lds r24, %[DH] \n"
|
||||
" lds r30, uart_rx_s \n"
|
||||
" or r24, r30 \n"
|
||||
" sts uart_rx_s, r24 \n"
|
||||
" lds r24, %[DL] \n"
|
||||
" lds r30, uart_rx_w \n"
|
||||
" cpi r30, 0x20 \n"
|
||||
" brcc 1f \n"
|
||||
" ldi r31, 0 \n"
|
||||
" subi r30, lo8(-(uart_rx)) \n"
|
||||
" sbci r31, hi8(-(uart_rx)) \n"
|
||||
" st Z+, r24 \n"
|
||||
#ifdef DEBUG
|
||||
" sts debug_data + 5, r24 \n"
|
||||
#endif
|
||||
" subi r30, lo8(uart_rx) \n"
|
||||
" sbrc r30, 4 ; log2(sizeof(uart_rx)) \n"
|
||||
" subi r30, 1 \n"
|
||||
" sts uart_rx_w, r30 \n"
|
||||
" cpi r24, '\n' \n"
|
||||
" brne 1f \n"
|
||||
|
|
@ -277,145 +188,7 @@ ISR(USART0_RXC_vect, ISR_NAKED)
|
|||
" out __SREG__, r24 \n"
|
||||
" pop r24 \n"
|
||||
" reti \n"
|
||||
: : [RXDATA] "n" (&USART0.RXDATAL)
|
||||
:: [DL] "n" (&USART0.RXDATAL), [DH] "n" (&USART0.RXDATAH)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// These are implemented in `uart_tx.S`
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
uint8_t uart_put_char(uint8_t c)
|
||||
{
|
||||
uint8_t r = uart_tx_r;
|
||||
uint8_t w = uart_tx_w;
|
||||
uint8_t ww = w + 1;
|
||||
if ((ww & uart_tx_m) == (r & uart_tx_m))
|
||||
return 1;
|
||||
uart_tx[w & uart_tx_m] = c;
|
||||
__asm__("" ::: "memory");
|
||||
uart_tx_w = ww;
|
||||
__asm__("" ::: "memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
void send_char(uint8_t c)
|
||||
{
|
||||
uint8_t s = 0;
|
||||
uint8_t b;
|
||||
while (1) {
|
||||
b = uart_put_char(c);
|
||||
uart_busy();
|
||||
if (!b)
|
||||
break;
|
||||
sleep_cpu();
|
||||
s = 1;
|
||||
}
|
||||
if (s)
|
||||
DEBUG_COUNTER(tx_sleep);
|
||||
}
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
void send_str(const char *s)
|
||||
{
|
||||
while (*s) {
|
||||
uint8_t c = *s++;
|
||||
if (!uart_put_char(c))
|
||||
continue;
|
||||
send_char(c);
|
||||
}
|
||||
uart_busy();
|
||||
}
|
||||
|
||||
static inline
|
||||
void rx_dismiss(uint8_t n)
|
||||
{
|
||||
cli();
|
||||
uint8_t i = 0;
|
||||
uint8_t m = 0;
|
||||
uint8_t w = uart_rx_w;
|
||||
if (w != uart_rx_m)
|
||||
while (n < w) {
|
||||
uint8_t c = uart_rx[n++];
|
||||
uart_rx[i++] = c;
|
||||
if (!m && c=='\n')
|
||||
m = i;
|
||||
}
|
||||
uart_rx_mes = m;
|
||||
uart_rx_w = i;
|
||||
sei();
|
||||
}
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
uint8_t uart_busy()
|
||||
{
|
||||
cli();
|
||||
tx();
|
||||
sei();
|
||||
return uart_tx_busy;
|
||||
}
|
||||
|
||||
static __attribute__ ((noinline, noclone))
|
||||
void send_hex_nibble(uint8_t b)
|
||||
{
|
||||
b += '0';
|
||||
if (b>'9')
|
||||
b += '@' - '9';
|
||||
send_char(b);
|
||||
}
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
void send_hex_byte(uint8_t b)
|
||||
{
|
||||
send_hex_nibble(b >> 4);
|
||||
send_hex_nibble(b & 0xf);
|
||||
}
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
void send_hex_word(uint16_t b)
|
||||
{
|
||||
send_hex_byte(b >> 8);
|
||||
send_hex_byte(b);
|
||||
}
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
void send_hex(uint8_t header, const uint8_t *s, uint8_t n, uint8_t words)
|
||||
{
|
||||
// dump little endian words.
|
||||
send_char(header);
|
||||
while (n--) {
|
||||
if (words & 1)
|
||||
send_char(' ');
|
||||
uint8_t l = *(s++);
|
||||
if (words & 2 && n & 1) {
|
||||
send_hex_byte(*(s++));
|
||||
n--;
|
||||
}
|
||||
send_hex_byte(l);
|
||||
}
|
||||
send_char('\n');
|
||||
}
|
||||
|
||||
void command(void)
|
||||
{
|
||||
uint8_t m = uart_rx_mes;
|
||||
if (!m)
|
||||
return;
|
||||
uint8_t *s = uart_rx;
|
||||
uint8_t i = 0;
|
||||
uint8_t c;
|
||||
send_str("R ");
|
||||
while (i++ < m) {
|
||||
c = *s++;
|
||||
send_char(c);
|
||||
}
|
||||
if (c != '\n')
|
||||
send_char('\n');
|
||||
else
|
||||
parse_command(uart_rx, m);
|
||||
rx_dismiss(m);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
26
src/uart.h
26
src/uart.h
|
|
@ -2,32 +2,20 @@
|
|||
// uart.h
|
||||
//
|
||||
|
||||
#include <stdint.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/sleep.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include "config.h"
|
||||
|
||||
void init_uart(uint16_t div, uint8_t mode);
|
||||
uint8_t uart_tick();
|
||||
|
||||
static inline
|
||||
uint8_t uart_break_p()
|
||||
{
|
||||
return !(VPORTB.IN & 0x08);
|
||||
}
|
||||
void init_uart(uint16_t mode, uint16_t div);
|
||||
|
||||
void send_char(uint8_t c);
|
||||
void send_eol();
|
||||
void send_str(const char *s);
|
||||
void send_hex_byte(uint8_t b);
|
||||
void send_hex_byte_eol(uint8_t b);
|
||||
void send_hex_word(uint16_t b);
|
||||
void send_hex(uint8_t header, const uint8_t *s, uint8_t n, uint8_t words);
|
||||
void send_hex(const void *s, uint8_t n);
|
||||
uint8_t uart_busy();
|
||||
void command(void);
|
||||
|
||||
void send_decimal(uint16_t b, uint8_t dec);
|
||||
|
||||
void parse_command(uint8_t *s, uint8_t n);
|
||||
void parse_command(const uint8_t *s, uint8_t n);
|
||||
|
||||
static inline
|
||||
void send_hex_long(uint32_t b)
|
||||
|
|
@ -36,5 +24,5 @@ void send_hex_long(uint32_t b)
|
|||
send_hex_word(b);
|
||||
}
|
||||
|
||||
extern uint8_t uart_cks;
|
||||
void send_cks();
|
||||
extern uint8_t uart_rx_err;
|
||||
extern uint8_t uart_rx_errors;
|
||||
|
|
|
|||
132
src/uart.py
Executable file
132
src/uart.py
Executable file
|
|
@ -0,0 +1,132 @@
|
|||
#! /usr/bin/ipython3 --profile=uart
|
||||
|
||||
import sys, serial, threading, struct
|
||||
from prompt import set_prompt
|
||||
|
||||
class uart(threading.Thread):
|
||||
|
||||
def __init__(self, port, baudrate=115200, parity='N'):
|
||||
self.baudrate=baudrate
|
||||
self.serial = serial.Serial(baudrate=baudrate, parity=parity, timeout=10.0,
|
||||
xonxoff=False, rtscts=False, dsrdtr=False)
|
||||
self.serial.port = port
|
||||
self.portname = port.split('/')[-1]
|
||||
self.serial.open()
|
||||
self.write = self.serial.write
|
||||
self.responses = []
|
||||
self.readbuffer = b""
|
||||
self.reader_lock = threading.Lock()
|
||||
self.resp_ready = threading.Condition()
|
||||
self.alive = True
|
||||
threading.Thread.__init__(self, target=self._reader)
|
||||
self.daemon = True
|
||||
self.start()
|
||||
|
||||
def _reader(self):
|
||||
data = b""
|
||||
while self.alive:
|
||||
data += self.serial.read_until(b'\n')
|
||||
data += self.serial.read_all()
|
||||
if data and self.reader_lock.acquire(False):
|
||||
self.readbuffer += data
|
||||
data = b""
|
||||
self.parser()
|
||||
self.reader_lock.release()
|
||||
|
||||
def parse(self):
|
||||
if self.reader_lock.acquire(False):
|
||||
self.parser()
|
||||
self.reader_lock.release()
|
||||
|
||||
def kill(self):
|
||||
self.alive = False
|
||||
self.join()
|
||||
|
||||
def parser(self):
|
||||
"do something with received chars in .readbuffer"
|
||||
if not self.resp_ready.acquire(False):
|
||||
return
|
||||
lines = self.readbuffer.split(b'\n')
|
||||
self.readbuffer = lines[-1]
|
||||
lines[-1:] = []
|
||||
|
||||
for ll in lines:
|
||||
if ll:
|
||||
self.parse_line(ll)
|
||||
if self.responses:
|
||||
self.resp_ready.notify()
|
||||
self.resp_ready.release()
|
||||
|
||||
_verbose = True
|
||||
|
||||
def parse_line(self, l):
|
||||
self.responses.append(l)
|
||||
if self._verbose:
|
||||
try:
|
||||
s = l.decode()
|
||||
print(f"{self.portname}<- {s}", file=sys.stderr)
|
||||
except:
|
||||
print(f"{self.portname}<- {repr(l)}", file=sys.stderr)
|
||||
|
||||
def resp(self, timeout=10, blocking=True):
|
||||
self.parse()
|
||||
if not self.resp_ready.acquire(blocking):
|
||||
return b""
|
||||
if blocking and not self.responses:
|
||||
self.resp_ready.wait(timeout)
|
||||
l = b""
|
||||
if self.responses:
|
||||
l = self.responses[0]
|
||||
self.responses[:1] = []
|
||||
self.resp_ready.release()
|
||||
return l
|
||||
|
||||
def flush(self):
|
||||
r = []
|
||||
while self.responses:
|
||||
r.append(self.resp())
|
||||
return r
|
||||
|
||||
def ucmd(self, c):
|
||||
if not isinstance(c, bytes):
|
||||
c = c.encode()
|
||||
if c[-1:] != b'\n':
|
||||
c = c + b'\n'
|
||||
if self._verbose:
|
||||
print(f"{self.portname}-> {c.decode().rstrip()}", file=sys.stderr)
|
||||
self.write(c)
|
||||
|
||||
def cmd(self, c):
|
||||
self.ucmd(c)
|
||||
|
||||
def _export(self, scope=None, prefix=""):
|
||||
"""usage: ..._export(globals())
|
||||
return a dict with all names 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
|
||||
|
||||
if __name__=="__main__":
|
||||
import getopt
|
||||
oo,ff = getopt.getopt(sys.argv[1:], "F:", ["tty="])
|
||||
port = "/dev/ttyUSB1"
|
||||
baud = 115200
|
||||
for o,v in oo:
|
||||
if o=="-F" or v=="--tty":
|
||||
v = v.split(",")
|
||||
port = v[0]
|
||||
if len(v)>1:
|
||||
baud = int(v[1])
|
||||
tty = uart(port, baud)
|
||||
tty._export(globals())
|
||||
set_prompt(tty.portname)
|
||||
214
src/uart_tx.S
214
src/uart_tx.S
|
|
@ -3,168 +3,146 @@
|
|||
//
|
||||
// avoid quite a few push and pops and jumps
|
||||
|
||||
#include <avr/io.h>
|
||||
|
||||
.global send_hex_word
|
||||
.global send_hex_byte
|
||||
.global send_hex_byte_eol
|
||||
.global send_char
|
||||
.global _send_char22
|
||||
.global send_str
|
||||
.global _send_str26
|
||||
.global uart_busy
|
||||
.global send_hex
|
||||
.global send_cks
|
||||
.global send_eol
|
||||
.global command
|
||||
|
||||
// `tx()` and `put_char()` do not gobble r18, r20, r22, r23, r26, and r27.
|
||||
// `tx()` and `put_char()` do not gobble r18, r20, r21, r22, r24, r26, and r27.
|
||||
|
||||
put_char:
|
||||
// non-global, non-C
|
||||
// arg: char r22
|
||||
lds r23, uart_tx_r
|
||||
lds r30, uart_tx_w
|
||||
ldi r19, 1
|
||||
add r19, r30
|
||||
eor r23, r19
|
||||
#ifdef UART_TX_SMALL
|
||||
andi r23, 0x7f // uart_tx_m
|
||||
breq 1f
|
||||
andi r30, 0x7f // uart_tx_m
|
||||
#else
|
||||
breq 1f
|
||||
#endif
|
||||
ldi r31, 0
|
||||
subi r30, lo8(-(uart_tx))
|
||||
sbci r31, hi8(-(uart_tx))
|
||||
st Z, r22
|
||||
sts uart_tx_w, r19
|
||||
lds r19, uart_cks
|
||||
add r19, r22
|
||||
sts uart_cks, r19
|
||||
1:
|
||||
// r22 preserved
|
||||
// r23 full when zero
|
||||
// r18, r26, and 27 must be preseved in the hex functions
|
||||
// …, r20, r21, r24, must be preserved in `uart_busy()` and `put_char()'
|
||||
|
||||
send_hex_byte_eol:
|
||||
ldi r22, ' '
|
||||
rcall _send_char22
|
||||
rcall send_hex_byte
|
||||
send_eol:
|
||||
ldi r22, '\n'
|
||||
rcall _send_char22
|
||||
uart_busy:
|
||||
cli
|
||||
rcall tx ; gobbles r25, r30, and r31
|
||||
sei
|
||||
lds r25, USART0_STATUS
|
||||
andi r25, SPI_TXCIF_bm
|
||||
9:
|
||||
ret
|
||||
|
||||
// r18, r20, r26, and 27 must be preseved in the hex functions
|
||||
// r22 and r23 must be preserved in `uart_busy()` and `put_char()'
|
||||
|
||||
#ifdef HEX_WORD
|
||||
send_hex_word:
|
||||
push r24
|
||||
mov r20, r24
|
||||
mov r24, r25
|
||||
rcall send_hex_byte
|
||||
pop r24
|
||||
mov r24, r20
|
||||
#endif
|
||||
send_hex_byte:
|
||||
push r24
|
||||
mov r21, r24
|
||||
swap r24
|
||||
rcall send_hex_nibble
|
||||
pop r24
|
||||
mov r24, r21
|
||||
send_hex_nibble:
|
||||
andi r24, 0x0f
|
||||
subi r24, -'0'
|
||||
cpi r24, '9'+1
|
||||
brlo send_char
|
||||
subi r24, '9'+1-'A'
|
||||
|
||||
send_char:
|
||||
mov r22, r24
|
||||
send_char22:
|
||||
rcall put_char
|
||||
rcall uart_busy
|
||||
tst r23
|
||||
brne 9f
|
||||
sleep
|
||||
rjmp send_char22
|
||||
|
||||
2:
|
||||
rcall put_char
|
||||
tst r23
|
||||
brne 1f
|
||||
rcall send_char22
|
||||
rjmp _send_char22
|
||||
1:
|
||||
movw r24, r26
|
||||
send_str:
|
||||
movw r26, r24
|
||||
ld r22, X+
|
||||
tst r22
|
||||
brne 2b
|
||||
uart_busy:
|
||||
cli
|
||||
rcall tx ; gobbles only r19, r21, r24, r25, r30, and r31
|
||||
sei
|
||||
lds r24, uart_tx_busy
|
||||
rcall uart_busy
|
||||
sleep
|
||||
_send_char22:
|
||||
// non-global, non-C
|
||||
// arg: char r22
|
||||
lds r23, uart_tx_r
|
||||
lds r30, uart_tx_w
|
||||
ldi r19, 1
|
||||
add r19, r30
|
||||
sub r23, r19
|
||||
andi r30, 0x1f // uart_tx_m
|
||||
ldi r31, 0
|
||||
subi r30, lo8(-(uart_tx))
|
||||
sbci r31, hi8(-(uart_tx))
|
||||
subi r23, 0xe0
|
||||
brcs 1b
|
||||
st Z, r22
|
||||
sts uart_tx_w, r19
|
||||
9:
|
||||
ret
|
||||
|
||||
; send_hex('Q', &uart_cks, 1, 0);
|
||||
send_cks:
|
||||
ldi r24, 'Q'
|
||||
ldi r18, 0
|
||||
ldi r20, 1
|
||||
ldi r22, lo8(uart_cks)
|
||||
ldi r23, hi8(uart_cks)
|
||||
send_str:
|
||||
movw r26, r24
|
||||
rjmp _send_str26
|
||||
1:
|
||||
__send_char22_str26:
|
||||
rcall _send_char22
|
||||
_send_str26:
|
||||
ld r22, X+
|
||||
tst r22
|
||||
brne 1b
|
||||
9:
|
||||
ret
|
||||
|
||||
#ifdef SEND_HEX
|
||||
send_hex:
|
||||
movw r26, r22
|
||||
rcall send_char
|
||||
rjmp 3f
|
||||
|
||||
movw r26, r24
|
||||
mov r18, r22
|
||||
1:
|
||||
ldi r22, ' '
|
||||
sbrc r18, 0
|
||||
rcall send_char22
|
||||
ld r24, X+
|
||||
sbrs r18, 1
|
||||
rjmp 2f
|
||||
sbrs r20, 0
|
||||
rjmp 2f
|
||||
push r24
|
||||
subi r20, 1
|
||||
ld r24, X+
|
||||
rcall send_hex_byte
|
||||
pop r24
|
||||
2:
|
||||
rcall send_hex_byte
|
||||
3:
|
||||
subi r20, 1
|
||||
brcc 1b
|
||||
send_eol:
|
||||
ldi r22, 10
|
||||
rjmp send_char22
|
||||
|
||||
command:
|
||||
lds r20, uart_rx_mes
|
||||
tst r20
|
||||
breq 9b
|
||||
ldi r22, 'R'
|
||||
rcall send_char22
|
||||
ldi r22, '>'
|
||||
rcall send_char22
|
||||
ldi r26, lo8(uart_rx)
|
||||
ldi r27, hi8(uart_rx)
|
||||
mov r18, r20
|
||||
1:
|
||||
ld r22, X+
|
||||
rcall send_char22
|
||||
subi r18, 1
|
||||
brne 1b
|
||||
9:
|
||||
ret
|
||||
#endif
|
||||
|
||||
command:
|
||||
;; when any frame errors occured, dismiss the buffer
|
||||
lds r22, uart_rx_s
|
||||
andi r22, 0x46
|
||||
brne uart_errs_p
|
||||
;; when there is no message, check for overflow
|
||||
lds r22, uart_rx_mes
|
||||
tst r22
|
||||
breq uart_full_p
|
||||
;; when the buffer was dismissed for errors, skip this command
|
||||
push r22
|
||||
lds r24, uart_rx_err
|
||||
sts uart_rx_err, r1
|
||||
lds r25, uart_rx_errors
|
||||
or r25, r24
|
||||
sts uart_rx_errors, r25
|
||||
tst r24
|
||||
brne 2f
|
||||
ldi r24, lo8(uart_rx)
|
||||
ldi r25, hi8(uart_rx)
|
||||
mov r22, r20
|
||||
push r20
|
||||
rcall parse_command
|
||||
2:
|
||||
pop r24
|
||||
rx_dismiss:
|
||||
cli
|
||||
lds r18, uart_rx_w
|
||||
clr r19
|
||||
clr r20
|
||||
cpi r18, 15
|
||||
brcc 3f
|
||||
sub r18, r24
|
||||
breq 3f
|
||||
brcs 3f // TCNH, n > w
|
||||
brcs 3f
|
||||
ldi r26, lo8(uart_rx)
|
||||
ldi r27, hi8(uart_rx)
|
||||
movw r30, r26
|
||||
add r30, r24
|
||||
adc r31, r1
|
||||
adc r31, r20
|
||||
1:
|
||||
ld r25, Z+
|
||||
st X+, r25
|
||||
|
|
@ -175,7 +153,7 @@ rx_dismiss:
|
|||
brne 2f
|
||||
mov r20, r19
|
||||
2:
|
||||
cp r19, r18
|
||||
subi r18, 1
|
||||
brne 1b
|
||||
3:
|
||||
sts uart_rx_mes, r20
|
||||
|
|
@ -183,3 +161,15 @@ rx_dismiss:
|
|||
sei
|
||||
9:
|
||||
ret
|
||||
|
||||
uart_full_p:
|
||||
lds r22, uart_rx_w
|
||||
andi r22, 0x20
|
||||
breq 9b
|
||||
uart_errs_p:
|
||||
lds r24, uart_rx_err
|
||||
or r24, r22
|
||||
rx_dismiss_buffer:
|
||||
sts uart_rx_err, r24
|
||||
lds r24, uart_rx_w
|
||||
rjmp rx_dismiss
|
||||
|
|
|
|||
108
sym/AT45DB081D-1.sym
Normal file
108
sym/AT45DB081D-1.sym
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
v 20140308 2
|
||||
T 1000 1600 8 10 1 1 0 4 1
|
||||
refdes=U?
|
||||
T 300 2950 8 10 0 1 0 0 1
|
||||
device=AT45DB081D
|
||||
T 1000 1050 8 10 1 1 0 4 1
|
||||
footprint=SOIC8
|
||||
T 300 3350 8 10 0 0 0 0 1
|
||||
author=bpaddock(at)csonline.net
|
||||
T 300 3550 8 10 0 0 0 0 1
|
||||
documentation=http://www.atmel.com/
|
||||
T 300 3750 8 10 0 0 0 0 1
|
||||
description=2-Megabit DataFlash
|
||||
T 300 3950 8 10 0 0 0 0 1
|
||||
numslots=0
|
||||
P 1100 2600 1100 2300 1 0 0
|
||||
{
|
||||
T 1050 2400 5 8 1 1 90 0 1
|
||||
pinnumber=6
|
||||
T 1150 2400 5 8 0 1 90 2 1
|
||||
pinseq=6
|
||||
T 1100 2250 9 8 1 1 90 6 1
|
||||
pinlabel=VCC
|
||||
T 1100 2250 5 8 0 1 90 8 1
|
||||
pintype=pwr
|
||||
}
|
||||
P 2000 1900 1700 1900 1 0 0
|
||||
{
|
||||
T 1800 1950 5 8 1 1 0 0 1
|
||||
pinnumber=4
|
||||
T 1800 1850 5 8 0 1 0 2 1
|
||||
pinseq=4
|
||||
T 1650 1900 9 8 1 1 0 6 1
|
||||
pinlabel=\_CS\_
|
||||
T 1650 1900 5 8 0 1 0 8 1
|
||||
pintype=in
|
||||
}
|
||||
P 2000 1500 1700 1500 1 0 0
|
||||
{
|
||||
T 1800 1550 5 8 1 1 0 0 1
|
||||
pinnumber=8
|
||||
T 1800 1450 5 8 0 1 0 2 1
|
||||
pinseq=8
|
||||
T 1650 1500 9 8 1 1 0 6 1
|
||||
pinlabel=SO
|
||||
T 1650 1500 5 8 0 1 0 8 1
|
||||
pintype=tri
|
||||
}
|
||||
P 0 700 300 700 1 0 0
|
||||
{
|
||||
T 200 750 5 8 1 1 0 6 1
|
||||
pinnumber=3
|
||||
T 200 650 5 8 0 1 0 8 1
|
||||
pinseq=3
|
||||
T 350 700 9 8 1 1 0 0 1
|
||||
pinlabel=\_RESET\_
|
||||
T 350 700 5 8 0 1 0 2 1
|
||||
pintype=in
|
||||
}
|
||||
P 0 1100 300 1100 1 0 0
|
||||
{
|
||||
T 200 1150 5 8 1 1 0 6 1
|
||||
pinnumber=2
|
||||
T 200 1050 5 8 0 1 0 8 1
|
||||
pinseq=2
|
||||
T 350 1100 9 8 1 1 0 0 1
|
||||
pinlabel=SCK
|
||||
T 350 1100 5 8 0 1 0 2 1
|
||||
pintype=in
|
||||
}
|
||||
P 0 1500 300 1500 1 0 0
|
||||
{
|
||||
T 200 1550 5 8 1 1 0 6 1
|
||||
pinnumber=1
|
||||
T 200 1450 5 8 0 1 0 8 1
|
||||
pinseq=1
|
||||
T 350 1500 9 8 1 1 0 0 1
|
||||
pinlabel=SI
|
||||
T 350 1500 5 8 0 1 0 2 1
|
||||
pintype=in
|
||||
}
|
||||
P 0 1900 300 1900 1 0 0
|
||||
{
|
||||
T 200 1950 5 8 1 1 0 6 1
|
||||
pinnumber=5
|
||||
T 200 1850 5 8 0 1 0 8 1
|
||||
pinseq=5
|
||||
T 350 1900 9 8 1 1 0 0 1
|
||||
pinlabel=\_WP\_
|
||||
T 350 1900 5 8 0 1 0 2 1
|
||||
pintype=in
|
||||
}
|
||||
P 1100 0 1100 300 1 0 0
|
||||
{
|
||||
T 1050 200 5 8 1 1 90 6 1
|
||||
pinnumber=7
|
||||
T 1150 200 5 8 0 1 90 8 1
|
||||
pinseq=7
|
||||
T 1100 350 9 8 1 1 90 0 1
|
||||
pinlabel=GND
|
||||
T 1100 350 5 8 0 1 90 2 1
|
||||
pintype=pwr
|
||||
}
|
||||
B 300 300 1400 2000 3 0 0 0 -1 -1 0 -1 -1 -1 -1 -1
|
||||
T 300 4200 8 10 0 0 0 0 1
|
||||
symversion=1.0
|
||||
T 1000 1350 8 10 1 1 0 4 1
|
||||
value=AT45DB161E
|
||||
56
sym/nmos-ub.sym
Normal file
56
sym/nmos-ub.sym
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
v 20111231 2
|
||||
T 600 900 5 10 0 0 0 0 1
|
||||
device=NMOS_TRANSISTOR
|
||||
T 600 1100 5 10 0 0 0 0 1
|
||||
numslots=0
|
||||
T 600 1300 5 10 0 0 0 0 1
|
||||
description=generic N channel MOS transistor (enhancement type)
|
||||
L 250 600 500 600 3 0 0 0 -1 -1
|
||||
L 250 200 500 200 3 0 0 0 -1 -1
|
||||
L 250 400 350 450 3 0 0 0 -1 -1
|
||||
L 250 400 350 350 3 0 0 0 -1 -1
|
||||
P 0 200 200 200 1 0 0
|
||||
{
|
||||
T 0 300 5 10 0 1 0 0 1
|
||||
pinnumber=1
|
||||
T 0 300 9 10 0 1 0 0 1
|
||||
pinlabel=G
|
||||
T 0 300 5 10 0 0 0 0 1
|
||||
pinseq=2
|
||||
T 0 300 5 10 0 0 0 0 1
|
||||
pintype=pas
|
||||
}
|
||||
P 500 600 500 800 1 0 1
|
||||
{
|
||||
T 300 700 5 10 0 1 0 0 1
|
||||
pinnumber=3
|
||||
T 300 700 9 10 0 1 0 0 1
|
||||
pinlabel=D
|
||||
T 300 700 5 10 0 0 0 0 1
|
||||
pinseq=1
|
||||
T 300 700 5 10 0 0 0 0 1
|
||||
pintype=pas
|
||||
}
|
||||
P 500 200 500 0 1 0 1
|
||||
{
|
||||
T 300 0 5 10 0 1 0 0 1
|
||||
pinnumber=2
|
||||
T 300 0 9 10 0 1 0 0 1
|
||||
pinlabel=S
|
||||
T 300 0 5 10 0 0 0 0 1
|
||||
pinseq=3
|
||||
T 300 0 5 10 0 0 0 0 1
|
||||
pintype=pas
|
||||
}
|
||||
T 700 600 8 10 1 1 0 0 1
|
||||
refdes=Q?
|
||||
L 250 675 250 525 3 0 0 0 -1 -1
|
||||
L 250 475 250 325 3 0 0 0 -1 -1
|
||||
L 250 275 250 125 3 0 0 0 -1 -1
|
||||
L 200 600 200 200 3 0 0 0 -1 -1
|
||||
L 250 400 400 400 3 0 0 0 -1 -1
|
||||
L 400 400 400 200 3 0 0 0 -1 -1
|
||||
T 700 400 8 10 1 1 0 0 1
|
||||
footprint=UB
|
||||
T 700 200 8 10 1 1 0 0 1
|
||||
value=2N7616UB
|
||||
36
turbo.net
36
turbo.net
|
|
@ -1,22 +1,22 @@
|
|||
LEDR R11-1 D1-2
|
||||
ADJ_RF R2-2 R1-1 U4-4
|
||||
DRAIN1 Q1-3 R36-1 R34-1
|
||||
GATE1 Q1-1 C32-2 R32-2
|
||||
LEDR R11-1 D1-1
|
||||
BYP C4-2 R13-1 U5-3
|
||||
ADJ_CC R4-2 R3-1 U5-4
|
||||
Vbat R9-2 CONN1-5 U4-1 C21-1 C20-1 B1-1 R13-2 U5-1
|
||||
Vbat CONN1-5 C20-1 B1-1 R10-1 R13-2 U5-1
|
||||
SCK U2-2 U1-13
|
||||
MISO U2-8 U1-12
|
||||
MOSI U2-1 U1-11
|
||||
Reset J1-1 R12-2 CONN1-2 U1-10
|
||||
PWM R30-1 U1-9
|
||||
Vcc U2-5 U2-3 U2-6 J1-3 R12-1 D1-2 C29-1 C26-1 C12-2 C11-2 C4-1 R10-2 R3-2 U5-5 U1-1
|
||||
TxD CONN1-3 R11-2 U1-7
|
||||
RxD CONN1-4 U1-6
|
||||
ADC_B C30-1 R9-1 C3-2 R10-2 U1-5
|
||||
LED R11-2 U1-3
|
||||
ADC_V R7-1 C2-2 R8-2 U1-2
|
||||
RF_EN U4-3 U1-8
|
||||
ADC_T R5-1 C1-2 R6-2 U1-4
|
||||
SCLK U1-13 U2-2
|
||||
MISO U1-12 U2-3
|
||||
MOSI U1-11 U2-4
|
||||
MCLK U1-9 U2-5
|
||||
Vcc J1-3 R12-1 C29-1 C28-1 C27-1 C26-1 C12-2 C11-2 C4-1 R3-2 U5-5 U1-1 U2-6
|
||||
ANTENNA CONN1-1 U3-4
|
||||
Vrf R7-2 R5-2 C25-1 C24-1 C23-1 C10-2 C22-1 R1-2 U4-5 U3-3
|
||||
TxD CONN1-3 U1-7 U3-2
|
||||
GND J1-2 C30-2 C3-1 R10-1 C2-1 R8-1 C1-1 R6-1 CONN1-6 CONN1-7 CONN1-8 CONN1-9 D1-1 C29-2 C28-2 C27-2 C26-2 C12-1 C11-1 C25-2 C24-2 C23-2 C10-1 C22-2 R2-1 U4-2 R4-1 C21-2 C20-2 B1-2 U5-2 U1-14 U2-1 U3-1 \
|
||||
BOARD-1
|
||||
AIN1 C34-2 R36-2 U1-5
|
||||
SSEL U2-4 U1-2
|
||||
AIN2 C33-2 R35-2 U1-8
|
||||
GATE R31-1 R32-1 C31-1 R30-2 U1-4
|
||||
DRAIN R33-2 R34-2 U1-3 U3-4
|
||||
DRAIN2 R35-1 R33-1 Q2-3 U3-3
|
||||
GATE2 R31-2 C30-2 Q2-1 U3-2
|
||||
GND Q1-2 C34-1 C33-1 U2-7 C30-1 Q2-2 C32-1 C31-2 J1-2 CONN1-6 CONN1-7 CONN1-8 CONN1-9 C29-2 C26-2 C12-1 C11-1 R4-1 C20-2 B1-2 U5-2 U1-14 U3-1 BOARD-1
|
||||
|
|
|
|||
BIN
turbo_sch.png
BIN
turbo_sch.png
Binary file not shown.
|
Before Width: | Height: | Size: 213 KiB After Width: | Height: | Size: 186 KiB |
Loading…
Add table
Add a link
Reference in a new issue