对于恩智浦的MCU来讲,目前官方用的blhost固件更新工具是命令行版的上位机。在工程师实际应用的过程中,有些朋友可能会觉得命令行版本的上位机不符合个人的使用习惯或者不好发布给自己的终端用户,我们需要的是一个简单易用的GUI版本的上位机。这里给大家安利一个利用python和QT5的组件PySide2使用python脚本快速调用blhost.exe实现简单上位机操作的方法,最后会有打包成exe文件方便发布给终端客户的。
建立开发环境
在使用python开发前,我个人是用Anaconda3和文本编辑器开发的,所以推荐先安装Anaconda3
,文本编辑器推荐使用Sublime
安装好开发环境后,进入python的执行环境
安装插件
安装PySide2
使用pip wheel为Python包安装Qt。从CMD运行以下命令进行安装:
pip install PySide2
或者:
pip install --index-url=http://download.qt.io/snapshots/ci/pyside/5.12/latest pyside2 --trusted-host download.qt.io
个人推荐国内的客户用第二种安装方法,第一种我经常安装超时。
安装QT5的开发工具Designer
pip install PyQt5-tools
或者:
pip install PyQt5-tools -i http://pypi.douban.com/simple --trusted-host=pypi.douban.com
安装打包exe的工具pyinstaller
pip install pyinstaller
如果你要开发基于串口的升级工具,还需要安装pyserial
pip install pyserial
这篇文章会以USB HID接口升级为主,串口玩法暂且不表
使用QT Designer设计UI
利用Everything工具搜索到QtDesigner
一般来将通过Windows搜索QtDesigner比较麻烦,建议安装Everything
在Everything里搜索designer.exe,找到anaconda3\Lib\site-packages\pyqt5_tools\Qt\bin下的designer.exe并运行。
创建界面
选择QVGA landscape(320x240)然后点击Create按钮,创建一个新的界面
添加按键和对话框
为新的界面添加3个按键Push Button以及2个对话框Text Browser
修改2个对话框的Object名字为Text_Path/Text_Result
Text_Path会用来显示烧录目标HEX文件的路径
Text_Reset会用来提示连接的状态和烧录的结果
修改3个按键的Object名字为But_Conn/But_Open/But_Prog
But_Conn按键用来测试是否与ISP状态的MCU连接正常
But_Open按键用来打开要烧录的HEX文件
But_Prog按键用来烧录But_Open选择的HEX文件
再修改3个按键的名字为Connect?/OpenBinary/Programm
设定好后保存UI界面
将UI文件转换成python脚本
在Anaconda3的命令行界面里进入UI保存的文件夹,然后输入以下命令
pyuic5 ui.ui >blhost_gui.py
转换好后,
在blhost_gui.py开头import的位置加入如下引用
注意,这里要看好PySide2而不是PyQt5
import sys
import os
import subprocess
from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtWidgets import *
from PySide2.QtCore import *
在blhost_gui.py最后一行加入如下代码
__author__ = "Magicoe.Niu"
__version__ = "v1.0"
class mainWin(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(mainWin, self).__init__(parent)
self.setupUi(self)
if __name__ == '__main__':
print("blhost application start")
app = QApplication(sys.argv)
main_win = mainWin()
main_win.show()
sys.exit(app.exec_())
尝试运行下GUI
转换好后,我们可以尝试运行下界面,在命令行里输入
python blhost_gui.py
这时候会弹出我们在QtDesigner里设计好的UI界面,并且在命令行终端里会显示blhost application start
OK,接下来我们就可以添加实际的控制逻辑的代码了
加入blhost的功能
为了引用blhost.exe的功能,我们直接通过python的subprocess方法,还记的我们添加的那行import代码么?
import subprocess
这里我们直接把bhost.exe复制到blhost_gui.py的文件夹下,blhost.exe在SDK包里,具体路径为SDK_2.7.0_LPC55S69\middleware\mcu-boot\bin\Tools\blhost\win
在def retranslateUi(self, MainWindow) 函数结尾的地方,加入按键响应(clicked.connect())的代码
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.But_Open.setText(_translate("MainWindow", "OpenBinary"))
self.But_Conn.setText(_translate("MainWindow", "Connect?"))
self.But_Prog.setText(_translate("MainWindow", "Program"))
self.But_Open.clicked.connect(self.openfile)
self.But_Prog.clicked.connect(self.program)
self.But_Conn.clicked.connect(self.connectwUSB)
新加入的3行clicked.connect功能需要调用openfile/program/connectwUSB三个函数来实现打开HEX文件,对芯片变成以及检查USB连接的状态。所以我们要在retranslateUi函数后加入3个新的函数。
首先我们先加入打开文件的函数
openfile_name在这里代表了选择的目标HEX文件的路径,我们把它显示在文本框“Text_Path”中
def openfile(self):
openfile_name = QFileDialog.getOpenFileName(self,'选择文件','','Hex File(*.hex)')
print(openfile_name)
self.Text_Path.setText(openfile_name[0])
接下来我们加入检查USB连接的函数
检查USB是否和开发板上进入ISP模式的MCU连接正常,我们使用blhost.exe的get-property的功能,通过python的subprocess.Popen调用,所以我们要把blhost.exe放在该脚本同一的文件夹下。
0x1FC9,0x0021是MCU USB ISP时的VID和PID,这里是LPC55S69的不同的恩智浦MCU该VID和PID可能不同,随时可以修改。
get-property 1是获取当前BOOT ROM的版本,如果获取的版本是2.2.0的则芯片是0A的版本,如果是3.0.0的则是1B的版本,如果是其他数字则需要根据KBOOT的版本号来确定芯片的版本。
获取到正确的KBOOT的版本号后悔在Text_Result对话框里显示出来信息,如果不正确则提示连接异常或者提示是未知的芯片版本。
def connectwUSB(self):
print("blhost programming connect")
blhost_main = "blhost.exe"
ret = subprocess.Popen(blhost_main + " -u 0x1FC9,0x0021 -- get-property 1", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
RetText = ret.communicate()
print (RetText)
if "Current Version" in str(RetText):
if "Current Version = K2.2.0" in str(RetText):
self.Text_Result.setText("Connected Silicon 0A Success")
elif "Current Version = K3.0.0" in str(RetText):
self.Text_Result.setText("Connected Silicon 1B Success")
else:
self.Text_Result.setText("Connected Silicon Success, unknown Silicon version")
else:
self.Text_Result.setText("Connected with USB Failed")
最后我们加入烧录芯片的函数
同检查芯片连接状况的函数差不多,这里烧录我们调用的是blhost的 flash-image功能,需要注意的是USB的VID和PID号要对,其他无碍。
正确的烧录blhost.exe会返回“Success”,烧录失败会返回其他信息。
def program(self):
target_bin = self.Text_Path.toPlainText()
print(target_bin)
print("blhost programming start")
blhost_main = "blhost.exe"
ret = subprocess.Popen(blhost_main + " -u 0x1FC9,0x0021 -- flash-image "+ target_bin +" erase", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
RetText = ret.communicate()
print (RetText)
if "Success" in str(RetText):
self.Text_Result.setText("Program Success")
else:
self.Text_Result.setText("Program Failed")
运行blhost_gui.py
当我们补充完以上提到的代码后,在Anaconda3的命令行里输入
python blhost_gui.py
就可以正常运行该UI,如果还没有连接开发板或者开发板上MCU的状态不对
开发板设置
LPC55S69-EVK配置为USB ISP模式需要注意以下几点
- J7断开
- J11断开
- J6选择HS
- 短接J10(上电进入ISP模式)
- 使用USB接口P9进行USB ISP操作
正常连接和烧录
如果USB连接正常,则按下Connect按钮会显示连接芯片的版本号。
接下来我们可以按下按钮OpenBinary选择一个我们要烧录的hex文件
再点击烧录按钮Program,就可以正常烧录了
打包成exe文件
为了便于我们发布该软件给其他没有建立python执行环境的客户,我们可以用pyinstaller。
为了把整个执行环境达成一个exe,我们需要在pyinstaller命令后加入-F使blhost_gui.py打包后只生成一个exe文件
pyinstaller.exe blhost_gui.py -F
最后会在文件夹dist下边找到blhost_gui
直接执行该exe文件,当按下功能按钮的时候会发现找不到blhost
原因是需要把blhost.exe和blhost_gui.exe放在同一文件夹下,复制blhost.exe过来就可以解决。
这里有个问题留给高手们,有谁知道如何把blhost.exe一起打包进来的么?欢迎高手们指点一二。