作業系統之前的程式 for stm32f4discovery (0) - 打造 linux 開發環境

the 1st edition: 20130405
the 2nd edition: 20150119

這個系列累積了不少篇幅, 以下是所有系列的文章目錄:
bare-metal for stm32f4 discovery board content

在 《作業系統之前的程式》這系列 x86 os kernel 開發紀錄的學習經驗, 我想依樣畫葫蘆拿到 arm 的學習上, 重新學習一個完全不一樣的平台。

Fig 1. stm32f4discovery
這是一個辛苦的開始, 縱使有了 x86 的學習經驗, 也無法帶來太多的助益, 仍然需要閱讀大量的資料, 甚至去找到相關資料也是個難題, 而程式的撰寫也只是最基本的練習。

但在開始第一個作業系統之前的程式 for stm32f4discovery 之前, 得先來打造開發環境, 這是與 x86 native toolchain 不同的地方, 別小看這部份, 這可不是一件容易的事, 最主要的部份就是 arm toolchain (cross compiler) 和燒錄程式碼到 stm32f4discovery flash 的工具。

目前市面上琳琅滿目的開發板, 要從中挑選實在不容易。Fig 1 是 stm32f4discovery, jserv 的 進階嵌入式系統開發與實作課程 (201209~201301) 就是使用這塊開發板, 以 700 NT 購得。因為參加了這個課程, 所以才選定這塊開發板, 照著課程的資源來學習, 最是省事。

選擇板子時會有一個問題, 怎麼把程式碼燒錄到那塊板子上呢? 這是個大問題。而這塊開發板珍貴的地方就是內建 ST-LINK/V2, 可以將程式碼燒錄到 flash, 再也不怕燒爛 flash; 更珍貴的地方是: 還可以使用類似 jtag 的方式 debug, 不用另外買個 jtag, 當然這些都需要搭配的軟體才能運作, openocd 或是 st-util 都可以做到, 這是開發 os 等級程式碼的利器。我知道還有一塊版子也有類似的功能, freescale m0+ 系列, 使用的是 opensda, 不過我不確定 openocd 是不是可以支援 opensda。

而 stm32 提供了 bootloader 的方式, 就算沒有 st-link 也可以燒錄程式, 但還要調整 jmp, 不是很方便。有興趣可參考: stm32f4discovery system memory - boot loader

Arduino 或是 Intel Galileo 這種開發版主打快速、簡單、好開發。看看這些書名就可窺探一二:
  • Arduino 快速上手指南
  • Intel Galileo 快速上手指南
這些書籍都會有一些很有趣的實作專題, 例如驅動馬達、機器人互動裝置等等 ... 這些很有趣, 能做出來會有一定的成就感。不過我志不在此, 我想研究最底層的秘密, 而不是作組合積木的事情, 例如上電之後怎麼執行第一支程式, 某個 gpio 該怎麼使用? 那個按鈕要能發揮作用需要做什麼事情 ... 所以我會需要有類似 jtag 功能的版子, 這種等級的除錯很難避免, 也很難靠 printf 來除錯, 甚至要自己寫 printf。

不過偶爾看到別人用這些東西做出很好玩的東西, 例如機器手臂、機器人, 自己卻和 datasheet, c/asm code, debugger 打交道, single step 錯誤的程式碼, 而終端機畫面只有一些簡易的文字訊息, 還真是有些落漠之感, 我也想做出一些有趣的裝置。

《 maker 雜誌中文版》有更多類似這樣的作品, 每一件都很能吸引人。

回到 stm32, stm32f4 mcu 全系列可參考 這裡。

這是以 ARM Cortex-M4 為核心的開發版。沒有 mmu, 所以不能練習 page mapping, 這是我覺得比較可惜的部份; 但有個記憶體保護單元 (MPU), 可以保護某個記憶體區塊。這塊板子用的是 stm32 的 STM32F407VG, 其 基本規格:

時脈: 168 MHz
flash & ram size:
STM32F407VGT6 microcontroller featuring 1 MB of Flash memory, 192 KB of RAM in an LQFP100 package.

以下的連結可以下載 firmware, 方便寫程式, 不用辛苦的對付暫存器。

Related Tools and Software
Part Number Description
STM-STUDIO STM Studio run-time variables monitoring and visualization tool for STM8 and STM32 microcontrollers
STM32CubeF4 Embedded software for STM32 F4 series (HAL low level drivers, USB, TCP/IP, File system, RTOS, Graphic - coming with examples running on ST boards)
STSW-STM32068 STM32F4DISCOVERY board firmware package, including 22 examples (covering USB Host, audio, MEMS accelerometer and microphone) (AN3983)
STSW-STM32142 Using STM32F4 MCU power modes with best dynamic efficiency (AN4365)


我還真不習慣只有 192KB 的記憶體。

usb 有兩邊, 插上 CN1 (如 Fig 1 白色 usb 線) 接到 pc 後, 就可看到 led 燈的閃爍效果 (如 Fig 1), 代表這是一塊正常的板子。開發程式, 燒錄程式也都是接在 CN1 上, 這是 ST-LINK/V2 chip 提供的功能。

這塊板子相關的 datasheet 和 sample code:  datasheet for stm32f4 discovery

這 3 本的厚度不輸給 intel 那 3 本, 真的很厚, 有得看了。

stm32f4 - discovery 用的是 stm32f407, 詳細的 mcu 資訊要找這顆的 datasheet。
stm32f407 datasheet: http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf

以下連結已經失效:
http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/REFERENCE_MANUAL/DM00031020.pdf

除了開發環境之外, 文件的閱讀也是一個難題, 並不是只讀 stm32f407 datasheet 就足夠。

AN2606 Application note 提到 system memory 的 bootloader。
UM0462 在介紹 flash loader demonstrator 的用法。
AN3155 Application note 介紹 USART protocol used in the STM32 bootloader。


用原廠準備的環境 (on ms windows), STM 沒提供自己的開發工具, 請參考: What should I use to develop on STM32? stm 有支援這些開發工具, 一定可以減輕開發環境的先前準備工作, 而 free 的版本幾乎都會有些限制, 例如執行檔大小不能超過 32K, 其實好像也不太容易超過這限制。而我習慣 linux vi + makefile 的工作環境, 打造這樣的開發環境並不算輕鬆, 否則也不會特地 blog 一篇, 來照著課程自虐吧!

在 linux 上的開發方式:


toolchain & qemu stm32 模擬器:  http://wiki.csie.ncku.edu.tw/embedded/Lab1

如果你喜歡從原始碼建立編譯器工具組的話可以參考以下連結, toolchain build from source:
  1. https://github.com/jsnyder/arm-eabi-toolchain (fb 顏 sir 提供)
  2. http://cu.rious.org/make/compiling-the-arm-cortex-m4-toolchain-yourself/
  3. https://github.com/cccc/STM32-Toolchain (gcc-4.8.0)
  4. STM32F4 – Build Your Own GNU ARM Cross-Toolchain From Scratch (cross compiler gcc 4.9 我使用 gcc 4.7 的版本才建構的出來)
    (cross compiler gcc 5.1 我使用 gcc 4.9/5.2 的版本才建構的出來)

我自己準備了 4.7, 4.8, 4.9.2 (從上述第四個修改而來) 三個版本。


debian 提供了這些 toolchain

root@debianlinux:apt# apt-cache search gcc|grep arm
cpp-aarch64-linux-gnu - GNU C preprocessor (cpp) for architecture arm64
cpp-arm-linux-gnueabi - GNU C preprocessor (cpp) for architecture armel
cpp-arm-linux-gnueabihf - GNU C preprocessor (cpp) for architecture armhf
gcc-aarch64-linux-gnu - GNU C compiler for architecture arm64
gcc-arm-linux-gnueabi - GNU C compiler for architecture armel
gcc-arm-linux-gnueabihf - GNU C compiler for architecture armhf
gfortran-aarch64-linux-gnu - GNU Fortran 95 compiler for architecture arm64
gfortran-arm-linux-gnueabi - GNU Fortran 95 compiler for architecture armel
gfortran-arm-linux-gnueabihf - GNU Fortran 95 compiler for architecture armhf
gcc-arm-none-eabi - GCC cross compiler for ARM Cortex-A/R/M processors

apt-get install gcc-arm-none-eabi

install gdb:
apt-get install gdb-arm-none-eabi
arm-2013.05-23-arm-none-eabi.src.tar.bz2 (上述第一個 url) 這個版本, 需要使用 makeinfo 4.13 (texinfo-4.13.tar.gz) 才可以正確編譯 binutils doc 目錄, 在我的 debian makeinfo 是 5.2 會在編譯 binutils 出問題。目前的版本已經修正這問題。

使用 openocd/stlink 來將程式寫到 stm32f4discovery flash (openocd/stlink/serialusb) :
http://wiki.csie.ncku.edu.tw/embedded/Lab6

Bus 002 Device 003: ID 0483:3748 SGS Thomson Microelectronics ST-LINK/V2
sudo apt-get install automake* libtool libusb-1.0-0-dev
apt-get install gdb-multiarch
git clone http://github.com/texane/stlink.git
cd stlink
./autogen.sh
./configure --prefix=/usr
make
sudo make install
sudo cp 49-stlinkv2.rules /etc/udev/rules.d/

stlink gui
git clone git://github.com/texane/stlink.git
sudo apt-get install libgtk-3-dev
cd stlink
./configure --with-gtk && make
cd gui && ./stlink-gui

apt-get install libjim-dev
cd openocd
./bootstrap
./configure --prefix=/opt/openocd \
    --enable-jlink \
    --enable-amtjtagaccel \
    --enable-buspirate \
    --enable-stlink \
    --disable-libftdi
echo -e "all:\ninstall:" > doc/Makefile
make
sudo make install

ref: http://openocd.sourceforge.net/
new git url:
git://git.code.sf.net/p/openocd/code

openocd 不是很好上手的工具, 設定也不容易。

openocd 需要設定檔, 長這樣:

openocd2.cfg
1 # openocd.cfg file for STM32F4Discovery board via integrated ST-Link/V2.
2 source [find interface/stlink-v2.cfg]
3 source [find target/stm32f4x_stlink.cfg]
4 reset_config srst_only srst_nogate

這是給 STM32F4Discovery 用的, 若是使用其他 jtag 設備或是其他開發版, 設定會不同, 這個不好設定, 需要 jtag 相關知識。

openocd/share/openocd/scripts/* 有很多類似的設定檔。

執行 openocd:
openocd -f openocd2.cfg

openocd.cmd
 1 bash# telnet localhost 4444
 2 Trying 127.0.0.1...
 3 Connected to localhost.
 4 Escape character is '^]'.
 5 Open On-Chip Debugger
 6 > poll
 7 background polling: on
 8 TAP: stm32f4x.cpu (enabled)
 9 target state: halted
10 target halted due to undefined, current mode: Thread
11 xPSR: 00000000 pc: 00000000 msp: 00000000
12 > reset halt
13 JTAG tap: stm32f4x.cpu tap/device found: 0x4ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x4)
14 JTAG tap: stm32f4x.bs tap/device found: 0x06413041 (mfg: 0x020, part: 0x6413, ver: 0x0)
15 target state: halted
16 target halted due to debug-request, current mode: Thread
17 xPSR: 0x01000000 pc: 0x08001944 msp: 0x20020000
18 > flash probe 0
19 stm32f4x errata detected - fixing incorrect MCU_IDCODE
20 device id = 0x10006413
21 flash size = 1024kbytes
22 stm32f4x errata detected - fixing incorrect MCU_IDCODE
23 device id = 0x10006413
24 flash size = 1024kbytes
25 flash 'stm32f2x' found at 0x08000000
26 > flash write_image erase main.bin 0x08000000
27 auto erase enabled
28 wrote 16384 bytes from file main.bin in 0.799573s (20.011 KiB/s)
29 > reset
30 JTAG tap: stm32f4x.cpu tap/device found: 0x4ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x4)
31 JTAG tap: stm32f4x.bs tap/device found: 0x06413041 (mfg: 0x020, part: 0x6413, ver: 0x0)
32 > exit
33 Connection closed by foreign host.

若你也把 Programming STM32 F2, F4 ARMs under Linux: A Tutorial from Scratch 裡頭的程式跑過一次, 就可體會整個開發流程了。上表就是這連結的內容。

g1.sh
1 file myur.elf
2 target remote localhost:1234
3 b getchar

這個 gdb script 可以減輕打字份量。

arm-none-eabi-gdb -x g1.sh

https://github.com/texane/stlink 的 readme 有些有用的資訊, 可瀏覽一下。

有個 free ide 可以參考:
http://www.coocox.org/index.html
原來 arm 除了 armcc 還有 arm gcc。
ref: https://launchpad.net/gcc-arm-embedded/+download

function reference:
http://stm32.kosyak.info/doc/struct_g_p_i_o___init_type_def.html

有了模擬器就不一定要把程式寫到版子上的 flash, flash 壽命有限, 減少讀寫次數不是壞主意。不過模擬器模擬的是 stm32-p103, 我使用的是 stm32f4 discovery, IO 部份可能有些不同, 僅能用來練習 arm coretex m 系列不含 IO 的程式, 而 qemu 似乎沒有模擬 svc, 我在測試有關 svc 的部份時, 都是使用真實開發板。若真要寫 stm32f4 開發版的程式, 最後還是得寫入 flash/ram 來測試, 只能在模擬器執行的程式, 那有什麼意思呢!

中文教學文件: http://wiki.csie.ncku.edu.tw/embedded/2012w7

恭喜! 看完這些文件和打造工作環境就去了半條命了吧!在 linux 下打造這些環境就要花上不少時間。不過真正的困難才剛開始, 先來練習模擬器上的程式, 不需要 st-link, openocd。

簡單的版本很簡單, 難的版本很難, 跟著 http://wiki.csie.ncku.edu.tw/embedded/Lab1 把 main.c compile 起來吧!

文件中的模擬器在這裡 https://github.com/beckus/qemu_stm32, 可自行更新。

qemu_stm32 編譯方式
./configure --disable-werror --enable-debug \
--target-list="arm-softmmu" \
--extra-cflags=-DDEBUG_CLKTREE \
--extra-cflags=-DDEBUG_STM32_RCC \
--extra-cflags=-DDEBUG_STM32_UART \
--extra-cflags=-DSTM32_UART_NO_BAUD_DELAY \
--extra-cflags=-DSTM32_UART_ENABLE_OVERRUN
  

main.c
 1 #define USE_STDPERIPH_DRIVER
 2 #include "stm32f10x.h"
 3 #include "stm32_p103.h"
 4
 5 void busyLoop(uint32_t delay )
 6 {
 7   while(delay) delay--;
 8 }
 9
10 int main(void)
11 {
12     init_led();
13
14     while(1) {
15        GPIOC->BRR = 0x00001000;
16        busyLoop(500000);
17        GPIOC->BSRR = 0x00001000;
18        busyLoop(500000);
19     }
20 }

這個簡單的程式隱藏了很多很多的細節, 會讓我們誤以為寫個 mcu 程式很簡單, 塞個 main 在裡頭就可以了。使用廠商給的 library 來開發有點像在 os 下寫應用程式, 也不是壞事, 只不過這標題是作業系統之前的程式, 自然不用這樣的開發方式, 得把隱藏在 library 下的秘密挖出來, 不過光是打造開發環境就很辛苦了, 先讓自己輕鬆一下。

這支程式不能在 stm32f4 - discovery 正確執行, 別浪費時間寫到 flash 中, 在模擬器練習即可, 這是暖身用的。

用這樣的方式來啟動 qemu stm32 模擬器

qemu_stm32/arm-softmmu/qemu-system-arm -M stm32-p103 -kernel mymain.bin -S -gdb tcp::1234
qemu-system-arm -M lm3s6965evb -kernel list.bin -S -gdb tcp::1234

開啟另外一個終端機:
arm-none-eabi-gdb
 1 descent@descent-u:cpp$ arm-none-eabi-gdb mycpp11.elf 
 2 GNU gdb (32-bit ARM EABI Toolchain JBS-2013.05-23-v2013.05-1-gd66a29f) 7.4.50.20120716-cvs
 3 Copyright (C) 2012 Free Software Foundation, Inc.
 4 License GPLv3+: GNU GPL version 3 or later 
 5 This is free software: you are free to change and redistribute it.
 6 There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
 7 and "show warranty" for details.
 8 This GDB was configured as "--host=x86_64-unknown-linux-gnu --target=arm-none-eabi".
 9 For bug reporting instructions, please see:
10 ...
11 Reading symbols from /home/descent/my-git/jserv-course/stm32f4_prog/cpp/mycpp11.elf...done.
12 (gdb) l
13 1       #include "stm32.h"
14 2       
15 3       
16 4       int print(int i)
17 5       {
18 6         i+=1;
19 7       }
20 8       
21 9       int print(char c)
22 10      {
23 (gdb) target remote :1234
24 Remote debugging using :1234
25 ResetISR () at stm32.h:21
26 21      {
27 (gdb) b mymain
28 Breakpoint 1 at 0x18e: file mycpp11.cpp, line 23.
29 (gdb) c
30 Continuing.
31 
32 Breakpoint 1, mymain () at mycpp11.cpp:23
33 23        constexpr int d=1;
34 (gdb) n
35 24        int x=3;
36 (gdb) n
37 25        int y=9;
38 (gdb) n
39 27        char path[]=R"(/usr/local/aaa)";
40 (gdb) n
41 28        char wpath[]=R"("\usr\local\aaa")";
42 (gdb) n
43 30        int total = lambda_test(x, y);
44 (gdb) n
45 31        print(35);
46 (gdb) n
47 32        print('A');
48 (gdb) n
49 33        int arr[]={1,2,3,4,5};
50 (gdb) n
51 34        for (int &e : arr)
52 (gdb) n
53 36          print(e);
54 (gdb) n
55 34        for (int &e : arr)
56 (gdb) n
57 36          print(e);
58 (gdb) p e
59 $1 = (int &) @0x2000008c: 2
60 (gdb) display e
61 1: e = (int &) @0x2000008c: 2
62 (gdb) n
63 34        for (int &e : arr)
64 1: e = (int &) @0x2000008c: 2
65 (gdb) n
66 36          print(e);
67 1: e = (int &) @0x20000090: 3
68 (gdb) n
69 34        for (int &e : arr)
70 1: e = (int &) @0x20000090: 3
71 (gdb) n
72 36          print(e);
73 1: e = (int &) @0x20000094: 4
74 (gdb) n
75 34        for (int &e : arr)
76 1: e = (int &) @0x20000094: 4
77 (gdb) n
78 36          print(e);
79 1: e = (int &) @0x20000098: 5
80 (gdb) n
81 34        for (int &e : arr)
82 1: e = (int &) @0x20000098: 5
83 (gdb) n
84 38        while(1);
85 (gdb) quit
86 A debugging session is active.
87 
88         Inferior 1 [Remote target] will be killed.
89 
90 Quit anyway? (y or n) y

這樣就像是在 x86-pc/linux 下使用 gdb。

lm3s6965evb 是 ti 的版子, 官方 qemu 即內建, 不用另外找 patch, 在我測試 cm3 和週邊無關的程式碼時, 相當方便。
ref:
http://www.techtraining.eng.br/files/uploads/2013/04/18/lm3s6965-evm.pdf

openocd load file to memory:
> load_image  /home/descent/git/jserv-course/stm32_prog/factorial.bin 0x20000000
24 bytes written at address 0x20000000
downloaded 24 bytes in 0.008389s (2.794 KiB/s)
> mdb 0x20000000 24
0x20000000: 00 08 00 20 09 00 00 00 0a 20 00 21 09 18 01 38 7f f4 fc af ff f7 fe bf 

這樣就可以不用寫到 flash, 直接 load 到 sram 測試。
ref: http://openocd.sourceforge.net/doc/html/General-Commands.html

openocd 似乎有些問題, 若遇到奇怪的問題可使用 st-util 配合 gdb 來 debug, 也有可能需要重新開機。
arm-none-eabi-gdb
target remote localhost:4242

也可以指定 gdb port
root@w-linux:descent# st-util -p 1234
arm-none-eabi-gdb
target remote localhost:1234

toolchain 比一比
18M stlink/
descent@w-linux:jserv-course$ du -sh openocd
88M openocd
descent@w-linux:jserv-course$ du -sh /usr/local/csl/
130M /usr/local/csl/

-rwxr-xr-x 1 descent descent 510M 2013-04-15 15:07 mdk470a.exe
blackmagic (類似 openocd, st-util 的 tool):
https://github.com/blacksphere/blackmagic/wiki
http://embdev.net/articles/STM_Discovery_as_Black_Magic_Probe

STM32Cube (新版的 library): http://www.st.com/web/catalog/tools/FM147/CL1794/SC961/SS1743/LN1897

ref:
  1. http://wiki.csie.ncku.edu.tw/embedded/2012w7
  2. http://wiki.csie.ncku.edu.tw/embedded/Lab6
  3. HowTo_ToolChain_STM32_Ubuntu
  4. http://cms.mcuapps.com/techinfo/emulators/st-link/
  5. http://forum.ubuntu.org.cn/viewtopic.php?t=384021&p=2839453
  6. http://www.amobbs.com/forum-3020-1.html
  7. STM32 的 BOOT 概述
  8. Flashing programs to STM32. Embedded Bootloader
  9. Getting Started with the STM32F4 and GCC
  10. STM32 BOOT 位理解及设置
  11. Programming STM32 F2, F4 ARMs under Linux: A Tutorial from Scratch
  12. http://www.waveshare.net/shop/STM32F4DISCOVERY.htm
  13. STM32 笔记(七)IAR 平台,在内存中调试 STM32
  14. ARM9 2410 移植之在 Linux 下, 用 OpenJTAG+OpenOCD 燒寫 NAND Flash
  15. x86 版的 Arduino 來了,Intel Galileo 開發板的體驗、分析和應用
  16. book: Eclipse,OpenOCD,OpenJTAGv3.3 嵌入式开发教程

你可能感兴趣的:(作業系統之前的程式 for stm32f4discovery (0) - 打造 linux 開發環境)