您的位置:首页 > 运维架构 > Linux

笔记四:linux下IO口模拟实现I2C协议

2017-10-25 17:25 926 查看
一、i2c总线是什么?
1、i2c总线是一种物理总线及实实在在的总线,通过板子pcb等图能看到。
2、i2c总线是一种主从结构。
3、i2c总线是一种通信协议。
4、i2c总线是两线制半双工串行总线
两线制:数据线(SDA)——>数据传输、时钟线(SCL)——>同步
半双工:同时刻数据只能从一端到另一端传输,一条数据线;对比全双工,同时刻完成数据的收发,两条数据线。
串行:一个时钟周期发送一位数据,一条线;对比并行,一个时钟周期发送一个字节数据,8条线。
注意:从相同时钟频率看并行比串行传输速度快,在实际传输中,随着时钟频率越来越高,并行数据传输时是有干扰,串行的传输优势更大一些。
5、i2c总线接口线少,控制简单,通信速率高。以上可以体现。

二、i2c总线协议怎么实现?

1、首先看一下i2c总线的时序图。



分析上图可以分为四部分,在学习的过程中我们要化整为零,逐个击破,然后再整合起来,这样就达到了学习的目的。
a、起始信号:时钟线为高电平时,数据线从高到低的变化;
b、数据传输:I2C为电平出发方式(数据先发高位,再发地位)
注:数据线上的数据必须在时钟线的高电平周期保持稳定,数据线上的电平状态在时钟线为低电平时才可以改变。
c、应答信号:接收端收到数据,发送一应答信号,低电平表示OK,高电平表示no。
d、 终止信号:时钟线为高电平时,数据线从低到高变化。

2、通过时序图完成模拟时序。
起始、终止、发送应
4000
答、接收应答、发送数据位、接收数据位

例子代码:
#define SCL (PAD_GPIO_D+6)
#define SDA (PAD_GPIO_D+7)
#define out_scl() 					nxp_soc_gpio_set_io_dir(SCL, 1)	//代替s3c_gpio_cfgpin
#define out_sda()					nxp_soc_gpio_set_io_dir(SDA, 1)
#define in_sda()					nxp_soc_gpio_set_io_dir(SDA, 0)
#define low_scl()					nxp_soc_gpio_set_out_value(SCL, 0)
#define high_scl()					nxp_soc_gpio_set_out_value(SCL, 1)
#define low_sda()					nxp_soc_gpio_set_out_value(SDA, 0)
#define high_sda()					nxp_soc_gpio_set_out_value(SDA, 1)
#define demo_delay()				udelay(6)
#define demo_i2c_get_data()		nxp_soc_gpio_get_in_value(SDA)
#define I2C_W 0
#define I2C_R 1
#define SLAVE_ADDR 0x1D


static void demo_i2c_send_byte(unsigned char data)
{
int i = 0;
out_scl();
out_sda();

low_scl();
for(i=0;i<8;i++) {
if(data & (0x80>>i))
high_sda();
else
low_sda();
demo_delay();
high_scl();
demo_delay();
low_scl();
}
}

static unsigned char demo_i2c_recv_byte(void)
{
int i = 0;
unsigned char data = 0;
out_scl();
in_sda();

low_scl();
for(i=0;i<8;i++) {
demo_delay();
high_scl();
demo_delay();
data <<= 1;//循环8次,最终只左移了7次
data |= demo_i2c_get_data();
low_scl();
}
return data;
}

static void demo_i2c_send_ack(unsigned char ack)
{
out_scl();
out_sda();
low_scl();
if(ack)
high_sda();
else
low_sda();
demo_delay();
high_scl();
demo_delay();
low_scl();
}

static unsigned char demo_i2c_recv_ack(void)
{
unsigned char ack = 0;
out_scl();
in_sda();

low_scl();
demo_delay();
high_scl();
demo_delay();
ack = demo_i2c_get_data();
low_scl();

return ack;
}

static void demo_i2c_start(void)
{
out_scl();
out_sda();

high_scl();

high_sda();
demo_delay();
low_sda();
demo_delay();

low_scl();
}

static void demo_i2c_stop(void)
{
out_scl();
out_sda();

high_scl();

low_sda();
demo_delay();
high_sda();
demo_delay();

low_scl();
}


三、i2c总线使用?

无外乎就是通过i2c总线协议进行数据收发!

1、这里我们用mma8653三轴重力加速度传感器来验证我们写的模拟时序
2、查看mma8653在咱们板子的位置以及所用的I/O口。
查看底板-->查看核心板-->得到所用I/O口



3、设置I/O口功能。
4、打开mma8653芯片资料。
查看i2c时序图,根据芯片的时序图,完成发送数据、接收数据的接口





例子代码:
static int demo_i2c_read_buffer(unsigned char reg, unsigned char *buff, int len)
{
int i = 0;

demo_i2c_start();
demo_i2c_send_byte((SLAVE_ADDR << 1) | I2C_W);
if(demo_i2c_recv_ack()) {
printk(KERN_WARNING "%d,get a nack.\n", __LINE__);
return -1;
}
demo_i2c_send_byte(reg);
if(demo_i2c_recv_ack()) {
printk(KERN_WARNING "%d,get a nack.\n", __LINE__);
return -1;
}

demo_i2c_start();
demo_i2c_send_byte((SLAVE_ADDR << 1) | I2C_R);
if(demo_i2c_recv_ack()) {
printk(KERN_WARNING "%d,get a nack.\n", __LINE__);
return -1;
}

for(i=0; i<(len-1); i++) {
buff[i] = demo_i2c_recv_byte();
demo_i2c_send_ack(0);
}
buff[i] = demo_i2c_recv_byte();
demo_i2c_send_ack(1);

demo_i2c_stop();
return (i+1);
}

static int demo_i2c_write_buffer(unsigned char reg, unsigned char *buff, int len)
{
int i = 0;

demo_i2c_start();
demo_i2c_send_byte((SLAVE_ADDR << 1) | I2C_W);
if(demo_i2c_recv_ack()) {
printk(KERN_WARNING "%d,get a nack.\n", __LINE__);
return -1;
}
demo_i2c_send_byte(reg);
if(demo_i2c_recv_ack()) {
printk(KERN_WARNING "%d,get a nack.\n", __LINE__);
return -1;
}
for(i=0; i<len; i++) {
demo_i2c_send_byte(buff[i]);
if(demo_i2c_recv_ack()) {
printk(KERN_WARNING "%d,get a nack.\n", __LINE__);
return -1;
}
}

demo_i2c_stop();
return i;
}


5、配置初始化mma8653芯片:active(0x2A)
检查chip_id(0x0D)
读取坐标信息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: