STM32自动化烧写
目的与适用范围
项目已经固定,每次烧写程序只会更改很少量的信息。比如设备编号,日期等信息,但每台设备这些信息都是不相同的。每次更改设备必须打开keil更改编号,再次编译,烧写,过程繁琐。于是就想可不可以直接更改hex文件,改好后直接烧写进板子拉?
使用到工具
pythonpylink(python实现的一个stm32模块)JLinkARM库(这个是C/C++实现的底层库)
步骤
找到不同设备号更改时hex改变位置使用python实现自动更改使用pylink烧写进去
具体操作
找出hex文件更改位置
keil编译生成两个不同设备号的hex文件,并使用比较命令找出更改位点。这里说下hex文件保存位置项目根目录\Output\下面会有一个.hex文件,这个文件就是要下载到STM32的程序。复制出来保存到你喜欢的文件夹下。
/* 第一个文件编号如下 */
/* 保存的hex文件命名为old.hex */
/* 第二个文件编号 */
/* 保存为new.hex */
/* 更改编号后一定要点编译,不然两个文件都完全一样了 */
/* linux 比较两个文件 */
diff old.hex new.hex
1329c1329
< :1052F0006846FCF7F1FB1CBD2C7649781CB50446CA
---
> :1052F0006846FCF7F1FB1CBD787549781CB504467F
/* 显示1329行不同并分别列出了不同的行 */
/* windows CMD 比较两个文件 */
FC new.hex old.hex
***** new.hex
:1052E0002088ADF800006088ADF802000248019007
:1052F0006846FCF7F1FB1CBD2C7649781CB50446CA
:105300002088ADF800006088ADF802000548B0F8CC
***** OLD.HEX
:1052E0002088ADF800006088ADF802000248019007
:1052F0006846FCF7F1FB1CBD787549781CB504467F
:105300002088ADF800006088ADF802000548B0F8CC
*****
/* window FC命令给出了不同行和上下各一行所以是3行,但没有说明是那一行,可以复制搜索下,也能确认是第1329行 */
/* 仔细数一下可以更加明确的那几列不同,因为我们到时候更改hex文件必须定位到那一行,那一列 */
使用python更改
分析下hex文件那几列不同 linux的diff比较结果很容易的看出来2C76和7875是不同的,行尾两个留后面说。使用计算器进制转化计算下我们的设备编号十六进制是什么? 2018080120对应0x78497578,2018080300对应0x7849762C 可以对比下发现最后四位数字不同7578和762C刚好和我们用diff比较出来结果对上只是前后两位对换,这种对换应该是因为计算机存储的关系。再对比下文件就可以发现2C764978对应2018080300, 78754978对应2018080120。这里的存储顺序需要特别留意下,因为使用python暴力更改文件必须一一对应。 比较下可以发现除这个数字不同外最后两位也是不一样的,这又是什么鬼? intel hex文件格式这里做了比较细的描述,总结下就是最后两位是对每一行前面计算得到的,用于检测这一行有没有错漏。更改hex文件
import os
file_name
= "data.hex"
row
= 1329
line
= 23
No_row_str
= list
()
current_No
= 0
next_No
= 0
if not os.access
(file_name, os.F_OK
|os.R_OK
|os.W_OK
):
print
(file_name,
"文件权限受限\n")
print
(file_name,
"加载中......")
while 1
:
file_ptr
= open
(file_name,
"r+")
def get_current_No
(file
):
global No_row_str
i
= row
while i
!= 0:
read_line
= file.readline
();
i
= i - 1
;
No_row_str
= list
(read_line
)
size
= len
(read_line
)
file.seek
((file.tell
() - size - 1
), 0
)
return x_to_10
(read_line
[25:33
])
def x_to_10
(str
):
global current_No
inpu
= ['0',
'x']
list_str
= list
(str
)
inpu
= inpu + list_str
[6:8
] + list_str
[4:6
] + list_str
[2:4
] + list_str
[0:2
]
No_str
= ''.join
(inpu
)
current_No
= int
(No_str, 16
);
def update_No
(new_No
):
global No_row_str
no_hex
= list
(hex
(new_No
))
No_row_str
[line + 2 + 6
] = no_hex
[2
];
No_row_str
[line + 2 + 7
] = no_hex
[3
];
No_row_str
[line + 2 + 4
] = no_hex
[4
];
No_row_str
[line + 2 + 5
] = no_hex
[5
];
No_row_str
[line + 2 + 2
] = no_hex
[6
];
No_row_str
[line + 2 + 3
] = no_hex
[7
];
No_row_str
[line + 2 + 0
] = no_hex
[8
];
No_row_str
[line + 2 + 1
] = no_hex
[9
];
ver_str
= tohex
(vertify
(No_row_str
))
No_row_str
[41
] = ver_str
[2
]
No_row_str
[42
] = ver_str
[3
]
No_row_str
[43
] = '\r'
return (''.join
(No_row_str
))
def tohex
(number
):
rst
= ['0',
'x']
rst.append
(hex
(int
(number / 16
))[2
])
rst.append
(hex
(number % 16
)[2
])
return rst
def vertify
(row_line
):
if row_line
== "":
print
("不能验证空行")
return
size
= len
(row_line
)
sum = 0
vertify
= 0
for cur_pos
in range
(1, size-3, 2
):
temp
= ''.join
(No_row_str
[cur_pos:
(cur_pos + 2
)])
sum = sum + int
(temp, 16
)
vertify
= 256 -
(sum % 256
)
return vertify
实现效果:
当前设备编号: 2020080301
默认下台设备编号: 2020080302
下台设备编号(使用默认编号直接按Enter)
正在更改设备编号为 2020080302
......
当前设备编号: 2020080302
默认下台设备编号: 2020080303
下台设备编号(使用默认编号直接按Enter)
正在更改设备编号为 2020080303
......
当前设备编号: 2020080303
默认下台设备编号: 2020080304
下台设备编号(使用默认编号直接按Enter)
正在更改设备编号为 2020080304
......
当前设备编号: 2020080304
默认下台设备编号: 2020080305
下台设备编号(使用默认编号直接按Enter)
正在更改设备编号为 2020080305
......
写入板子 使用pylink写入。但pylink国内使用的还真不多,于是又是各种找用法,本来是想用人家提供API自己写,但无耐文档是真的坑,只能直接使用提供的命令行。说说遇到的坑: 1. 开门不利,安装。要求我安装Microsoft Visual C++ 14.0,更神奇的是给我网页是认我安装visual studio。我安装一个python部件你叫我安装一个IDE,只想骂人。装了最新的你还提示找不到。只能找网友帮忙了。安装模块报错,因为我是psutil安装不上,直接<Ctrl + f>搜索psutil,下载安装OK。 2. pylink.JLink()错误连不上,百度搜的文档我压根儿都没看到JLinkARM啥事。连又连接不上,没法只能上github看看。github上说的很明确JLinkARM.dll要放在指定目录才可以,于是把keil下面的JLinkARM放windows,sys32,sys,当前目录,但没有一个可用的。仔细阅读github说明,要在这里下载JLinkARM.dll。下载下来写的有三个目录可以放,当前目录、windows目录、windows/sys32目录,我放在sys32好像是可以了,也不知道是因为放在sys32下面还是因为path中加入新安装软件的运行目录的原因。反正就是可以用了 3. 打开设备pylink.JLink().open()。要一个参数,这参数文档也不写。自己摸索发现win10设备管理器里面的事件里会有一行"已配置设备 USB\VID_1366&PID_0101\000000123456。",使用123456试试,还可以。 4. 打开了准备用flash_file写进去说我没有连接target,好吧只能用connect连接,连接又要用到设备名,这个设备名又不用有说只能自己摸索。这次使用设备管理器救不了我了,keil才能帮助我,keil的每个项目都要选择一个Device类型,比如STM32F103RC,现在想来感觉当时傻不知道用这个,但文档不说我怎么知道用那一串字符表示啊。 5. 到这里我其实还是没有成功运行connect,还是会提示pylink.errors.JLinkException: J-Link DLL is not open.,但我发现一个好东西,可以完全放弃它的API,使用命令行就可以了。pylink提供了一个pylink命令,所以转而使用他的命令就可以了,我又不用管什么效率,它API也不一定带来什么效率。 6. 命令行就友好太多了想办法填满见个参数就好了。我确定设备名就是使用命令行确定STM32F103RC可用的
$ pylink emulator -s STM32F103RC
Device Name: STM32F103RC
Core ID: 1000342647
Flash Address: 134217728
Flash Size: 262144 bytes
RAM Address: 536870912
RAM Size: 49152 bytes
Manufacturer: ST
STM32F103R is not supported :
(
说说烧写命令
pylink flash -a 8000000 -t SWD -d STM32F103RC -s 123456 data.hex
这里还是有坑,-a/address是写入地址,这个可以keil里面项目中找到一般都0x8000000或以上,但都知道0x8000000是一个16进制数,我还特意计算了下它的十进制数,用不了。文档中写要用int数。试试直接8000000,可以用。好吧没啥说的。 -t 是下载方式就两种JTA和SWD和你板子的接线有关 -s/serial 就是设备管理器”事件“里面查到的那个 -d/device 就是设备名,keil项目里面有 最后是hex文件 有了以上命令就可以使用python写入了,但还有一点要注意写入前hex文件要关闭状态,pylink会去读hex文件,所以pylink写必须在file.close()后面。
使用脚本烧写的好处
自动完成自加操作,懒人必备防止输入出错,写入重复编号可以自己加入日志功能,实现自动记录烧写日期,烧写编号还可以加入导出到excl功能,可定制程度相当高