AliOS Things 硬件抽象层(HAL)对接系列2 — SPI driver porting
HAL層(Hardware abstraction layer) 的目的是為了屏蔽底層不同芯片平臺的差異,從而使驅動層上面的軟件不會隨芯片平臺而改變。AliOS Things定義了全面的HAL抽象層,這個系列主要介紹AliOS ThingsHAL層與不同芯片平臺對接的poring要點,并舉例說明。
Hal porting系列2 —— SPI driver porting
一. 接口定義說明
SPI 對外接口定義在 include/hal/soc下面,接口函數主要有以下幾個: int32_t hal_spi_init(spi_dev_t *spi); int32_t hal_spi_send(spi_dev_t *spi, const uint8_t *data, uint16_t size, uint32_t timeout); int32_t hal_spi_recv(spi_dev_t *spi, uint8_t *data, uint16_t size, uint32_t timeout); int32_t hal_spi_send_recv(spi_dev_t *spi, uint8_t *tx_data, uint8_t *rx_data, uint16_t size, uint32_t timeout); int32_t hal_spi_finalize(spi_dev_t *spi);其中,結構體 spi_dev_t 定義為: typedef struct {uint8_t port; /* spi port */spi_config_t config; /* spi config */void *priv; /* priv data */ } spi_dev_t;結構體 spi_config_t 定義為: typedef struct {uint32_t mode; /* spi communication mode */uint32_t freq; /* communication frequency Hz */ } spi_config_t;port 指spi的端口號,在一個系統中,可能會有不止一對的spi主從設備,此時可以通過port值來區分是哪個spi設備,如spi0、spi1等等;
config是用戶需要指定的配置,這里給出了2個較為常見的配置數據。分別是:
mode --- 模式 master or slave
freq --- 傳輸頻率,不用硬件支持的頻率不同,一般可選從125K到8M。
若用戶還有其他需要指定的數據,可以通過priv來傳入。
二. 接口使用說明
初始化 spi 設備:
需要定義spi_dev_t 的變量,舉例說明:
三. hal層對接要點
以 STM32L4 系列為例介紹hal層具體porting步驟:
HAL層接口函數位于/include/hal/soc目錄下,SPI 的HAL層接口函數定義在對應的spi.h中
hal層定義的接口為:
int32_t hal_spi_init(spi_dev_t *spi)STM32L4的初始化接口為:
HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)其中 SPI_HandleTypeDef 是ST系列自定義的結構體定義,可參考ST驅動源碼。
由于STM32L4的驅動函數和hal層定義的接口并非完全一致,我們需要在STM32L4驅動上封裝一層,以對接hal層。
我們需要新建兩個文件hal_spi_stm32l4.c和hal_spi_stm32l4.h,將封裝層代碼放到這兩個文件中。
在hal_spi_stm32l4.c中,首先定義相應的STM32L4的spi句柄:
/ handle for spi /
SPI_HandleTypeDef spi1_handle;
然后自定義如下函數,將用戶指定的mode和freq傳入 spi1_handle
int32_t spi_mode_transform(uint32_t mode_hal, uint32_t *mode_stm32l4); int32_t spi_freq_transform(uint32_t freq_hal, uint32_t *BaudRatePrescaler_stm32l4_stm32l4);代碼示例如下:
int32_t spi1_init(spi_dev_t *spi) {int32_t ret = 0;spi1_handle.Instance = SPI1;ret = spi_mode_transform(spi->config.mode, &spi1_handle.Init.Mode);ret = spi_freq_transform(spi->config.freq, &spi1_handle.Init.BaudRatePrescaler);if (ret != 0) {return -1;}/* init spi */ret = HAL_SPI_Init(&spi1_handle);return ret; }int32_t hal_spi_init(spi_dev_t *spi) {int32_t ret = -1;if (spi == NULL) {return -1;}/*init spi handle*/memset(&spi1_handle, 0, sizeof(spi1_handle));switch (spi->port) {case PORT_SPI1:spi->priv = &spi1_handle;ret = spi1_init(spi);break;/* if ohter spi exist add init code here */default:break;}return ret; }以 Nordic NRF52xxx系列為例:
NRF的spi init驅動定義如下:
所以,要對接NRF系列的HAL層,需要仔細研究驅動的定義,下面給出示例:
我們在新建的hal_spi_nrf52xxx.h中可以將 上述接口中使用的函數入參統一到一個新的結構體中,并命名為SPI_HandleTypeDef:
發送數據:
ret = hal_spi_send(spi_0 , buf, nbytes, timeout);表示在timeout時間范圍內,將buf開始的大小為nbytes字節的數據通過spi_0 設備發送。
調用這個接口時需要注意兩點:
ST系列:
typedef enum {HAL_OK = 0x00,HAL_ERROR = 0x01,HAL_BUSY = 0x02,HAL_TIMEOUT = 0x03 } HAL_StatusTypeDef;NRF系列:
要根據不同返回值的定義判斷驅動此時的狀態。
2.不同芯片平臺驅動中,對timeout的理解不同:
ST系列,底層發送驅動中會對 timeout進行判斷,若timeout時間到仍未發送完成,則返回 HAL_TIMEOUT ;
NRF系列,若不使用中斷,則發送驅動中采用的是while死等的操作方式,此時參數 timeout將不起作用。
數據接收 hal_spi_recv 接口的對接與發送類似。
總結
以上是生活随笔為你收集整理的AliOS Things 硬件抽象层(HAL)对接系列2 — SPI driver porting的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 金蝶K/3 同步用核算项目配置
- 下一篇: (十四)struts2的国际化