feat: add capture sketch, Vidor image tool and jitter analysis script
This commit is contained in:
parent
0332d8eb33
commit
d51a6c0ca8
20 changed files with 2085 additions and 0 deletions
69
tools/vidor_image.py
Normal file
69
tools/vidor_image.py
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Turn a Quartus .ttf bitstream into the app image embedded in a MKR Vidor 4000 sketch.
|
||||
|
||||
The Vidor bootloader expects the bitstream bytes bit-reversed relative to Quartus' .ttf
|
||||
output, written as a C initializer list (bitstream.h), plus a signature block (signature.h)
|
||||
describing where the image goes in the FPGA's flash. The app image slot starts at 512 KB.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
|
||||
APP_OFFSET_KB = 512
|
||||
IMAGE_TYPE_APP = 1
|
||||
|
||||
|
||||
def reverse_bits(byte: int) -> int:
|
||||
return int(f"{byte:08b}"[::-1], 2)
|
||||
|
||||
|
||||
def read_ttf(path: Path) -> bytes:
|
||||
values = (field.strip() for field in path.read_text().split(","))
|
||||
return bytes(reverse_bits(int(v)) for v in values if v)
|
||||
|
||||
|
||||
def format_initializer(data: bytes) -> str:
|
||||
lines = []
|
||||
for start in range(0, len(data), 16):
|
||||
chunk = data[start:start + 16]
|
||||
if len(chunk) == 16:
|
||||
lines.append(", ".join(f"{b:3d}" for b in chunk) + ",")
|
||||
else:
|
||||
lines.append("".join(f"{b:3d}, " for b in chunk))
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
def hex_bytes(data: bytes) -> str:
|
||||
return ", ".join(f"0x{b:02x}" for b in data) + ","
|
||||
|
||||
|
||||
def format_signature(image_text: str, length: int) -> str:
|
||||
digest = hashlib.sha256(image_text.encode()).digest()
|
||||
return "\n".join([
|
||||
"NO_BOOTLOADER,",
|
||||
hex_bytes((APP_OFFSET_KB * 1024).to_bytes(4, "little")),
|
||||
hex_bytes(length.to_bytes(4, "little")),
|
||||
hex_bytes(digest),
|
||||
hex_bytes(IMAGE_TYPE_APP.to_bytes(4, "little")),
|
||||
"0x00, 0x00, 0x00, 0x00, // force flag",
|
||||
"NO_USER_DATA,",
|
||||
]) + "\n"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("ttf", type=Path, help="Quartus .ttf bitstream")
|
||||
parser.add_argument("out_dir", type=Path, help="directory for bitstream.h and signature.h")
|
||||
args = parser.parse_args()
|
||||
|
||||
data = read_ttf(args.ttf)
|
||||
image_text = format_initializer(data)
|
||||
args.out_dir.mkdir(parents=True, exist_ok=True)
|
||||
(args.out_dir / "bitstream.h").write_text(image_text)
|
||||
(args.out_dir / "signature.h").write_text(format_signature(image_text, len(data)))
|
||||
print(f"{len(data)} bytes -> {args.out_dir}/bitstream.h, signature.h")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue