開篇分割線,再研究驅動程序之前我們先看下RTT 關于SPI應用的代碼層級結構:
應用層:只做應用層開發的小伙伴是有福的,你不需要了解整個驅動是怎樣構架的,只需要了解驅動構架層提供的API接口函數直接調用,即可操作SPI設備。
設備驅動框架層:由RTT系統提供的一個重要的中間層,用于驅動層和應用層之間聯系的建立,對應用層開放API調用接口,對驅動層開放注冊函數和操作函數,將驅動層的操作注冊到系統中,實現應用與驅動之間的軟連接。
總線設備驅動層:該層是驅動開發工程師的主攻戰場,后面展開詳細講。
硬件SPI控制器層:一般情況下就是MCU自帶的控制外設,這里當然就是SPI控制器,玩過單片機的小伙伴最熟悉的部分。
外掛模塊層:最后一層就是SPI類型總線通信設備的模塊,常用的flash芯片、網絡控制模塊等都生活在這一層,實際電路中通過SPI通信線與MCU連接。
接下來就是看下基于STM32開發SPI的設備模型(模型即結構體定義)了,代碼如下:
/* stm32 spi dirver class */
struct stm32_spi
{
SPI_HandleTypeDef handle;
struct stm32_spi_config *config;
struct rt_spi_configuration *cfg;
struct
{
DMA_HandleTypeDef handle_rx;
DMA_HandleTypeDef handle_tx;
} dma;
rt_uint8_t spi_dma_flag;
struct rt_spi_bus spi_bus;
};
這里需要注意的是,模型的最后一個成員spi_bus,它是由RTT系統提供,有了它這個模型就與系統之間產生了聯系,spi_bus是系統的一個SPI類型硬件設備模型。 有了模型以后,我們就是針對這個模型進行設備的實例化,一般來講MCU會有多個SPI控制器,所以針對這一情況,我們就定義了另一個模型專門用于實例化SPI對象模型:
struct stm32_spi_config
{
SPI_TypeDef *Instance; /*SPI外設*/
char *bus_name; /*SPI總線設備名稱*/
struct dma_config *dma_rx, *dma_tx; /*DMA發送及接收配置參數*/
};
接下來需要采用預處理命令宏定義硬件外設所有的SPI設備配置項,至于是否開啟我們可以通過rt_config.h文件是否定義該宏來決定:
#ifdef BSP_USING_SPI1
#ifndef SPI1_BUS_CONFIG
#define SPI1_BUS_CONFIG \
{ \
.Instance = SPI1, \
.bus_name = "spi1", \
}
#endif /* SPI1_BUS_CONFIG */
#endif /* BSP_USING_SPI1 */
#ifdef BSP_USING_SPI2
#ifndef SPI2_BUS_CONFIG
#define SPI2_BUS_CONFIG \
{ \
.Instance = SPI2, \
.bus_name = "spi2", \
}
#endif /* SPI2_BUS_CONFIG */
#endif /* BSP_USING_SPI2 */
有了設備配置模型,就需要定義一個真實的需要配置的設備模型數據,用于實例化多個SPI控制器,實際上就一個數組搞定:
static struct stm32_spi_config spi_config[] =
{
#ifdef BSP_USING_SPI1
SPI1_BUS_CONFIG,
#endif
#ifdef BSP_USING_SPI2
SPI2_BUS_CONFIG,
#endif
};
有了設備類型模型,也有了配置模型數組,就需要定義通過模型來定義真實的設備實例,定義完并沒有進行初始化:
/*定義SPI總線對象*/
static struct stm32_spi spi_bus_obj[sizeof(spi_config) / sizeof(spi_config[0])] = {0};
到這里,關于SPI總線對象的創建就完了,但是關于SPI總線對象還是一個空空如也的數組,我想你也應該知道如何基于配置對象給總線對象進行初始化,當然這個我們下篇接著講。