windows qtcreator + gcc +openocd 编译调试stm32

qtcreator + gcc +openocd 编译调试stm32

准备的软件:
1.Qtcreator
2. gcc-arm-none-eabi (新版的可能有bug )
3. openocd
4. python-2.7(用于qtceator 的gdb python版本调试器 用新版本)

安装好上面的软件
配置好openocd python的环境变量

打开qtceator , 菜单->帮助->关于插件 找到Bare Metal 插件 勾先该插件
windows qtcreator + gcc +openocd 编译调试stm32_第1张图片
关闭后 重新启动qtcreator

菜单->工具->选项 找到 设备选项 在Bare Metal页上 add ->OpenOCD 添加一个类型
windows qtcreator + gcc +openocd 编译调试stm32_第2张图片
名字可根据Stm32 cpu类型和下载器名命

Startup mode 选择为 TCP/IP mode
Host 填localhost 端口为3333
Executable file 填安装的openocd程序文件路径

Addition argument 填 -f interface/cmsis-dap.cfg -f target/stm32f4x.cfg
根据下载器及实际的Stm32 芯片填写 这些配置文件是在openocd安装的位置

Init command 填

set remote hardware-breakpoint-limit 6
set remote hardware-watchpoint-limit 4
monitor reset halt
monitor report_flash_progress on
monitor program "%{CurrentRun:Executable:FilePath}" reset
monitor poll on
monitor reset halt
b main

%{CurrentRun:Executable:FilePath}就当前qtcreator的变量 表示要下载的文件路径 在项目/运行/ 中填写的被调试的elf文件
b main 表示在main函数上下一个断点

Reset command 填

monitor reset halt
b main

点击Apply应用设置

然后到 设备页 新建一个 Bare Matel设备 选择刚刚设置好的openocd类型
windows qtcreator + gcc +openocd 编译调试stm32_第3张图片

点击apply 配置 Bare Metal设置完成

点击左则的 在这里插入图片描述 Kits 进到套件设置

在编译器选项 新建 c 和 c++编译器 选择安装好的arm gcc 和 g++
windows qtcreator + gcc +openocd 编译调试stm32_第4张图片
点击Apply

转到debugger 页 新增一个调试器 选 arm-gdb-py python版本
windows qtcreator + gcc +openocd 编译调试stm32_第5张图片
点Apply

根据上面的设置 在构建套件页 增加一个套件
windows qtcreator + gcc +openocd 编译调试stm32_第6张图片
点Ok
Qtcreator 设置完毕

然后新建一个工程 选Non-Qt Project Plain C Application模版
项目的路径不要有空格和中文

Build system选Qbs
windows qtcreator + gcc +openocd 编译调试stm32_第7张图片

构建位置填为 .\Qbs
Kits选建好的Stm32构建套件
windows qtcreator + gcc +openocd 编译调试stm32_第8张图片
Main.c文件 main()改成没有参数输入的

双击编辑 *.qbs文件

import qbs
import qbs.Environment
import qbs.FileInfo
import qbs.Probes
import qbs.TextFile
import qbs.Process    //导入的一样qbs提供的库
//import qbs.ModUtils
//import qbs.Utilities
//import qbs.WindowsUtils

Project {
    minimumQbsVersion: "1.7.1"
    Product {
        name:project.name
// type: 类型是指这个Product 最终需要生成的Artifact 的Filetags 
//根据这里的设置来一步步向上查找顶Rule 再反向生成需要的文件
//如application= elf文件  - obj – c c++ asm
        type: [
            "flash",		
            "obj_asm_out",
//            "application",
        ]     // the final resualt Artifact filetags this produt want
        Depends { name: "cpp" }     //refer "cpp" Module 这里指引用Qbs
//的内建Module 常用”cpp”用于 c c++项目的编译

        property string openocdDir:""
        property string openocdInterfacePath:"\""+sourceDirectory+"/cmsis-dap-swd.cfg"+"\""   //"./cmsis-dap-swd.cfg" "interface/cmsis-dap.cfg" "interface/stlink.cfg"
// openocdInterfacePath 用于指定openocd接口配置 文件内容见下文所示

        property string openocdCpuCfgPath:"target/stm32f4x.cfg"   //"target/stm32f1x.cfg" 指定stm32 cpu配置文件
        property string openocdEraseCpuSector:"" //"-c \"flash erase_sector 0 0 11\""   // flash erase_sector bank_num first last
//设置是否下载前擦除
        property string toolChainPath:FileInfo.path(cpp.compilerPath)
        property string elfSizeExePath:toolChainPath+"/arm-none-eabi-size.exe"
        property string objCopyExePath:toolChainPath+"/arm-none-eabi-objcopy.exe"
        property string objDumpExePath:toolChainPath+"/arm-none-eabi-objdump.exe"
//这里获取配置好的gnu-arm工具链路径
        files: [
            "driver/led.c",
            "driver/stm32f4xx_it.c",
            "driver/system_stm32f4xx.c",
            "fwlib/inc/stm32f4xx_conf.h",
            "fwlib/inc/stm32f4xx_gpio.h",
            "fwlib/inc/stm32f4xx_rcc.h",
            "fwlib/src/misc.c",
            "fwlib/src/stm32f4xx_gpio.c",
            "fwlib/src/stm32f4xx_rcc.c",
            "include/led.h",
            "include/main.h",
            "include/stm32f4xx.h",
            "include/stm32f4xx_conf.h",
            "include/stm32f4xx_it.h",
            "include/system_stm32f4xx.h",
            "main/main.c",
        ]
// files:是指项目引入的源文件
        Group {     // Properties for the produced executable
            fileTagsFilter: ["obj","objc","application","flash","obj_asm_out"] //,"application","obj","objc","asm","asm_cpp"
            qbs.install: true
            //            qbs.installDir: "bin"
        }
//Group 指定一些文件 相同的属性 如上是指定的fileTager文件的
//qbs.install属性设置为true  即这些文件安装到install-root
        cpp.cLanguageVersion:"c11" //c语言指定的版本
        cpp.includePaths:
        [
            "./CMSIS/Include",
            "./CMSIS/Device/ST/STM32F4xx/Include",
            "./fwlib/inc",
            "./include",
//            toolChainPath+"/../arm-none-eabi/include",
//            toolChainPath+"/../arm-none-eabi/include/c++/8.2.1",
//            toolChainPath+"/../arm-none-eabi/include/c++/8.2.1/tr1",
//            toolChainPath+"/../arm-none-eabi/include/c++/8.2.1/arm-none-eabi",
//            toolChainPath+"/../lib/gcc/arm-none-eabi/8.2.1/include"
        ]
//编译和编辑中用到的头文件引用路径
//        cpp.compilerIncludePaths:base.concat(cpp.includePaths)

        cpp.defines:["STM32F40_41xxx","STM32F407xx=1","_RTE_=1","__GCC=1","USE_STDPERIPH_DRIVER"]
//设置一些项目中用到的编译器预定义宏
        Group {
            files: ["./gcc/startup_stm32f40_41xxx.s"]
            fileTags: "asm"
            cpp.assemblerFlags:[
                "-mcpu=cortex-m4","-mthumb","-gdwarf-2","-mthumb-interwork",
                "-g",//"-Wall",
            ]
        }
//设置汇编文件 gnu-arm-as编译器的编译参数
//这里的汇编文件不是keil格式的 而是gcc格式的  可以在stm32的标准库中
//找到

        cpp.positionIndependentCode: false
        cpp.enableExceptions: false
        cpp.debugInformation: true
        cpp.executableSuffix: ".elf"

        cpp.driverFlags:[
            "-mcpu=cortex-m4","-mthumb","-mthumb-interwork",
            "-mfloat-abi=hard",  //softfp
            "-mfpu=fpv4-sp-d16"
        ]
// cpp.driverFlags 指的是编译和链接时直接传给编译器的参数 
        cpp.commonCompilerFlags:[
//            "-fno-strict-aliasing","-g3",
            "-g","-Wall","-O0",
            "-fdata-sections",
            "-ffunction-sections",
            "-mapcs-frame","-mapcs-stack-check",
//            "-flto","-fno-inline","-std=c99", "-flto"
        ]
//c c++编译时的一些公共参数
//        cpp.driverLinkerFlags:["-mcpu=cortex-m4","-mthumb","-mthumb-interwork"]
        cpp.linkerFlags:
        [
            "-T"+path+"/STM32F417IG_FLASH.ld",
//            "-specs=nano.specs","-static","-specs=nosys.specs",
//            "-nostartfiles",
//            "?u,_printf_float",//"-cref","-u,Reset_Handler",
//            "--start-group",
            "-lnosys",
            "-lgcc",
            "-lc",
//            "-lstdc++",
            "-lm",
//            "--end-group",
            "-Map=Project.map",
            "--gc-sections",
            "--defsym=malloc_getpagesize_P=0x80",
        ]
//链接成elf 文件的linker参数 STM32F417IG_FLASH.ld可在Stm32标准库中找到   并放在本工程同级目录 

//        Properties
//        {
//            condition: qbs.buildVariant === "debug"
//            cpp.defines: outer.concat(["DEBUG=1"])
//            cpp.debugInformation: true
//            cpp.optimization: "none"
//        }

//        Properties
//        {
//            condition: qbs.buildVariant === "release"
//            cpp.debugInformation: false
//            cpp.optimization: "small"
//        }

//这里自定义一个生成规则  用于把生成过程中的”obj” “objc” Artifact 输//出作为输入 再生成汇编文件   new Command()是运行的命令
        Rule
        {
            inputs: ["obj","objc"]
            Artifact
            {
                filePath: input.baseName+".s"
                fileTags: "obj_asm_out"
            }
            prepare:
            {
                var objDumpPath = product.objDumpExePath;
                var argsObjDump = ["-S",input.filePath];  //,output.filePath
                var cmdObjDump = new Command(objDumpPath, argsObjDump);
                cmdObjDump.stdoutFilePath=output.filePath;
                cmdObjDump.description = input.fileName+" convert to asm...";
                return [cmdObjDump];
            }
        }


//这个Rule是用来将"application" Artifact输出文件 即elf文件转换为hex
//文件用于其它下载(如串口)  打印elf文件的大小信息
//再生成一个openocd的下载 bat文件 (这个command可以不要)
        Rule
        {
            inputs: ["application"]   //application
            Artifact
            {
                filePath: input.completeBaseName+".hex"//qbs.installRoot + "output1" + ".hex"  //installRoot install
                fileTags: "flash"
            }
            prepare:
            {
                var sizePath = product.elfSizeExePath;
                var argsSize = [input.filePath];
                var objcopyPath = product.objCopyExePath;
                var argsObjcopy = [input.filePath,"-Oihex",output.filePath];

                var openocdDir=product.openocdDir;
                var configInterfacePath = product.openocdInterfacePath;//"interface/stlink.cfg";
                var configStm32CfgPath = product.openocdCpuCfgPath;"target/stm32f4x.cfg";

                var argsFlashing =
                        " -f " +  configInterfacePath+
                        " -f " +  configStm32CfgPath+
                        " -c " +  "init" +
                        " -c " +  "halt" +
                        product.openocdEraseCpuSector +//"\"flash erase_sector 0 0 127\""
//                        " -c " +  "reset" +
//                        " -c " +  "halt" +
                        " -c " +  "\"flash write_image erase "  + "\\\"" + input.filePath + "\\\"" +"\"" +
                        " -c " +  "\"verify_image " + "\\\""+ input.filePath +"\\\"" +"\""+
//                        " -c " +  "reset"+
//                        " -c " +  "halt"+
                        " -c " +  "exit";


                var cmdSize = new Command(sizePath, argsSize);
                var cmdObjcopy = new Command(objcopyPath, argsObjcopy);
                var cmdWriteFile=new JavaScriptCommand();
                cmdWriteFile.maxExitCode=1000;
                cmdWriteFile.writedata=
                        openocdDir+"openocd.exe " +
                        " -f "+ configInterfacePath
                        +" -f " + configStm32CfgPath;

                cmdWriteFile.writedata1=openocdDir+"openocd.exe " + argsFlashing;
                cmdWriteFile.askyesorno=
                        "@echo OFF\n"+
                        "set /a yes=0 \n"+
                        "set /a no=0 \n"+
                        "set /p YESORNO=\"Are you want to go on?(Y/N)\"\n"+
                        "if not defined YESORNO set YESORNO=y\n"+
                        "if %YESORNO%==y set /a yes=1 \n"+
                        "if %YESORNO%==n set /a no=1 \n"+
                        "if %YESORNO%==Y set /a yes=1 \n"+
                        "if %YESORNO%==N set /a no=1 \n"+
                        "set /a x=yes \"|\" no \n"+
                        "if %x% equ 0 GOTO TEND\n"+
                        "if %no% equ 1 GOTO TEND\n"+
                        "if %yes% equ 1 GOTO ALIVE\n"+
                        ":ALIVE\n"+
                        "@echo ON\n";

                cmdWriteFile.sourceDir=project.sourceDirectory;
                cmdWriteFile.downloadBat=project.sourceDirectory+"/openocdDownload.bat";
                cmdWriteFile.elfFile=input.filePath;
                cmdWriteFile.sourceCode=function()
                {
                    var file=TextFile(sourceDir+"/openocd.bat",TextFile.WriteOnly);
                    file.truncate();
                    file.writeLine(writedata);
                    file.writeLine("pause");
                    file.close();

                    var file1=TextFile(downloadBat,TextFile.WriteOnly);
                    file1.truncate();
                    file1.writeLine("@echo prepare to download elf file: ");
                    file1.writeLine("@echo "+elfFile);
                    file1.write(askyesorno);
                    file1.writeLine(writedata1);
                    file1.writeLine("pause");
                    file1.writeLine(":TEND");
                    file1.writeLine("exit");
                    file1.close();

                    var process=new Process();
                    process.exec("cmd",["/c","start "+downloadBat]);  //+ "C:/Windows/System32/cmd.exe" %COMSPEC% qbs.shellPath
                }

                cmdSize.description = "Size of sections:";
                cmdSize.highlight = "linker";
                cmdObjcopy.description = "convert to bin...";
                cmdObjcopy.highlight = "linker";
                cmdWriteFile.description = "generate openocd download bat ...";
                return [cmdSize,cmdObjcopy,cmdWriteFile];
            }
        }

    }
}

构建好的qbs工程结构如图
windows qtcreator + gcc +openocd 编译调试stm32_第9张图片
startup_stm32f40_41xxx.s汇编启动文件 不是keil格式的 而是gcc格式的 可以在stm32的标准库中找到 上面的cmsis-dap接口配置文件cmsis-dap-swd.cfg 放在项目的同级目录 内容如下:

interface cmsis-dap
transport select swd  
adapter_khz 2000

其它接口要百度

Qbs工程配置好后 就选 on RemoteOpenOCD的构建目标

点构建 如无错误如下所示

然后就点项目 设置运行配置为custom on remoteOpenocd 设置executable 为生成的elf文件

连接好下载器 点击调试运行就会进行下载并运行断点在main函数入口了

有时中断会断不下来 可能是gdb-py或者是openocd的bug吧,更换版本可能好点
有时调试会假死 在进程管理器中关掉openocd各gdb-py的假死进程 重连下载器才可以再进行调试

还有就是点连续运行后再按暂停是停不下来的
Restart debuggin 一按就会假死
单步调试较慢 步过一些时间较长的指命会假死

最好用 先下好断点-直接运行到断点-删除断点-单步/步过 的方式进行调试

你可能感兴趣的:(windows qtcreator + gcc +openocd 编译调试stm32)