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\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 驅動程序分析