日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

AliOS Things 硬件抽象层(HAL)对接系列2 — SPI driver porting

發布時間:2025/3/20 编程问答 67 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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 的變量,舉例說明:

spi_dev_t spi_0 = {.port = 0,.config = {SPI_MODE, SPI_FREQ_8M},.priv = 0};初始化: hal_spi_init(spi_0);發送數據: ret = hal_spi_send(spi_0 , buf, nbytes, timeout); 接收數據: ret = hal_spi_recv(spi_0, buf, nbytes, timeout)master發送數據同時接收slvae發來的數據: ret = hal_spi_send_recv( spi_0, buf_tx, buf_rx, nbytes , timeout)

三. 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驅動定義如下:

ret_code_t nrf_drv_spi_init(nrf_drv_spi_t const * const p_instance,nrf_drv_spi_config_t const * p_config,nrf_drv_spi_evt_handler_t handler,void * p_context)

所以,要對接NRF系列的HAL層,需要仔細研究驅動的定義,下面給出示例:
我們在新建的hal_spi_nrf52xxx.h中可以將 上述接口中使用的函數入參統一到一個新的結構體中,并命名為SPI_HandleTypeDef:

typedef struct __SPI_HandleTypeDef {nrf_drv_spi_t spi_dev;nrf_drv_spi_config_t spi_config;nrf_drv_spi_evt_handler_t spi_handler;void * p_context; } SPI_HandleTypeDef;在 hal_spi_nrf52xxx.c中 定義相應的NRF52的spi句柄: /* handle for spi */SPI_HandleTypeDef spi0_handle = {NRF_DRV_SPI_INSTANCE(AOS_PORT_SPI0), NRF_DRV_SPI_DEFAULT_CONFIG, 0, NULL};(其中的 NRF_DRV_SPI_INSTANCE 和 NRF_DRV_SPI_DEFAULT_CONFIG定義參考NRF驅動源碼)static int32_t spi0_init(spi_dev_t *spi) {int32_t ret1 = 0, ret2 = 0;spi0_handle.spi_config.ss_pin = SPIM0_SS_PIN;spi0_handle.spi_config.miso_pin = SPIM0_MISO_PIN;spi0_handle.spi_config.mosi_pin = SPIM0_MOSI_PIN;spi0_handle.spi_config.sck_pin = SPIM0_SCK_PIN;ret1 = spi_mode_transform(spi->config.mode, &spi0_handle.spi_config.mode);ret2 = spi_freq_transform(spi->config.freq, &spi0_handle.spi_config.frequency);if ((ret1 != 0) || (ret2 != 0))return -1;return nrf_drv_spi_init(&spi0_handle.spi_dev, &spi0_handle.spi_config, NULL, NULL); }static int32_t spi_mode_transform(uint32_t mode_hal, uint32_t *mode_nrf52xxx) {nrf_drv_spi_mode_t mode = 0;int32_t ret = 0;switch (mode_hal){case SPI_MODE_0:mode = NRF_DRV_SPI_MODE_0;break;case SPI_MODE_1:mode = NRF_DRV_SPI_MODE_1;break;case SPI_MODE_2:mode = NRF_DRV_SPI_MODE_2;break;case SPI_MODE_3:mode = NRF_DRV_SPI_MODE_3;break;default:ret = -1;}if(ret == 0)*mode_nrf52xxx = (uint32_t)mode;return ret; }static int32_t spi_freq_transform(uint32_t freq_hal, uint32_t *freq_nrf52xxx) {nrf_drv_spi_frequency_t freq = 0;int32_t ret = 0;switch (freq_hal){case SPI_FREQ_125K:freq = NRF_SPI_FREQ_125K;break;case SPI_FREQ_250K:freq = NRF_SPI_FREQ_250K;break;case SPI_FREQ_500K:freq = NRF_SPI_FREQ_500K;break;case SPI_FREQ_1M:freq = NRF_SPI_FREQ_1M;break;case SPI_FREQ_2M:freq = NRF_SPI_FREQ_2M;break;case SPI_FREQ_4M:freq = NRF_SPI_FREQ_4M;break;case SPI_FREQ_8M:freq = NRF_SPI_FREQ_8M;break;default:ret = -1;}if(ret == 0)*freq_nrf52xxx = (uint32_t)freq;return ret; }

發送數據:

ret = hal_spi_send(spi_0 , buf, nbytes, timeout);

表示在timeout時間范圍內,將buf開始的大小為nbytes字節的數據通過spi_0 設備發送。

調用這個接口時需要注意兩點:

  • 需要對返回值ret進行判斷,不用芯片平臺驅動的返回值不同:
  • 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的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。