Linux环境搭建MCU开发环境

操作系统版本: ubuntu 22.04

文本编辑器:    vscode

开发板:           stm32f103c8t6

调试器:           st-link

前言

步骤一: 安装交叉编译工具链

步骤二: 创建工程目录结构

步骤三: 调试器驱动安装

步骤四: 烧录工具安装

步骤五: 调试环境搭建

一  交叉编译工具链

交叉编译工具链是用于在一种计算机平台(x86架构)上编译生成另一种平台(ARM架构)可执行代码的开发工具集合,包含交叉编译器(arm-none-eabi-gcc)、交叉链接器(arm-none-eabi-ld)、交叉调试器(arm-none-eabi-gdb)、标准库(newlib 标准库)等组件;

交叉编译工具链命名规则

arch [-vendor] [-os] [-eabi/gnueabi/gnueabihf] [-gcc/g++]

arch: 目标架构,常见架构: ARM架构(arm/aarch64) RISC-V架构

vendor: 工具链提供商,当工具链不依赖特定芯片厂商,采用 none 代替

OS: 用于明确目标设备的操作环境,当os字段值为 none 时,表示目标设备无操作系统(裸机),当os字段值为 linux 时,表示目标设备运行Linux操作系统;

注意:

  • 实时操作系统的运行环境仍被视为 裸机 ,因为其内核不提供传统 OS 的系统调用和复杂功能;
  • 同时没有 vendor 与 os,采用一个none代替;

eabi/gnueabi/gnueabihf(Embedded Application Binary Interface):

EABI规定

  • 函数调用约定(如寄存器使用、参数传递顺序)
  • 栈帧布局和内存管理规则
  • 数据类型对齐方式(如结构体成员的内存布局)
  • 浮点运算处理方式(硬件 FPU 或软件模拟)

注意:

  • 如果芯片支持硬件浮点,需选择带hf(硬浮点)后缀的工具链,如 arm-none-linux-gnueabihf-gcc,无硬件浮点则使用软浮点(-gnueabi
  • eabi 通常与 none 结合使用(如 arm-none-eabi),表示裸机程序的二进制接口规范
  • gnueabi 或 gnueabihf:通常与与linux 结合(如 arm-none-linux-gnueabihf),表示Linux应用的二进制接口(支持硬浮点)

二 安装交叉编译工具链

STM32F103C8T6为ARM cortex-m3内核(基于ARMV7-M架构),32位架构,目标开发板需要运行裸机程序,因此选择交叉编译工具链为 arm-none-eabi-gcc

uname -a # 用于获取系统的内核相关信息包括内核名称,主机名,硬件架构
lsb_release -a #用于查询发行版的用户层面信息包括系统名称、版本号等

官网地址: Downloads | GNU Arm Embedded Toolchain Downloads – Arm Developer

 步骤一:将arm-none-eabi-gcc指定版本下载到本地

步骤二:将本地交叉编译工具包上传到ubuntu中自定义文件夹并解压

语法格式:     scp [选项] <源路径> <目标路径>
使用前提:     linux开启SSH服务,Windows使用PowerShell
示例:         scp C:\文件路径\文件.txt 用户名@ip地址:/home/用户名/目标路径

 本文采用scp指令上传压缩包,等待上传完成

 scp C:\Users\Admin\Downloads\gcc-arm-none-eabi-10.3.tar.bz2 shuju@123.249.39.44:/home/shuju/ToolChain

xshell环境中进入到ToolChain目录下,创建arm-none-eabi-gcc目录,将压缩包剪切到该目录下,进入该目录解压压缩包

tar -xjvf gcc-arm-none-eabi-10.3.tar.bz2

步骤三:安装arm-none-eabi-gcc

 安装环境依赖包,依赖包指软件运行所必需的其他软件组件,它们提供基础功能(如系统调用接口、库函数、编译工具等),确保主程序能正常编译和执行;

使用 arm-none-eabi-gcc 编译代码时:

1. 编译阶段:依赖包提供基础库(如 libclibm)和头文件(如 stdio.h);

2. 链接阶段:依赖包中的 binutils(如 ldobjcopy)负责生成可执行文件;

3. 调试阶段gdb-multiarch(依赖包的一部分)用于调试 ARM 程序;

sudo apt-get update
sudo apt-get install build-essential libncurses-dev flex bison gperf python3 python3-pip python3-setuptools python3-serial python3-click python3-cryptography python3-future python3-pyparsing python3-pyelftools cmake ninja-build ccache libffi-dev libssl-dev dfu-util

首先查找到交叉编译工具链的可执行路径,然后进行系统级配置

创建全局配置文件

# 创建系统级配置文件(需要管理员权限)
sudo vim /etc/profile.d/arm_toolchain.sh

# 在文件中添加以下内容(替换 /home/shuju/toolchain/gcc-arm-none-eabi/gcc-arm-none-eabi-10.3-2021.07/bin 为你的实际路径)

export PATH="/home/shuju/toolchain/gcc-arm-none-eabi/gcc-arm-none-eabi-10.3-2021.07/bin
:$PATH"

修改文件权限

sudo chmod +x /etc/profile.d/arm_toolchain.sh
创建符号链接到系统目录
# 创建工具链目录的符号链接(注意替换为bin文件的上层路径)
sudo ln -s /home/shuju/toolchain/gcc-arm-none-eabi/gcc-arm-none-eabi-10.3-2021.07 /usr/local/arm-toolchain

# 将工具链 bin 目录链接到系统路径
sudo ln -s /usr/local/arm-toolchain/bin/* /usr/local/bin/

最后检查交叉编译器是否安装成功

arm-none-eabi-gcc -v  #判断安装是否成功

三 创建工程目录结构

  • ST官网获取标准外设库

官网地址:https://www.st.com.cn/zh/embedded-software/stsw-stm32054.html

标准库目录结构介绍

进入到Libraries文件夹中,只有CMSIS文件夹与STM32F10x_StdPeriph_Driver,CMSIS(Cortex-M系列微控制器的软件接口标准)目录组织结构如下:

core_cm3.h文件:Cortex-M3处理器核心寄存器定义,提供NVIC、SysTick等内核功能;

stm32f10x.h文件:提供STM32外设寄存器基础定义,封装寄存器结构体,方便底层操作;system_stm32f10x.h文件:配置系统时钟和PLL,设置系统时钟频率;

arm目录:存放keil专用的启动文件;

gcc_ride7目录:存放 GCC 专用的启动文件;

STM32F10x_StdPeriph_Driver(外设驱动标准库文件)目录组织结构如下:

misc.c stm32f10x_xxx.c/misc.h stm32f10x_xxx.h文件:提供常用外设的接口,封装了GPIO、USART、RCC、TIM、SPI、I2C、DMA等常用外设的函数库;

开发STM32项目,必须包含以下文件:

  • 启动文件,启动文件的作用为MCU复位后执行的汇编启动代码,负责初始化堆栈指针,程序计数器,异常向量表等等,由于采用gcc编译程序,开发板为stm32f103c8t6,因此选择启动文件为startup_stm32f10x_md.s;
  • 内核文件 (core_cm3.h/core_cm3.c)
  • 芯片头文件 (stm32f10x.h)
  • 系统初始化文件(system_stm32f10x.c/system_stm32f10x.h)
  • 外设驱动标准库文件 (STM32F10x_StdPeriph_Driver目录下所有文件)
  • 外设配置头文件用户自定义创建)选择启用哪些外设驱动模块并配置库的参数选项,标准库的stm32f10x.h文件默认会包含stm32f10x_conf.h,如果此文件不存在会导致编译错误;
  • 链接脚本,链接脚本用于设置程序的入口点并且决定了编译器生成的可执行文件(ELF/HEX/BIN)在芯片中的内存布局,但STM32F1 标准库中,官方并未直接提供预配置的 GCC 链接脚本
  • Makefile 自动化编译整个工程

外设配置文件(stm32f10x_conf.h)

#ifndef __STM32F10x_CONF_H
#define __STM32F10x_CONF_H

//启用需要的外设库头文件,未启用的库就注释掉
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"

//启用断言
#define assert_param(expr) ((void)0)

#endif

mcu工程结构配置如下:

链接脚本STM32F103C8T6_FLASH.ld文件

/* 定义芯片内存区域 */
MEMORY
{
  FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 64K   /* Flash 起始地址与大小 */
  RAM  (xrw)  : ORIGIN = 0x20000000, LENGTH = 20K   /* RAM 起始地址与大小 */
}

/* 定义堆栈空间 */
_Min_Heap_Size = 0x200;   /* 最小堆大小(根据需要调整) */
_Min_Stack_Size = 0x400;  /* 最小栈大小(根据需要调整) */

/* 定义关键符号地址 */
_estack = ORIGIN(RAM) + LENGTH(RAM);  /* 栈顶地址(RAM末尾) */

/* 段分配 */
SECTIONS
{
  /* 中断向量表必须放在 Flash 起始地址 */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector))  /* 保留中断向量表 */
    . = ALIGN(4);
  } >FLASH

  /* 代码段(.text)和只读数据(.rodata) */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* 代码 */
    *(.text*)          /* 其他代码(如内联函数) */
    *(.glue_7)         /* ARM/Thumb 胶水代码 */
    *(.glue_7t)        /* Thumb-2 胶水代码 */
    *(.eh_frame)

    /* 只读数据(常量、字符串等) */
    *(.rodata)
    *(.rodata*)
    . = ALIGN(4);
  } >FLASH

  /* 初始化数据(.data):在 Flash 中存储初始值,运行时复制到 RAM */
  _sidata = .;  /* .data 初始值的 Flash 地址 */
  .data : AT ( _sidata )
  {
    . = ALIGN(4);
    _sdata = .;  /* .data 的 RAM 起始地址 */
    *(.data)
    *(.data*)
    . = ALIGN(4);
    _edata = .;  /* .data 的 RAM 结束地址 */
  } >RAM

  /* 未初始化数据(.bss):运行时清零 */
  .bss :
  {
    . = ALIGN(4);
    _sbss = .;  /* .bss 的起始地址 */
    *(.bss)
    *(.bss*)
    *(COMMON)    /* 公共符号 */
    . = ALIGN(4);
    _ebss = .;  /* .bss 的结束地址 */
  } >RAM

  /* 用户堆栈空间 */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM

  /* 移除调试信息(可选) */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
    *(.init)
    *(.fini)
  }
}

Makefile文件编写如下:

# 工具链配置
CC = arm-none-eabi-gcc
AS = arm-none-eabi-gcc -x assembler-with-cpp
OBJCOPY = arm-none-eabi-objcopy
SIZE = arm-none-eabi-size

# 目标名称和构建目录
TARGET = main
BUILD_DIR = build

# MCU配置
MCU = -mcpu=cortex-m3 -mthumb
DEFS = -DSTM32F10X_MD -DUSE_STDPERIPH_DRIVER

# 头文件路径(已包含 User/ 目录)
INC_DIRS = -I. \
           -IUser \
           -ICMSIS/CM3/CoreSupport \
           -ICMSIS/CM3/DeviceSupport \
           -ILibrary/inc

# 编译选项
CFLAGS = $(MCU) $(DEFS) -O0 -g3 -Wall -fdata-sections -ffunction-sections $(INC_DIRS)
ASFLAGS = $(MCU) $(DEFS) $(INC_DIRS)
LDFLAGS = $(MCU) -TStart/STM32F103C8T6_FLASH.ld \
          -Wl,--gc-sections -specs=nosys.specs -Wl,-Map=$(BUILD_DIR)/$(TARGET).map

# 源文件列表
SRCS = \
  User/main.c \
  Start/startup_stm32f10x_md.s \
  CMSIS/CM3/DeviceSupport/system_stm32f10x.c \
  $(wildcard Library/src/*.c)

# 生成目标文件列表
OBJS = $(addprefix $(BUILD_DIR)/,$(notdir $(SRCS:.c=.o)))
OBJS := $(OBJS:.s=.o)

# 默认目标(添加 .o 文件清理步骤)
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
	@echo "Cleaning intermediate .o files..."
	rm -f $(OBJS) 

# 生成ELF文件
$(BUILD_DIR)/$(TARGET).elf: $(OBJS)
	$(CC) $^ $(LDFLAGS) -o $@
	$(SIZE) $@

# 生成HEX和BIN文件
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(OBJCOPY) -O ihex $< $@

$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(OBJCOPY) -O binary -S $< $@

# 编译规则(保持不变)
$(BUILD_DIR)/%.o: User/%.c | $(BUILD_DIR)
	$(CC) -c $(CFLAGS) $< -o $@

$(BUILD_DIR)/%.o: CMSIS/CM3/DeviceSupport/%.c | $(BUILD_DIR)
	$(CC) -c $(CFLAGS) $< -o $@

$(BUILD_DIR)/%.o: Library/src/%.c | $(BUILD_DIR)
	$(CC) -c $(CFLAGS) $< -o $@

$(BUILD_DIR)/%.o: Start/%.s | $(BUILD_DIR)
	$(AS) -c $(ASFLAGS) $< -o $@

# 创建构建目录
$(BUILD_DIR):
	mkdir -p $@

# 清理(删除整个 build 目录)
clean:
	rm -rf $(BUILD_DIR)

.PHONY: all clean flash

测试用例

#include "stm32f10x.h"
#include "stm32f10x_conf.h"

//定义板载LED引脚
#define LED_PIN     GPIO_Pin_13
#define LED_PORT    GPIOC

// 简单延时函数
void delay(uint32_t count) 
{
    for (volatile uint32_t i = 0; i < count; i++);
}

int main()
{
    // 1. 初始化系统时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    // 2. 配置GPIO为推挽输出
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Pin = LED_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;  // 推挽输出
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; // 速度50MHz
    GPIO_Init(LED_PORT, &GPIO_InitStruct);

    // 3. 主循环:LED闪烁
    while (1) 
    {
        GPIO_WriteBit(LED_PORT, LED_PIN, Bit_SET);  // LED灭
        delay(500000);
        GPIO_WriteBit(LED_PORT, LED_PIN, Bit_RESET); // LED亮
        delay(500000);
    }
}

运行结果:

三 安装调试器驱动程序

安装ST-Link驱动程序

Linux内核默认支持ST-Link/V2,因此无需单独安装驱动;

纯Linux环境 - udev规则配置(可选)

udevLinux系统中的一个 用户空间设备管理器,负责动态管理 /dev 目录下的设备节点usb、 键盘、 鼠标等等 ),操作系统作为软硬件资源的管理者,不允许用户跨过操作系统直接访问硬件资源;

Linux系统默认将  usb 设备ST-LinkJ-Link)的权限设置为 root 所有,普通用户无法直接访问;
udev 规则是用户编写的配置文件(位置: /etc/udev/rules.d/ ),用于定义当设备插入或移除时系统应执行的操作,可以为设备设置权限(允许普通用户访问);

root身份进入/etc/udev/rules.d/目录,创建49-stlinkv2.rules文件(数字49决定了规则加载的顺序,数字越小的文件越先被处理,后面的文件中的规则可能会覆盖前面的),添加如下内容

# ST-Link/V2
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="3748", MODE="0666", GROUP="plugdev"
# ST-Link/V2.1
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="374b", MODE="0666", GROUP="plugdev"
# ST-Link/V3
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="374d", MODE="0666", GROUP="plugdev"

生效规则并重启服务

Linux环境

普通用户执行如下指令:

sudo udevadm control --reload-rules
sudo udevadm trigger
sudo usermod -aG plugdev $USER  # 将当前用户加入plugdev组
sudo reboot  # 重启生效

 wsl环境

 wsl系统中默认不运行 systemd-udevd 守护进程,因此即使配置了 udev 规则,规则也不会自动生效,但是需要手动配置权限,方便以普通用户的身份烧录程序;

# 安装 USBIP 工具和依赖
sudo apt update
sudo apt install linux-tools-virtual hwdata
sudo update-alternatives --install /usr/local/bin/usbip usbip `ls /usr/lib/linux-tools/*/usbip | tail -n1` 20

# 将用户加入dialout组
sudo usermod -aG dialout $USER

 创建权限修复脚本

# 创建自动修复脚本
sudo vim /usr/local/bin/fix_stlink_perms.sh

 将下述内容拷贝到新创建的脚本fix_stlink_perms.sh 文件中

#!/bin/bash
# 修复 ST-Link 设备权限
for dev in /dev/bus/usb/*/*; do
  if [ -e "$dev" ]; then
    sudo chmod 666 "$dev"
  fi
done

 设置脚本权限并添加到 .bashrc 自动执行

#设置脚本权限
sudo chmod +x /usr/local/bin/fix_stlink_perms.sh

#自动执行修复脚本
echo '/usr/local/bin/fix_stlink_perms.sh' >> ~/.bashrc
source ~/.bashrc

安装J-Link驱动程序(可选)

由于开发主机为 x86_64 架构,因此选择Linux (x86/x64) 版本的 J-Link 驱动;

J-Link驱动只负责与调试器硬件通信,JLink驱动版本的选择与目标单片机型号无关,只要开发主机架构相同,驱动选择就相同;

官网地址:SEGGER - The Embedded Experts - Downloads - J-Link / J-Trace

本文选择:SEGGER - The Embedded Experts - Downloads

DEB(Debian Package)是基于 Debian 系统(Ubuntu)的软件包格式,将deb安装包上传到ubuntu中自定义的JLink_Deb目录,执行如下指令进行安装

# 直接安装DEB包
sudo dpkg -i JLink_Linux_V792_x86_64.deb

# 若出现依赖错误,修复缺失依赖
sudo apt --fix-broken install

输入JLink,Tab键按两次判断JLink是否安装成功

udev规则配置

打开/etc/udev/rules.d/99-jlink.rules文件,添加如下内容

# SEGGER J-Link devices
SUBSYSTEM=="usb", ATTR{idVendor}=="1366", MODE="0666", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="1366", ATTR{idProduct}=="0101", MODE="0666", GROUP="plugdev"  # J-Link Edu
SUBSYSTEM=="usb", ATTR{idVendor}=="1366", ATTR{idProduct}=="0102", MODE="0666", GROUP="plugdev"  # J-Link Plus
SUBSYSTEM=="usb", ATTR{idVendor}=="1366", ATTR{idProduct}=="0103", MODE="0666", GROUP="plugdev"  # J-Link Ultra
SUBSYSTEM=="usb", ATTR{idVendor}=="1366", ATTR{idProduct}=="0121", MODE="0666", GROUP="plugdev"  # J-Link OB

生效规则并重启服务

切换到普通用户,执行如下操作

sudo udevadm control --reload-rules
sudo udevadm trigger
sudo usermod -aG plugdev $USER  # 将当前用户加入plugdev组
sudo reboot  # 重启生效

四 安装烧录工具

 官网地址:Client Challenge

本文选择pyOCD进行安装,pyOCD 要求 Python 版本至少为 3.6,输入如下指令查看python版本

pyocd --version

pyOCD 可以通过 pip 直接安装,pip 是 Python Package Index (PyPI) 的官方包管理工具,用于安装、升级、卸载和管理 Python 的第三方库(Packages),

# 安装PyOCD
pip3 install --user pyocd

# 验证安装
pyocd list --targets | grep stm32f103  # 应显示stm32f103RC

纯Linux环境 - udev规则配置

创建规则文件99-pyocd.rules 并添加如下内容

sudo vim /etc/udev/rules.d/99-pyocd.rules
# ST-Link/V2
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="3748", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="374b", MODE="0666"

# J-Link
SUBSYSTEM=="usb", ATTR{idVendor}=="1366", MODE="0666"

sudo udevadm control --reload-rules
sudo udevadm trigger
sudo usermod -aG plugdev $USER  # 将当前用户加入plugdev组
sudo reboot  # 重启生效

 WSL环境

 创建权限修复脚本

# 创建自动修复脚本
sudo vim /usr/local/bin/fix_usb_perms.sh

 将下述内容拷贝到新创建的脚本fix_usb_perms.sh 文件中

#!/bin/bash
# 修复所有 USB 设备权限
for dev in /dev/bus/usb/*/*; do
  [ -e "$dev" ] && sudo chmod 666 "$dev"
done

# 每次打开终端自动修复权限
echo "fix_usb_perms" >> ~/.bashrc

pyOCD 烧录固件

存储器地址映射

  Flash主存储区 (Main Flash Memory) : 0x0800 0000 - 0x0800 FFFF (64KB),存储用户程序(代码、常量数据),上电后默认从 0x0800 0000 开始执行;

pyOCD烧录指令

擦除指令 pyocd erase:清除芯片Flash存储区,支持三种模式

--chip: 全片擦除   --sector:按扇区擦除    --mass: 深度擦除

pyocd erase --target stm32f103rc --chip  # 长选项版本
pyocd erase -t stm32f103rc -c            # 短选项版本

烧录指令 pyocd load: 将程序文件(Hex/Bin)写入 Flash

  • 烧录Hex文件
pyocd load 16进制文件名 --target stm32f103rc --erase sector #长选项版本
pyocd load 16进制文件名 -t stm32f103rc -e sector            #短选项版本
  • 烧录Bin文件
pyocd load -a 0x08000000 -e sector -t stm32f103rc 二进制文件

复位指令 pyocd erase:重启目标芯片,使新程序生效

复位类型存在软件复位,硬件复位,系统复位,核心复位四种方式,--reset-type sw 指定复位方式为软件复位,--reset-type hw 指定复位方式为硬件复位;

pyocd reset --reset-type sw --target stm32f103rc

辅助指令:

# 列出已连接的调试器
pyocd list --probes

# 列出支持的芯片型号
pyocd list --targets

安装usbipd-win

wsl2 未提供 USB 设备的直接映射功能,无法直接访问本地Windows 的 USB 设备,Ubuntu 系统相当于远程服务器,若ST-Link 设备连接在本地 Windows 电脑上,而远程服务器 物理上不直接连接该设备,因此必然无法识别,所以需要将本地 Windows 的 USB 设备 跨网络共享给远程服务器,usbip 是一个 Linux 工具,允许通过网络共享 USB 设备,而 usbipd-win 是 Windows 版本的实现,usbipd-win 允许将 USB 设备从 Windows 主机共享到其他设备或虚拟机;

官网地址:https://github.com/dorssel/usbipd-win/releases

解决方案

Windows 端:      安装usbipd-win,将 ST-Link 设备共享为 IP 设备

远程 Ubuntu 端: 安装usbip工具,通过 IP 地址连接共享的 USB 设备

windows端安装usbipd-win

管理员身份运行Windows PowerShell,输入如下指令,若出现下载失败,启动 fq 软件即可;

winget install dorssel.usbipd-win

 下载结束之后以管理员身份重启Windows PowerShell, 按照如下步骤进行配置usbipd-win

# 功能: 列出当前系统上所有可用的USB设备
usbipd list

# 功能: 用于将本地 USB 设备注册到 USB/IP 守护进程(usbipd),使其能够通过网络被远程客户端访问
# --busid:指定待绑定的USB设备的总线ID,可通过usbipd list获得设备的总线ID
  usbipd bind --busid=<busid>

# usbipd bind --busid 2-2

# 查看usbipd的服务状态,判断况是否需要手动启动usbipd server
usbipd state

# 查看windows端的IP地址供后续使用
ipconfig

# 允许TCP 3240端口通过防火墙
New-NetFirewallRule -DisplayName "USBIPD" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 3240

 注意:保持当前PowerShell窗口运行,不要关闭此窗口

纯Linux环境安装usbip (可选)

ubuntu系统中安装 usbip 客户端工具,无论是哪个版本的ubuntu系统,皆可按照此方案安装usbip,执行如下指令:

步骤一: ubuntu系统安装必要的编译工具和依赖库:

sudo apt update
sudo apt install -y build-essential libudev-dev libwrap0-dev libtool automake autoconf pkg-config hwdata

步骤二:克隆并编译linux-tools源码

# Ubuntu软件源下载并安装Linux内核源代码包
sudo apt install linux-source

# 解压内核源码
sudo tar -xjvf /usr/src/linux-source-5.15.0/linux-source-5.15.0.tar.bz2

# 进入usbip目录
cd linux-source-*/tools/usb/usbip

步骤三:进入源码目录(已进入 linux-source-*/tools/usb/usbip)后,执行以下命令生成编译配置文件

# 生成configure脚本
./autogen.sh

步骤四:采用configure 命令指定编译参数

# --with-tcp-wrappers=no 关闭TCP包装器
# --with-usbids-dir      指定 USB 设备数据库路径

./configure --with-tcp-wrappers=no --with-usbids-dir=/usr/share/hwdata

步骤五:编译并安装

# 编译 -j$(nproc) 利用多核加速编译
make -j$(nproc) 
# 安装
sudo make install

步骤六:验证安装是否成功

usbip version

 wsl环境安装usbip

步骤一:Windows 端更新 WSL 2 内核,以管理员权限打开 PowerShell并执行

#更新wsl2内核
wsl --update

#重启所有WSL实例
wsl --shutdown

步骤二:wsl环境中安装编译依赖

sudo apt install build-essential libusb-1.0-0-dev git

步骤三:下载适用于 WSL 2 的内核源码

mkdir -p ~/src && cd ~/src
git clone https://github.com/microsoft/WSL2-Linux-Kernel.git -b linux-msft-wsl-6.6.y --depth 1
cd WSL2-Linux-Kernel/tools/usb/usbip

步骤四: 获取 WSL2 内核配置文件

步骤五:编译 usbip 工具

# 进入到usbip目录
cd tools/usb/usbip

# 安装必要编译工具
sudo apt install autoconf automake libtool libusb-1.0-0-dev

# 生成configure脚本
./autogen.sh

# 配置编译选项(指定安装路径)
./configure --prefix=/usr/local

# 编译
make

# 安装
sudo make install

步骤六:验证安装

# 检查 usbip 版本
usbip version

烧录测试

硬件连接

烧录流程总结

步骤一:以管理员身份打开powershell,输入usbipd list查看系统上所有可用的usb设备以及设备状态

步骤二:powershell输入ipconfig,查看windows的ip地址

步骤三:wsl环境中进入二进制/十六进制存放目录,进入该目录只是方便后续烧录程序;

 步骤四: 采用usbip attach 指令将windows端USB 设备连接到本地ubuntu系统;

sudo usbip attach -r <远程主机IP> -b <总线ID>

# 列出当前系统检测到的所有USB设备及其详细信息
lsusb

步骤五:采用pyocd erase指令擦除扇区;

pyocd erase -c -t stm32f103rc

步骤六:采用pyocd load指令烧录程序

步骤七:Cortex-M系列芯片烧录程序后复位自动完成,无需操作;

步骤八(可选):采用usbip detach指令断开已连接的 usb 设备;

# 查看待断开设备的usb端口号
sudo usbip port

# 断开设备
sudo usbip detach -p <端口号>

五 调试环境搭建

搭建思路

安装gdb-multiarch

步骤一:wsl 中安装调试工具链,其中gdb-multiarch专门用于调试不同架构的程序;

sudo apt update
sudo apt install gdb gdb-multiarch

pyOCD 实现了GDB 远程串行协议(Remote Serial Protocol, RSP),通过RSP协议,pyOCD具有如下功能:

  • 接收 GDB 客户端的命令(如断点设置、内存读取)。
  • 操作硬件调试器(如 ST-Link)与单片机通信。
  • 将结果返回给 GDB 客户端。

所以pyOCD不仅可以烧录,还可以作为GDB服务器

配置vscode

安装vscode插件

Cortex-Debug 是 vs code 中专门针对ARM Cortex-M 系列微控制器的调试适配器,负责

vs code 与 gdb-multiarch 的通信,用于将调试协议(DAP, Debug Adapter Protocol)消息转换为gdb命令,调试适配器作用如下:

  • 将 vs code 的调试 UI 操作(如设置断点、单步执行)转换为调试器命令;
  • 将调试器的响应(如变量值、程序状态)转换为 vs code 可识别的格式;

按照上述方式,安装WSL插件 C/C++插件 C/C++ Themes插件即可;

创建调试配置文件launch.json

调试配置文件(launch.json)是一种描述如何启动和控制调试会话的设置文件,它就像是调试过程的 "操作手册",假设你是一位导演,要拍一场复杂的戏:

  • 需要知道演员是谁(调试器类型,如 GDB、Cortex-Debug)。
  • 需要知道场景在哪(目标设备,如 STM32F103C8T6)。
  • 需要知道用什么道具(调试探头,如 ST-Link)。
  • 需要知道从哪一幕开始拍(程序入口点,如 main 函数)。

调试配置文件相当于拍摄脚本,告知调试系统如何启动、连接和控制调试会话;

vs code 中使用快捷键Ctrl + Shift + P打开命令面板,输入 "WSL:", 选择在新窗口打开wsl环境中的项目文件夹,在项目根目录创建 .vscode/launch.json文件;

 

SVD文件简介:SVD 文件(System View Description File)是一种用于描述MCU外设寄存器和外设信息的文件,SVD 文件的核心作用可以将外设寄存器映射可视化,方便开发者直观地查看和操作硬件寄存器

# 在WSL中下载STM32F103 SVD文件
wget https://github.com/posborne/cmsis-svd/raw/master/data/STMicro/STM32F103xx.svd

# 移动到用户目录下
mv STM32F103xx.svd ~/STM32F103.svd

输入如下指令,查找launch.json文件所需要文件路劲

#PyOCD设备名称
pyocd list --targets | grep stm32f103

# 调试器路径
which gdb-multiarch

# 交叉编译工具链路径
which arm-none-eabi-gcc
//launch.json文件

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "STM32F103C8T6 Debug (PyOCD)",
      "cwd": "${workspaceFolder}",
      "executable": "/home/shuju/project/template/build/main.elf",//替换为实际的ELF文件路径
      "request": "launch",
      "type": "cortex-debug",     //使用Cortex-Debug扩展
      "servertype": "pyocd",
      "device": "STM32F103RC",    //PyOCD设备名称(必须精确匹配)
      "runToEntryPoint": "main",  //自动运行到main函数
      "gdbPath": "/usr/bin/gdb-multiarch", //gdb-multiarch安装路径
      "showDevDebugOutput": true,
      "armToolchainPath": "/usr/local/bin/arm-none-eabi-gcc", //ARM交叉编译工具链的安装路径
      "pyocdConfig": {
        "frequency": 4000000,  // SWD时钟频率 (4MHz)
        "enable_semihosting": false
      },
      "preLaunchTask": "connect-usbip",    // 调试前自动连接USB设备
      "postDebugTask": "disconnect-usbip"  // 调试后断开USB设备
    }
  ]
}

调试流程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小呆瓜历险记

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

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

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

打赏作者

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

抵扣说明:

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

余额充值