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

转载于:https://www.cnblogs.com/ZQQH/p/8870122.html

ST IKS01A1 驱动程序分析相关推荐

  1. STM32-I2C总线驱动程序分析

    文章目录 I2C硬件电路原理图 I2C 简介 添加相应的文件并添加进工程文件 I2C驱动程序结构 I2C驱动程序分析 LM75A温度传感器电路原理图 LM75A温度传感器驱动程序分析 杨桃32学习笔记 ...

  2. android 电容屏(三):驱动调试之驱动程序分析篇

    平台信息: 内核:linux3.4.39 系统:android4.4  平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新 ...

  3. Microsoft宣布为Power BI提供AI模型构建器,关键驱动程序分析和Azure机器学习集成...

    微软的Power BI现在是一种正在大量结合人工智能(AI)的商业分析服务,它使用户无需编码经验或深厚的技术专长就能够创建报告,仪表板等.近日西雅图公司宣布推出几款新的AI功能,包括图像识别和文本分析 ...

  4. Linux NAND FLASH驱动程序分析(mini2440)

    Linux NAND FLASH驱动程序分析(mini2440) 一.Linux-MTD Subsystem介绍 FLASH在嵌入式系统中是必不可少的,它是bootloader.linux内核和文件系 ...

  5. linux网卡驱动程序分析

    linux网卡驱动程序分析 学习应该是一个先把问题简单化,在把问题复杂化的过程.一开始就着手处理复杂的问题,难免让人 有心惊胆颤,捉襟见肘的感觉.读Linux网卡驱动也是一样.那长长的源码夹杂着那些我 ...

  6. linux3.4.0 按键驱动程序分析(pandaboard omap4460)

    linux3.4.0 按键驱动程序分析(pandaboard omap4460) 在内核中,按键的驱动程序已经设计好了,要使自己板上的按键工作起来,需要做的是在相应的文件中添加硬件信息,然后对内核进行 ...

  7. Linux系统GIC驱动程序分析

    百问网技术交流群,百万嵌入式工程师聚集地: https://www.100ask.net/page/2248041 资料下载 coding无法使用浏览器打开,必须用git工具下载: git clone ...

  8. MTD 设备驱动 和 NAND Flash 驱动程序分析。

    硬件环境: 飞凌OK6410,256MB DDR,2GB NAND Flash.   NAND Flash 型号:K9G8G08U9A   .     分析源码:Linux 2.6.36.2 内核源码 ...

  9. RT-Thread下的串口驱动程序分析

    编写本文稿的目的,在于通过分析stm32平台上的串口中断源码,学习 RTT中如何编写中断处理程序 如何编写RTT设备驱动接口代码 了解串行设备的常见处理机制 先以RTT官方源码中的STM32 BSP包 ...

最新文章

  1. Uncaught SyntaxError: Unexpected token
  2. 【Java 网络编程】TCP 数据传输示例 ( 客户端参数设置 | 服务器端参数设置 | ByteBuffer 存放读取数据类型 )
  3. Linux如何显示文件数目的技巧比较两个文件夹是否相同
  4. SignalR ——Android实践
  5. React-引领未来的用户界面开发框架-读书笔记(二)
  6. java文本框背景_用Java编写小程序(包含组合框下拉和文本框)变换背景颜色
  7. SAP License:AM手工折旧计算外折旧
  8. linux db2在线备份,DB2 pureScale在线备份恢复实例
  9. 你凭什么被叫做程序员?
  10. html5的video怎么把里面的控制器移出来_6个月宝宝米粉怎么冲,一次吃多少?一天吃几次?关于宝宝米粉的难题,答案都在这了!...
  11. Asp.net Core 2.1新功能Generic Host(通用主机),了解一下
  12. POJ- 1751 Highways
  13. 深入理解C语言指针的奥秘
  14. 菜鸟教程的Linux命令大全
  15. python | 秦九昭算法详细介绍
  16. xio you c语言 程序设计入门——函数的定义
  17. android保存url图片到相册简书,Android保存图片到系统相册
  18. 0.1uf 电容浅析
  19. 网易我的世界能安装java模组吗_网易的我的世界能不能自己制作模组?怎么制作?...
  20. 我们不一样!告诉你百度是如何做智能流量异常检测的

热门文章

  1. Python自学笔记-列表生成式(来自廖雪峰的官网Python3)
  2. Hibernate 具体用法(自整理)
  3. Linux学习之CentOS(三十四)--配置域主DNS服务器
  4. 润乾转html居中,[分享]润乾报表内置的jsp编辑器
  5. Git中的工作区(Working Directory)、暂存区(stage)和历史记录区(history)
  6. java soa例子_哪位大牛能举个实例讲下SOA与传统架构的区别?
  7. python HTTP后台响应服务
  8. 三安光电圈钱凶猛 两年三轮再融资逾百亿
  9. OSPF虚拟链路实验
  10. DDoS攻击走向应用层