diff --git a/buildroot-external/package/xvf3510/app_xvf3510_int_spi_boot_v4_1_0.bin b/buildroot-external/package/xvf3510/app_xvf3510_int_spi_boot_v4_1_0.bin new file mode 100644 index 00000000..7a9ef5f6 Binary files /dev/null and b/buildroot-external/package/xvf3510/app_xvf3510_int_spi_boot_v4_1_0.bin differ diff --git a/buildroot-external/package/xvf3510/xvf3510-flash b/buildroot-external/package/xvf3510/xvf3510-flash new file mode 100755 index 00000000..11e79f09 --- /dev/null +++ b/buildroot-external/package/xvf3510/xvf3510-flash @@ -0,0 +1,209 @@ +#!/usr/bin/env python3 +# Copyright (c) 2019-2020, XMOS Ltd, All rights reserved +# 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. +""" + +import sys +import os +import time +import argparse +import spidev +import RPi.GPIO as GPIO +from smbus import SMBus +from pathlib import Path + +if sys.version[0] != '3': + print("Run this script with Python 3") + sys.exit(1) + +def bit_reversed_byte(byte_to_reverse): + """ + Function to reverse the bit-order 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 + + Returns: + None + """ + + bus = SMBus(1) + + # reset BOOT_SEL + bus.write_byte_data(0x20, 3, 0xFE) + bus.write_byte_data(0x20, 7, 0xFF) + + state = {} + 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) + + + +def send_image(bin_filename, verbose=False, max_spi_speed_mhz = 5, block_transfer_pause_ms = 1, direct = False, delay = False): + """ + Function to 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 + """ + + if direct: + #setup GPIO + GPIO.setmode(GPIO.BOARD) + GPIO.setwarnings(False) + + #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! + + if direct: + GPIO.output(rst_n, 0) + GPIO.setup(boot_sel, GPIO.OUT, initial=GPIO.HIGH) + GPIO.output(rst_n, 1) + 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 = [] + 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) + + if block_count == 0: + #Long delay for PLL reboot + time.sleep(0.1) + + if delay: + # release boot_sel early to prevent startup + if direct: + GPIO.setup(boot_sel, GPIO.IN) + 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) + + + + +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') + + 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) + + end_time = time.time() + if args.verbose: + print("Sending image took {:.3} seconds".format(end_time - start_time)) diff --git a/buildroot-external/package/xvf3510/xvf3510-start b/buildroot-external/package/xvf3510/xvf3510-start new file mode 100755 index 00000000..9e2d1625 --- /dev/null +++ b/buildroot-external/package/xvf3510/xvf3510-start @@ -0,0 +1,20 @@ +#! /usr/bin/env sh + +modprobe i2s_master_loader + +setup_bclk +setup_mclk + +# Startup xvf3510 +XMOS_POWER=16 +XMOS_RESET=27 +gpio -g mode $XMOS_POWER out +gpio -g mode $XMOS_RESET out +sleep 0.1 +gpio -g write $XMOS_POWER 1 +gpio -g write $XMOS_RESET 1 + +sleep 1 +xvf3510-flash --direct "/usr/lib/firmware/xvf3510/app_xvf3510_int_spi_boot_v4_1_0.bin" +sleep 1 +i2cdetect -y 1 diff --git a/buildroot-external/package/xvf3510/xvf3510-stop b/buildroot-external/package/xvf3510/xvf3510-stop new file mode 100755 index 00000000..e3cb6f70 --- /dev/null +++ b/buildroot-external/package/xvf3510/xvf3510-stop @@ -0,0 +1,25 @@ +#!/bin/bash + +function set_all_leds() { + B=$1 + + i2cset -y 1 0x04 10 $B $B $B 9 $B $B $B 8 $B $B $B i + sleep 0.1 + i2cset -y 1 0x04 7 $B $B $B 6 $B $B $B 5 $B $B $B i + sleep 0.1 + i2cset -y 1 0x04 4 $B $B $B 3 $B $B $B 2 $B $B $B i + sleep 0.1 + i2cset -y 1 0x04 1 $B $B $B 0 $B $B $B i +} + +set_all_leds 127 +sleep 0.7 +set_all_leds 0 +sleep 0.7 +set_all_leds 63 +sleep 0.7 +set_all_leds 0 +sleep 0.7 +set_all_leds 31 +sleep 0.7 +set_all_leds 0 diff --git a/buildroot-external/package/xvf3510/xvf3510.mk b/buildroot-external/package/xvf3510/xvf3510.mk index 8a069ffc..bc04d571 100644 --- a/buildroot-external/package/xvf3510/xvf3510.mk +++ b/buildroot-external/package/xvf3510/xvf3510.mk @@ -25,9 +25,23 @@ endef define XVF3510_INSTALL_TARGET_CMDS $(INSTALL) -D -m 0755 $(@D)/resources/clk_dac_setup/setup_bclk \ - $(TARGET_DIR)/usr/bin + $(TARGET_DIR)/usr/sbin $(INSTALL) -D -m 0755 $(@D)/resources/clk_dac_setup/setup_mclk \ - $(TARGET_DIR)/usr/bin + $(TARGET_DIR)/usr/sbin + + $(INSTALL) -D -m 0644 $(BR2_EXTERNAL_OPENVOICEOS_PATH)/package/xvf3510/xvf3510.service \ + $(TARGET_DIR)/usr/lib/systemd/system/xvf3510.service + + $(INSTALL) -D -m 755 $(BR2_EXTERNAL_OPENVOICEOS_PATH)/package/xvf3510/xvf3510-start \ + $(TARGET_DIR)/usr/sbin/xvf3510-start + $(INSTALL) -D -m 755 $(BR2_EXTERNAL_OPENVOICEOS_PATH)/package/xvf3510/xvf3510-stop \ + $(TARGET_DIR)/usr/sbin/xvf3510-stop + $(INSTALL) -D -m 755 $(BR2_EXTERNAL_OPENVOICEOS_PATH)/package/xvf3510/xvf3510-flash \ + $(TARGET_DIR)/usr/sbin/xvf3510-flash + + mkdir -p $(TARGET_DIR)/usr/lib/firmware/xvf3510 + $(INSTALL) -D -m 0644 $(BR2_EXTERNAL_OPENVOICEOS_PATH)/package/xvf3510/app_xvf3510_int_spi_boot_v4_1_0.bin \ + $(TARGET_DIR)/usr/lib/firmware/xvf3510/app_xvf3510_int_spi_boot_v4_1_0.bin endef $(eval $(generic-package)) diff --git a/buildroot-external/package/xvf3510/xvf3510.service b/buildroot-external/package/xvf3510/xvf3510.service new file mode 100644 index 00000000..459a0efb --- /dev/null +++ b/buildroot-external/package/xvf3510/xvf3510.service @@ -0,0 +1,13 @@ +[Unit] +Description=Setup audio environment for xvf3510 +After=systemd-modules-load.service +Requires=systemd-modules-load.service + +[Service] +Type=oneshot +ExecStart=xvf3510-start +ExecStop=xvf3510-stop +RemainAfterExit=True + +[Install] +WantedBy=multi-user.target