zoukankan      html  css  js  c++  java
  • 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.思维导图

    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
  • 相关阅读:
    Linux中ctrl+z 、ctrl+c、 ctrl+d区别
    linux文件与用户权限的设置
    查找jdk的安装目录
    linux上修改防火墙操作
    linux上打包与压缩操作
    安装hive操作参考视频
    linux上设置环境变量每次需要source /etc/profile问题处理
    【c语言趣味编程100例】出售金鱼
    【c语言趣味编程100例】三色球问题
    【c语言】递归实现strlen()函数
  • 原文地址:https://www.cnblogs.com/ZQQH/p/8870122.html
Copyright © 2011-2022 走看看