LPS25HB 寄存器读写程序解读
一般地,芯片公司都会提供芯片驱动的一些驱动代码,以LPS25HB 为例,该Mems工作时,与主MCU通信通过IIC或者SPI的方式进行,从而实现Mems的寄存器的读写。
1、读写功能的统一接口函数
为了兼容IIC和SPI的通信,我们这里设计两个基于STM32 HAL 库的的读写函数platform_write()、platform_read():
static int32_t platform_write(void *handle, uint8_t Reg, uint8_t *Bufp,
uint16_t len)
{
if (handle == &hi2c1)
{
/* enable auto incremented in multiple read/write commands */
Reg |= 0x80;
HAL_I2C_Mem_Write(handle, LPS25HB_I2C_ADD_L, Reg,
I2C_MEMADD_SIZE_8BIT, Bufp, len, 1000);
}
#ifdef MKI109V2
else if (handle == &hspi2)
{
/* enable auto incremented in multiple read/write commands */
Reg |= 0x40;
HAL_GPIO_WritePin(CS_SPI2_GPIO_Port, CS_SPI2_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(handle, &Reg, 1, 1000);
HAL_SPI_Transmit(handle, Bufp, len, 1000);
HAL_GPIO_WritePin(CS_SPI2_GPIO_Port, CS_SPI2_Pin, GPIO_PIN_SET);
}
else if (handle == &hspi1)
{
/* enable auto incremented in multiple read/write commands */
Reg |= 0x40;
HAL_GPIO_WritePin(CS_SPI1_GPIO_Port, CS_SPI1_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(handle, &Reg, 1, 1000);
HAL_SPI_Transmit(handle, Bufp, len, 1000);
HAL_GPIO_WritePin(CS_SPI1_GPIO_Port, CS_SPI1_Pin, GPIO_PIN_SET);
}
#endif
return 0;
}
static int32_t platform_read(void *handle, uint8_t Reg, uint8_t *Bufp,
uint16_t len)
{
if (handle == &hi2c1)
{
/* enable auto incremented in multiple read/write commands */
Reg |= 0x80;
HAL_I2C_Mem_Read(handle, LPS25HB_I2C_ADD_L, Reg,
I2C_MEMADD_SIZE_8BIT, Bufp, len, 1000);
}
#ifdef MKI109V2
else if (handle == &hspi2)
{
/* enable auto incremented in multiple read/write commands */
Reg |= 0xC0;
HAL_GPIO_WritePin(CS_DEV_GPIO_Port, CS_DEV_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(handle, &Reg, 1, 1000);
HAL_SPI_Receive(handle, Bufp, len, 1000);
HAL_GPIO_WritePin(CS_DEV_GPIO_Port, CS_DEV_Pin, GPIO_PIN_SET);
}
else
{
/* enable auto incremented in multiple read/write commands */
Reg |= 0xC0;
HAL_GPIO_WritePin(CS_RF_GPIO_Port, CS_RF_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(handle, &Reg, 1, 1000);
HAL_SPI_Receive(handle, Bufp, len, 1000);
HAL_GPIO_WritePin(CS_RF_GPIO_Port, CS_RF_Pin, GPIO_PIN_SET);
}
#endif
return 0;
}
2、设计结构体函数指针来调用统一的读写函数
typedef int32_t (*lps25hb_write_ptr)(void *, uint8_t, uint8_t*, uint16_t);
typedef int32_t (*lps25hb_read_ptr) (void *, uint8_t, uint8_t*, uint16_t);
typedef struct {
/** Component mandatory fields **/
lps25hb_write_ptr write_reg;
lps25hb_read_ptr read_reg;
/** Customizable optional pointer **/
void *handle;
} lps25hb_ctx_t;
这样我们定义了一个结构体lps25hb_ctx_t,该结构体中设计了三个指针。通过声明一个该结构体的变量,将变量的成员指向统一的读写结构函数。
/* Initialize mems driver interface */
lps25hb_ctx_t dev_ctx;
dev_ctx.write_reg = platform_write;
dev_ctx.read_reg = platform_read;
dev_ctx.handle = &hi2c1;
这样Mems 的驱动接口就实现了。但是为了程序更好的可读性,我们需要将Mems 寄存器读写的具体功能函数进一步实现。
这里我们设计与上层接口函数无关的寄存器读写函数,利用还函数实现Mems内部所有寄存器的读写。
3、与通信方式无关的寄存器读写抽象函数接口
/**
* @brief Read generic device register
*
* @param ctx read / write interface definitions(ptr)
* @param reg register to read
* @param data pointer to buffer that store the data read(ptr)
* @param len number of consecutive register to read
* @retval interface status (MANDATORY: return 0 -> no Error)
*
*/
int32_t lps25hb_read_reg(lps25hb_ctx_t* ctx, uint8_t reg, uint8_t* data,
uint16_t len)
{
int32_t ret;
ret = ctx->read_reg(ctx->handle, reg, data, len);
return ret;
}
/**
* @brief Write generic device register
*
* @param ctx read / write interface definitions(ptr)
* @param reg register to write
* @param data pointer to data to write in register reg(ptr)
* @param len number of consecutive register to write
* @retval interface status (MANDATORY: return 0 -> no Error)
*
*/
int32_t lps25hb_write_reg(lps25hb_ctx_t* ctx, uint8_t reg, uint8_t* data,
uint16_t len)
{
int32_t ret;
ret = ctx->write_reg(ctx->handle, reg, data, len);
return ret;
}
这样,我们就实现了接口函数的对应关系
于是,我们可以根据Mems的寄存器表进行相关的寄存器读写设计了。
如:
/**
* @brief The Reference pressure value is a 24-bit data expressed as 2’s
* complement. The value is used when AUTOZERO or AUTORIFP function
* is enabled.[set]
*
* @param ctx Read / write interface definitions.(ptr)
* @param buff Buffer that contains data to write
* @retval Interface status (MANDATORY: return 0 -> no Error).
*
*/
int32_t lps25hb_pressure_ref_set(lps25hb_ctx_t *ctx, uint8_t *buff)
{
int32_t ret;
ret = lps25hb_read_reg(ctx, LPS25HB_REF_P_XL, buff, 3);
return ret;
}
/**
* @brief The Reference pressure value is a 24-bit data expressed as 2’s
* complement. The value is used when AUTOZERO or AUTORIFP function
* is enabled.[get]
*
* @param ctx Read / write interface definitions.(ptr)
* @param buff Buffer that stores data read.(ptr)
* @retval Interface status (MANDATORY: return 0 -> no Error).
*
*/
int32_t lps25hb_pressure_ref_get(lps25hb_ctx_t *ctx, uint8_t *buff)
{
int32_t ret;
ret = lps25hb_read_reg(ctx, LPS25HB_REF_P_XL, buff, 3);
return ret;
}
4、寄存器的数据描述:
寄存器表的数据描述包括 define 定义、结构体数据类型定义、枚举变量的定义
例如:
#define LPS25HB_CTRL_REG1 0x20U
typedef struct {
uint8_t sim : 1;
uint8_t reset_az : 1;
uint8_t bdu : 1;
uint8_t diff_en : 1;
uint8_t odr : 4; /* pd + odr -> odr */
} lps25hb_ctrl_reg1_t;
#define LPS25HB_CTRL_REG2 0x21U
typedef struct {
uint8_t one_shot : 1;
uint8_t autozero : 1;
uint8_t swreset : 1;
uint8_t i2c_dis : 1;
uint8_t fifo_mean_dec : 1;
uint8_t stop_on_fth : 1;
uint8_t fifo_en : 1;
uint8_t boot : 1;
} lps25hb_ctrl_reg2_t;
#define LPS25HB_CTRL_REG3 0x22U
typedef struct {
uint8_t int_s : 2;
uint8_t not_used_01 : 4;
uint8_t pp_od : 1;
uint8_t int_h_l : 1;
} lps25hb_ctrl_reg3_t;
#define LPS25HB_CTRL_REG4 0x23U
typedef struct {
uint8_t drdy : 1;
uint8_t f_ovr : 1;
uint8_t f_fth : 1;
uint8_t f_empty : 1;
uint8_t not_used_01 : 4;
} lps25hb_ctrl_reg4_t;
typedef enum {
LPS25HB_BYPASS_MODE = 0,
LPS25HB_FIFO_MODE = 1,
LPS25HB_STREAM_MODE = 2,
LPS25HB_Stream_to_FIFO_mode = 3,
LPS25HB_BYPASS_TO_STREAM_MODE = 4,
LPS25HB_MEAN_MODE = 6,
LPS25HB_BYPASS_TO_FIFO_MODE = 7,
} lps25hb_f_mode_t;
这样,依赖这些个寄存器变量的描述,设计相关的具体的某一个寄存器读写函数,Mems 的驱动程序代码就可以轻松实现了。