From ab185de7f5dcdb7701cf944076a3c6e3372c0a26 Mon Sep 17 00:00:00 2001 From: liangkangnan Date: Sat, 4 Jul 2020 14:36:02 +0800 Subject: [PATCH] tools: add uart download script Signed-off-by: liangkangnan --- tools/tinyriscv_fw_downloader.py | 215 +++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 tools/tinyriscv_fw_downloader.py diff --git a/tools/tinyriscv_fw_downloader.py b/tools/tinyriscv_fw_downloader.py new file mode 100644 index 0000000..63d06cd --- /dev/null +++ b/tools/tinyriscv_fw_downloader.py @@ -0,0 +1,215 @@ +''' + Copyright 2020 Blue Liang, liangkangnan@163.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +''' + +import os +import sys + +import serial +#import serial.tools.list_ports + +''' +通过串口下载固件到FPGA开发板,FPGA收到数据后将数据烧写到ROM(Flash)。 +有两种包类型:包0和其他包。包0用来传输文件名和文件大小,其他包用来传输文件内容。 +每个包的大小固定为131个字节(1字节包号+128字节数据+2字节CRC)。 +''' + +# 包0格式 +# number:0,包序号 +# data[0] ~ data[59]:文件名 +# data[60] ~ data[63]:文件大小(字节),其中data[60]为MSB +# crc[0]:crc低字节,crc[1]:crc高字节 +''' + 0 1 2 ... 128 129 130 +|-------------------------------------------------------------------| +| number | data[0] | data[1] | ... | data[127] | crc[0] | crc[1] | +|-------------------------------------------------------------------| +''' + +# 包1 ~ n格式 +# number:包序号 +# data[0]~data[127]:文件内容 +# crc[0]:crc低字节,crc[1]:crc高字节 +''' + 0 1 2 ... 128 129 130 +|-------------------------------------------------------------------| +| number | data[0] | data[1] | ... | data[127] | crc[0] | crc[1] | +|-------------------------------------------------------------------| +''' + + +ACK = bytes([0x6]) +FIRST_PACKET_LEN = 131 +FILE_NAME_INDEX = 1 +FILE_SIZE_INDEX = 61 +FIRST_PACKET_CRC0_INDEX = 129 +FIRST_PACKET_CRC1_INDEX = 130 +OTHER_PACKET_LEN = 131 + + +serial_com = serial.Serial() + + +# 串口初始化 +# 串口参数:115200, 8 N 1 +def serial_init(): + serial_com.port = sys.argv[1] + serial_com.baudrate = 115200 + serial_com.bytesize = serial.EIGHTBITS + serial_com.parity = serial.PARITY_NONE + serial_com.stopbits = serial.STOPBITS_ONE + serial_com.xonxoff = False + serial_com.rtscts = False + serial_com.dsrdtr = False + + if serial_com.is_open == False: + serial_com.open() + if serial_com.is_open: + return 0 + else: + return -1 + +def serial_deinit(): + if serial_com.is_open == True: + serial_com.close() + +# 串口写数据 +def serial_write(b): + if serial_com.is_open == True: + serial_com.write(b) + return len(b) + else: + return 0 + +# 串口读数据 +def serial_read(length, timeout): + if (timeout > 0): + serial_com.timeout = timeout + + if serial_com.is_open == True: + data = serial_com.read(length) + if len(data) > 0: + return data + else: + return -1 + else: + return -1 + +# CRC计算 +def calc_crc16(data): + crc = 0xFFFF + for pos in data: + crc ^= pos + for i in range(8): + if ((crc & 1) != 0): + crc >>= 1 + crc ^= 0xA001 + else: + crc >>= 1 + return crc + +# 主函数 +def main(): + if serial_init() == 0: + bin_file_size = os.path.getsize(sys.argv[2]) + print('bin file size: %d bytes' % bin_file_size) + bin_file_name = os.path.basename(sys.argv[2]) + print('bin file name: ' + bin_file_name) + print('Total %d packets to be sent' % (int(bin_file_size / 128) + 1)) + + ############### 第一个包 ############### + print('send #0 packet') + packet = [0] * FIRST_PACKET_LEN + # 1.包号 + packet[0] = 0 + i = FILE_NAME_INDEX + # 2.文件名 + for c in bin_file_name: + packet[i] = ord(c) + i = i + 1 + # 3.文件大小 + packet[FILE_SIZE_INDEX] = (bin_file_size >> 24) & 0xff + packet[FILE_SIZE_INDEX + 1] = (bin_file_size >> 16) & 0xff + packet[FILE_SIZE_INDEX + 2] = (bin_file_size >> 8) & 0xff + packet[FILE_SIZE_INDEX + 3] = (bin_file_size >> 0) & 0xff + crc = calc_crc16(packet[1:129]) + # 4.CRC + packet[FIRST_PACKET_CRC0_INDEX] = (crc >> 0) & 0xff + packet[FIRST_PACKET_CRC1_INDEX] = (crc >> 8) & 0xff + + #print(packet) + # 5.发送 + serial_write(bytes(packet)) + # 6.读应答 + ack = serial_read(1, 3) + if (ack != ACK): + print('packet0 NACK from slave') + return + + ############### 剩余包 ############### + bin_file = open(sys.argv[2], 'rb') + data = bin_file.read(bin_file_size) + remain_data_len = bin_file_size + remain_data_index = 0 + # 文件有多少个128字节 + for i in range(int(bin_file_size / 128) + 1): + print('send #%d packet' % (i + 1)) + packet = [0] * OTHER_PACKET_LEN + packet[0] = i + 1 + j = 1 + k = remain_data_index + if (remain_data_len >= 128): + for r in range(128): + packet[j] = data[k] + j = j + 1 + k = k + 1 + crc = calc_crc16(packet[1:129]) + packet[FIRST_PACKET_CRC0_INDEX] = (crc >> 0) & 0xff + packet[FIRST_PACKET_CRC1_INDEX] = (crc >> 8) & 0xff + serial_write(bytes(packet)) + ack = serial_read(1, 3) + if (ack != ACK): + print('NACK1 from slave') + return + remain_data_len = remain_data_len - 128 + remain_data_index = remain_data_index + 128 + else: + for r in range(remain_data_len): + packet[j] = data[k] + j = j + 1 + k = k + 1 + crc = calc_crc16(packet[1:129]) + packet[FIRST_PACKET_CRC0_INDEX] = (crc >> 0) & 0xff + packet[FIRST_PACKET_CRC1_INDEX] = (crc >> 8) & 0xff + serial_write(bytes(packet)) + ack = serial_read(1, 3) + if (ack != ACK): + print('NACK2 from slave') + return + + bin_file.close() + + print('Send successfully...') + else: + print('!!! serial init failed !!!') + + serial_deinit() + +# 程序入口 +if __name__ == "__main__": + if (len(sys.argv) != 3): + print('Usage: python ' + sys.argv[0] + ' COMx ' + 'bin_file') + else: + main()