2.1 建立樣板專案
STmicroelectronics 提供的標準函式庫中,已經有其他編譯器用的樣板專案。我們從裡面去修改成 gcc 用的樣板專案。一開始建立專案的步驟較為繁瑣,所以先建立一個空的專案當作樣板留下來,以後要寫程式就可以直接把樣板複製一份。
- 建立一個放置專案的目錄 stm32f466 ,並在裡面再建立子目錄 src 和 inc
- 將從 STmicroelectronics 下載的 stm32f4_dsp_stdperiph_lib.zip 解壓縮,放在自己習慣的目錄
- 進入 Project\STM32F4xx_StdPeriph_Templates\
- 將 main.c, stm32f4xx_it.c, system_stm32f4xx.c 複製到 stm32f466\src\ 下
- 將 main.h, stm32f4xx_conf.h, stm32f4xx_it.h 複製到 stm32f466\inc\ 下
- 再進入 TrueSTUDIO\STM32F446xx\
- 將 STM32F446ZETx_FLASH.ld 複製到 stm32f466\ 下
- 回到 stm32f4_dsp_stdperiph_lib 的最上層
- 進入 Libraries\CMSIS\Device\ST\STM32F4xx\Include\
- 將 stm32f4xx.h, system_stm32f4xx.h 複製到 stm32f466\inc\ 下
- 回到上一層,進入 Source\Templates\TrueSTUDIO\
- startup_stm32f446xx.s 複製到 stm32f466\src\ 下
- 回到 Libraries\CMSIS\ ,進入 Incluse\
- 將 core_cm4.h, core_cmFunc.h, core_cmInstr.h, core_cmSimd.h 複製到 stm32f466\inc\ 下
- 回到 Libraries\
- 將 STM32F4xx_StdPeriph_Driver 整個目錄複製一份到 stm32f466\src\ 下
- 根據 mcufreaks 的網頁打造 makefile 或是下載製作好的版本: makefile, common.mk。放到 stm32f466\ 下
接著就能進入 DOS 的開發環境,打 make 進行編譯。編譯完成的檔案會放在 stm32f446\bin 下。
目前專案中各檔案內容的簡單說明如下
- core_cm4.h, core_cmFunc.h, core_cmInstr.h, core_cmSimd.h:CORTEX-M4 的標準介面
- stm32f4xx_conf.h, stm32f4xx.h, system_stm32f4xx.h, system_stm32f4xx.c:STM32F4 週邊硬體的介面以及開機時的 clock 設定
- startup_stm32f446xx.s:中斷向量表及 reset_handler ( reset 後進入 main() 之前的程式 )
- stm32f4xx_it.h, stm32f4xx_it.c:中斷服務常式
- STM32F4xx_StdPeriph_Driver:STM32F4 週邊硬體的標準函式庫
- STM32F446ZETx_FLASH.ld:STM32F446 的 Linker Script,定義最後程式的記憶體配置。只需確認 FLASH 和 RAM 的大小是否正確,在弄懂 Linker Script 之前,不要去修改它
- makefile, common.mk:定義編譯專案的流程。當專案增加檔案或是目錄結構變動時,就需要修改 makefile 內容
其中 makefile 是較需要注意的檔案,裡面分別設定了 .h 和 .c 檔的路徑和需要編譯的 .c 檔,如果新增加檔案或是改變目錄結構就需要修改內容。另外 makefile 裡面也有定義了一些常數名稱,-DUSE_STDPERIPH_DRIVER -DSTM32F446xx -D__FPU_PRESENT=1 ,這些都是 STM32F4 標準函式庫會用到的。
2.2 燒錄程式
2.2.1 使用 ST-LINK_CLI
ST-LINK_CLI.exe -c SWD -p "bin/STM32F446.hex" -Rst -Run
2.2.2 使用 OpenOCD
- 打開 dos 工作環境,進入專案目錄。輸入 openocd -f board/st_nucleo_f4.cfg ,成功後保留視窗不要關閉
- 打開 putty ,使用 telnet 連線 localhost , port: 4444 ,即可連上 Open On-Chip Debugger
- 輸入 reset halt ,將 mcu 重新啟動後停止
- 輸入 load_image bin/STM32F446.elf 0 ,將 STM32F446.elf 檔載入 flash address 0x00000000 的位址
- 輸入 reset run ,將 mcu 重新啟動後,繼續執行
- 如果沒有要繼續使用 Open On-Chip Debugger 可輸入 shutdown 關閉 putty 和 openocd
除了燒錄程式碼外,Open On-Chip Debugger 的環境內還可以執行其他 debug 的命令,如讀寫記憶體等。詳細操作可參考 openocd 目錄下的 OpenOCD User’s Guide.pdf。若只是要單純燒錄程式碼,上述動作可結合成下面一行 dos 命令
- openocd -f board/st_nucleo_f4.cfg -c "init" -c "reset halt" -c "load_image bin/STM32F446.elf 0" -c "reset run" -c "shutdown"
2.3 建立 eclipse 專案
2.3.1 設定 Workspace
進入 eclipse 時要要求選擇一個 Workspace 的目錄,這是 eclipse 存放工作環境設定的目錄,以後新建專案會放在這個目錄下。依個人習慣選擇一個放專案的目錄即可。如果不想每個打開 eclipse 都問一次,記得把 "Use this as the default and do not ask again" 打勾。
將 make 需要用到的程式路徑加入環境設定中。從上方的 Menu bar 點選 Window 再選 Preferences 打開設定視窗。選到 C/C++ -> Build -> Environment 分頁,點選 Add 加入一個新的環境變數。欄位 Name 填寫 PATH ,欄位 Value 填寫 d:\ARM-SDK\cygwin\;d:\ARM-SDK\gcc-arm\bin\;d:\ARM-SDK\gcc-arm\arm-none-eabi\bin\
修改將 eclipse 自動搜尋 Include Paths 。選到 C/C++ -> Build -> Setting。選到 Discovery 分頁,點 CDT Cross GCC Built-in Compiler Settings [Shared]。將下方 Command to get compiler specs: 中的 ${COMMAND} 改成 arm-none-eabi-gcc.exe
2.3.2 建立 Project
- 開啟 New 的視窗
- 選擇 C/C++ 裡的 Makefile Project with Existing Code
- 填寫 Project Name ,選擇 Existing Code Location
- Languages 要勾 C ,C++ 可勾可不勾
- Toolchain for Indexer Setting 選 Cross GCC
- 最後點選 Finish 按鈕,Project 就建好了
2.3.3 設定 Project Properties
eclipse 無法自動找到 makefile 中的 define ,因此需要手動加入。
- 打開 Project 選單,選擇 Properties 打開設定視窗
- 左邊選擇 C/C++ General 下的 Paths and Symbols
- 右邊選擇 Symbols 分頁,Langiages 選擇 GNU C
- 新增 USE_STDPERIPH_DRIVER 和 STM32F446xx
- 新增 __FPU_PRESENT ,值記得設定為 1
- 左邊選擇 Preprocessor Include Paths, Macros etc.
- 選擇 Providers 分頁,選擇 CDT Cross GCC Built-in Setting Entries [Shared]
- 將下方 Use global provider shared between projects 打勾
設定完成後,eclipse 的 indexer 就能正確解析程式碼內容了。若覺得每次設定 Symbols 很麻煩,可以利 Symbols 頁面的下方 Export Setting 按鈕將設定存成檔案,以後新的專案再利用 Import Settings 載入即可。
2.4 參考資料:
您好,我目前也在使用STM32F446,之前都是使用 Keil MDK 做開發,日前發現 Keil 可以支援 GCC 編譯器,這幾天嘗試改成 GCC 來編譯,但對 __libc_init_array 的問題一直無法解決,因本身沒有碰過這種底層與 GNU 的相關經驗,想請教您是否在使用 GCC 編譯過程中也有遇到相同問題?
回覆刪除在 Keil 中使用 GCC 編譯的方法大致與以下教學相同 http://eeontheway.com/1170.html
xxx.ld 與 xxx.s 都是從 STM32F4_StdPeriph_Lib_V1.7.1/.../TrueSTUDIO 拉進來的
以下是完整的錯誤訊息:
linking...
c:/program files (x86)/gnu tools arm embedded/5.4 2016q2/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/lib/armv7e-m\libc.a(lib_a-init.o): In function `__libc_init_array':
init.c:(.text.__libc_init_array+0x22): undefined reference to `_init'
collect2.exe: error: ld returned 1 exit status
希望可以給予解決方向或方法,非常謝謝:)
幫你 google 了一下。根據下面這篇,應該是 Keil 使用的 link 參數 -nostartfiles 的關係,而一般是使用 --gc-sections。
刪除http://stackoverflow.com/questions/13734745/why-do-i-have-an-undefined-reference-to-init-in-libc-init-array