首先参考前一篇配置环境:Mini2440 调试环境搭建(wsl + vscode + openOCD)-CSDN博客

一、 关键配置

1.修改launch.json

修改launch.json是我们调试的主要手段之一,之前复制的json文件需要替换为本文部分。

重点:

  1. WSL 通常不自带 GDB,需安装 sudo apt install gdb-multiarch,并在配置中指定 /usr/bin/gdb-multiarch

  2. 调试必须加载 .elf 文件(带符号表),千万别加载 .bin,否则 GDB 会报 No executable file specified

  3. 不要在 JSON 中配置 miDebuggerServerAddress,这会导致 VS Code 抢在 setupCommands 之前尝试连接,造成冲突。要在 setupCommands 里手动连。

  4. 手动初始化 SDRAM:這是裸机调试的痛点。代码是下载到 SDRAM (0x30000000) 的,但下载前 SDRAM 控制器没初始化,导致写入失败(读出来全是垃圾值)。必须在 load 之前通过 monitor mww 配置寄存器。

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug Mini2440 (Stable)",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/mini2440.elf", // 指向 ELF
            "cwd": "${workspaceFolder}",
            "MIMode": "gdb",
            "miDebuggerPath": "/usr/bin/gdb-multiarch", 
            "targetArchitecture": "arm",
            
            // 关键:setupCommands 顺序不能乱
            "setupCommands": [
                // 1. 连接 Windows 上的 OpenOCD (端口 3333)
                { "text": "target extended-remote 127.0.0.1:3333" },
                
                // 2. 复位芯片
                { "text": "monitor reset halt" },
                
                // 3. 手动初始化 SDRAM 控制器 (根据板子配置修改)
                // 必须在 load 之前执行,否则代码写不进内存!
                { "text": "monitor mww 0x48000000 0x22121110" }, // BWSCON
                { "text": "monitor mww 0x4800001c 0x00018005" }, // BANKCON6
                { "text": "monitor mww 0x48000020 0x00018005" }, // BANKCON7
                { "text": "monitor mww 0x48000024 0x009604f4" }, // REFRESH
                { "text": "monitor mww 0x48000028 0x00000032" }, // BANKSIZE
                { "text": "monitor mww 0x4800002c 0x00000030" }, // MRSRB6
                { "text": "monitor mww 0x48000030 0x00000030" }, // MRSRB7

                // 4. 关看门狗 & 蜂鸣器
                { "text": "monitor mww 0x53000000 0x00000000" },
                { "text": "monitor mww 0x56000010 0x00155550" }, 

                // 5. 加载符号表
                { "text": "file ${workspaceFolder}/build/mini2440.elf" },

                // 6. 下载代码
                { "text": "load" },
                
                // 7. 设置入口断点
                { "text": "break main" }
            ],
            "stopAtEntry": false, // 启动后手动按 F5,防止自动逻辑出错
            "externalConsole": false
        }
    ]
}

2.快捷键

动作 VS Code 快捷键 OpenOCD (Telnet) GDB (调试控制台)
暂停 F6 / 暂停按钮 halt -exec interrupt
继续 F5 / 播放按钮 resume -exec c
单步跳过 F10 step  -exec n
单步进入 F11 step -exec s
复位 Ctrl+Shift+F5 reset -exec monitor reset

二、 调试技巧

环境通了只是第一步,如何利用工具解决 Bug 才是关键。以下是几个非常实用的调试技巧。

连接好你的硬件,这部分有疑问麻烦移步上篇:Mini2440 调试环境搭建(wsl + vscode + openOCD)-CSDN博客

cmd里使用openOCD命令:

openocd -f interface/jlink.cfg -f board/mini2440.cfg

在vscode中按下F5进入调试,底部会变成橙色

1. 直接操作寄存器

想验证 LED 电路是否正常?或者想测试某个寄存器配置的效果?不需要改代码重新编译。

在 调试控制台 (Debug Console) 输入:

# 例如:将 GPBDAT (0x56000014) 写 0,点亮所有 LED

-exec set {int}0x56000014 = 0

你会看到板子上的灯瞬间全亮。

2. 运行时修改变量

在测试循环逻辑边界条件时(比如循环 100次),不需要按 100 次 F10。

  • 打个断点进入循环,直接单击即可。

  • 在“监视”窗口或控制台,将循环变量 i 的值从 0 直接改为100。

  • 继续运行,程序会直接执行最后一次循环的逻辑。

3. 解决无法暂停程序

VS Code 在嵌入式调试时有个 Bug:当程序在死循环中全速运行(CPU 占用 100%)时,点击“暂停”按钮往往无效,报错 Unable to perform this action

解决方法:绕过 VS Code,直接给 OpenOCD 下令。

新开一个管理员cmd窗口,旧的openOCD也不要关闭,输入指令,安装telnet:

dism /online /Enable-Feature /FeatureName:TelnetClient

安装完成后直接在该窗口,输入指令:

telnet localhost 4444

在该页面输入:

halt

这会强制挂起 CPU,夺回控制权,大概率会强行停在延时里面,如图所示。

使用resume命令恢复状态

resume

4. 汇编调试与 SP 指针

如果程序一进 main 就死机(报错 0x80004004),通常是因为启动代码 (startup.S) 没写好,导致堆栈指针 (SP) 非法。

  • 技巧:在 VS Code 代码区右键 -> “打开反汇编视图 (Open Disassembly View)”

  • 使用 F10 单步执行汇编指令。

  • 观察 寄存器 (Registers) 窗口中的 R13 (SP),确保在跳转到 C 代码前,SP 指向了合法的 RAM 地址。

5. 高级监视

  • Hex 查看:在左侧监视窗口添加表达式,通过输入指令,可以直接看十六进制值或者二进制,x:hex,b:bin。

    *(volatile int*)0x56000014,x
    
    *(volatile int*)0x56000014,b

  • 数据断点 :想知道是谁偷偷改了全局变量?在调试控制台输入命令,如果有人修改了地址的值程序会自动暂停。

    -exec watch *0x56000014
  • 条件断点:点击生成断点之后,右键编辑断点输入逻辑表达式,比如我这里输入的i == 8,就会在i=8的时候停下来,其他时候不会,可以快速跳过需要重复很多次的循环。

三、 常见玄学问题

Q: 为什么每次 Halt 都停在 delay 函数里?

A: 概率问题。CPU 99.9% 的时间都在执行 delay 空循环,只有 0.1% 的时间在操作 IO。随机暂停几乎肯定会抓到它在“摸鱼”。如果想看 IO 操作,请在该行打断点。

Q: 为什么调试控制台报错 unable to create variable object?

A: 在控制台输入 GDB 原生命令时,必须加上 -exec 前缀(例如 -exec info reg),否则 VS Code 会把它当成 C 语言变量去解析。


结语

通过 VS Code + WSL 进行嵌入式开发,既能享受 Linux 强大的命令行生态,又能拥有 Windows 舒适的 GUI 体验。虽然配置初期有些繁琐,但一旦打通了 OpenOCDGDB 的任督二脉,配合上述的调试技巧,你将拥有掌控硬件底层的强大能力。

希望这篇文章能帮你少走弯路,享受裸机开发的乐趣!

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐