1.為什么不是gcc
之前我們花了三篇文章介紹Linux下如何進(jìn)行C語(yǔ)言編程:
Linux C語(yǔ)言編程(上篇) | gcc的使用
Linux C語(yǔ)言編程(中篇) | make的使用
Linux C語(yǔ)言編程(下篇) | gdb的使用
這是為了給接下來(lái)的Linux下嵌入式開(kāi)發(fā)打好基礎(chǔ),盡快熟悉Linux下c編程,但是在開(kāi)發(fā)stm32的時(shí)候,編譯工具鏈要使用gcc-arm-none-eabi,為什么不是gcc呢?這就要說(shuō)到linux下的交叉編譯了,因?yàn)槲覀円赑C機(jī)上編譯出可以運(yùn)行在ARM上的程序,使用gcc編譯出的是在PC上運(yùn)行的程序,所以我們要使用gcc-arm-none-eabi進(jìn)行交叉編譯~
2.gcc-arm-none-eabi toolchain 介紹及安裝
gcc-arm-none-eabi是一個(gè)開(kāi)源的ARM開(kāi)發(fā)工具鏈,適用于Arm Cortex-M和Coretex-A系列處理器,包括GNU編譯器(GCC),以及GDB,可用于Windows,Linux,MacOS上的交叉編譯。
gcc-arm-none-eabi在ubuntu軟件源倉(cāng)庫(kù)中就有,但是版本比較陳舊:

在此我們從[ARM官方下載鏈接](https://developer./open-source/gnu-toolchain/gnu-rm/downloads)選擇合適的版本下載(這里我選擇Linux64):

解壓下來(lái)是tar.ba2
格式包,使用命令tar -jxf <要解壓的文件>
解壓到我們要安裝的目錄:

為了以后使用方便,將文件夾重命名:

它下面的bin
目錄就是我們要使用的編譯工具鏈:

share
目錄的doc
下包含了大量的使用幫助文檔,可以先略讀一二,特別是readme.txt
:

接下來(lái)我們要將bin
目錄添加到環(huán)境變量,這樣可以直接在命令行輸入要使用的工具名,然后系統(tǒng)就可以找到該工具,在此我們僅為當(dāng)前用戶添加環(huán)境變量,使用vim ~/.bashrc
編輯當(dāng)前用戶配置文件,在最后添加export PATH=$PATH:/home/mculover666/gcc-arm-none-eabi/bin
:

然后使用命令source ~/.bashrc
更新系統(tǒng)路徑,使添加的環(huán)境變量立即生效:

然后輸入命令arm-none
,然后按三下Tab
(一定不要輸入全部),檢查系統(tǒng)是否可以自動(dòng)補(bǔ)全:

如果系統(tǒng)可以提示,說(shuō)明環(huán)境變量配置成功,可以開(kāi)心的使用arm-none-eabi工具鏈啦~
3.從裸機(jī)工程開(kāi)始
3.1.硬件說(shuō)明
這里我使用的是野火霸道開(kāi)發(fā)板,板載芯片為STM32F103ZET6
,下載器使用e-link
,這個(gè)下載器使用CMSIS-DAP下載程序,同時(shí)并帶有一個(gè)串口,非常好用~

板載RGB-LED的原理圖如圖所示:

3.2.新建空的裸機(jī)工程
首先新建一個(gè)文件夾mkdir 00-template-reg
用來(lái)存放整個(gè)工程,然后整個(gè)工程包含三個(gè)文件:
#include 'stm32f10x.h'
int main()
{
/* 開(kāi)啟GPIOB時(shí)鐘 */
*(unsigned int*)(0x40021000+0x18) |= 1<<3;
/* 配置PB0為推挽輸出 */
*(unsigned int*)(0x40010c00+0x00) |= 1<<(4*0);
/* PB0輸出低電平,點(diǎn)亮綠色LED */
*(unsigned int*)(0x40010c00+0x0c) &= ~(1<<0);
while(1);
}
void SystemInit(void)
{
}
4.編譯
接下來(lái)就是激動(dòng)人心的編譯步驟了~編譯的時(shí)候有兩種文件,一種是匯編啟動(dòng)文件,一種是c源文件,接下來(lái)分別編譯:
首先需要說(shuō)明一些編譯任何一個(gè)文件都需要帶上的參數(shù):
參數(shù) | 說(shuō)明 |
---|
-mthumb | 表明使用的指令集(必需) |
-mcpu=cortex-m3 | 表明芯片內(nèi)核(必需) |
-g | 產(chǎn)生調(diào)試信息 |
4.1.啟動(dòng)文件編譯
啟動(dòng)文件一般是由匯編寫(xiě)成,此處需要注意的是,匯編文件的格式有.S
和.s
之分:
之前我們添加的啟動(dòng)文件是小寫(xiě).s,所以直接進(jìn)行編譯,另外說(shuō)一下,如果使用的是.S
文件,那么需要帶上-x assembler-with-cpp
參數(shù)。
接下來(lái)說(shuō)明一些匯編文件gcc編譯器使用的參數(shù):
參數(shù) | 說(shuō)明 |
---|
-x assembler-with-cpp | 先對(duì)文件進(jìn)行預(yù)處理 |
-Wa,option | 向匯編器Assembler傳遞參數(shù) |
注:可以向匯編器傳遞的參數(shù):
參數(shù) | 說(shuō)明 |
---|
-W或--no-warn | 關(guān)閉所有告警 |
--fatal-warnings | 將所有的警告提示為錯(cuò)誤 |
--warn | 正常提示告警信息 |
所以,接下來(lái)我們可以使用如下的參數(shù)組合來(lái)編譯啟動(dòng)文件(不進(jìn)行預(yù)處理,并且正常提示告警信息):
arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m3 -g -Wa,--warn -o startup_stm32f10x_hd.o startup_stm32f10x_hd.s

4.2.C文件編譯
因?yàn)閙ain.c中沒(méi)有特殊的東西,只是兩個(gè)函數(shù),所以簡(jiǎn)單的編譯一下就可以了:
arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m3 -g -Wall -o main.o main.c
5.鏈接
鏈接重要的部分有兩點(diǎn):鏈接文件和傳遞給鏈接器的參數(shù)。
鏈接文件在固件庫(kù)中給的示例工程中有,在下面這個(gè)目錄:

其中stm32_flash.ld
是針對(duì)于STM32F103ZE的鏈接文件,如果是別的芯片,需要進(jìn)行修改,將它復(fù)制到我們的工程中去:

然后就要讓鏈接器開(kāi)始根據(jù)stm32_flash.ld
這個(gè)文件對(duì)startup_stm32f10x_hd.o
和main.o
這兩個(gè)文件開(kāi)始鏈接,生成包含了調(diào)試信息的elf文件,同時(shí),我們還需要給鏈接器傳遞一些參數(shù):arm-none-eabi-gcc -o test.elf main.o startup_stm32f10x_hd.o -mthumb -mcpu=cortex-m3 -T stm32_flash.ld -specs=nosys.specs -static -Wl,-cref,-u,Reset_Handler -Wl,-Map=test.map -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group
6.生成bin文件和hex文件
利用arm-none-eabi-objcopy
工具可以將elf文件轉(zhuǎn)化為適合于單片機(jī)的bin文件和hex文件,其中參數(shù)-O
(大寫(xiě)o)用于指定輸出文件的格式(默認(rèn)是bin格式)
arm-none-eabi-objcopy test.elf test.bin
arm-none-eabi-objcopy test.elf -Oihex test.hex
7.編寫(xiě)一個(gè)makefile雛形
TARGET=test
CC=arm-none-eabi-gcc
OBJCOPY=arm-none-eabi-objcopy
RM=rm -f
CORE=3
CPUFLAGS=-mthumb -mcpu=cortex-m$(CORE)
LDFLAGS = -T stm32_flash.ld -Wl,-cref,-u,Reset_Handler -Wl,-Map=$(TARGET).map -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group
CFLAGS=-g -o
$(TARGET):startup_stm32f10x_hd.o main.o
$(CC) $^ $(CPUFLAGS) $(LDFLAGS) $(CFLAGS) $(TARGET).elf
startup_stm32f10x_hd.o:startup_stm32f10x_hd.s
$(CC) -c $^ $(CPUFLAGS) $(CFLAGS) $@
main.o:main.c
$(CC) -c $^ $(CPUFLAGS) $(CFLAGS) $@
bin:
$(OBJCOPY) $(TARGET).elf $(TARGET).bin
hex:
$(OBJCOPY) $(TARGET).elf -Oihex $(TARGET).hex
clean:
$(RM) *.o $(TARGET).*
使用命令make
編譯生成elf文件;
使用命令make bin
將elf文件轉(zhuǎn)化生成bin文件;
使用命令make hex
將elf文件轉(zhuǎn)化生成hex文件;
使用命令make clean
即可清除掉所有編譯產(chǎn)生的文件。
==下一篇==:Linux下開(kāi)發(fā)stm32(二) | 使用openocd下載與調(diào)試
(https://blog.csdn.net/Mculover666/article/details/84900665)