Linux绝对是开发者的上帝之鞭!但想要做到使用起来得心应手,比对window真的还差一些。但对于真正的开发者来说,这些还真都不是事!
前面我们说过要在Ubuntu上搭建STM32的开发调试环境,比对前面的系统框图,配置起来,也就清晰并且轻松多了。但Ubuntu就是Ubuntu,比起Windows的<下一步>&<下一步>还是麻烦不少。这样吧,给大家搞一个python脚本吧... ...
先上流程图:
再贴代码:
#
# This script is created by haibojiang
# email:32191103@qq.com
# Tel:15940146108
#
#!/usr/bin/env python3
import os
import subprocess
import sys
import time
from pathlib import Path
# 颜色定义
COLORS = {
'HEADER': '\033[95m',
'OKBLUE': '\033[94m',
'OKCYAN': '\033[96m',
'OKGREEN': '\033[92m',
'WARNING': '\033[93m',
'FAIL': '\033[91m',
'ENDC': '\033[0m',
'BOLD': '\033[1m',
'UNDERLINE': '\033[4m'
}
def print_color(text, color):
print(f"{COLORS[color]}{text}{COLORS['ENDC']}")
def run_command(cmd, description, exit_on_fail=True):
print_color(f"▶ {description}...", "OKBLUE")
print_color(f"$ {cmd}", "OKCYAN")
try:
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while True:
output = process.stdout.readline()
if output == b'' and process.poll() is not None:
break
if output:
print(output.decode().strip())
return_code = process.poll()
if return_code != 0:
print_color(f"✖ 命令执行失败,返回码: {return_code}", "FAIL")
if exit_on_fail:
sys.exit(1)
return False
print_color("✔ 完成", "OKGREEN")
return True
except Exception as e:
print_color(f"✖ 执行命令时出错: {str(e)}", "FAIL")
if exit_on_fail:
sys.exit(1)
return False
def check_installation(package):
try:
subprocess.check_output(f"which {package}", shell=True)
return True
except subprocess.CalledProcessError:
return False
def install_stlink():
if check_installation("st-flash") and check_installation("st-util"):
print_color("✔ ST-LINK 工具已安装", "OKGREEN")
return
print_color("▶ 安装 ST-LINK 工具...", "HEADER")
# 安装依赖
run_command("sudo apt-get update", "更新软件包列表")
run_command("sudo apt-get install -y cmake usbutils libusb-1.0-0-dev", "安装编译依赖")
# 克隆并编译 stlink
stlink_dir = Path.home() / "stlink"
if not stlink_dir.exists():
run_command(f"git clone https://github.com/stlink-org/stlink {stlink_dir}", "克隆 stlink 仓库")
else:
print_color("✔ stlink 目录已存在,跳过克隆", "OKGREEN")
os.chdir(stlink_dir)
run_command("make release", "编译 stlink")
run_command("sudo make install", "安装 stlink")
run_command("sudo cp config/udev/rules.d/49-stlinkv* /etc/udev/rules.d/", "配置 udev 规则")
run_command("sudo udevadm control --reload-rules", "重新加载 udev 规则")
run_command("sudo udevadm trigger", "触发 udev 规则")
print_color("✔ ST-LINK 工具安装完成", "OKGREEN")
def install_jlink():
if check_installation("JLinkExe"):
print_color("✔ J-LINK 软件已安装", "OKGREEN")
return
print_color("▶ 安装 J-LINK 软件...", "HEADER")
# 下载 J-LINK (需要用户手动下载,因为需要接受许可协议)
jlink_deb = "JLink_Linux_V788a_x86_64.deb"
jlink_url = "https://www.segger.com/downloads/jlink/JLink_Linux_V788a_x86_64.deb"
download_path = Path.home() / "Downloads" / jlink_deb
if not download_path.exists():
print_color("⚠ 请从以下 URL 手动下载 J-LINK 软件并接受许可协议:", "WARNING")
print_color(jlink_url, "OKBLUE")
print_color(f"请将下载的 {jlink_deb} 文件保存到 {download_path}", "OKBLUE")
input("按 Enter 键继续安装 (确保文件已下载)...")
if not download_path.exists():
print_color("✖ 未找到 J-LINK 安装文件,跳过 J-LINK 安装", "FAIL")
return
run_command(f"sudo dpkg -i {download_path}", "安装 J-LINK 软件包")
run_command("sudo apt-get install -f", "修复依赖关系")
# 添加用户到 dialout 组
run_command(f"sudo usermod -a -G dialout {os.getenv('USER')}", "将用户添加到 dialout 组")
print_color("✔ J-LINK 软件安装完成", "OKGREEN")
print_color("⚠ 请注销并重新登录以使组更改生效", "WARNING")
def install_toolchain():
if check_installation("arm-none-eabi-gcc"):
print_color("✔ ARM 工具链已安装", "OKGREEN")
return
print_color("▶ 安装 ARM 工具链...", "HEADER")
run_command("sudo apt-get update", "更新软件包列表")
run_command("sudo apt-get install -y gcc-arm-none-eabi binutils-arm-none-eabi gdb-arm-none-eabi libnewlib-arm-none-eabi", "安装 ARM 工具链")
print_color("✔ ARM 工具链安装完成", "OKGREEN")
def install_openocd():
if check_installation("openocd"):
print_color("✔ OpenOCD 已安装", "OKGREEN")
return
print_color("▶ 安装 OpenOCD...", "HEADER")
run_command("sudo apt-get update", "更新软件包列表")
run_command("sudo apt-get install -y openocd", "安装 OpenOCD")
print_color("✔ OpenOCD 安装完成", "OKGREEN")
def generate_config_files():
print_color("▶ 生成配置文件...", "HEADER")
project_dir = Path.cwd()
# 创建 openocd 配置文件
openocd_cfg = project_dir / "openocd.cfg"
with open(openocd_cfg, "w") as f:
f.write("""# OpenOCD 配置文件 for STM32F407
source [find interface/stlink-v2.cfg]
# source [find interface/jlink.cfg] # 取消注释以使用 J-LINK
transport select hla_swd
source [find target/stm32f4x.cfg]
reset_config srst_nogate
# 启用 SWO 跟踪 (如果使用)
# tpiu config internal uart off 168000000 1680000
""")
print_color(f"✔ 已创建 OpenOCD 配置文件: {openocd_cfg}", "OKGREEN")
# 创建 gdb 初始化文件
gdbinit = project_dir / "gdbinit"
with open(gdbinit, "w") as f:
f.write("""# GDB 初始化文件 for STM32F407
target extended-remote :3333
monitor reset halt
load
monitor reset halt
break main
""")
print_color(f"✔ 已创建 GDB 初始化文件: {gdbinit}", "OKGREEN")
# 创建烧录脚本
flash_sh = project_dir / "flash.sh"
with open(flash_sh, "w") as f:
f.write("""#!/bin/bash
# STM32F407 烧录脚本
# 使用 ST-LINK
arm-none-eabi-gdb -x gdbinit your_firmware.elf
# 使用 J-LINK 的替代命令
# JLinkExe -device STM32F407VG -if SWD -speed 4000 -autoconnect 1 -CommanderScript flash.jlink
""")
flash_sh.chmod(0o755) # 使脚本可执行
print_color(f"✔ 已创建烧录脚本: {flash_sh}", "OKGREEN")
# 创建 J-LINK 烧录脚本
jlink_flash = project_dir / "flash.jlink"
with open(jlink_flash, "w") as f:
f.write("""// J-LINK 烧录脚本
device STM32F407VG
speed 4000
if swd
connect
halt
loadfile your_firmware.hex
r
q
""")
print_color(f"✔ 已创建 J-LINK 烧录脚本: {jlink_flash}", "OKGREEN")
print_color("✔ 配置文件生成完成", "OKGREEN")
def main():
print_color("="*60, "HEADER")
print_color(" STM32F407 Ubuntu 开发环境自动配置脚本", "HEADER")
print_color("="*60, "HEADER")
print()
# 检查是否为 Ubuntu
try:
with open("/etc/os-release") as f:
if "Ubuntu" not in f.read():
print_color("⚠ 此脚本专为 Ubuntu 设计,其他发行版可能不兼容", "WARNING")
except FileNotFoundError:
print_color("⚠ 无法确定操作系统类型,继续执行但可能不兼容", "WARNING")
# 检查 sudo 权限
print_color("▶ 检查 sudo 权限...", "OKBLUE")
try:
subprocess.check_call("sudo -v", shell=True)
print_color("✔ 已获得 sudo 权限", "OKGREEN")
except subprocess.CalledProcessError:
print_color("✖ 需要 sudo 权限来运行此脚本", "FAIL")
sys.exit(1)
# 安装组件
install_toolchain()
install_stlink()
# install_jlink()
install_openocd()
# 生成配置文件
generate_config_files()
print()
print_color("="*60, "HEADER")
print_color(" 环境配置完成!", "OKGREEN")
print_color("="*60, "HEADER")
print()
# 使用说明
print_color("使用说明:", "HEADER")
print("1. 将 STM32F407 开发板通过 ST-LINK 或 J-LINK 连接到电脑")
print("2. 确保你的工程目录包含编译生成的 ELF 或 HEX 文件")
print()
print_color("调试方法:", "OKBLUE")
print("- 使用 OpenOCD 和 GDB:")
print(" 1. 在一个终端中运行: openocd -f interface/stlink-v2.cfg -f target/stm32f4x.cfg")
print(" 2. 在另一个终端中运行: arm-none-eabi-gdb -x gdbinit your_firmware.elf")
print()
print_color("烧录方法:", "OKBLUE")
print("- 使用 ST-LINK:")
print(" st-flash write your_firmware.bin 0x8000000")
print(" 或运行: ./flash.sh")
print()
print("- 使用 J-LINK:")
print(" JLinkExe -device STM32F407VG -if SWD -speed 4000 -autoconnect 1 -CommanderScript flash.jlink")
print()
print_color("提示:", "WARNING")
print("- 首次使用 J-LINK 可能需要注销并重新登录")
print("- 确保你的用户有访问调试器的权限 (通常在 dialout 组)")
print("- 如果遇到权限问题,尝试重新插拔调试器或运行:")
print(" sudo udevadm control --reload-rules && sudo udevadm trigger")
if __name__ == "__main__":
main()
Ubuntu1~20.04.2 & python3 测试通过。后续调试过程慢慢追加