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 ]
这其实是一个全局的设备参数结构体定义
原定义
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来使用
4.简单例子
#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