學習如何建立一個 stm32 的 bare-metal 專案,完整專案可見 [cm4bm](https://github.com/Risheng1128/cm4bm)
## 使用設備: NUCLEO-F303ZE
1. [官方文件規格](https://www.st.com/en/evaluation-tools/nucleo-f303ze.html)
2. 開發板: [STM32F303ZE](https://www.st.com/en/microcontrollers-microprocessors/stm32f303ze.html)
## 安裝 ST-Link
1. 記得要安裝必要的模組和工具
> sudo apt-get install git make cmake libusb-1.0-0-dev
> sudo apt-get install gcc build-essential
2. 下載並構建ST-Link v2驅動程式
> cd ~
> git clone https://github.com/stlink-org/stlink
> cd stlink
> cmake .
> make
`cmake` 成功可以看到以下結果
```shell
-- Rewrite /home/benson/stlink/.version with 1.7.0!
-- stlink version: 1.7.0-201-g254a525
-- Major 1 Minor 7 Patch 0
-- Found libusb: /usr/lib/x86_64-linux-gnu/libusb-1.0.so
-- Looking for __stack_chk_fail in ssp
-- Looking for __stack_chk_fail in ssp - not found
-- Looking for sys/mman.h
-- Looking for sys/mman.h - found
-- Looking for sys/time.h
-- Looking for sys/time.h - found
-- Looking for unistd.h
-- Looking for unistd.h - found
-- Looking for dirent.h
-- Looking for dirent.h - found
-- STLINK_LIB_SHARED: stlink-shared
-- PROJECT_VERSION_MAJOR: 1
-- VERSION: 1.7.0
-- STLINK_LIB_STATIC: stlink-static
-- PROJECT_VERSION_MAJOR: 1
-- VERSION: 1.7.0
-- Found PkgConfig: /usr/bin/pkg-config (found version "0.29.1")
-- Checking for module 'gtk+-3.0'
-- No package 'gtk+-3.0' found
-- GTK3 not found!
-- Debian-based Linux OS detected
-- Manpage generation disabled
-- Configuring done
-- Generating done
-- Build files have been written to: /home/benson/stlink
```
`make` 成功可以看到以下結果 (擷取部份)
```shell
[ 60%] Building C object CMakeFiles/stlink-static.dir/src/stlink-lib/logging.c.o
[ 62%] Building C object CMakeFiles/stlink-static.dir/src/stlink-lib/md5.c.o
[ 64%] Building C object CMakeFiles/stlink-static.dir/src/stlink-lib/sg.c.o
[ 66%] Building C object CMakeFiles/stlink-static.dir/src/stlink-lib/usb.c.o
[ 68%] Building C object CMakeFiles/stlink-static.dir/src/stlink-lib/helper.c.o
[ 70%] Linking C static library lib/libstlink.a
[ 70%] Built target stlink-static
Scanning dependencies of target st-trace
[ 72%] Building C object CMakeFiles/st-trace.dir/src/st-trace/trace.c.o
[ 75%] Linking C executable bin/st-trace
[ 75%] Built target st-trace
Scanning dependencies of target st-flash
[ 77%] Building C object CMakeFiles/st-flash.dir/src/st-flash/flash.c.o
[ 79%] Building C object CMakeFiles/st-flash.dir/src/st-flash/flash_opts.c.o
[ 81%] Linking C executable bin/st-flash
[ 81%] Built target st-flash
Scanning dependencies of target st-info
[ 83%] Building C object CMakeFiles/st-info.dir/src/st-info/info.c.o
[ 85%] Linking C executable bin/st-info
[ 85%] Built target st-info
Scanning dependencies of target test-flash
[ 87%] Building C object tests/CMakeFiles/test-flash.dir/flash.c.o
[ 89%] Building C object tests/CMakeFiles/test-flash.dir/__/src/st-flash/flash_opts.c.o
[ 91%] Linking C executable ../bin/test-flash
[ 91%] Built target test-flash
Scanning dependencies of target test-sg
[ 93%] Building C object tests/CMakeFiles/test-sg.dir/sg.c.o
[ 95%] Linking C executable ../bin/test-sg
[ 95%] Built target test-sg
Scanning dependencies of target test-usb
[ 97%] Building C object tests/CMakeFiles/test-usb.dir/usb.c.o
[100%] Linking C executable ../bin/test-usb
[100%] Built target test-usb
```
3. 將重構的二進位制檔案複製到其系統位置
```
cd bin
sudo cp st-* /usr/local/bin
cd ../lib
sudo cp *.so* /lib32
cd ../config/udev/rules.d/
sudo cp 49-stlinkv* /etc/udev/rules.d/
```
使用命令 `lsusb` 查看裝置,可以看到已經有連到 ST-LINK/v2.1
```shell
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 0bda:57f2 Realtek Semiconductor Corp. HD WebCam
Bus 001 Device 003: ID 04ca:3015 Lite-On Technology Corp.
Bus 001 Device 002: ID 046d:c092 Logitech, Inc. G102 LIGHTSYNC Gaming Mouse
Bus 001 Device 020: ID 0483:374b STMicroelectronics ST-LINK/V2.1
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
```
## 安裝 [GNU ARM Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads)
[ARM gcc 編譯指令](https://www.itread01.com/content/1547624713.html)
參考 [How To Install gcc-arm-none-eabi on Ubuntu 20.04](https://installati.one/ubuntu/20.04/gcc-arm-none-eabi/) 更新 apt-get 及下載 arm toolchain
```shell
sudo apt-get update
sudo apt-get -y install gcc-arm-none-eabi
```
下載完後新增環境變數
```shell
vim ~/.bashrc
# 在最後一行加上
export PATH=$PATH:/home/benson/tmp/gcc-arm-none-eabi-10.3-2021.10/bin
```
測試是否成功加到環境變數,可以輸入命令 `arm-none-eabi-gcc --version`
```shell
arm-none-eabi-gcc (GNU Arm Embedded Toolchain 10.3-2021.10) 10.3.1 20210824 (release)
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```
## OpenOCD
首先輸入以下命令安裝 openOCD
> sudo apt install openocd
接著測試有無安裝成功,輸入命令 `openocd -v` 測試,有成功可以看到以下訊息
```shell
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
```
## putty
都安裝好後可以開始測試啦,首先安裝 putty
> sudo apt-get install putty
安裝完畢後輸入命令 `sudo putty` 並選擇 serial 的選項,可以看到以下的樣子
![](https://i.imgur.com/HvkwzFT.png)
接著輸入命令 `sudo dmesg | grep tty` 可以看到 serial 連接了哪些裝置
```c
[ 0.076626] printk: console [tty0] enabled
[ 0.521220] tty tty2: hash matches
[ 19.317722] cdc_acm 1-2:1.2: ttyACM0: USB ACM device
[ 145.002427] cdc_acm 1-2:1.2: ttyACM0: USB ACM device
[ 2628.688812] cdc_acm 1-2:1.2: ttyACM0: USB ACM device
[ 3436.742686] cdc_acm 1-1:1.2: ttyACM0: USB ACM device
[ 3553.949930] cdc_acm 1-1:1.2: ttyACM0: USB ACM device
```
經測試,測試的開發板使用 `ttyACM0` ,因此需要在 serial line 上輸入 `/dev/ttyACM0` 並給出正確的鮑率,最後就會成功開啟並列印出訊息
```shell
Input a data!!
255
data = 255
Input a data!!
```
## 在 VS code 上使用 Cortex-Debug 做 debug
首先需要安裝 OpenOCD 以及 VS code 的模組 Cortex_Debug
![](https://i.imgur.com/UVdyR6t.png)
> 目前 Cortex-Debug 的版本使用 1.6.3
而 OpenOCD 比較特別,需要使用版本 0.11.0 以後才可以 (用 0.10.0 會失敗) ,這裡就使用 ST 給的 [STMicroelectronics/OpenOCD](https://github.com/STMicroelectronics/OpenOCD)
首先先 clone 該專案
> git clone https://github.com/STMicroelectronics/OpenOCD.git
> cd OpenOCD
接著先安裝需要的函式庫
> sudo apt-get install make
> sudo apt-get install libtool
> sudo apt-get install pkg-config
> sudo apt-get install autoconf
> sudo apt-get install automake
> sudo apt-get install texinfo
> sudo apt-get install libusb-1.0
可以開始建構專案了
> ./bootstrap
> ./configure
> sudo make install
成功完成後可以確認 openocd 版本,使用命令 `openocd -v`
```shell
Open On-Chip Debugger 0.11.0+dev-00454-gd3b71197b (2022-09-10-17:00) [https://github.com/STMicroelectronics/OpenOCD]
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
```
兩者都安裝完後即可開啟 debugger ,開啟結果如下所示
![](https://i.imgur.com/i7BtX6X.png)
:::info
要可以追蹤 source file 的話,記得要在編譯時新增 `-g` 選項
:::
## OpenOCD Debuger 測試
### GDB Client
1. 利用檔案 `st_nucleo_f3.cfg` 開啟 openOCD ,成功可以看到以下訊息
```shell
openocd -f board/st_nucleo_f3.cfg
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
none separate
srst_only separate srst_nogate srst_open_drain connect_deassert_srst
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v2 JTAG v38 API v2 SWIM v27 VID 0x0483 PID 0x374B
Info : using stlink api v2
Info : Target voltage: 3.243541
Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
```
2. 在 cmd 上開啟 GDB client 並連上 openocd
> arm-none-eabi-gdb.exe
```shell
$ arm-none-eabi-gdb
GNU gdb (GNU Arm Embedded Toolchain 10.3-2021.10) 10.2.90.20210621-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-none-eabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb)
```
接著連到 openocd 上
> target remote localhost:3333
接著列出比較常用的指令 (記得前面要加 monitor)
- Reset
1. reset
2. reset run
3. reset halt
4. reset init
- Halt: 暫停目前的執行
> monitor halt
- Resume: 結束 halt 並開始執行程式
> monitor resume
- 燒入程式
> monitor flash write_image erase Debug/main.elf
### Telnet Client
1. Install Putty
> sudo apt-get install putty
2. 利用檔案 `st_nucleo_f3.cfg` 開啟 openOCD ,成功可以看到以下訊息
```shell
openocd -f board/st_nucleo_f3.cfg
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
none separate
srst_only separate srst_nogate srst_open_drain connect_deassert_srst
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v2 JTAG v38 API v2 SWIM v27 VID 0x0483 PID 0x374B
Info : using stlink api v2
Info : Target voltage: 3.243541
Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
```
2. 使用 putty 裡的 Telnet 連上 OpenOCD (Port 為 4444)
- Hostname: localhost
- Port: 4444
接著列出比較常用的指令
- Reset
1. reset
2. reset run
3. reset halt
4. reset init
- Halt: 暫停目前的執行
> halt
- Resume: 結束 halt 並開始執行程式
> resume
- 燒入程式
> flash write_image erase Debug/main.elf
## 錯誤紀錄
### 使用 GDB 的問題
使用命令 `sudo apt-get -y install gcc-arm-none-eabi` 所下載的編譯器並不含有 `arm-none-eabi-gdb` ,因此需要額外加入,可從 [Arm GNU Toolchain Downloads](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads) 下載
下載後將 `arm-none-eabi-gdb` 加入到 Linux 的輸入命令的預測路徑 `/usr/bin`
```shell
$ mv arm-none-eabi-gdb /usr/bin/
```
接著執行 `arm-none-eabi-gdb` ,如果發生以下錯誤
```
/usr/bin/arm-none-eabi-gdb: error while loading shared libraries: libncursesw.so.5
: cannot open shared object file: No such file or directory
```
解法: 安裝對應的函式庫
```shell
$ sudo apt-get install libncursesw5
```
接著如果出現以下的問題
```
Could not find platform independent libraries <prefix>
Could not find platform dependent libraries <exec_prefix>
Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
Python path configuration:
PYTHONHOME = (not set)
PYTHONPATH = (not set)
program name = '/usr/local/bld-tools/bld-tools-virtual-env/bin/python'
isolated = 0
environment = 1
user site = 1
import site = 1
sys._base_executable = '/usr/local/bld-tools/bld-tools-virtual-env/bin/python'
sys.base_prefix = '/usr'
sys.base_exec_prefix = '/usr'
sys.executable = '/usr/local/bld-tools/bld-tools-virtual-env/bin/python'
sys.prefix = '/usr'
sys.exec_prefix = '/usr'
sys.path = [
'/usr/lib/python38.zip',
'/usr/lib/python3.8',
'/usr/lib/lib-dynload',
]
Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
Python runtime state: core initialized
ModuleNotFoundError: No module named 'encodings'
Current thread 0x00007fd07c45ac00 (most recent call first):
<no Python frame>
```
問題就是該版本的 GDB 使用了 python3.8 的函式庫,而我的 Ubuntu 版本為 22.04 ,其 Python 的預設版本為 3.10.6 ,對應的函式庫不同,而導致這樣的錯誤。因此解法就是直接安裝 python3.8 的版本,命令如下
```shell
$ sudo apt install python3.8
```