为tinyriscv软核串口下载编写的一个图形界面软件

tinyriscv软核是一个基于riscv指令集的cpu,作者在该cpu中加入了串口下载的功能,基于作者提供的下载脚本,编写了该图形界面,简化了一些下载的难度,软件存在很多不足,只供简单调试使用。

cpu开源地址:tinyriscv: 一个从零开始写的极简、非常易懂的RISC-V处理器核。

软件源代码:

import tkinter
from tkinter import filedialog
from tkinter import ttk
import serial.tools.list_ports
import os
import serial
top = tkinter.Tk()

file_text = None
file_get = None
com_list = None
status = None
file_status = False
file_path = ''
com_str = ''

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()

def serial_init():
    serial_com.port = com_str
    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:
        try:
            serial_com.open()
            if serial_com.is_open:
                return 0
        except:
            tkinter.messagebox.showerror(title='错误', message='请检查端口是否被占用')
            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


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 program_flash(bin_file):
    if serial_init() == 0:
        bin_file_size = os.path.getsize(bin_file)
        status.insert('end',f'bin文件大小: {bin_file_size}字节\n')
        bin_file_name = os.path.basename(bin_file)
        status.insert('end','bin文件名: \n' + bin_file_name)
        status.insert('end', '一共有%d个数据包需要发送\n' % (int(bin_file_size / 128) + 1))
        status.insert('end','发送第1个数据包\n')
        packet = [0] * FIRST_PACKET_LEN
        packet[0] = 0
        i = FILE_NAME_INDEX
        for c in bin_file_name:
            packet[i] = ord(c)
            i = i + 1
        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])
        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):
            status.insert('end','请检查是否打开串口下载模式\n')
            return
        bin_file = open(bin_file, 'rb')
        data = bin_file.read(bin_file_size)
        remain_data_len = bin_file_size
        remain_data_index = 0
        for i in range(int(bin_file_size / 128) + 1):
            status.insert('end','发送第%d个数据包\n' % (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):
                    status.insert('end','NACK1应答错误\n')
                    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):
                    status.insert('end','NACK2应答错误\n')
                    return
        bin_file.close()
        status.insert('end','下载成功\n')
    else:
        status.insert('end','串口初始化失败\n')

    serial_deinit()

def refresh_comlist(event):
    port_list = list(serial.tools.list_ports.comports())
    port_list = list(port_list)
    com_list['value'] = port_list


def pro_bin(event):
    global com_str
    com_str = com_list.get()
    com_str = com_str[0:com_str.find('-') - 1]
    if file_status and com_str != '':
        program_flash(file_path)
    else:
        tkinter.messagebox.showerror(title='错误', message='请选择文件或者端口')


def set_button(event):
    global file_status
    global  file_path
    file_path = filedialog.askopenfilename(filetypes=[('binary', '*.bin')])
    file_text.delete(0, "end")
    file_text.insert('insert', file_path)
    file_get['text'] = '文件名:' + file_path[file_path.rfind("/") + 1 : len(file_path)]
    file_status = True


def clear_status(event):
    status.delete(1.0, 'end')


def init_window():
    global file_text
    global file_get
    global com_list
    global status

    frame_file = tkinter.LabelFrame(top, text='文件', height=100, width=400)
    frame_file.pack()
    top.title('tiny risc-v串口下载工具')
    top.geometry('410x350+10+10')
    top.resizable(0, 0)
    file_label = tkinter.Label(frame_file, text='文件路径:', height=2)
    file_label.grid(row=0, column=0)
    file_text = tkinter.Entry(frame_file, width=40)
    file_text.grid(row=0, column=1)
    file_button = tkinter.Label(frame_file, text='选择文件', height=2)
    file_button.bind('<Button-1>', set_button)
    file_button.grid(row=0, column=2)
    file_get = tkinter.Label(frame_file, text='文件名:', height=2)
    file_get.grid(row=1, column=1)

    frame_com = tkinter.LabelFrame(top, text='下载', height=100, width=400)
    frame_com.pack()
    com_label = tkinter.Label(frame_com, text='端口:')
    com_label.grid(row=0, column=0)
    com_list = ttk.Combobox(frame_com, height=1, width=10)
    com_list.grid(row=0, column=1, ipadx=40, padx=60)
    com_refresh = tkinter.Label(frame_com, text='刷新端口', height=1)
    com_refresh.grid(row=0, column=2)
    com_refresh.bind('<Button-1>', refresh_comlist)
    pro_button = tkinter.Label(frame_com, text='开始下载', height=1)
    pro_button.grid(row=1, column=1)
    pro_button.bind('<Button-1>', pro_bin)

    frame_status = tkinter.LabelFrame(top, text='状态', height=100, width=400)
    frame_status.pack()
    status = tkinter.Text(frame_status, height=10)
    status.pack()
    status.config(wrap=tkinter.WORD)
    clear_button = tkinter.Label(frame_status, text='清空所有状态信息')
    clear_button.pack()
    clear_button.bind('<Button-1>', clear_status)


if __name__ == '__main__':
    init_window()
    top.mainloop()

使用方法:

下载成功截图:

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值