ST IKS01A1 驱动程序分析

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.思维导图
ST IKS01A1 驱动程序分析

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
");
    }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
",cnt);
        printf("Init Handle->who am i : %d
",handle->who_am_i);
}
void ACC_DeInit(DrvContextTypeDef *handle)
{
//    printf("DeInit LSM6DS0 %d
",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