Merge remote-tracking branch 'BohdanBuinich/xvf3510-rpi5-compatibility' into fix/gpio

This commit is contained in:
j1nx 2024-02-10 10:36:48 +00:00
commit 75479afcfd
21 changed files with 290 additions and 185 deletions

View File

@ -136,6 +136,7 @@ endmenu
menu "Additional external python modules"
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-adafruit-blinka/Config.in"
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-adafruit-circuitpython-neopixel/Config.in"
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-adafruit-circuitpython-typing/Config.in"
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-adafruit-platformdetect/Config.in"
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-adafruit-pureio/Config.in"
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-adapt-parser/Config.in"
@ -173,6 +174,7 @@ menu "Additional external python modules"
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-google-auth-httplib2/Config.in"
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-google-auth/Config.in"
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-google-trans-new/Config.in"
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-gpiod/Config.in"
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-gpsdclient/Config.in"
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-gtts/Config.in"
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-gtts_token/Config.in"

View File

@ -333,3 +333,5 @@ BR2_PACKAGE_USERLAND_TOOLS=y
BR2_PACKAGE_VOCALFUSION=y
BR2_PACKAGE_WIFI_CONNECT=y
BR2_PACKAGE_PYTHON_SMBUS2=y
BR2_PACKAGE_PYTHON_ADAFRUIT_BLINKA=y
BR2_PACKAGE_PYTHON_GPIOD=y

View File

@ -333,3 +333,5 @@ BR2_PACKAGE_USERLAND_TOOLS=y
BR2_PACKAGE_VOCALFUSION=y
BR2_PACKAGE_WIFI_CONNECT=y
BR2_PACKAGE_PYTHON_SMBUS2=y
BR2_PACKAGE_PYTHON_ADAFRUIT_BLINKA=y
BR2_PACKAGE_PYTHON_GPIOD=y

View File

@ -1,11 +1,14 @@
config BR2_PACKAGE_PYTHON_ADAFRUIT_BLINKA
bool "python-adafruit-blinka"
select BR2_PACKAGE_PYTHON_ADAFRUIT_CIRCUITPYTHON_TYPING # runtime
select BR2_PACKAGE_PYTHON_ADAFRUIT_PLATFORMDETECT # runtime
select BR2_PACKAGE_PYTHON_ADAFRUIT_PUREIO # runtime
select BR2_PACKAGE_PYTHON_PYFTDI # runtime
select BR2_PACKAGE_PYTHON_ADAFRUIT_CIRCUITPYTHON_TYPING
select BR2_PACKAGE_PYTHON_ADAFRUIT_PLATFORMDETECT
select BR2_PACKAGE_PYTHON_ADAFRUIT_PUREIO
select BR2_PACKAGE_PYTHON_PYFTDI
select BR2_PACKAGE_PYTHON_RPI_GPIO
select BR2_PACKAGE_PYTHON_SYSV_IPC
select BR2_PACKAGE_PYTHON_GPIOD
help
CircuitPython APIs for non-CircuitPython versions of Python
such as CPython on Linux and MicroPython.
CircuitPython APIs for non-CircuitPython versions of Python such as
CPython on Linux and MicroPython.
https://github.com/adafruit/Adafruit_Blinka
https://pypi.org/project/Adafruit-Blinka

View File

@ -1,5 +1,5 @@
# md5, sha256 from https://pypi.org/pypi/adafruit-blinka/json
md5 b15a11eb7e0910af0d5825ed386b71d6 Adafruit-Blinka-8.6.0.tar.gz
sha256 b05f03468edc898aa07af59bafa88ca78e1b50f7d263a53e6573ace0050f64eb Adafruit-Blinka-8.6.0.tar.gz
md5 835cabd601befbe78dc64720f7efacd6 Adafruit-Blinka-8.31.0.tar.gz
sha256 720edca821066022e912dffcb364ea04bd3e3f208132b975876a21b2a2daa850 Adafruit-Blinka-8.31.0.tar.gz
# Locally computed sha256 checksums
sha256 50e0c3b5b4486be0ed420639f8a1f6f115f29101feee6bcd954a4b81db04d0f3 LICENSE

View File

@ -4,11 +4,13 @@
#
################################################################################
PYTHON_ADAFRUIT_BLINKA_VERSION = 8.6.0
PYTHON_ADAFRUIT_BLINKA_VERSION = 8.31.0
PYTHON_ADAFRUIT_BLINKA_SOURCE = Adafruit-Blinka-$(PYTHON_ADAFRUIT_BLINKA_VERSION).tar.gz
PYTHON_ADAFRUIT_BLINKA_SITE = https://files.pythonhosted.org/packages/76/29/541a6a22d923fbe0d4cf52f953a2c737370cb717f8df1cbd95ab97fe2fba
PYTHON_ADAFRUIT_BLINKA_SITE = https://files.pythonhosted.org/packages/74/ed/e51689be726338ba16f2a88373ad4690702c5ddf8668be1b0289cb279840
PYTHON_ADAFRUIT_BLINKA_SETUP_TYPE = setuptools
PYTHON_ADAFRUIT_BLINKA_LICENSE = MIT
PYTHON_ADAFRUIT_BLINKA_LICENSE_FILES = LICENSE
PYTHON_ADAFRUIT_BLINKA_BIN_ARCH_EXCLUDE = usr/lib/python$(PYTHON3_VERSION_MAJOR)/site-packages/adafruit_blinka/microcontroller/bcm283x/pulseio
PYTHON_ADAFRUIT_BLINKA_BIN_ARCH_EXCLUDE += usr/lib/python$(PYTHON3_VERSION_MAJOR)/site-packages/adafruit_blinka/microcontroller/amlogic/a311d/pulseio
$(eval $(python-package))

View File

@ -0,0 +1,6 @@
config BR2_PACKAGE_PYTHON_ADAFRUIT_CIRCUITPYTHON_TYPING
bool "python-adafruit-circuitpython-typing"
help
Types needed for type annotation that are not in `typing`
https://pypi.org/project/adafruit-circuitpython-typing

View File

@ -0,0 +1,5 @@
# md5, sha256 from https://pypi.org/pypi/adafruit-circuitpython-typing/json
md5 3ff67f52cdb0ece5df86a477b1be5572 adafruit-circuitpython-typing-1.9.6.tar.gz
sha256 dc69ed6362dcb890f7103d4da0db94b7d1849bc66804598d34508f413724d152 adafruit-circuitpython-typing-1.9.6.tar.gz
# Locally computed sha256 checksums
sha256 50e0c3b5b4486be0ed420639f8a1f6f115f29101feee6bcd954a4b81db04d0f3 LICENSE

View File

@ -0,0 +1,14 @@
################################################################################
#
# python-adafruit-circuitpython-typing
#
################################################################################
PYTHON_ADAFRUIT_CIRCUITPYTHON_TYPING_VERSION = 1.9.6
PYTHON_ADAFRUIT_CIRCUITPYTHON_TYPING_SOURCE = adafruit-circuitpython-typing-$(PYTHON_ADAFRUIT_CIRCUITPYTHON_TYPING_VERSION).tar.gz
PYTHON_ADAFRUIT_CIRCUITPYTHON_TYPING_SITE = https://files.pythonhosted.org/packages/c7/2e/acfeeed27e42cfcb0450bc4afe0746e4d8ddd5d9081b7d7cec01705149e1
PYTHON_ADAFRUIT_CIRCUITPYTHON_TYPING_SETUP_TYPE = setuptools
PYTHON_ADAFRUIT_CIRCUITPYTHON_TYPING_LICENSE = MIT
PYTHON_ADAFRUIT_CIRCUITPYTHON_TYPING_LICENSE_FILES = LICENSE LICENSES/CC-BY-4.0.txt LICENSES/MIT.txt LICENSES/Unlicense.txt
$(eval $(python-package))

View File

@ -1,5 +1,5 @@
# md5, sha256 from https://pypi.org/pypi/Adafruit-PlatformDetect/json
md5 7e7b10a48f6e6a7c650bb6bd432ec613 Adafruit-PlatformDetect-3.32.0.tar.gz
sha256 31bad17fb91c3cd61bd62fb9712902bcef5225bbeb3c078a196c6d7e2d4599a4 Adafruit-PlatformDetect-3.32.0.tar.gz
md5 4e80a7d7200a67d4528d580b16d3ca98 Adafruit-PlatformDetect-3.60.0.tar.gz
sha256 644deb113c00ba1bfba4703fcd80cab52b5638d4a1146f2d58378df4af09746f Adafruit-PlatformDetect-3.60.0.tar.gz
# Locally computed sha256 checksums
sha256 50e0c3b5b4486be0ed420639f8a1f6f115f29101feee6bcd954a4b81db04d0f3 LICENSE

View File

@ -4,9 +4,9 @@
#
################################################################################
PYTHON_ADAFRUIT_PLATFORMDETECT_VERSION = 3.32.0
PYTHON_ADAFRUIT_PLATFORMDETECT_VERSION = 3.60.0
PYTHON_ADAFRUIT_PLATFORMDETECT_SOURCE = Adafruit-PlatformDetect-$(PYTHON_ADAFRUIT_PLATFORMDETECT_VERSION).tar.gz
PYTHON_ADAFRUIT_PLATFORMDETECT_SITE = https://files.pythonhosted.org/packages/15/42/2192f64a9732878ddb39bb4359864d1398849e90f39f5591a23005e65d8e
PYTHON_ADAFRUIT_PLATFORMDETECT_SITE = https://files.pythonhosted.org/packages/e5/e3/71ba7ff4cbcecf40783613c192bd0ec6c69a70053915567a998ce41050bc
PYTHON_ADAFRUIT_PLATFORMDETECT_SETUP_TYPE = setuptools
PYTHON_ADAFRUIT_PLATFORMDETECT_LICENSE = MIT
PYTHON_ADAFRUIT_PLATFORMDETECT_LICENSE_FILES = LICENSE

View File

@ -1,5 +1,5 @@
# md5, sha256 from https://pypi.org/pypi/Adafruit-PureIO/json
md5 f7d2f93db567333321b4097b4858bea5 Adafruit_PureIO-1.1.9.tar.gz
sha256 2caf22fb07c7f771d83267f331a76cde314723f884a9570ea6f768730c87a879 Adafruit_PureIO-1.1.9.tar.gz
md5 f9ddf83f2166ce69522a25f82d1fcdf7 Adafruit_PureIO-1.1.11.tar.gz
sha256 c4cfbb365731942d1f1092a116f47dfdae0aef18c5b27f1072b5824ad5ea8c7c Adafruit_PureIO-1.1.11.tar.gz
# Locally computed sha256 checksums
sha256 aa5e54136c840ed2e333f65d43fecbc6c0e8fff62ebaece4ff281cd2a6672088 LICENSE

View File

@ -4,9 +4,9 @@
#
################################################################################
PYTHON_ADAFRUIT_PUREIO_VERSION = 1.1.9
PYTHON_ADAFRUIT_PUREIO_VERSION = 1.1.11
PYTHON_ADAFRUIT_PUREIO_SOURCE = Adafruit_PureIO-$(PYTHON_ADAFRUIT_PUREIO_VERSION).tar.gz
PYTHON_ADAFRUIT_PUREIO_SITE = https://files.pythonhosted.org/packages/df/ca/9162d4648669d12af16d5a66d808bdef6967eb684cbed9b1a3ebc19b361a
PYTHON_ADAFRUIT_PUREIO_SITE = https://files.pythonhosted.org/packages/e5/b7/f1672435116822079bbdab42163f9e6424769b7db778873d95d18c085230
PYTHON_ADAFRUIT_PUREIO_SETUP_TYPE = setuptools
PYTHON_ADAFRUIT_PUREIO_LICENSE = MIT
PYTHON_ADAFRUIT_PUREIO_LICENSE_FILES = LICENSE

View File

@ -0,0 +1,14 @@
config BR2_PACKAGE_PYTHON_GPIOD
bool "python-gpiod"
depends on !BR2_PACKAGE_LIBGPIOD
help
This is a C library that abstracts the GPIO character
device operations on linux.
https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/
This package is the continuation of the libgpiod package
for versions 2.0 and above.
Note that a kernel of 5.10 or above is required for the
ioctls to work.

View File

@ -0,0 +1,5 @@
# md5, sha256 from https://pypi.org/pypi/gpiod/json
md5 faf8736f9584a28426e4832fe22f38f4 gpiod-2.1.3.tar.gz
sha256 a33193d6cab79d252329f71666a35a3668e04f1f82bf9b93ee2c9ae852398b20 gpiod-2.1.3.tar.gz
# Locally computed sha256 checksums
sha256 50e0c3b5b4486be0ed420639f8a1f6f115f29101feee6bcd954a4b81db04d0f3 LICENSE

View File

@ -0,0 +1,13 @@
################################################################################
#
# python-gpiod
#
################################################################################
PYTHON_GPIOD_VERSION = 2.1.3
PYTHON_GPIOD_SOURCE = gpiod-$(PYTHON_GPIOD_VERSION).tar.gz
PYTHON_GPIOD_SITE = https://files.pythonhosted.org/packages/a8/56/730573fe8d03c4d32a31e7182d27317b0cef298c9170b5a2994e2248986f
PYTHON_GPIOD_SETUP_TYPE = setuptools
#PYTHON_LIBGPIOD_DEPENDENCIES = libgpiod
$(eval $(python-package))

View File

@ -1,5 +1,5 @@
# md5, sha256 from https://pypi.org/pypi/pyftdi/json
md5 d8969beb9cd11c123f1249963bf8c0d8 pyftdi-0.54.0.tar.gz
sha256 8df9af22077d17533d2f95b508b1d87959877627ea5dc2369056e90a3b5a232d pyftdi-0.54.0.tar.gz
md5 fa9feda5b80db51d538ed9b98e25504e pyftdi-0.55.0.tar.gz
sha256 a747bbbccc4eeea26cefa2c8bd3d2b8bef8c94ecb6969bb9c75a63640887519a pyftdi-0.55.0.tar.gz
# Locally computed sha256 checksums
sha256 7342c9ccf3ec21eee9a23c6c74af15fb08ac1b79ddbccb4e063ddeaa6ef7c52d pyftdi/doc/license.rst

View File

@ -4,9 +4,9 @@
#
################################################################################
PYTHON_PYFTDI_VERSION = 0.54.0
PYTHON_PYFTDI_VERSION = 0.55.0
PYTHON_PYFTDI_SOURCE = pyftdi-$(PYTHON_PYFTDI_VERSION).tar.gz
PYTHON_PYFTDI_SITE = https://files.pythonhosted.org/packages/49/a3/6cd09c0493662b285b2ba87a08b1378a5b13e5cab44eb6a3f740c801c804
PYTHON_PYFTDI_SITE = https://files.pythonhosted.org/packages/da/db/b900789a154e32dba50f132a2a76837331801f8b521b7e1bcbb852b01a35
PYTHON_PYFTDI_SETUP_TYPE = setuptools
PYTHON_PYFTDI_LICENSE = FIXME: please specify the exact BSD version
PYTHON_PYFTDI_LICENSE_FILES = pyftdi/doc/license.rst

View File

@ -1,5 +1,5 @@
# md5, sha256 from https://pypi.org/pypi/smbus2/json
md5 ea4bba25b43863aecd6ec33b2252fdae smbus2-0.4.1.tar.gz
sha256 6276eb599b76c4e74372f2582d2282f03b4398f0da16bc996608e4f21557ca9b smbus2-0.4.1.tar.gz
md5 ab83d83e9eb3bd1d0bef8d6fd64b1398 smbus2-0.4.3.tar.gz
sha256 36f2288a8e1a363cb7a7b2244ec98d880eb5a728a2494ac9c71e9de7bf6a803a smbus2-0.4.3.tar.gz
# Locally computed sha256 checksums
sha256 6ee9cf18c3a75dd76fb549a4b607ae34eedc31a796c48157895e2ad28d66ce79 LICENSE

View File

@ -4,9 +4,9 @@
#
################################################################################
PYTHON_SMBUS2_VERSION = 0.4.1
PYTHON_SMBUS2_VERSION = 0.4.3
PYTHON_SMBUS2_SOURCE = smbus2-$(PYTHON_SMBUS2_VERSION).tar.gz
PYTHON_SMBUS2_SITE = https://files.pythonhosted.org/packages/d9/33/787448c69603eec96af07d36f7ae3a7e3fce4020632eddb55152dc903233
PYTHON_SMBUS2_SITE = https://files.pythonhosted.org/packages/98/17/9663936e52a348b3ad1c85e6ca6071d2abf00a5f64f2df50bec8dcca6e16
PYTHON_SMBUS2_SETUP_TYPE = setuptools
PYTHON_SMBUS2_LICENSE = MIT
PYTHON_SMBUS2_LICENSE_FILES = LICENSE

View File

@ -3,146 +3,196 @@
# requires dtparam=spi=on in /boot/config.txt
"""
This script configures the XVF3510 board in boot from SPI slave and load a
binary file. It requires a bin file as input parameter.
This script configures the XVF3510 board to boot from SPI slave and loads a
binary file. It requires a bin file as an input parameter.
"""
import sys
import os
import time
import argparse
import spidev
import RPi.GPIO as GPIO
from smbus import SMBus
from smbus2 import SMBus
import digitalio
import busio
from pathlib import Path
import board
from typing import Optional
if sys.version[0] != '3':
print("Run this script with Python 3")
# Global variables for GPIO pins
BOOT_SEL_PIN = digitalio.DigitalInOut(board.D26) # GPIO pin used for boot selection (PIN 37)
RST_N_PIN = digitalio.DigitalInOut(board.D27) # GPIO pin used for reset (PIN 13)
I2C_ADDRESS = 0x2C # I2C address for the I/O expander. TODO: 0x20 was in original code, misstake?
if sys.version_info[0] < 3:
print("This script requires Python 3.")
sys.exit(1)
def bit_reversed_byte(byte_to_reverse):
def bit_reversed_byte(byte_to_reverse: int) -> int:
"""
Function to reverse the bit-order of a byte
Reverse the bits of a byte.
Args:
byte_to_reverse: byte to process
Retruns:
byte in reversed order
"""
return int('{:08b}'.format(byte_to_reverse)[::-1], 2)
def set_boot_sel():
"""
Function to set XVF3510 board in SPI slave boot mode
Args:
None
byte_to_reverse (int): The byte to reverse.
Returns:
None
int: The reversed byte.
"""
return int("{:08b}".format(byte_to_reverse)[::-1], 2)
bus = SMBus(1)
# reset BOOT_SEL
bus.write_byte_data(0x20, 3, 0xFE)
bus.write_byte_data(0x20, 7, 0xFF)
def set_boot_sel() -> None:
"""
Set XVF3510 board in SPI slave boot mode using I2C to manipulate BOOT_SEL pin.
"""
try:
with SMBus(1) as bus:
# Reset BOOT_SEL to default
bus.write_byte_data(I2C_ADDRESS, 3, 0xFE)
bus.write_byte_data(I2C_ADDRESS, 7, 0xFF)
state = {}
# Preserve other settings while manipulating BOOT_SEL
state = {i: bus.read_byte_data(I2C_ADDRESS, i) for i in [2, 6]}
# Start reset sequence
for i in [2, 6]:
state[i] = bus.read_byte_data(0x20, i)
# start reset
data_to_write = 0x00 | (state[2] & 0xDF)
bus.write_byte_data(0x20, 2, data_to_write)
data_to_write = 0x00 | (state[6] & 0xDF)
bus.write_byte_data(0x20, 6, data_to_write)
# set BOOT_SEL high
data_to_write = 0x01
bus.write_byte_data(0x20, 3, data_to_write)
data_to_write = 0xFE
bus.write_byte_data(0x20, 7, data_to_write)
# stop reset
data_to_write = 0x20 | (state[2] & 0xDF)
bus.write_byte_data(0x20, 2, data_to_write)
data_to_write = 0x20 | (state[6] & 0xDF)
bus.write_byte_data(0x20, 6, data_to_write)
bus.write_byte_data(I2C_ADDRESS, i, 0x00 | (state[i] & 0xDF))
# Set BOOT_SEL high
bus.write_byte_data(I2C_ADDRESS, 3, 0x01)
bus.write_byte_data(I2C_ADDRESS, 7, 0xFE)
# End reset sequence
for i in [2, 6]:
bus.write_byte_data(I2C_ADDRESS, i, 0x20 | (state[i] & 0xDF))
except Exception as e:
print(f"Error setting BOOT_SEL via I2C: {e}")
sys.exit(1)
def send_image(bin_filename, verbose=False, max_spi_speed_mhz = 5, block_transfer_pause_ms = 1, direct = False, delay = False):
def send_image(
bin_filename: str,
verbose: bool = False,
max_spi_speed_mhz: float = 5,
block_transfer_pause_ms: float = 1,
direct: bool = False,
delay: bool = False,
) -> None:
"""
Function to send the given image to the device via SPI slave
Send the given image to the device via SPI slave.
Args:
bin_filename: binary file containing the image to boot
verbose: flag to print debug printouts
direct: Use Pi GPIO outputs rather than the XVF3510 Pi HAT
delay: Release BootSel early to delay startup on version 4.0.0 onwards
Returns:
None
bin_filename (str): Binary file name.
verbose (bool, optional): Enable verbose output. Defaults to False.
max_spi_speed_mhz (float, optional): Max SPI speed in MHz. Defaults to 5.
block_transfer_pause_ms (float, optional): Pause between blocks in milliseconds. Defaults to 1.
direct (bool, optional): Direct mode flag. Defaults to False.
delay (bool, optional): Delay startup flag. Defaults to False.
"""
binary_size = Path(bin_filename).stat().st_size
print(f'Read file "{bin_filename}" size: {binary_size} Bytes')
if direct:
#setup GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
BOOT_SEL_PIN.switch_to_input()
RST_N_PIN.switch_to_output(value=True)
#boot_sel = 8
#rst_n = 10
'''
Mycroft board update
'''
#GPIO.setmode(GPIO.BCM)
boot_sel = 37 #26 #= 25 # fix these numbers to be Wiring Pi
rst_n = 13 #27 #= 2
GPIO.setup(boot_sel, GPIO.IN) # Normally, the Pi should not drive this
GPIO.setup(rst_n, GPIO.OUT, initial=GPIO.HIGH)
#setup SPI
spi = spidev.SpiDev()
bus_spi = 0
device = 0
spi.open(bus_spi, device)
#SPI Settings
spi.max_speed_hz = int(max_spi_speed_mhz * 1000000)
spi.mode = 0b00 #XMOS supports 00 or 11
spi_block_size = 4096 #Limitation in spidev and xfer2 doesn't work!
spi = setup_spi(max_spi_speed_mhz)
if direct:
GPIO.output(rst_n, 0)
GPIO.setup(boot_sel, GPIO.OUT, initial=GPIO.HIGH)
GPIO.output(rst_n, 1)
RST_N_PIN.value=False
BOOT_SEL_PIN.switch_to_output(value=True)
RST_N_PIN.value=True
else:
set_boot_sel()
# Create a table to map byte values to their bit-reversed values
reverse_table = [bit_reversed_byte(byte) for byte in range(256)]
data = []
try:
with open(bin_filename, "rb") as f:
bytes_read = f.read()
data = list(bytes_read)
binary_size = len(data)
block_count = 0
print('Read file "{0}" size: {1} Bytes'.format(args.bin_filename, binary_size))
if binary_size % spi_block_size != 0:
print("Warning - binary file not a multiple of {} - {} remainder".format( \
spi_block_size, binary_size % spi_block_size))
while binary_size > 0:
block = [reverse_table[byte] for byte in data[:spi_block_size]]
del data[:spi_block_size]
binary_size = len(data)
if verbose:
print("Sending {} Bytes in block {} checksum 0x{:X}".format( \
len(block), block_count, sum(block)))
spi.xfer(block)
data = list(f.read())
except Exception as e:
print(f"Error reading binary file: {e}")
sys.exit(1)
send_data_over_spi(data, spi, reverse_table, verbose, block_transfer_pause_ms, direct, delay)
print("Sending complete")
if direct:
# Once booted, the Pi should not need to drive boot_sel and reset
BOOT_SEL_PIN.switch_to_input()
RST_N_PIN.value=True
else:
# Reset BOOT_SEL to default state
with SMBus(1) as bus:
bus.write_byte_data(I2C_ADDRESS, 3, 0xFE)
bus.write_byte_data(I2C_ADDRESS, 7, 0xFF)
def setup_spi(max_spi_speed_mhz: float) -> busio.SPI:
"""
Set up the SPI bus.
Args:
max_spi_speed_mhz (float): Max SPI speed in MHz.
Returns:
busio.SPI: Configured SPI bus.
"""
spi = busio.SPI(board.SCLK, MOSI=board.MOSI, MISO=board.MISO)
while not spi.try_lock():
pass
spi.configure(baudrate=max_spi_speed_mhz * 1_000_000)
return spi
def send_data_over_spi(
data: list,
spi: busio.SPI,
reverse_table: list,
verbose: bool,
pause_ms: float,
direct: bool,
delay: bool,
) -> None:
"""
Send data over SPI, handling block transfers and optional delays.
Args:
data (list): Data to send.
spi (busio.SPI): Configured SPI bus.
reverse_table (list): Table of bit-reversed byte values.
verbose (bool): Enable verbose output.
pause_ms (float): Pause between blocks in milliseconds.
direct (bool): Direct mode flag.
delay (bool): Delay startup flag.
"""
spi_block_size = 4096
block_count = 0
total_data_length = len(data)
for i in range(0, total_data_length, spi_block_size):
block = [reverse_table[byte] for byte in data[i : i + spi_block_size]]
if verbose:
print(f"Sending {len(block)} Bytes in block {block_count} checksum 0x{sum(block):X}")
spi.write(block)
# Update the remaining data length after each block transfer
remaining_data_length = total_data_length - (i + len(block))
handle_block_transfer(
block_count, delay, direct, pause_ms, remaining_data_length
)
block_count += 1
def handle_block_transfer(
block_count: int, delay: bool, direct: bool, pause_ms: float, remaining_data_length: int
) -> None:
"""
Handle specifics of block transfer, including initial delays and conditional logic for direct mode.
Args:
block_count (int): Number of blocks sent.
delay (bool): Delay startup flag.
direct (bool): Direct mode flag.
pause_ms (float): Pause between blocks in milliseconds.
remaining_data_length (int): Length of remaining data to send.
"""
if block_count == 0:
# Long delay for PLL reboot
time.sleep(0.1)
@ -150,60 +200,47 @@ def send_image(bin_filename, verbose=False, max_spi_speed_mhz = 5, block_transfe
if delay:
# release boot_sel early to prevent startup
if direct:
GPIO.setup(boot_sel, GPIO.IN)
# release boot_sel early to prevent startup
BOOT_SEL_PIN.switch_to_input()
else:
#bus = smbus.SMBus(1)
bus = SMBus(1)
data_to_write = 0xFE
bus.write_byte_data(0x20, 3, data_to_write)
data_to_write = 0xFF
bus.write_byte_data(0x20, 7, data_to_write)
elif binary_size > 0:
time.sleep(block_transfer_pause_ms / 1000)
block_count += 1
print("Sending complete")
if direct:
GPIO.setup(boot_sel, GPIO.IN) # Once booted, the Pi should not need to drive boot_sel
GPIO.setup(rst_n, GPIO.OUT, initial=GPIO.HIGH) # Once booted, the Pi should not need to drive reset
#GPIO.cleanup()
else:
#bus = smbus.SMBus(1)
bus = SMBus(1)
# reset BOOT_SEL
data_to_write = 0xFE
bus.write_byte_data(0x20, 3, data_to_write)
data_to_write = 0xFF
bus.write_byte_data(0x20, 7, data_to_write)
# Reset BOOT_SEL to default state
with SMBus(1) as bus:
bus.write_byte_data(I2C_ADDRESS, 3, 0xFE)
bus.write_byte_data(I2C_ADDRESS, 7, 0xFF)
elif remaining_data_length > 0:
time.sleep(pause_ms / 1000)
if __name__ == "__main__":
start_time = time.time()
parser = argparse.ArgumentParser(description='Load an image via SPI slave from an RPi')
parser.add_argument('bin_filename', help='binary file name')
parser.add_argument('--direct', action='store_true', \
help='Use just direct GPIO outputs rather than using the XVF3510 Development Kit Pi HAT')
parser.add_argument('--delay', action='store_true', \
help='Delay xvf3510 device start. Release the BootSel pin early to prevent the XVF3510 (V4.0.0 onwards) from starting with the default I2S configuration. This gives AP a chance to configure and start the XVF3510 device.')
parser.add_argument('--max-spi-speed-mhz', type=float, default=5, \
help='Max SPI speed in MHz')
parser.add_argument('--block-transfer-pause-ms', type=float, default=1, \
help='pause between SPI transfers in milliseconds, default 1ms')
parser.add_argument('--verbose', action='store_true', \
help='print debug information')
parser = argparse.ArgumentParser(description="Load an image via SPI slave from an RPi")
parser.add_argument("bin_filename", help="binary file name")
parser.add_argument("--direct", action="store_true", help="Use direct GPIO outputs rather than the XVF3510 Development Kit Pi HAT")
parser.add_argument("--delay", action="store_true", help="Delay xvf3510 device start")
parser.add_argument("--max-spi-speed-mhz", type=float, default=5, help="Max SPI speed in MHz")
parser.add_argument("--block-transfer-pause-ms", type=float, default=1, help="Pause between SPI transfers in milliseconds")
parser.add_argument("--verbose", action="store_true", help="Print debug information")
args = parser.parse_args()
if not Path(args.bin_filename).is_file():
print("Error: input file {} not found".format(args.bin_filename))
exit(1)
send_image(args.bin_filename, args.verbose, args.max_spi_speed_mhz, args.block_transfer_pause_ms, args.direct, args.delay)
bin_path = Path(args.bin_filename)
if not bin_path.is_file():
print(f"Error: input file {bin_path} not found")
sys.exit(1)
start_time = time.time()
send_image(
bin_path,
args.verbose,
args.max_spi_speed_mhz,
args.block_transfer_pause_ms,
args.direct,
args.delay,
)
end_time = time.time()
BOOT_SEL_PIN.deinit()
RST_N_PIN.deinit()
if args.verbose:
print("Sending image took {:.3} seconds".format(end_time - start_time))
print(f"Sending image took {end_time - start_time:.3f} seconds")