1. 程式人生 > >STM32高階開發(9)-學習與編譯libopencm3-example

STM32高階開發(9)-學習與編譯libopencm3-example

在前面的幾篇中我們為大家介紹了在Linux下stm32開發環境的新特性和使用方式,可能大家覺得,我怎麼寫一個工程還要自己寫連結檔案和啟動檔案,是不是太不方便了點。那麼這篇中我會告訴大家其實並不是這樣的。在我們日常的一些小規模工程下我們是可以使用一個叫做libopencm3的cortexM核的通用驅動庫來配置我們的工程。那麼大型的工程呢?有童鞋還會問道。對於大型的工程,我想:自己去改寫連結檔案和啟動檔案,使得你對整個系統的啟動及執行流程更好的把控絕對是物有所值的,在這兩個檔案上付出的短短的時間絕對會為我們帶來超出他們花費的價值。

Libopencm3簡介

libopencm3專案(以前稱為libopenstm32)旨在建立一個適用於ARM Cortex-M0(+)/M3/M4核心微控制器的免費、自由與開源(LGPL v3或更新)的韌體庫,其支援的微控制器包括ST STM32, Ti Tiva and Stellaris, NXP LPC 11xx, 13xx, 15xx, 17xx parts, Atmel SAM3, Energy Micro EFM32等。

以上內容翻譯自libopencm3在GitHub上的官方wiki中的介紹(請不要嘲笑我的翻譯啦,大家明白意思就好,我就不費勁的去整理更好的語言描述了):
https://github.com/libopencm3/libopencm3/wiki

從Status的頁面中我們可以查詢到libopencm3目前所支援的微控制器型別,其中由於該專案起初是為stm32而開發的,所以韌體庫對stm32的支援性是最好的,其次是TI和NXP的微控制器,其他公司的MCU則要差許多,對支援性的描述大家可以在Status頁面中自行閱讀查詢。

  • ST:STM32F0, F1, F2, F3, F4, F7, L0, L1, L4
  • TI: MSP432 nee LM4F nee TM4C
  • NXP:LPC13xx, LPC15xx and LPC17xx
  • NXP:LPC43xx
  • EFM32:Tiny Gecko, Gecko, Leopard Gecko and Giant Gecko
  • Atmel:SAM 3a, 3n, 3s, 3x, 3u
  • Freescale:Vybrid VF6xx

下載Libopencm3及其例程

在我們學習一個韌體庫的過程中最重要的顯然是找到一個我們可以參考的樣例工程,所以在我們此處選擇下載Libopencm3的官方樣例工程。

首先cd到我們之前建立的workspace目錄下

$ cd
~/workspace
$ git clone https://github.com/libopencm3/libopencm3-examples.git

這裡寫圖片描述

我們點開克隆下來的工程進入其中的libopencm3韌體庫,會發現在資料夾下並不存在任何的檔案,這是由於在樣例工程中,配置引用了一個libopencm3韌體庫模組,這個submodule在我gitclone的過程中並不會被一起下載,所以我們需要cd進入工程使用git submodule init和update來更新註冊並下載它。

$ cd ./libopencm3-examples
$ git submodule init
$ git submodule update

這裡寫圖片描述

這裡寫圖片描述

到此我們就已經成功的將樣例工程下載下來了。

編譯Libopencm3的樣例

編譯Libopencm3韌體庫

在我們編譯樣例工程之前我們首先要編譯Libopencm3韌體庫從而生成庫檔案 .a,得以被樣例工程呼叫。所以我們cd進入Libopencm3的目錄並使用make編譯。

這裡寫圖片描述

這裡寫圖片描述

這裡再次講一下這裡生成的.a檔案,.a檔案是一種Linux下的靜態連結庫檔案,而在我們的應用中我們可以把它理解為是一種由韌體庫中的.c.h檔案編譯生成的整合庫,就像keil下的 .lib 是一樣的。

樣例工程的檔案結構

在剛剛下載下來樣例工程的時候我想大家想我一樣,對它兩眼一摸黑,甚至連樣例工程的下各個例子在哪都找不到。所以在下面我們首先為大家來介紹一下我們下載下來的樣例工程結構,來為大家分析一下它的用法。

首先我們要明白,我們下載下來的是一個完整的樣例工程即就像st官方的韌體庫資料一樣,裡面包含了很多小的工程,如流水燈,LCD顯示,ADC等等,但他們都是引用檔案結構下的一個庫檔案進行編譯,這點是和國內stm32開發板(如:原子、野火等)的教程不大一樣的。在瞭解這點後,我們來看下資料夾下的內容。

-libopencm3-examples
|-examples\
|-libopencm3\
|-scripts\
|-Makefile
|-README.md

在 examples 存放的是樣例的原始碼,在其目錄下以晶片型號分類成不同的資料夾。在libopencm3下,是libopencm3韌體庫的本體。scripts下存放的是libopencm3專案推薦的一個叫black_magic的偵錯程式的啟動檔案,我們不需理會,README.md則是專案的說明檔案,使用markdown語言編寫,會在GitHub中的專案檔案列表下自動顯示。在此處頂層資料夾中的makefile中,它的功能是編譯所有的樣例檔案下的子工程,我們不理會它,因為我們不會使用這個檔案來編譯。

下面我們進入 examples/stm32/f4的目錄,由於我使用的是一塊官方的F429DISCO開發板,所以在這個資料夾下是可以直接找到給這塊開發板使用的子工程的,如果大家使用的是其他牌子或自行設計的開發板,大家可以選擇一個與開發板上晶片主型號相同的官方開發板開啟,因為除卻外設接駁的埠等,實際上它們都是一樣的。在板子的目錄下我們可以看到不同功能的子工程,如 ADC、blink、button等。

這裡寫圖片描述

我們進入最簡單的例程:miniblink同時將終端cd進入該資料夾,輸入make+空格,而後雙擊Tab,看看可以執行的目標:

$ make 

這裡寫圖片描述

由於我們沒有在makefile中配置好偵錯程式,所以這裡我們先選擇編譯.hex來編譯。對於開發板上LED埠不對應的童鞋,在make前,可以先開啟目錄下miniblink.c的原始碼修改其中的埠,及時我們之前沒有接觸過libopencm3的韌體庫,但我相信大家都是能夠理解裡面的內容的。

這裡寫圖片描述

在修改完成後,我們使用make執行。

$ make hex

很快編譯就會完成,並在子工程目錄下生成一個.hex檔案,我們將hex檔案移出,下載進入微控制器,看~是不是LED開始閃爍了?

這裡寫圖片描述

由此我想大家就明白這個樣例工程該怎麼使用了,但是進一步的,大家肯定會產生疑問,這個樣例工程下,makefile是怎樣產生功能的,它是怎麼配置的,麼下下面我們就來深入的分析一下這個問題。

樣例工程的makefile

我們來看看子工程目錄下的make 也就是我們在該資料夾下執行make指令時首先呼叫的makefile檔案。

BINARY = miniblink

LDSCRIPT = ../stm32f429i-discovery.ld

include ../../Makefile.include
MEMORY
{
    rom (rx) : ORIGIN = 0x08000000, LENGTH = 2048K
    ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K /* (esden) This should be 256 but I get segfault. :( */
}

/* Include the common ld script. */
INCLUDE libopencm3_stm32f4.ld

我們開啟上層目錄的ld檔案stm32f429i-discovery.ld,發現它定義了板子上STM32F429ZIT6的ROM、RAM大小並引用了libopencm3韌體庫下的libopencm3_stm32f4.ld檔案,再開啟libopencm3_stm32f4.ld檔案,我們發現其中只定義了除ROM、RAM大小的所有連結規則。至此我們就明白了ld檔案的設定及引用結構。接下來再來看看被子工程引用的makefile:Makefile.include

ifeq ($(DEVICE),)
LIBNAME     = opencm3_stm32f4
DEFS        += -DSTM32F4

FP_FLAGS    ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
ARCH_FLAGS  = -mthumb -mcpu=cortex-m4 $(FP_FLAGS)
endif

################################################################################
# OpenOCD specific variables

OOCD        ?= openocd
OOCD_INTERFACE  ?= stlink-v2
OOCD_TARGET ?= stm32f4x

################################################################################
# Black Magic Probe specific variables
# Set the BMP_PORT to a serial port and then BMP is used for flashing
BMP_PORT    ?=

################################################################################
# texane/stlink specific variables
#STLINK_PORT    ?= :4242


include ../../../../rules.mk

第一行,如果DEVICE變數為空,就執行下面的賦值,我們之前並未定義DEVICE所以下面的賦值會被執行。這裡我們看到他定義了韌體庫的名稱、晶片的型號和編譯的引數。下面則定義了各種偵錯程式的引數。並在最後再一次引用了一個makefile:rules.mk。而這一次我們先不開啟這個makefile,在下面一個階段裡我們再來分析。

這裡首先我們先講講,這裡makefile和ld檔案問什麼分了這麼多,搞得這麼麻煩,其中最大的原因就是層次性和通用性,在我翻看其他的子工程原始碼的情況下,我們會發現除了子工程目錄下的makefile檔案,其他的makefile檔案和ld檔案都被不同的子工程呼叫的多次,而到了rules.mk的檔案,所有的不同型號晶片和板子的子工程都呼叫了這個makefile。以這種分層次分結構的的方式編寫,顯然的可以極大地方便最終子工程的設定修改和快速配置。

呃,是不是有點沒大說清楚,我們舉個具體的例子;就如在miniblink子工程資料夾下的makefile中,定義了子工程的設定。在開發板型號的目錄下定義了,開發板和編譯引數的具體設定,在最後的mk.rule中,則定義了所有樣例工程的makefile設定。同理,ld檔案的結構也是這樣。

到這裡我們對libopencm3工程的介紹就告一段落了,想來大家也對樣例工程的結構有了一定的瞭解,從而可以自己去學習官方的樣例工程了,在這裡我還是建議大家先嚐試的去更改官方樣例工程的原始碼,和makefile來試著編譯自己的一個blink程式,來藉此學習一下樣例工程,從而為我們接下來的內容奠定一個基礎。