基于Tkinter制作简易的串口bootloader上位机

前言

最开始打算使用pyqt5制作bootloader上位机的,但是折腾开发环境太麻烦,对应的资料太多太杂,导致进展缓慢。后来在网上发现了基于tkinter的串口助手项目以及适合新手的tkinter学习网站,决定尝试使用tkinter,终于在春节的这段时间折腾出来一个简易的串口bootloader上位机。

1.测试设备

NXP官网有发布基于S32K148EVB的串口bootloader例程以及对应的应用笔记AN12218,链接如下:

但是笔者手上只有S32K144的官方开发板,所以针对AN12218的软件做了一些简单修改,适配S32K144EVB-Q100,修改后的S32K144例程会和上位机源码一起在文末分享出来。

下面简要介绍下S32K144的串口bootloader例程。

1.1 UART Bootloaer软件架构图

该串口bootloader例程采用了分层设计,整体的软件架构图如下图:

软件架构

每层的说明如下:

  • Bootloader:检查5S内是否有数据输入,超过5s没有数据或者应用程序升级完成,就跳转到应用程序。
  • Communication handling / Memory handling:处理接收的数据并写入到对应的Flash中
  • Microcontroller drivers:提供MCU的UART驱动和Flash驱动

1.2 UART Bootloader流程图

该串口bootloader例程的整体流程如下:

bootloader流程图

  1. 首先初始化需要用到的通信外设,并开启超时功能。
  2. 如果在超时时间(默认为5S)内,通信接口收到数据,就下载传输过来的APP固件。
  3. 如果超时发生或者APP固件下载完成,就将配置过的寄存器设置为复位时的状态,然后跳转到用户程序。

这个例程有一个需要注意的问题,如果上电后5s内没有收到数据,程序就会跳到一段没有代码的地址处(默认为0x2000)运行,从而跑飞。如果想要继续测试升级功能,需要手动复位下MCU。

1.3 通信数据处理

该串口bootloader例程升级的APP固件需要使用S19文件格式,并且对于S19文件的解析基本都在MCU端,上位机对S19文件的处理不多。

1.3.1 S19文件的简单介绍
  1. S19文件内容为ASCII编码,截取部分S19内容如下:

S19文件内容

  1. S19文件每行的构成如下图,以上图的hello_s32k144.srec的第一行为例,S0就是type,15是count,0000是Address,68656C6C6F5F7333326B3134342E73726563就是实际要传输的data,最后的C0是Checksum。

S19文件构成

有关S19文件的进一步介绍可以查看下图或者网上搜索,相关资料非常丰富。
S19文件解析

1.3.2 S19文件的传输方式

对于S19每行的内容,上位机按如下两种方式发送:

  • Type(S0-S9)部分数据按照字符形式发送,如S1,MCU的串口接收到的就是"S"(0x53),“1”(0x31)
  • Count/Address/Data/Checksum部分数据将字符类型转变成十六进制的数字类型进行发送,如132000,MCU的串口接收到的就是0x13,0x20,0x00

MCU端也按照如上两种方式接收。

1.3.2 接收数据之后的处理

接收到S19之后MCU的处理流程如下图:

数据处理流程

  1. MCU会预先定义一个结构体,用来存储每次收到的数据,并按照S19的格式进行存储,然后校验Checksum(CRC校验)。
  2. 如果校验成功,按照地址刷写flash,并发送ACK(0x41);如果校验失败,发送CRC错误码(0x45)。
  3. 当S19所有行的数据都发送完毕之后,跳出通信数据处理函数。

AN12218文档中关于MCU的响应码描述有误,具体参考comm.h文件中的宏定义,如下:

/* Error codes */
#define ERR_OK 	0x41
#define ERR_CRC	0x45

1.4 链接文件设置

对于bootloader以及APP工程,还需要约定各自的地址地址,防止相互干扰。S32DS因为采用的GCC编译器,所以对于工程地址的修改,只需要修改链接文件即可。

1.4.1 Bootloader设置
  1. Bootloader的代码如果放在P-flash中,链接文件保持原样。

bootloader链接文件(P-flash)

  1. Bootloader的代码如果放在D-flash中,链接文件按如下方式修改,可以按需要修改m_text段的大小。

bootloader链接文件(D-flash)

1.4.2 Application设置
  1. 应用层代码从0x00002000处开始运行,链接文件修改如下:

APP链接文件

  1. 上述配置的应用层代码只能在调试模式下查看效果,如果想要在非调试模式下查看代码效果(即制作伪APP工程),需要修改中断向量位置和flash配置区域,如下所示:

伪APP链接文件

有关下位机的功能介绍以及注意事项上文已介绍完毕,接下来介绍上位机部分。

2.上位机

2.1 参考资料

本次制作串口上位机参考的gitee上面的项目链接如下:

关于tkinter的新手学习资料,推荐如下:

2.2 Tkinter简介

Tkinter 是 Python 自带的标准库,因此无须另行安装,它支持跨平台运行,不仅可以在 Windows 平台上运行,还支持在 Linux 和 Mac 平台上运行。

Tkinter适用于有Python基础,想做个图形化界面程序,但不会C++、C#的人员快速开发一些简单的小工具。对于复杂、绚丽的图形界面程序,使用tkinter开发比较吃力。

2.3 上位机开发

2.3.1 环境准备

本次使用的python版本为3.6.6,因为要使用串口,还得安装下python serial模块,在命令行输入如下命令即可。

pip install pyserial

如果后续想打包成exe文件,还需要安装pyinstaller模块,方法同上。

2.3.2 用户界面开发

用户界面的布局如下:

主窗口放置了三个容器,其中

  • 容器1主要存放串口信息、文件选择按钮和发送按钮;
  • 容器2主要包含文件升级的情况;
  • 容器3主要存放升级进度条,升级信息情况和作者信息。

截取容器1的实现代码如下:

# a frame contains COM's information, start/stop button, and select files button/label
frame_COMinf = tk.Frame(window)
frame_COMinf.grid(row = 1, column = 1)

labelCOM = tk.Label(frame_COMinf,text="Port: ")
self.COM = tk.StringVar(value = "COM15")
ertryCOM = tk.Entry(frame_COMinf, textvariable = self.COM)
labelCOM.grid(row = 1, column = 1, padx = 5, pady = 3)
ertryCOM.grid(row = 1, column = 2, padx = 5, pady = 3)

labelBaudrate = tk.Label(frame_COMinf,text="Baudrate: ")
self.Baudrate = tk.IntVar(value = 19200)
ertryBaudrate = tk.Entry(frame_COMinf, textvariable = self.Baudrate)
labelBaudrate.grid(row = 1, column = 3, padx = 5, pady = 3)
ertryBaudrate.grid(row = 1, column = 4, padx = 5, pady = 3)

labelParity = tk.Label(frame_COMinf,text="Parity: ")
self.Parity = tk.StringVar(value ="NONE")
comboParity = ttk.Combobox(frame_COMinf, width = 17, textvariable=self.Parity)
comboParity["values"] = ("NONE","ODD","EVEN","MARK","SPACE")
comboParity["state"] = "readonly"
labelParity.grid(row = 2, column = 1, padx = 5, pady = 3)
comboParity.grid(row = 2, column = 2, padx = 5, pady = 3)

labelStopbits = tk.Label(frame_COMinf,text="Stopbits: ")
self.Stopbits = tk.StringVar(value ="1")
comboStopbits = ttk.Combobox(frame_COMinf, width = 17, textvariable=self.Stopbits)
comboStopbits["values"] = ("1","1.5","2")
comboStopbits["state"] = "readonly"
labelStopbits.grid(row = 2, column = 3, padx = 5, pady = 3)
comboStopbits.grid(row = 2, column = 4, padx = 5, pady = 3)

self.buttonSelect = tk.Button(frame_COMinf, text="Select Files", relief="raised", command=self.processButtonSelect)
self.buttonSelect.grid(row = 3, column = 1, padx = 5, pady = 3)
self.labelFile = tk.Label(frame_COMinf, anchor = "w", relief="sunken", width = 30, wraplength = 200, justify = "left")
self.labelFile.grid(row = 3, column = 2, columnspan = 2, padx = 5, pady = 3, sticky = tk.W)
self.fileName = ""
        
self.buttonSS = tk.Button(frame_COMinf, text = "Start", command = self.processButtonSS)
self.buttonSS.grid(row = 3, column = 4, padx = 5, pady = 3, sticky = tk.E)
2.3.3 串口发送实现

整个通信流程如下:

  1. 上位机和测试设备之间使用UART通信,上位机需要逐行读取S19文件并转换成字节串发送出去。
  2. 上位机将一行数据发送给测试设备之后,会收到测试设备回复的字节。如果发送的数据校验无误,测试设备回复0x41,否则回复0x45。
  3. 上位机如果收到0x45的回复,需要重复发送这一行的数据,直至收到0x41的回复。

截取串口发送的实现代码如下:

self.OutputText.insert(tk.END,"Start sending the file !\r\n")
self.progressbarSend['maximum']=len(self.str_appFile)
for appFile_line in range(len(self.str_appFile)):
    self.progressbarSend["value"] = appFile_line + 1
    strToSend = self.str_appFile[appFile_line].strip()
    self.OutputText.insert(tk.END,"The data of line "+str(appFile_line+1)+ " was sent!\r\n")
    # dispaly update
    self.OutputText.yview_moveto(1)
    bytesToSend_type = strToSend[0:2].encode(encoding='ASCII')
    self.ser.write(bytesToSend_type)
    bytesToSend_data = bytes.fromhex(strToSend[2:])
    self.ser.write(bytesToSend_data)
    time.sleep(0.05)
2.3.4 异常情况的处理

用户实际在操作上位机时,有时并不一定按开发者预想的方式进行,所以需要考虑一些异常情况并处理。

本次上位机demo主要考虑了如下几种异常情况:

  • 串口信息填写错误,导致没有可用的串口
  • 用户点击选择文件按钮之后并没有选择文件
  • 用户点击开始按钮之前没有选择文件
  • 文件传输过程中点击停止按钮会关闭串口导致WriteUART函数运行异常

截取文件选择按钮的回调函数代码如下:

def processButtonSelect(self):
    self.fileName = filedialog.askopenfilename(filetypes = [("SREC","*.srec")])
    if self.fileName != "":
        self.labelFile.config(text = self.fileName)
        appFile = open(self.fileName, mode="r")
        self.str_appFile = appFile.readlines()
        appFile.close()
    else:
        self.labelFile.config(text = "You have not selected any files!")
2.3.5 总结

上位机的整体实现思路如下面的思维导图所示:

3.升级测试

准备一块S32K144EVB-Q100的板子,烧录好串口bootloader程序,连接上电脑。接下来的操作如下GIF所示:

由于测试设备的串口bootloader代码中对每行传输的有效数据字节限制在37以内,所以如果每次传输的有效数据字节超过37也会回复0x45。

4.例程分享

此次文中提到的测试设备的程序以及上位机源码已分享到gitee,链接接如下:

  • https://gitee.com/Yingming_Cai/tkinter_-s32k144-evb_-bootloader/tree/master

如果觉得本文对您有用,,不妨给个一键三连!!!

  • 8
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Auto FAE进阶之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值