Прошивка моста BL616 для Tang Primer 25K и программатор TangProgrammer
- src/: прошивка встроенного отладчика BL616 — составное USB-устройство 1209:C0CA: DirtyJTAG v3 (WinUSB через MS OS 2.0) + CDC-ACM UART к FPGA B3/C3; UART до 20 Мбод на DMA, JTAG до 30 МГц через аппаратный SPI; - bin/: загрузчик Sipeed (0x0) и штатная прошивка 2025030317 для отката; - gui/: TangProgrammer.exe (C# WinForms, .NET Framework 4) — загрузка FPGA в SRAM и во флеш-память, копия и стирание флеш-памяти FPGA, прошивка моста; светлая и тёмная тема; - scripts/: setup, build, flash, build_gui, make_portable, а также make_release и publish_release для релизов Gitea; - fpga_test/, tests/: тестовые проекты Gowin (loopback, stream) и тесты UART на Python; - tools/openFPGALoader/: openFPGALoader 1.1.1 для Windows x64.
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
UART bridge test with fpga_test/loopback loaded into the FPGA (uart_tx = uart_rx).
|
||||
|
||||
Writes random data at several baud rates and checks that exactly the same
|
||||
bytes come back; prints the sustained full-duplex throughput.
|
||||
|
||||
python tests/uart_loopback_test.py --port COM12
|
||||
"""
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
import serial
|
||||
|
||||
BAUDS = [9600, 115200, 460800, 921600, 1000000, 2000000, 3000000, 4000000,
|
||||
5000000, 6000000, 8000000, 10000000, 12000000]
|
||||
|
||||
|
||||
def run(port, baud, nbytes, fmt):
|
||||
data = os.urandom(nbytes)
|
||||
rx = bytearray()
|
||||
bytesize, parity, stopbits = fmt
|
||||
with serial.Serial(port, baud, bytesize=bytesize, parity=parity,
|
||||
stopbits=stopbits, timeout=0.05) as s:
|
||||
if bytesize < 8:
|
||||
data = bytes(b & ((1 << bytesize) - 1) for b in data)
|
||||
time.sleep(0.05)
|
||||
s.reset_input_buffer()
|
||||
done = threading.Event()
|
||||
|
||||
def reader():
|
||||
idle_since = None
|
||||
while len(rx) < len(data):
|
||||
chunk = s.read(65536)
|
||||
if chunk:
|
||||
rx.extend(chunk)
|
||||
idle_since = None
|
||||
elif done.is_set():
|
||||
idle_since = idle_since or time.time()
|
||||
if time.time() - idle_since > 0.5:
|
||||
break
|
||||
|
||||
t = threading.Thread(target=reader)
|
||||
t0 = time.time()
|
||||
t.start()
|
||||
for i in range(0, len(data), 4096):
|
||||
s.write(data[i:i + 4096])
|
||||
s.flush()
|
||||
done.set()
|
||||
t.join(timeout=60 + nbytes * 12 / baud)
|
||||
dt = time.time() - t0
|
||||
ok = bytes(rx) == data
|
||||
first_bad = next((i for i, (a, b) in enumerate(zip(rx, data)) if a != b), None)
|
||||
return ok, len(rx), dt, first_bad
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--port', required=True)
|
||||
ap.add_argument('--bytes', type=int, default=0, help='bytes per test (default: ~1 s of data)')
|
||||
ap.add_argument('--baud', type=int, action='append', help='test only these baud rates')
|
||||
args = ap.parse_args()
|
||||
|
||||
fails = 0
|
||||
for baud in args.baud or BAUDS:
|
||||
n = args.bytes or max(4096, min(2_000_000, baud // 10))
|
||||
ok, got, dt, bad = run(args.port, baud, n, (8, serial.PARITY_NONE, serial.STOPBITS_ONE))
|
||||
rate = got / dt / 1024
|
||||
status = 'OK ' if ok else 'FAIL'
|
||||
extra = '' if ok else f' (received {got}/{n}, first mismatch at {bad})'
|
||||
print(f'{status} {baud:>9} baud 8N1 {n:>8} bytes {rate:8.1f} KiB/s{extra}', flush=True)
|
||||
fails += not ok
|
||||
|
||||
for fmt, name in [((7, serial.PARITY_EVEN, serial.STOPBITS_ONE), '7E1'),
|
||||
((8, serial.PARITY_ODD, serial.STOPBITS_TWO), '8O2')]:
|
||||
ok, got, dt, bad = run(args.port, 115200, 4096, fmt)
|
||||
print(f'{"OK " if ok else "FAIL"} 115200 baud {name}', flush=True)
|
||||
fails += not ok
|
||||
|
||||
print('ALL PASSED' if fails == 0 else f'{fails} FAILED')
|
||||
sys.exit(1 if fails else 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
FPGA -> PC stream test with fpga_test/stream loaded into the FPGA: the FPGA
|
||||
sends a byte counter at exactly 10 Mbaud (1 MB/s) from its own 50 MHz clock.
|
||||
Checks absolute baud accuracy and that no byte is lost or corrupted.
|
||||
|
||||
--switches N first reopens the port N times at other baud rates while the
|
||||
stream keeps coming (the BL616 receiver used to lock up on such changes).
|
||||
|
||||
python tests/uart_stream_test.py --port COM12 --seconds 20 --switches 10
|
||||
"""
|
||||
import argparse
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
|
||||
import serial
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--port', required=True)
|
||||
ap.add_argument('--baud', type=int, default=10_000_000)
|
||||
ap.add_argument('--seconds', type=float, default=10)
|
||||
ap.add_argument('--switches', type=int, default=0)
|
||||
args = ap.parse_args()
|
||||
|
||||
for i in range(args.switches):
|
||||
other = random.choice([9600, 115200, 921600, 3_000_000, 12_000_000])
|
||||
with serial.Serial(args.port, other, timeout=0.05) as s:
|
||||
time.sleep(random.uniform(0.02, 0.2))
|
||||
s.read(65536)
|
||||
|
||||
with serial.Serial(args.port, args.baud, timeout=0.1) as s:
|
||||
s.set_buffer_size(rx_size=1 << 20)
|
||||
time.sleep(0.3)
|
||||
s.reset_input_buffer()
|
||||
expect = None
|
||||
total = errors = 0
|
||||
t0 = time.time()
|
||||
while time.time() - t0 < args.seconds:
|
||||
buf = s.read(65536)
|
||||
for b in buf:
|
||||
if expect is not None and b != expect:
|
||||
errors += 1
|
||||
expect = (b + 1) & 0xFF
|
||||
total += len(buf)
|
||||
dt = time.time() - t0
|
||||
|
||||
rate = total / dt
|
||||
print(f'received {total} bytes in {dt:.1f} s = {rate / 1e6:.3f} MB/s '
|
||||
f'({rate * 10 / 1e6:.2f} Mbaud of 8N1 payload), sequence errors: {errors}')
|
||||
ok = errors == 0 and rate > 0.97e6 * args.baud / 10_000_000
|
||||
print('PASS' if ok else 'FAIL')
|
||||
sys.exit(0 if ok else 1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user