一.背景
LM75,温度传感器.
工作电压:2.7V-5.5V
精度:



设备地址:0x48,低三位可通过焊接置0或1


表示温度,十六进制值乘以分辨率0.5,负温度值用补码保存,先转为原码再计算

通过配置寄存器低三位的值选择不同寄存器,本次配置000,即读取温度。

读取2字节温度,舍弃低7位。
float get_lm75_temp(void)
{
short temp;
unsigned char s[2];
i2c_read(I2C1, 0x48, 0, s, 2);
temp = s[0] << 8;
temp |= s[1];
temp >>= 7;
return temp * 0.5;
}
此外,对read和write的传输寄存器地址代码进行改进,由于寄存器地址可能不止一位(AT24C02能存储256字节数据,所以char刚好可以表示;LMA75从P0-P7也为一字节长度,这两都可用char表示,但后续操作显示屏时char则不够),所以用char类型定义寄存器地址会出现问题,用unsigned short reg_address定义地址, int reg_len定义寄存器地址长度,改进如下
int i = 0;
for (i = 0; i < reg_len; i++)
{
// 中断标记位清零
base->I2SR &= ~(1 << IIF);
// 发送寄存器地址
base->I2DR = reg_address >> (reg_len - i - 1) * 8;
// 等待从机ACK
while ((base->I2SR & (1 << IIF)) == 0);
}
二.底层

最下面的硬件层即上篇及本篇使用的传感器,AT24C02和LMA75等,连接的上面I2C_adapter即SOC芯片内部的I2C控制器,具体实现就是适配器驱动这一层,最近对I2C的学习所实现的代码其实写的就是控制器这块的代码,显然偏底层,这部分代码通常为芯片厂商负责写,比如使用imx6ull为NXP公司生产,所以由他们负责写控制器底层代码,而不同芯片厂商生产的芯片对应的寄存器自然不相同。

再往上则可以由Linux系统进行调用这些封装好的代码,可适配不同芯片,屏蔽底层芯片,直接面向已经被芯片厂商封装好的函数。图中核心层的 i2c_transfer 是灵魂函数。当设备驱动调用i2c_transfer 时,核心层会打包好 i2c_msg(包含设备地址、读写标志、数据长度),然后去调用底层适配器驱动注册好的 master_xfer 函数指针。底层再根据这个指针,去操作真正的 i.MX6ULL 寄存器。

master_xfer,每个芯片厂商都会写的,不管使用哪个芯片,想使用I2C都可调用master_xfer。
以下为该函数的实现
// I2C传输方向
enum I2C_Direction
{
I2C_Write = 0,
I2C_Read = 1
};
// I2C信息
typedef struct
{
unsigned char dev_address;
unsigned short reg_address;
int reg_len;
unsigned char *data;
int len;
enum I2C_Direction direction;
}I2C_Msg;
void master_xfer(I2C_Type *base, I2C_Msg *msg) //主机_发送/接收,不管是哪个芯片厂商生产的,在linux系统下,都可以调用此函数
{
if (msg->direction == I2C_Write)
{
i2c_write(base, msg->dev_address, msg->reg_address, msg->reg_len, msg->data, msg->len);
}
else if (msg->direction == I2C_Read)
{
i2c_read(base, msg->dev_address, msg->reg_address, msg->reg_len, msg->data, msg->len);
}
}
调用该封装函数实现LM75传感器读取温度
float get_lm75_temp(void)
{
short temp;
unsigned char s[2];
I2C_Msg msg =
{
.direction = I2C_Read,
.dev_address = 0x48,
.reg_address = 0,
.reg_len = 1,
.data = s,
.len = 2
};
master_xfer(I2C1, &msg);
temp = s[0] << 8;
temp |= s[1];
temp >>= 7;
return temp * 0.5;
}
总结:Linux社区不管每一款芯片在底层怎么操作自己的寄存器,只是提供芯片厂商一个函数,比如master_xfer,告诉厂商你们负责实现你们自己芯片对应的这个函数,而不同厂商则在master_xfer中实现如何操纵自己的寄存器,实现好了之后由Linux封装到自己的函数接口i2c_transfer内部,再把这个函数接口提供给用户层使用,用户使用该i2c_transfer函数也不用考虑底层是哪个芯片厂商生产的,底层寄存器是怎么操作的,都由芯片厂商实现了。
576



被折叠的 条评论
为什么被折叠?



