嵌入式軟件就是某一項目的源碼文件集合,源碼文件的數量,根據項目復雜程度的不同而有規模和層次的差別。
就拿簡單的一個芯片廠商提供的demo來說,代碼也會被細分到寄存器操作(Drv層)、板級支持包接口(Bsp層)、功能模塊驗證(App層)等各層,但是這里的“分層”很多時候都不太明顯,因為它僅僅是個demo,所謂的“分層”更多的還是人為給它做的定義。
真正意義的分層,是從代碼的編碼規范、程序的執行邏輯來體現的。
關于分層設計的意義在這暫不做太多的探討,只是做個引子,來講講SPI接口的設計過程,如何設計一套擁有自己規范和方便移植的SPI接口。
SPI在分層架構中的設計思路
剛剛提到分層設計的思路,那么SPI作為一個通信接口,如果按照分層設計的思路,如何把接口設計得更合理,更方便?
此處需要設計的SPI是介于“應用”和“驅動”之間的,“應用”就是項目業務需求的功能模塊將數據、數據包等傳給SPI接口,而“驅動”是SPI接口拿到數據包后,把數據轉變為SPI的時序發送出去。
當我們拿到一款芯片,大多數情況下官方提供的demo程序已經給我們實現好了很多的驅動(或者自己從網絡資源中Download),各個接口的驅動,已經被封裝成函數或者庫供我們直接調用。
想象一下我們的項目工程,如果需要操作芯片硬件接口的時候,直接調用官方提供的接口函數,雖然能實現功能,但是在需要更換芯片平臺的時候,就需要在繁雜的、與業務需求相關的應用層里找和去修改為目標驅動接口。
這里就牽扯到了分層設計的優勢所在:由于平臺的更換,驅動接口已經變了樣,那么對代碼的移植就會變得非常費力,不僅是腦力活,更是體力活(即使可以批量替換,你也需要仔細核對接口,更要解決接口的差異性)。
而此時如果是分層設計的,在應用和驅動中間有個BSP層,應用層調用的只是BSP層,完全不涉及驅動、寄存器,不涉及與芯片平臺相關的接口,那么即使平臺怎么更換、驅動怎么改變,你只需要改變BSP層的具體實現,相對就輕松很多了。
從上一篇《嵌入式硬件通信接口協議-SPI(一)協議基礎》對SPI協議的介紹,設計BSP層的時候,根據SPI可配置項來設計接口功能。設計BSP層的SPI功能函數時考慮接口模式、數據寬度、時鐘極性與相位、時鐘速率、數據bit位大小端選擇、管腳定義。
設計BSP層時,首先想到的是接口初始化和數據收發。設計初始化,把SPI可配置項放在函數接口,作參數傳遞;設計數據收發,傳數據的同時也把SPI端口號作為參數之一,因為我們都知道MCU可能會有多個SPI接口,將SPI端口號作為參數也是比較必要。
SPI接口本身就是可以實現1對N的串行總線,為什么在使用過程中有時要分別使用不同的SPI端口來接不同的外圍器件呢?
主要原因是SPI的可配置項的不一致,有些外圍器件對SPI時鐘信號SCLK的極性要求為高、低不一樣,時鐘相位不一樣,并且通信數據bit位大小端選擇的不一樣,這些接口配置項的差異,導致了有些場景下操作不同器件時需要使用不同的SPI端口。
SPI時序使用IO引腳模擬
從零開始設計自有的一套SPI板級支持包(BSP)接口,那就從初始化開始。這里設計的是模擬SPI,所以會調用GPIO設置的接口。
當前使用的芯片平臺是STM32F103系列,雖然此時已經完全可以調用官方的StdPeriphDrivers V3.5.0版本的標準外設庫。調用接口庫不是目的,成為“調庫俠”其實很簡單。此處重新寫的模擬實現方式,旨在說明在BSP層,實現自有系統的軟件架構,為系統集成提供底層接口。同時也是在深入學習和了解SPI接口的時序特性。
初始化函數接口里暫時做了SPI端口號、數據寬度、接口時鐘模式、數據位優先模式這四個參數,基本上這四個參數已經可以完成對大部分應用需求。在編碼初期先不急于填入過多的配置項,首先按照最簡單的默認方式編碼,保證程序邏輯可以跑通。
其中用到的管腳定義,是在完成原理圖或者完成原型機驗證時,基本就確定了管腳的使用,因此管腳的定義一般的都是放在BSP層的頭文件中。這樣更便于移植和開發。
數據發送時,先寫發送一個字節的數據,數據是“踩”著SPI接口時鐘信號SCLK的“節拍”逐個bit位發送出去,因此在發送數據的時候也是需要主機操作時鐘信號SCLK和數據信號MOSI:
SPI的數據發送接口dcbsp_spi_sendbyte函數實現了將1個字節的數據通過GPIO輸出,實現了SPI接口的時序,其中關鍵的是SCLK信號輸出、1字節數據的移位輸出、SCLK信號做延時輸出脈沖。
而發送多數據的接口就可以采用dcbsp_spi_sendbyte函數來逐字節發送完成。
另外接收數據的接口,同樣參考著字節發送接口的思路,數據的接收過程也是“踩”著SPI接口時鐘信號SCLK的“節拍”逐個bit位傳輸,這個過程主機繼續提供SCLK,然后讀取MISO信號的電平,再將讀到的電平逐bit緩存在一個變量里:
就這樣,利用GPIO進行電平的輸出的讀取,實現了SPI接口的部分時序。這些接口的內部實現過程,因人而異、因平臺變化而微調,但是對外接口不動,對上層應用來說,這就是同一個接口同一個東西,上層的應用層程序改動就很小了。
對于每次移植,BSP層提供了一定架構接口,層次清晰改動小,所以對于一個嵌入式開發者而言,寫好BSP層也很重要。
總結,本文主要想分享的是設計嵌入式軟件時,分出BSP層,作為應用和驅動的中間層,以便于在項目移植過程中,應用的完美匹配。文中的代碼未完,關于驅動類的代碼,其執行結果必須在示波器等儀器下觀測,仍需確認執行的效率和時序的實現效果!
-
嵌入式
+關注
關注
5068文章
19017瀏覽量
303253
發布評論請先 登錄
相關推薦
評論