利用rt Thread構建STM32執行環境

2021-09-25 10:35:57 字數 3767 閱讀 5353

硬體:正點原子精英版stm32f103zet6

軟體:rt-thread-v4.0.1

一、搭建環境

(1)進入到rt-thread\bsp\stm32f10x-hal目錄下,在此處開啟comemu命令列介面(不會的同學請參考官網提供的示例:env的使用方法),並輸入menuconfig命令,然後有如下介面:

配置選項如圖所示,這裡主要介紹一下rt-thread components選項的配置:進入到rt-thread components選項,選擇了the main() function as user entry function;這裡的意思是將main()作為使用者的入口函式,稍後會講到這裡的具體作用;

(2)儲存配置,退出;

之後編譯有多種方法可選:

①使用命令列scons命令編譯,其中編譯器是arm-gcc,編譯結果是bin檔案;

②使用scons –target=mdk5命令,構建keil5的開發環境,然後開啟project.uvprojx工程,這裡告訴大家乙個小技巧,因為每次修改配置後,這個project.uvprojx工程都會根據template.uvprojx工程重新生成一遍,然後在keil介面裡設定有關硬體引數,再編譯燒寫,所以,可以根據自己的板子,把template.uvprojx利用文字工具開啟,修改裡面的硬體引數,例如:我的板子的主晶元是stm32f103zet6,而template.uvprojx中設定的是

$$device:stm32f103rc$device\include\stm32f10x.h

直接把stm32f103rc用stm32f103ze替換掉,另外包括時鐘,ram rom設定這裡也可以改:

iram(0x20000000,0xc000) irom(0x08000000,0x40000) cputype("cortex-m3") clock(8000000) elittle

根據自己需要做修改,就省得每次都要進keil重新配置了;keil4工程類似如此;

③iar編譯環境,沒有嘗試過編譯stm32,就不多說了;

(3)構建環境完成,然後留給我們的main()函式裡面啥都沒有,但是恭喜你,你可以燒寫到你的板子上驗證一下,rt-thread是可以跑起來的,把串列埠開啟可以看到一堆列印在刷屏,就這麼簡單?中間到底發生了什麼?

二、啟動分析

接下來,根據之前的配置簡要分析rt-thread的啟動過程了;

在startup_stm32f103xe.s有下面一段彙編:

; reset handler

reset_handler proc

export reset_handler [weak]

import __main

import systeminit

ldr r0, =systeminit

blx r0

ldr r0, =__main

bx r0

endp

由此處進入到c語言的main函式;但這裡進入到的並不是那個什麼都沒的main()函式中,而是在rt-thread/src/components.c中,有這麼一段**:

#ifdef rt_using_user_main

void rt_hw_board_init(void);

int rtthread_startup(void);

#if defined(__cc_arm) || defined(__clang_arm) //這個巨集表示採用arm-gcc編譯器編譯的

extern int $super$$main(void);

/* re-define main function */

int $sub$$main(void)

#elif defined(__iccarm__) //這個巨集表示採用iar編譯器編譯的

extern int main(void);

/* __low_level_init will auto called by iar cstartup */

extern void __iar_data_init3(void);

int __low_level_init(void)

#elif defined(__gnuc__) //這個巨集表示採用arm-none-eabi-gcc編譯器編譯的

extern int main(void);

/* add -eentry to arm-none-eabi-gcc argument */

int entry(void)

#endif

這裡是預編譯巨集,根據不同編譯器選擇對應啟動入參,這裡不作詳細介紹,有興趣可以了解一下;所以我們用得到的**就是:

extern int $super$$main(void);

/* re-define main function */

int $sub$$main(void)

這是一種特殊模式:用於有乙個已經存在且不能被改變的函式的情況,使用這兩個模式可以幫原函式打補丁,如存在乙個函式foo():$sub$$foo:定義的新功能函式,原先的foo()的入口變為$sub$$foo(),在$sub$$foo裡面可以對foo()函式功能重寫;$super$$foo:指的是原始的foo()函式,使用$super$$foo時,使用者呼叫的實際上就是foo();因此,那段彙編執行完成後調到的main()是這個$sub$$main;然後往下執行,注意函式rtthread_startup();裡面才是主要的:

int rtthread_startup(void)

都是一堆初始化的操作,在這裡我們最起碼能知道:啟動任務排程器的時候,已經有兩個執行緒可以跑起來了:(1)系統軟定時器執行緒;(2)空閒執行緒;分別進入到其中看下就可以明白之前不斷列印刷屏的是啥玩意了,所以即使外面的main()我們啥都沒寫,系統起來還是沒問題的;

這裡很簡單,就是建立乙個叫」main」的執行緒,然後啟動它,執行緒入口是main_thread_entry,繼續看:

void main_thread_entry(void *parameter)

關鍵的東東來了,首先宣告了main()和$super$$main();再有乙個初始化,然後去呼叫$super$$main();,按照之前的解釋(忘記了回過頭再看下),這裡的呼叫就是那個什麼都沒有的main()函式了,然後吭哧吭哧的就可以執行使用者的業務,所以我們自己的應用程式就是完善那個什麼都沒有的main函式,在main裡面建立乙個執行緒跑下,看是不是這樣,這裡提供乙個點燈的demo程式:

三、總結

rt-thread給我們的嵌入式環境搭建提供了極大便利,官方能想得到的幾乎都給你幹了,關鍵在於他們提供的env工具,按照其它嵌入式系統的做法,沒有有env工具,必須從原始碼著手去撘環境,移植rtt的核心,這種做法我嘗試過,總會有一些莫名的報錯,估計還是系統架構不太熟悉,不過最終也是可以跑起來的,之前也出過乙個例程可以參考:當然這種做法不會受限於env工具,對於工程檔案組織可以隨心所欲,而不用去修改配置指令碼,還是不能忘本;系統環境和啟動流程搞清楚了,然後就是對接業務需求,驅動和應用開發;

利用Dockerfile構建映象

dockerfile 是乙個文字檔案,其內包含了一條條的指 instruction 每一條指令構建一層,因此每一條指令的內容,就是描述該層應當如何構建。還以之前定製 nginx 映象為例,這次我們使用 dockerfile 來定製。first dockerfile from ubuntu 14.04...

利用scons構建project

scons有非常多相對於make構建系統的優秀特性,可是因為發展時間比較短如今的應用範圍還是不太多,可以找到的資料也不是非常多。scons如今一大問題就是初始上手還是有點難度的,對於有python的基礎的還是有點問題,畢竟他跟寫成的python還是不一樣的。儘管他遵循了python語言的語法,相同用...

利用PowerDesigner構建PDM的心得

工欲善其事,必先利其器。通過構建pd的物理資料模型,我們可以方便直觀的對資料庫進行開發和維護。而且在學習過程中,也無疑的對資料庫的設計有了更深一層的理解。新建並選擇好相應型別dbms後我們就可以著手模型的環境配置了。1 建立業務規則 model business rules 如果建立驗證規則與列或域...