這一次的主角是STM32。
照片中是一塊STM32開發板,搭配的 debugger 是 ST-Link-V2 。
STM32具有優異的性能,各種強大的設計使得開發產品非常容易,而且這晶片也不貴。
這次作為實驗對象的是 STM32F103vet6。
在前面的章節不斷的使用 Code Blocks 這個優秀的 IDE ,而本次的實驗要用 Code Blocks 來進行整合開發環境的建置,並且能夠單步執行。
首先要取得 Compiler 。可以先閱讀
How to install the ARM toolchain 這網站的指示。
或者去
CodeSourcery 網站取得也行。
接著是STM32要運作時的一些必備函式庫,可以去STM32原廠網站找
下載並且解壓縮後,會有一個名為 STM32F10x_StdPeriph_Lib_V3.5.0 的資料匣
我下載的是3.5版所以會有這樣尾數命名。
在 STM32F10x_StdPeriph_Driver 這個目錄底下有原廠先寫好的函式庫方便操作硬體,我們將複製使用。
在CMSIS目錄下,有著原廠寫好的核心啟動程式碼,也就是STM32這種32位元啟動複雜的行為不必我們自己寫。
以上就是行前預備。
安裝 Compiler 完成之後,啟動 Code Blocks 做點設定。
從 Settings -> Compiler... 進入
Selected compiler 選擇 GNU GCC compiler for ARM 的項目,根據你自己安裝compiler位置設定好。
然後進入 Settings -> Debugger 設定新的 debugger 專門針對STM32的
記得 Do "not" run the debugee 這個項目要打勾,避免在非預期狀態下被啟動。
然後進入 Tools -> Configure tools ,設定一個快速工具好讓OpenOCD啟動。
這樣就可以在 GDB debugger 啟動前先快速的啟動 OpenOCD 以利連線。
開啟一個新專案來做STM32的範例。
一樣使用空白的專案,但下一步之後的Compiler選項記得點選 ARM 專用的。
專案開好後,專案設定的一些東西要變更。
首先是 Projetc -> Build options
由於選定的晶片,STM32屬於 Cortex-M3 系列的,所以要勾選 M3
然後在 Other options 底下要增加文字
-gdwarf-2 -mthumb -fomit-frame-pointer -Wall -Wstrict-prototypes -fverbose-asm -Os
在 #defines 下要增加
STM32F10X_HD
USE_STDPERIPH_DRIVER
在 Linker settings 的頁籤下,other linker options 要添加
-mthumb -nostartfiles -Tstm32f103vet6.ld -Wl,-Map=main.map,--cref,--no-warn-mismatch
最後是 Pre/post build steps 頁籤項目裡,Post-build steps 要增加
C:\Program Files (x86)\CodeBlocks\GunARM2016q2\bin\arm-none-eabi-objcopy -O ihex ${TARGET_OUTPUT_DIR}${PROJECT_NAME}.elf ${TARGET_OUTPUT_DIR}${PROJECT_NAME}.hex
cmd /c "C:\Program Files (x86)\CodeBlocks\GunARM2016q2\bin\arm-none-eabi-objdump" -S ${TARGET_OUTPUT_DIR}${PROJECT_NAME}.elf > ${TARGET_OUTPUT_DIR}${PROJECT_NAME}.asm
C:\Program Files (x86)\CodeBlocks\GunARM2016q2\bin\arm-none-eabi-size ${TARGET_OUTPUT_DIR}${PROJECT_NAME}.elf
這段是為了在編譯完成後,自動產生可燒錄檔以及組合語言碼方便找錯誤。
接著進入 Project-> Properties ,在 Build targets 頁籤裡做這樣的設定
在 Debugger 頁籤加上遠端遙控的設定, IP位址是 localhost 而 port 是 3333。
同樣在 Debugger 頁籤下, Additional GDB commands 添加連線後的指令設定
monitor halt
load bin/STM32_Hello.elf
monitor sleep 1000
monitor reset
這段指令的意思就是,啟動後先停止,然後載入執行檔,睡眠 1000mS 再 Reset。
這些設定完成後,預備寫程式的檔案必須要有:
core_cm3.c
core_cm3.h
system_stm32f10x.c
system_stm32f10x.h
stm3210x.h
stm32x.conf.h
startup_stm32f10x_hd.s
stm32f103vet6.ld
以上構成基本的開機啟動功能。然後
main.c 放我們自己的程式
stm32f10x_gpio.c 和 stm32f10x_gpio.h 做 IO操作
stm32f10x_rcc.c 和 stm32f10x_rcc.h 做振盪器控制操作
但是在ARM compiler 裡,似乎有個辨識上的 bug 會使得 compiler 不會過關。
這兩個小小需要修改的點在 core_cm3.c 裡面。分別是
STREXB 和 STREXH
在程式內 "=r" (result) 會導致編譯失敗,因此改為 "=&r" (result)
添加一個 & 符號解決。
該問題的修改法參考來自此
http://www.cesareriva.com/fix-registers-may-not-be-the-same-error/
以上的程式建置進專案後,build 完成,就可以啟動單步除錯器了。
當然硬體要先接好
首先透過 Tools 啟動 OpenOCD
當出現這些訊息時,代表OpenOCD已經成功啟動。等待GDB去做連線。
這時只要按下
紅色的三角鍵,Code Blocks 就會啟動 GDB 去做連線。按下後log視窗會出現
可以看到 load 指令後載程式到晶片的資訊。
再按一次紅色的三角鍵就會開始運作,跑到斷點才會停止
然後可以看見點亮LED的情景
當斷點停止的時候,可以在OpenOCD的視窗內看到被停止的位址
以上範例程式碼放在
GitHub
Code Blocks 的操作設定參考自
http://www.hackvandedam.nl/blog/?p=707
OpenOCD 的操作可參考自
詹姆士酷斯拉