aboutsummaryrefslogtreecommitdiff
path: root/projects
diff options
context:
space:
mode:
authorFredrik Thulin <fredrik@thulin.net>2016-05-18 21:14:52 +0200
committerFredrik Thulin <fredrik@thulin.net>2016-05-18 21:14:52 +0200
commit523d1f66453e9b92835ecc661085e4575426e661 (patch)
tree008ff6e22deeecbcb6fc9571db1fd7ecce306ea1 /projects
parent5e32bc524c4987cfe33cccdb544e3f8d66802895 (diff)
Add FPGA bitstream upload command to cli-test.
This code needs more error checking etc. but together with the Python script 'filetransfer', a new bitstream may be loaded into the FPGA config memory like this: filetransfer --fpga /path/to/bitstream The bitstream is identified by 'file' e.g. like this: alpha_test_top.bit: Xilinx BIT data - from alpha_test_top.ncd;UserID=0xFFFFFFFF - for 7a200tfbg484 - built 2016/05/12(13:59:24) - data length 0xe0164
Diffstat (limited to 'projects')
-rw-r--r--projects/cli-test/cli-test.c92
-rwxr-xr-xprojects/cli-test/filetransfer126
2 files changed, 189 insertions, 29 deletions
diff --git a/projects/cli-test/cli-test.c b/projects/cli-test/cli-test.c
index 6102d32..922fcba 100644
--- a/projects/cli-test/cli-test.c
+++ b/projects/cli-test/cli-test.c
@@ -35,6 +35,7 @@
#include "stm-init.h"
#include "stm-led.h"
#include "stm-uart.h"
+#include "stm-fpgacfg.h"
#include "mgmt-cli.h"
#include <string.h>
@@ -56,15 +57,65 @@ int cmd_show_cpuspeed(struct cli_def *cli, const char *command, char *argv[], in
int cmd_filetransfer(struct cli_def *cli, const char *command, char *argv[], int argc)
{
+ uint32_t filesize = 0, crc = 0, my_crc = 0, n = 256, counter = 0;
+ uint8_t buf[256];
+
+ cli_print(cli, "OK, write file size (4 bytes), data in %li byte chunks, CRC-32 (4 bytes)", n);
+
+ uart_receive_bytes(STM_UART_MGMT, (void *) &filesize, 4, 1000);
+ cli_print(cli, "File size %li", filesize);
+
+ while (filesize) {
+ if (filesize < n) {
+ n = filesize;
+ }
+
+ if (uart_receive_bytes(STM_UART_MGMT, (void *) &buf, n, 1000) != HAL_OK) {
+ cli_print(cli, "Receive timed out");
+ return CLI_ERROR;
+ }
+ filesize -= n;
+ my_crc = update_crc(my_crc, buf, n);
+ counter++;
+ uart_send_bytes(STM_UART_MGMT, (void *) &counter, 4);
+ }
+
+ cli_print(cli, "Send CRC-32");
+ uart_receive_bytes(STM_UART_MGMT, (void *) &crc, 4, 1000);
+ cli_print(cli, "CRC-32 %li", crc);
+ if (crc == my_crc) {
+ cli_print(cli, "CRC checksum MATCHED");
+ } else {
+ cli_print(cli, "CRC checksum did NOT match");
+ }
+
+ return CLI_OK;
+}
+
+int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
uint32_t filesize = 0, crc = 0, my_crc = 0, n = 4096, counter = 0;
uint8_t buf[4096];
- cli_print(cli, "OK, write file size (4 bytes), data in 4096 byte chunks, CRC-32 (4 bytes)");
+ fpgacfg_give_access_to_stm32();
+
+ cli_print(cli, "Checking if FPGA config memory is accessible");
+ if (n25q128_check_id() != 1) {
+ cli_print(cli, "ERROR: FPGA config memory not accessible. Check that jumpers JP7 and JP8 are installed.");
+ return CLI_ERROR;
+ }
+
+ cli_print(cli, "OK, write FPGA bitstream file size (4 bytes), data in 4096 byte chunks, CRC-32 (4 bytes)");
uart_receive_bytes(STM_UART_MGMT, (void *) &filesize, 4, 1000);
cli_print(cli, "File size %li", filesize);
while (filesize) {
+ uint32_t page, offset;
+ uint8_t *ptr;
+
+ memset(buf, 0xff, 4096);
+
if (filesize < n) {
n = filesize;
}
@@ -75,6 +126,33 @@ int cmd_filetransfer(struct cli_def *cli, const char *command, char *argv[], int
}
filesize -= n;
my_crc = update_crc(my_crc, buf, n);
+
+ if ((counter % (N25Q128_SECTOR_SIZE / 4096)) == 0) {
+ /* first page in sector, need to erase sector */
+ offset = (counter * 4096) / N25Q128_SECTOR_SIZE;
+ if (! n25q128_erase_sector(offset)) {
+ cli_print(cli, "Failed erasing sector at offset %li (counter = %li)", offset, counter);
+ return CLI_ERROR;
+ }
+ /* XXX add timeout and check for < 0 */
+ while (n25q128_get_wip_flag()) { HAL_Delay(10); };
+ }
+
+ ptr = buf;
+ for (page = 0; page < 4096 / N25Q128_PAGE_SIZE; page++) {
+ offset = counter * (4096 / N25Q128_PAGE_SIZE) + page;
+ if (! n25q128_write_page(offset, ptr)) {
+ cli_print(cli, "Failed writing page %li at offset %li (counter = %li)", page, offset, counter);
+ return CLI_ERROR;
+ }
+ ptr += N25Q128_PAGE_SIZE;
+
+ /* XXX add timeout and check for < 0 */
+ while (n25q128_get_wip_flag()) { HAL_Delay(10); };
+
+ /* XXX read back data and verify it */
+ }
+
counter++;
uart_send_bytes(STM_UART_MGMT, (void *) &counter, 4);
}
@@ -88,6 +166,8 @@ int cmd_filetransfer(struct cli_def *cli, const char *command, char *argv[], int
cli_print(cli, "CRC checksum did NOT match");
}
+ fpgacfg_give_access_to_fpga();
+
return CLI_OK;
}
@@ -119,6 +199,12 @@ main()
struct cli_command cmd_filetransfer_s = {(char *) "filetransfer", cmd_filetransfer, 0,
(char *) "Test file transfering",
PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL};
+
+ struct cli_command cmd_fpga_s = {(char *) "fpga", NULL, 0, NULL, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL};
+ struct cli_command cmd_fpga_bitstream_s = {(char *) "bitstream", NULL, 0, NULL, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL};
+ struct cli_command cmd_fpga_bitstream_upload_s = {(char *) "upload", cmd_fpga_bitstream_upload, 0,
+ (char *) "Upload new FPGA bitstream",
+ PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL};
struct cli_command cmd_reboot_s = {(char *) "reboot", cmd_reboot, 0,
(char *) "Reboot the STM32",
PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL};
@@ -136,6 +222,10 @@ main()
cli_register_command2(&cli, &cmd_filetransfer_s, NULL);
+ cli_register_command2(&cli, &cmd_fpga_s, NULL);
+ cli_register_command2(&cli, &cmd_fpga_bitstream_s, &cmd_fpga_s);
+ cli_register_command2(&cli, &cmd_fpga_bitstream_upload_s, &cmd_fpga_bitstream_s);
+
cli_register_command2(&cli, &cmd_reboot_s, NULL);
led_off(LED_RED);
diff --git a/projects/cli-test/filetransfer b/projects/cli-test/filetransfer
index 674a7f1..2b74570 100755
--- a/projects/cli-test/filetransfer
+++ b/projects/cli-test/filetransfer
@@ -1,13 +1,74 @@
#!/usr/bin/python
-
+#
+# Copyright (c) 2016, NORDUnet A/S All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# - Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# - Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# - Neither the name of the NORDUnet nor the names of its contributors may
+# be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+Utility to test file upload (or FPGA bitstream upload.
+"""
import os
import sys
import time
import struct
import serial
+import argparse
from binascii import crc32
+CHUNK_SIZE = 256
+FPGA_CHUNK_SIZE = 4096
+
+
+def parse_args():
+ """
+ Parse the command line arguments
+ """
+ parser = argparse.ArgumentParser(description = "File uploader",
+ add_help = True,
+ formatter_class = argparse.ArgumentDefaultsHelpFormatter,
+ )
+
+ parser.add_argument('--fpga',
+ dest='fpga',
+ action='store_true', default=False,
+ help='Perform FPGA bitstream upload',
+ )
+
+ parser.add_argument('--device',
+ dest='device',
+ default='/dev/ttyUSB0',
+ help='Name of management port USB serial device',
+ )
+
+ # positional argument(s)
+ parser.add_argument('filename')
+
+ return parser.parse_args()
+
def _write(dst, data):
for i in range(len(data)):
@@ -46,41 +107,45 @@ def _execute(dst, cmd):
response = _read(dst)
return response
-def send_file(filename, device='/dev/ttyUSB0', initiate=True):
+def send_file(filename, args, dst):
s = os.stat(filename)
size = s.st_size
src = open(filename, 'rb')
-
- dst = serial.Serial(device, 921600, timeout=0.1)
-
- if initiate:
+ if args.fpga:
+ # Skip header in FPGA bitstream file
+ size -= 0x64
+ src.read(0x64)
+ chunk_size = FPGA_CHUNK_SIZE
+ response = _execute(dst, 'fpga bitstream upload')
+ else:
+ chunk_size = CHUNK_SIZE
response = _execute(dst, 'filetransfer')
- if 'OK' not in response:
- sys.stderr.write('Device did not accept the filetransfer command (got {!r})\n'.format(response))
- return False
+ if 'OK' not in response:
+ sys.stderr.write('Device did not accept the upload command (got {!r})\n'.format(response))
+ return False
+ crc = 0
+ counter = 0
# 1. Write size of file (4 bytes)
_write(dst, struct.pack('<I', size))
_read(dst)
# 2. Write file contents while calculating CRC-32
- crc = 0
- counter = 0
while True:
- data = src.read(4096)
+ data = src.read(chunk_size)
if not data:
break
dst.write(data)
- print("Wrote {!s} bytes".format(len(data)))
+ print("Wrote {!s} bytes (chunk {!s}/{!s})".format(len(data), counter, int(size / chunk_size)))
# read ACK (a counter of number of 4k chunks received)
while True:
- ack = dst.read(4)
- if len(ack) == 4:
+ ack_bytes = dst.read(4)
+ if len(ack_bytes) == 4:
break
- print('ERROR: Did not receive an ACK, got {!r}'.format(ack))
- dst.write('\r')
- new_counter = struct.unpack('<I', ack)[0]
- if new_counter != counter + 1:
- print('ERROR: Did not receive the expected counter as ACK (got {!r}/{!r}, not {!r})'.format(new_counter, ack, counter))
+ print('ERROR: Did not receive an ACK, got {!r}'.format(ack_bytes))
+ dst.write('\r') # eventually get back to the CLI prompt
+ ack = struct.unpack('<I', ack_bytes)[0]
+ if ack != counter + 1:
+ print('ERROR: Did not receive the expected counter as ACK (got {!r}/{!r}, not {!r})'.format(ack, ack_bytes, counter))
flush = dst.read(100)
print('FLUSH data: {!r}'.format(flush))
return False
@@ -95,16 +160,21 @@ def send_file(filename, device='/dev/ttyUSB0', initiate=True):
_read(dst)
src.close()
- dst.close()
return True
-if len(sys.argv) != 2:
- sys.stderr.write('Syntax: {!s} filename\n'.format(sys.argv[0]))
- sys.exit(1)
-
-if send_file(sys.argv[1]):
- sys.exit(0)
+def main(args):
+ dst = serial.Serial(args.device, 921600, timeout=2)
+ send_file(args.filename, args, dst)
+ dst.close()
+ return True
-sys.exit(1)
+if __name__ == '__main__':
+ try:
+ args = parse_args()
+ if main(args):
+ sys.exit(0)
+ sys.exit(1)
+ except KeyboardInterrupt:
+ pass