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

2019-07-13 08:13发布

一、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. ", __LINE__); return -1; } demo_i2c_send_byte(reg); if(demo_i2c_recv_ack()) { printk(KERN_WARNING "%d,get a nack. ", __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. ", __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. ", __LINE__); return -1; } demo_i2c_send_byte(reg); if(demo_i2c_recv_ack()) { printk(KERN_WARNING "%d,get a nack. ", __LINE__); return -1; } for(i=0; i
5、配置初始化mma8653芯片:active(0x2A) 检查chip_id(0x0D) 读取坐标信息。