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

一、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、通过时序图完成模拟时序。
起始、终止、发送应答、接收应答、发送数据位、接收数据位
例子代码:
#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)
读取坐标信息。


  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值