1. 程式人生 > >ST IKS01A1 驅動程序分析

ST IKS01A1 驅動程序分析

== ini driver case 臨時 bsp this null done

1.問題出現

  我想把st官方的IKS01A1 板子的驅動程序移植到另一個板子上(stm32F767ZI NUCLEO),他原本的程序都是比較難懂,並且耦合度高,挺難移植的,但是我還是移植成功了,這裏要對這個驅動代碼進行分析。雖然我本來都比較喜歡正點原子那種簡單易懂的程序,但是這種代碼看了對自己的提高還是挺大的。

2.驅動代碼

  我以一個初始化函數為例。

首先主函數定義一個 static void *LSM6DS0_X_0_handle = NULL;

BSP_ACCELERO_Init(LSM6DS0_X_0, &LSM6DS0_X_0_handle);  //初始化函數

函數原型: 這裏就對 BSP_LSM6DS0_ACCELERO_Init(handle)

進行分析。

這裏 &LSM6DS0_X_0_handle 賦值給 **handle ,傳入的handle即LSM6DS0_X_0_handle 。

DrvStatusTypeDef BSP_ACCELERO_Init( ACCELERO_ID_t id, void **handle )
{

  *handle = NULL;

  switch(id)
  {
    case ACCELERO_SENSORS_AUTO:
    default:
    {
      /* Try to init the LSM6DS3 before */
      if( BSP_LSM6DS3_ACCELERO_Init(handle) == COMPONENT_ERROR )
      {
        
/* Try to init the LSM6DS0 if we do not use the LSM6DS3 */ if( BSP_LSM6DS0_ACCELERO_Init(handle) == COMPONENT_ERROR ) { return COMPONENT_ERROR; } } break; } case LSM6DS0_X_0: { if( BSP_LSM6DS0_ACCELERO_Init(handle) == COMPONENT_ERROR )//我的板子執行這個
{ return COMPONENT_ERROR; } break; } case LSM6DS3_X_0: { if( BSP_LSM6DS3_ACCELERO_Init(handle) == COMPONENT_ERROR ) { return COMPONENT_ERROR; } break; } } return COMPONENT_OK; }

接下來是對static DrvStatusTypeDef BSP_LSM6DS0_ACCELERO_Init( void **handle )分析

源代碼為

static DrvStatusTypeDef BSP_LSM6DS0_ACCELERO_Init( void **handle )
{
  ACCELERO_Drv_t *driver = NULL;

  if(ACCELERO_SensorHandle[ LSM6DS0_X_0 ].isInitialized == 1)
  {
    /* We have reached the max num of instance for this component */
    return COMPONENT_ERROR;
  }

  if ( Sensor_IO_Init() == COMPONENT_ERROR )
  {
    return COMPONENT_ERROR;
  }

  /* Setup sensor handle. */
  ACCELERO_SensorHandle[ LSM6DS0_X_0 ].who_am_i      = LSM6DS0_ACC_GYRO_WHO_AM_I;
  ACCELERO_SensorHandle[ LSM6DS0_X_0 ].ifType        = 0; /* I2C interface */
  ACCELERO_SensorHandle[ LSM6DS0_X_0 ].address       = LSM6DS0_ACC_GYRO_I2C_ADDRESS_HIGH;
  ACCELERO_SensorHandle[ LSM6DS0_X_0 ].instance      = LSM6DS0_X_0;
  ACCELERO_SensorHandle[ LSM6DS0_X_0 ].isInitialized = 0;
  ACCELERO_SensorHandle[ LSM6DS0_X_0 ].isEnabled     = 0;
  ACCELERO_SensorHandle[ LSM6DS0_X_0 ].isCombo       = 1;
  ACCELERO_SensorHandle[ LSM6DS0_X_0 ].pData         = ( void * )&ACCELERO_Data[ LSM6DS0_X_0 ];
  ACCELERO_SensorHandle[ LSM6DS0_X_0 ].pVTable       = ( void * )&LSM6DS0_X_Drv;
  ACCELERO_SensorHandle[ LSM6DS0_X_0 ].pExtVTable    = 0;

  LSM6DS0_X_0_Data.comboData = &LSM6DS0_Combo_Data[0];
  ACCELERO_Data[ LSM6DS0_X_0 ].pComponentData = ( void * )&LSM6DS0_X_0_Data;
  ACCELERO_Data[ LSM6DS0_X_0 ].pExtData       = 0;

  *handle = (void *)&ACCELERO_SensorHandle[ LSM6DS0_X_0 ];

  driver = ( ACCELERO_Drv_t * )((DrvContextTypeDef *)(*handle))->pVTable;

  if ( driver->Init == NULL )
  {
    memset((*handle), 0, sizeof(DrvContextTypeDef));
    *handle = NULL;
    return COMPONENT_ERROR;
  }

  if ( driver->Init( (DrvContextTypeDef *)(*handle) ) == COMPONENT_ERROR )
  {
    memset((*handle), 0, sizeof(DrvContextTypeDef));
    *handle = NULL;
    return COMPONENT_ERROR;
  }

  /* Configure interrupt lines for LSM6DS0 */
  LSM6DS0_Sensor_IO_ITConfig();

  return COMPONENT_OK;
}

重點對我畫紅圈的地方進行分析。

1.ACCELERO_SensorHandle[ LSM6DS0_X_0 ]

  這其實是一個全局的設備參數結構體定義

  原定義

  static DrvContextTypeDef ACCELERO_SensorHandle[ ACCELERO_SENSORS_MAX_NUM ]; 這個 DrvContextTypeDef 就是一個通用的外設內容結構體,可以關聯到外設的所有參數
typedef struct
{

  /* Identity */
  uint8_t who_am_i;

  /* Configuration */
  uint8_t ifType;        /* 0 means I2C, 1 means SPI, etc. */
  uint8_t address;       /* Sensor I2C address (NOTE: Not a unique sensor ID). */
  uint8_t spiDevice;     /* Sensor Chip Select for SPI Bus */
  uint8_t instance;      /* Sensor instance (NOTE: Sensor ID unique only within its class). */
  uint8_t isInitialized; /* Sensor setup done. */
  uint8_t isEnabled;     /* Sensor ON. */
  uint8_t isCombo;       /* Combo sensor (component consists of more sensors). */

  /* Pointer to the Data */
  void *pData;
  /* Pointer to the Virtual Table */
  void *pVTable;
  /* Pointer to the Extended Virtual Table */
  void *pExtVTable;
} DrvContextTypeDef;

最後的三個還可以關聯到這個設備的數據、驅動函數、擴展驅動函數

2.LSM6DS0_X_Drv

  這是一個全局的驅動函數結構體,保存了這個設備的所有驅動。將所有的函數指針賦值到結構體。

  定義:

typedef struct
{
  DrvStatusTypeDef ( *Init            ) ( DrvContextTypeDef* );
  DrvStatusTypeDef ( *DeInit          ) ( DrvContextTypeDef* );
  DrvStatusTypeDef ( *Sensor_Enable   ) ( DrvContextTypeDef* );
  DrvStatusTypeDef ( *Sensor_Disable  ) ( DrvContextTypeDef* );
  DrvStatusTypeDef ( *Get_WhoAmI      ) ( DrvContextTypeDef*, uint8_t* );
  DrvStatusTypeDef ( *Check_WhoAmI    ) ( DrvContextTypeDef* );
  DrvStatusTypeDef ( *Get_Axes        ) ( DrvContextTypeDef*, SensorAxes_t* );
  DrvStatusTypeDef ( *Get_AxesRaw     ) ( DrvContextTypeDef*, SensorAxesRaw_t* );
  DrvStatusTypeDef ( *Get_Sensitivity ) ( DrvContextTypeDef*, float* );
  DrvStatusTypeDef ( *Get_ODR         ) ( DrvContextTypeDef*, float* );
  DrvStatusTypeDef ( *Set_ODR         ) ( DrvContextTypeDef*, SensorOdr_t );
  DrvStatusTypeDef ( *Set_ODR_Value   ) ( DrvContextTypeDef*, float );
  DrvStatusTypeDef ( *Get_FS          ) ( DrvContextTypeDef*, float* );
  DrvStatusTypeDef ( *Set_FS          ) ( DrvContextTypeDef*, SensorFs_t );
  DrvStatusTypeDef ( *Set_FS_Value    ) ( DrvContextTypeDef*, float );
  DrvStatusTypeDef ( *Get_Axes_Status ) ( DrvContextTypeDef*, uint8_t* );
  DrvStatusTypeDef ( *Set_Axes_Status ) ( DrvContextTypeDef*, uint8_t* );
  DrvStatusTypeDef ( *Read_Reg        ) ( DrvContextTypeDef*, uint8_t, uint8_t* );
  DrvStatusTypeDef ( *Write_Reg       ) ( DrvContextTypeDef*, uint8_t, uint8_t );
  DrvStatusTypeDef ( *Get_DRDY_Status ) ( DrvContextTypeDef*, uint8_t* );
} ACCELERO_Drv_t;

ACCELERO_Drv_t LSM6DS0_X_Drv =
{
  LSM6DS0_X_Init,
  LSM6DS0_X_DeInit,
  LSM6DS0_X_Sensor_Enable,
  LSM6DS0_X_Sensor_Disable,
  LSM6DS0_X_Get_WhoAmI,
  LSM6DS0_X_Check_WhoAmI,
  LSM6DS0_X_Get_Axes,
  LSM6DS0_X_Get_AxesRaw,
  LSM6DS0_X_Get_Sensitivity,
  LSM6DS0_X_Get_ODR,
  LSM6DS0_X_Set_ODR,
  LSM6DS0_X_Set_ODR_Value,
  LSM6DS0_X_Get_FS,
  LSM6DS0_X_Set_FS,
  LSM6DS0_X_Set_FS_Value,
  LSM6DS0_X_Get_Axes_Status,
  LSM6DS0_X_Set_Axes_Status,
  LSM6DS0_X_Read_Reg,
  LSM6DS0_X_Write_Reg,
  LSM6DS0_X_Get_DRDY_Status
};

3.*handle = (void *)&ACCELERO_SensorHandle[ LSM6DS0_X_0 ];

  這個的意思就是把賦值好的 全局設備參數結構體地址 傳給 自己定義的LSM6DS0_X_0_handle。

並且轉換成(void *);

4.driver = ( ACCELERO_Drv_t * )((DrvContextTypeDef *)(*handle))->pVTable;

  首先把(*handle)強制轉換 (DrvContextTypeDef *)。也就是這個時候相當於原來的ACCELERO_SensorHandle[LSM6DS0_X_0 ]。再把這個結構體的 void * pVTable,強制轉換成ACCELERO_Drv_t *,相當於又變成了LSM6DS0_X_Drv。 現在把這個 LSM6DS0_X_Drv結構體的地址賦值給driver。

5.driver->Init( (DrvContextTypeDef *)(*handle)

  driver->Init( (DrvContextTypeDef *)(*handle);現在就可以通過driver調用init來使用

static DrvStatusTypeDef LSM6DS0_X_Init( DrvContextTypeDef *handle ); 同樣,也可以通過他別的內容來該使用該設備的驅動函數。 3.思維導圖 技術分享圖片

4.簡單例子

  main.c
#include <stdio.h>
#include "func.h"

static void *LSM6DS0_X_0_handle = NULL;

void Init_acc(void **handle);

int main(int argc, char *argv[])
{
    Init_acc(&LSM6DS0_X_0_handle);
    return 0;
}

void Init_acc(void **handle)
{
    //臨時--初始化----設備結構體
    DrvContextTypeDef ACCELERO_SensorHandle;
    //設備驅動結構體初始化
    ACCELERO_Drv_t *driver=NULL ;

    //初始化一些信息
    ACCELERO_SensorHandle.who_am_i=110;

    //將驅動函數連接到設備的驅動
    ACCELERO_SensorHandle.pVTable=( void * )&LSM6DS0_X_Drv;

    //將剛剛初始化的信息傳給handle,這樣傳進來的handle就會被賦值
    *handle =(void *)&ACCELERO_SensorHandle;

    //
    driver=(ACCELERO_Drv_t *)((DrvContextTypeDef *)(*handle))->pVTable;
    if(driver->Init == NULL)
    {
        printf("error\r\n");
    }else {
        driver->Init( (DrvContextTypeDef *)(*handle));
    }

}

  fun.c

#include "func.h"
#include "stdio.h"
#include "stdint.h"
void ACC_Init(DrvContextTypeDef *handle)
{
//    printf("Init LSM6DS0 %d\r\n",cnt);
        printf("Init Handle->who am i : %d\r\n",handle->who_am_i);
}
void ACC_DeInit(DrvContextTypeDef *handle)
{
//    printf("DeInit LSM6DS0 %d\r\n",cnt);
}

//驅動結構體賦值,將函數關聯到結構體中
ACCELERO_Drv_t LSM6DS0_X_Drv =
{
  ACC_Init,
  ACC_DeInit,
};

  fun.h

#ifndef FUNC_H
#define FUNC_H
#include "stdint.h"

//定義設備內容結構體
typedef struct
{

  /* Identity */
  uint8_t who_am_i;

  /* Configuration */
  uint8_t ifType;        /* 0 means I2C, 1 means SPI, etc. */
  uint8_t address;       /* Sensor I2C address (NOTE: Not a unique sensor ID). */
  uint8_t spiDevice;     /* Sensor Chip Select for SPI Bus */
  uint8_t instance;      /* Sensor instance (NOTE: Sensor ID unique only within its class). */
  uint8_t isInitialized; /* Sensor setup done. */
  uint8_t isEnabled;     /* Sensor ON. */
  uint8_t isCombo;       /* Combo sensor (component consists of more sensors). */

  /* Pointer to the Data */
  void *pData;
  /* Pointer to the Virtual Table */
  void *pVTable;
  /* Pointer to the Extended Virtual Table */
  void *pExtVTable;

} DrvContextTypeDef;



//定義驅動結構體
typedef struct
{
  void ( *Init            ) (DrvContextTypeDef *handle);
  void ( *DeInit          ) (DrvContextTypeDef *handle);
} ACCELERO_Drv_t;



extern ACCELERO_Drv_t LSM6DS0_X_Drv;



#endif // FUNC_H

ST IKS01A1 驅動程序分析