GD32 CMake example
一個(gè)串口收發(fā)簡(jiǎn)單例子。
https://github.com/Huffer342-WSH/GD32_CMake_Example
可以下載該工程,稍微了解一點(diǎn)cmake就可以簡(jiǎn)單修改直接使用。
-
GD32 CMake example
- 使用到的工具
-
編譯與燒錄
- 命令行
- VSCode
-
調(diào)試
- 配合VSCode的marus25.cortex-debug插件實(shí)現(xiàn)調(diào)試功能
-
RTT使用方法
- marus25.cortex-debug
- 手動(dòng)連接
-
注意事項(xiàng)
- 交叉編譯工具鏈設(shè)置
- 鏈接腳本
- 啟動(dòng)文件
- 從零開(kāi)始搭建工程
使用到的工具
交叉編譯器:gcc-arm-none-eabi-10.3-2021.10-win32
構(gòu)建工具: Ninja
編輯器:vscode
調(diào)試接口連接: openocd-xpack(第三方構(gòu)建的OpenoCD)
調(diào)試器:cmsis-dap (淘寶購(gòu)買(mǎi)的 猛龍DAP ,¥35擁有碾壓野火DAP的性能,性能比肩jlink-v8)淘寶鏈接
單片機(jī): GD32F310
工程結(jié)構(gòu)
/bin 生產(chǎn)的二進(jìn)制文件等
/build cmake構(gòu)建目錄
/cmake cmake文件目錄
/OpenOCD openocd腳本存放位置
/Core 自己編寫(xiě)的源文件存放位置
/Drivers 固件庫(kù)與segger RTT
|- CMSIS
|- GD32F3x0_standard_peripheral
|- RTT
/Retarget 重定向printf,里面有別人寫(xiě)的printf和scanf,相比使用C標(biāo)準(zhǔn)庫(kù)中的函數(shù)節(jié)省一些空間
編譯與燒錄
- 首先下載上文中提到的gcc-arm-none-eabi和openocd,構(gòu)建器使用make或者ninja都可以,工程里的源文件多了以后ninja啟動(dòng)速度會(huì)更快一點(diǎn)。
- 準(zhǔn)備好以上工具后將可執(zhí)行文件所在目錄的路徑添加都PATH(Path)環(huán)境變量
- 然后在以下文件中修改路徑
.vscode\GD32_CMake_Example.code-workspace(必須改)
cmake\arm-none-eabi-gcc.cmake (可選,環(huán)境變量添加了就不用指定絕對(duì)路徑了)
Core\CMakeLists.txt(該文件末尾將cmake install 指定成了使用openocd燒錄)
- 將
OpenOCD\gd32f3x0.cfg
文件復(fù)制到OpenOCD\openocd\scripts\target
目錄中
做完以上工作后可以開(kāi)始編譯工程了
命令行
進(jìn)入工程文件夾目錄中
#配置
cmake -DCMAKE_TOOLCHAIN_FILE=cmake/arm-none-eabi-gcc.cmake -DCMAKE_BUILD_TYPE:STRING=Debug -G Ninja -S ./ -B ./build
#編譯
cmake --build ./build --config Debug --target all --
#燒錄
cmake --install ./build
VSCode
- 安裝拓展ms-vscode.cmake-tools和marus25.cortex-debug
- 把文件夾保存為工作區(qū)
- 修改.workspace文件,在里面指定generator和cmake參數(shù)等內(nèi)容
- 修改相關(guān)文件里的路徑
- ctrl+p打開(kāi)命令面板,CMake:Configure 配置
- 點(diǎn)擊vscode狀態(tài)欄的build編譯工程,或者命令面板里的CMake:Build
- ctrl+p打開(kāi)命令面板,選擇CMake: Install燒錄
調(diào)試
配合VSCode的marus25.cortex-debug插件實(shí)現(xiàn)調(diào)試功能
- 安裝marus25.cortex-debug插件
- 在工作區(qū)配置文件.code-workspace或者文件夾啟動(dòng)配置文件launch.json中添加調(diào)試配置
{
"cwd": "${workspaceRoot}",
"executable": "${workspaceRoot}/bin/Debug/GD32_CMake_Example.elf",
"name": "Cortex-Debug",
"request": "launch",
"type": "cortex-debug",
"servertype": "openocd",
"configFiles": [
"interface/cmsis-dap.cfg",
"target/gd32f310.cfg",
],
"svdFile": "${workspaceRoot}/OpenOCD/GD32F3x0.svd",
"searchDir": [
"E:/SDK-Win/OpenOCD/openocd/scripts/"
],
"runToEntryPoint": "main",
"showDevDebugOutput": "none",
"rttConfig": {
"enabled": true,
"polling_interval": 1,
"address": "auto",
"decoders": [
{
"label": "",
"port": 0,
"type": "console"
},
]
}
},
添加后可以在VSCode左側(cè)邊欄的Run and Debug
選項(xiàng)卡看到剛添加的調(diào)試配置
- 連接調(diào)試器,點(diǎn)擊運(yùn)行
RTT使用方法
下文講述基于openocd和cmsis-dap的SEGGER RTT使用方法,jlink用戶(hù)使用jlink RTT view即可
marus25.cortex-debug
在使用vscode插件marus25.cortex-debug時(shí),在配置文件中添加rtt相關(guān)配置,就會(huì)在調(diào)試時(shí)自動(dòng)鏈接segger rtt。
"rttConfig": {
"enabled": true,
"polling_interval": 1,
"address": "auto",
"decoders": [
{
"label": "",
"port": 0,
"type": "console"
},
]
}
手動(dòng)連接
編寫(xiě)openocd配置文件 OpenOCD\Start_RTT.cfg,內(nèi)容中除了普通的配置接口和設(shè)備,還要增加rtt相關(guān)設(shè)置。
source [find interface/cmsis-dap.cfg]
transport select swd
cmsis_dap_backend usb_bulk
source [find target/gd32f310.cfg]
init
rtt setup 0x20000000 8192 "SEGGER RTT"
rtt polling_interval 1
rtt start
rtt server start 9990 0
rtt server start 9991 1
rtt server start 9992 2
reset init
resume
上文中rtt server start 9990 0
就代表將RTT通道一通過(guò)端口為9990的TCP serve轉(zhuǎn)發(fā)。
連接單片機(jī)和調(diào)試器,使用openocd指定該配置文件
openocd -f .\OpenOCD\Start_RTT.cfg
openocd輸出如下
然后打開(kāi)串口和TCP工具,在串口輸入RTT test
,就可以運(yùn)行RTT測(cè)試
注意事項(xiàng)
假如想要自己從零開(kāi)始新建一個(gè)使用CMake管理,通過(guò)GNU工具鏈編譯的工程,需要注意以下三點(diǎn)。
交叉編譯工具鏈設(shè)置
cmake通過(guò) -DCMAKE_TOOLCHAIN_FILE 參數(shù)指定工具鏈的配置文件。
cmake\arm-none-eabi-gcc.cmake文件中是交叉工具鏈的配置
鏈接腳本
鏈接器(Linker)負(fù)責(zé)將編譯后的目標(biāo)文件和所需的庫(kù)文件合并在一起,生成最終的可執(zhí)行文件或庫(kù)文件。鏈接器腳本(Linker Script)是用來(lái)指導(dǎo)鏈接器在這個(gè)合并過(guò)程中如何排列和組織代碼段、數(shù)據(jù)段、符號(hào)表等內(nèi)容的文本文件。
GD32官方提供了IAR和Keil環(huán)境的支持包,但是沒(méi)有適用于GNU工具鏈的鏈接腳本,但是我們可以參考同架構(gòu)的STM32的了解腳本,通過(guò)STM32CubeIDE或者STM32CubeMX生產(chǎn)makefile工程,里面就有鏈接腳本。
鏈接腳本中需要包含內(nèi)存布局和分段的定義,比如改工程中的鏈接腳本gd32f3x0.ld
中
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
}
它描述了存儲(chǔ)器(內(nèi)存)的布局和分配。這個(gè)鏈接腳本片段指定了兩個(gè)不同的存儲(chǔ)器段:RAM 和 FLASH。
-
RAM:
-
ORIGIN = 0x20000000
:這是 RAM 段在內(nèi)存中的起始地址。在這個(gè)例子中,RAM 的起始地址被設(shè)置為0x20000000
。 -
LENGTH = 8K
:這是 RAM 段的長(zhǎng)度。在這個(gè)例子中,RAM 的長(zhǎng)度被設(shè)置為 8K(8192字節(jié))。因此,RAM 的地址范圍是從0x20000000
到0x20001FFF
。
-
-
FLASH:
-
ORIGIN = 0x08000000
:這是 FLASH 段在內(nèi)存中的起始地址。在這個(gè)例子中,F(xiàn)LASH 的起始地址被設(shè)置為0x08000000
。 -
LENGTH = 64K
:這是 FLASH 段的長(zhǎng)度。在這個(gè)例子中,F(xiàn)LASH 的長(zhǎng)度被設(shè)置為 64K(65536字節(jié))。因此,F(xiàn)LASH 的地址范圍是從0x08000000
到0x0800FFFF
。
-
在這個(gè)鏈接腳本中,每個(gè)段都有一個(gè)或多個(gè)屬性:
- (xrw):這是段的屬性,指定了段是否可執(zhí)行(x,executable)、可讀(r,readable)和可寫(xiě)(w,writable)。
- (rx):同樣是段的屬性,這里指定了段是否可執(zhí)行和可讀,但不可寫(xiě)。
鏈接腳本的作用是告訴鏈接器如何分配和組織代碼和數(shù)據(jù)在存儲(chǔ)器中的位置。這是編譯器和鏈接器合作的關(guān)鍵部分,確保生成的可執(zhí)行文件在內(nèi)存中正確加載和運(yùn)行。在這個(gè)例子中,你的可執(zhí)行程序的代碼部分通常會(huì)被加載到 FLASH 存儲(chǔ)器段,而數(shù)據(jù)(變量、堆棧等)則通常會(huì)被加載到 RAM 存儲(chǔ)器段。
RAM和FLASH的地址和大小可以從用戶(hù)手冊(cè)中找到,如 GD32F3x0_User_Manual_CN_Rev2.7.pdf>1.系統(tǒng)及存儲(chǔ)器架構(gòu)>1.3存儲(chǔ)器映射
點(diǎn)擊展開(kāi) 段定義SECTIONS{
...
}
需要包含以下部分
.isr_vector:
這部分定義了啟動(dòng)代碼,其中包含中斷向量表(Interrupt Vector Table)。中斷向量表存儲(chǔ)了各種中斷和異常的處理函數(shù)的入口地址。.isr_vector 節(jié)在 FLASH 存儲(chǔ)器段中。
.text:
這是程序的代碼段,包括執(zhí)行代碼和一些初始化代碼。在這個(gè)部分,.text 節(jié)存儲(chǔ)了程序的代碼,.glue_7 和 .glue_7t 是 ARM 和 Thumb 之間的粘合代碼,.eh_frame 是與異常處理有關(guān)的信息。
.rodata:
這是只讀數(shù)據(jù)段,用于存儲(chǔ)常量和字符串等只讀數(shù)據(jù)。
.ARM.extab:
這部分存儲(chǔ)了與 ARM 異常處理相關(guān)的信息,可能包括異常類(lèi)型、處理代碼等。
.ARM:
這部分可能與異常處理索引表有關(guān),存儲(chǔ)了異常處理的索引信息。
.preinit_array、.init_array、.fini_array:
這些部分存儲(chǔ)了初始化和終止函數(shù)的指針數(shù)組,用于在程序啟動(dòng)和退出時(shí)執(zhí)行特定操作。
.data:
這是已初始化數(shù)據(jù)段,包括全局和靜態(tài)變量的初始化數(shù)據(jù)。
.bss:
這是未初始化數(shù)據(jù)段,包括全局和靜態(tài)變量的未初始化數(shù)據(jù)。這些變量在程序啟動(dòng)時(shí)會(huì)被自動(dòng)初始化為零。
._user_heap_stack:
這部分用于定義堆和棧的位置,確保在分配內(nèi)存時(shí)有足夠的空間。
/DISCARD/:
這是用于從編譯器庫(kù)中丟棄不需要的部分的部分,以減小生成的可執(zhí)行文件的大小。
.ARM.attributes:
這是用于存儲(chǔ)與 ARM 架構(gòu)有關(guān)的屬性信息,例如硬件特性和指令集等。
啟動(dòng)文件
啟動(dòng)文件也是一段普通的代碼。Cortex-M系列的處理器在啟動(dòng)后會(huì)在內(nèi)存中固定位置(0x00000000)找中斷向量表,中斷向量表中包含了各種中斷和異常的初始處理函數(shù)的入口地址,當(dāng)觸發(fā)中斷后MCU就回到向量表中找到函數(shù)入口地址,然后調(diào)用對(duì)應(yīng)的中斷服務(wù)函數(shù)。
在啟動(dòng)文件startup_gd32f3x0.s中,包含了復(fù)位服務(wù)函數(shù)Reset_Handler以及中斷向量表,這個(gè)文件一般用匯編編寫(xiě),但也有使用c語(yǔ)言編寫(xiě)的。
匯編語(yǔ)言中通過(guò).section語(yǔ)句可以指定數(shù)據(jù)段或者代碼段的存儲(chǔ)位置。在鏈接文件中我們定義了.isr_vector段,位于FLASH中最開(kāi)頭的位置(0x08000000),在啟動(dòng)文件中通過(guò).section .isr_vector,“a”,%progbits將向量表指定到這個(gè)段,從而實(shí)現(xiàn)了將向量表鏈接到我們想要的位置。當(dāng)單片機(jī)從主FLASH啟動(dòng)書(shū)會(huì)將0x08000000開(kāi)頭的地址映射到0x00000000。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-670673.html
向量表中的內(nèi)容由單片機(jī)廠商決定,可以在用戶(hù)手冊(cè)中找到向量地址的定義,比如我使用的GD32F3x0,可以在GD32F3x0_User_Manual_CN_Rev2.7.pdf>6.中斷/事件控制器(EXTI)> 6.3功能描述
中找到向量表的描述。在官方提供的固件庫(kù)中也有適用于Keil和IAR的啟動(dòng)文件,在路徑Drivers\CMSIS\GD\GD32F3x0\Source
下,但是我們要使用的是GNU工具鏈匯編風(fēng)格的啟動(dòng)文件,可以依據(jù)這兩個(gè)文件修改得到文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-670673.html
到了這里,關(guān)于VSCode+CMake+Arm GNU Toolchain搭建GD32開(kāi)發(fā)環(huán)境的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!