STM32 Shell脚本编译和烧录指南
一.前言
Shell脚本来编译STM32固件具有一些优势:
-
自动化编译流程: 使用Shell脚本可以将编译过程自动化,减少手动操作。这样可以节省时间并降低出错的可能性。
-
简化复杂的编译命令: STM32的编译可能涉及到较长的编译命令和参数,通过Shell脚本可以将这些复杂的命令整合在一起,使编译过程更加简洁明了。
-
易于维护和修改: 将编译过程封装在Shell脚本中,可以更轻松地对编译过程进行修改和维护。如果需要更改编译参数或添加其他操作,只需修改Shell脚本即可,而不必修改每个编译命令。
-
跨平台兼容性: Shell脚本通常在各种Unix和Linux系统中都能运行,因此具有很好的跨平台兼容性。这意味着您可以在不同的开发环境中使用相同的Shell脚本来编译STM32固件。
-
版本控制和共享: 将编译过程封装在Shell脚本中可以更好地进行版本控制,并方便与团队共享。团队成员可以轻松地使用相同的脚本来编译项目,确保整个团队的开发环境保持一致。
总的来说,编写Shell脚本来编译STM32固件可以提高工作效率,简化编译过程,并使项目更易于维护和共享。
二.所需工具
1).Visual Studio Code(VScode)以及vscode平台下的shell脚本插件。
3).JLink_Windows_V796b.exe。
4).Jlink仿真器。
1.安装Visual Studio Code
VScode下载地址:Visual Studio Code – Code Editing. Redefined。下载windows版本,直接双击即可安装。
我使用的是vscode来开发shell脚本,具体如何使用vscode开发shell,可以平台上搜,教程很多,我在这里就不赘述了。
2.安装JLink工具
打开segger官网:SEGGER – The Embedded Experts – Downloads – J-Link / J-Trace。找到J-Link Software and Documentation Pack:
点击Click for downloads, 下载windows版本。
三.移植操作
1.添加环境变量
需要添加到电脑系统环境变量 Path中的有:
1.找到JLink安装路径下JFlash.exe所处目录
2.Keil软件UV4.exe软件所处目录
四.脚本实现
1.UV4.exe命令的使用
可以从命令行(Keil的UV4.exe)调用uVision来构建项目、启动调试器或将程序下载到Flash中。该命令适用于项目和多项目文件。使用命令参考µVision User's Guide (arm.com)
2.build.sh和config.sh
创建这两个文件,移植到stm32工程中 .uvprojx文件同级目录下
shell.sh
#!/bin/bash
source config.sh
print_green() {
echo -e "\e[32m$1\e[0m"
}
# Function to print text in red
print_red() {
echo -e "\e[31m$1\e[0m"
}
print_yellow() {
echo -e "\e[33m$1\e[0m"
}
print_blue() {
echo -e "\e[34m$1\e[0m"
}
print_building_msg() {
error_count=$(grep -i "error:" $1 | wc -l)
warning_count=$(grep -i "warning:" $1 | wc -l)
if [ $error_count -ne 0 ]; then
echo ""
grep -A 1 -B 1 -i "error:" $1 | while read -r line; do
print_red "$line"
done
echo ""
print_red "Build failed with $error_count errors."
echo ""
else
warning_count=$(grep -i "warning" $1 | wc -l)
grep -i "warning:" $1 >build_warning.log
print_green "[Warning Statistics]"
if [ $warning_count -ne 0 ]; then
print_yellow "Build succeeded with $warning_count warnings. Details are saved in build_warning.log"
else
print_green "0 Error(s), 0 Warning(s)"
fi
fi
}
while true; do
# 显示菜单
echo ""
echo "[Menu]"
echo "Please choose an option:"
echo "1. STM32 >> Build OR Burn"
echo "2. Dev >> Hex turn to Bin"
echo "3. Dev >> Erase Chip"
echo "4. Dev >> Make app_combine_boot file"
read -p "Your choice: " choice
case $choice in
1)
uvprojxPath=$(pwd)
# 将反斜杠转换为斜杠
uvProjxDirectory=$(echo $uvprojxPath | sed 's/\\/\//g')
# 读取uvprojx文件
for uvProjxFile in $uvProjxDirectory/*.uvprojx; do
if [ -f "$uvProjxFile" ]; then
# temp_file=$(mktemp)
uvProjxFilename=$(basename "$uvProjxFile")
# 找到.uvprojx的文件
uvProjxFile=".\\${uvProjxFilename%.*}.uvprojx"
# 指定编译日志路径
temp_file=".\temp_file.txt"
read -p "Whether you need to >> Build << (Y/N) " inputBuild
# 将用户输入转换为大写字母
buildOperation=$(echo "$inputBuild" | tr '[:lower:]' '[:upper:]')
if [ "$buildOperation" = "Y" ]; then
# 编译
cmd.exe /c "$UV -j0 -sg -b $uvProjxFile -o $temp_file"
# 全局编译
# cmd.exe /c "$UV -j0 -sg -r $uvProjxFile -o $temp_file"
# 打印.txt文件内容
cat $temp_file
fi
print_building_msg $temp_file
read -p "Whether you need to >> Burn << (Y/N) " inputBurn
# 将用户输入转换为大写字母
burnOperation=$(echo "$inputBurn" | tr '[:lower:]' '[:upper:]')
if [ "$burnOperation" = "Y" ]; then
# 烧录
cmd.exe /c "$UV -j0 -sg -f $uvProjxFile -o $temp_file"
cat $temp_file
fi
rm -f $temp_file
fi
done
;;
2)
elfprojxPath=$(pwd)
elfProjxDirectory=$(echo $elfprojxPath | sed 's/\\/\//g')
# 在app_debug/boot_debug文件夹下找到.elf文件
for elfProjxFile in $elfProjxDirectory/*.elf; do
if [ -f "$elfProjxFile" ]; then
# .elf文件名对应 .hex 的名字
echo "Convert to bin............"
# .hex文件转.bin文件
# %.*用于去除文件名中的扩展名,并将其替换为.bin
cmd.exe /c "$hex2binPath .\\${elf_filename%.*}.hex .\\${elf_filename%.*}.bin true"
print_green "Hex2Bin operation completed."
fi
done
;;
3)
cmd.exe /C "$JFlashPath $jflashDevice -connect -erasechip"
;;
4)
# 获取当前用户的用户名
nameTemp=$(whoami)
username=$(basename "$nameTemp")
# # 获取桌面路径
desktop_path="$HOME/Desktop"
# 获取当前路径
current_path=$(pwd)
# 使用 basename 命令提取文件名部分
file_name=$(basename "$current_path")
echo "1. app area >>> *.bin file"
echo "2. app combine boot area>>> *.hex file"
read -p "What file you want to generate " codeFileType
# 使用 if 语句根据用户选择进行打印操作
if [ "$codeFileType" = "1" ]; then
cmd.exe /C "$JFlashPath $jflashDevice -connect$Device -readrange$app_start_addr,$app_end_addr -saveasC:\\Users\\$username\\Desktop\\${file_name%.*}.bin -auto -exit"
print_yellow "app *.bin is saved in C:\\Users\\$username\\desktop"
# 在这里执行打印操作1
elif [ "$codeFileType" = "2" ]; then
cmd.exe /C "$JFlashPath $jflashDevice -connect$Device -readrange$boot_start_addr,$app_end_addr -saveasC:\\Users\\$username\\Desktop\\${file_name%.*}.hex -auto -exit"
print_yellow "app combine boot *.bin is saved in C:\\Users\\$username\\desktop"
# 在这里执行打印操作2
else
echo "Error: Invalid choice. Please enter 1 or 2."
fi
;;
*)
echo "Invalid choice."
;;
esac
done
config.sh
该文件为脚本配置文件,这里需要跟进修改相关路径和芯片相关配置信息
#!/bin/bash
# *******************tool****************************
# JLink.exe
JLinkPath="D:\SEGGER\JLink\JLink.exe"
# JFlash.exe
JFlashPath="D:\SEGGER\JLink\JFlash.exe"
# JLinkGDBServer.exe
JLinkGDBServerPath="D:\SEGGER\JLink\JLinkGDBServer.exe"
#HEX2BIN
hex2binPath="E:\MC_LOCK\hex2bin.exe"
# UV4.exe
UV="D:\keil\UV4\UV4.exe"
# ****************read flash area *******************************
# 这里需要到JFlash.exe那里创建名为STM32F103.jflash,并添加到.uvprojx文件所处路径下
jflashDevice=".\STM32F103.jflash"
Device=STM32F103
# 在这里修改需要读取芯片的flash地址,我程序里带有boot和app程序,因此拆分成了两块flash区域用作读取
boot_start_addr=0x00
boot_end_addr=0x7000
app_start_addr=0x7000
app_end_addr=0X10000
# ****************JLINK*******************************
# 将多行指令写入临时文件
cat <<EOF > jlinkTempCommands.jlink
USB
si 1
speed 1000
device $Device
r
h
erase $app_start_addr $app_end_addr
loadfile .\\${elf_filename%.*}.bin $app_start_addr
r
q
EOF
3.创建JFlash工程,
该文件放置到.uvprojx所处目录下,该文件作用是方便脚本调用JFlash.exe从芯片中读取flash,生成hex/bin文件
这里我以stm32f103c8t6芯片为例
五.调用脚本
可以使用cmd窗口方式或vscode终端调用脚本。cmd终端调用脚本,需要cd到 .uvprojx 所处目录下,输入 bash build.sh 调用指令
作者:a̤̮i̤̮r̤̮_city