GPIO软件模拟i2c
结构及宏定义
struct i2c { unsigned int scl; unsigned int sda; };
#define I2C_ACK 0 /* PD_SDA level to ack a byte */
#define I2C_NOACK 1 /* PD_SDA level to noack a byte */
#define CONFIG_SOFT_I2C_READ_REPEATED_START
各函数详细实现
clock动作函数
void i2c_scl(struct i2c *i2c,int bit) { gpio_direction_output(i2c->scl, bit); }
data动作函数
这里需要注意的是,当i2c master想要让data为高,是把data的gpio设置为输入,这是因为SCL和SDA都是默认硬件上拉的。同时也是为了master写完数据以后去获取ACK。
void i2c_sda(struct i2c *i2c, int bit) { if (bit) { gpio_direction_input(i2c->sda); } else { gpio_direction_output(i2c->sda, bit); } }
获取data线的状态
int i2c_read_sda(struct i2c *i2c) { return gpio_get_value(i2c->sda); }
start函数
/*----------------------------------------------------------------------- * START: High -> Low on SDA while SCL is High */ void send_start(struct i2c *i2c) { udelay(5); i2c_sda(i2c, 1); udelay(5); i2c_scl(i2c, 1); udelay(5); i2c_sda(i2c, 0); udelay(5); }
stop函数
/*----------------------------------------------------------------------- * STOP: Low -> High on SDA while SCL is High */ static void send_stop(struct i2c *i2c) { i2c_scl(i2c, 0); udelay(5); i2c_sda(i2c, 0); udelay(5); i2c_scl(i2c, 1); udelay(5); i2c_sda(i2c, 1); udelay(5); }
reset函数
/*----------------------------------------------------------------------- * Send a reset sequence consisting of 9 clocks with the data signal high * to clock any confused device back into an idle state. Also send a * <stop> at the end of the sequence for belts & suspenders. */ void send_reset(struct i2c *i2c) { int j; i2c_scl(i2c, 1); i2c_sda(i2c, 1); for (j = 0; j < 9; j++) { i2c_scl(i2c, 0); udelay(5); udelay(5); i2c_scl(i2c, 1); udelay(5); udelay(5); } send_stop(i2c); }
ACK函数
ACK: send_ack(i2c, 0)
NOACK: send_ack(i2c, 1)
/*----------------------------------------------------------------------- * ack should be I2C_ACK or I2C_NOACK */ void send_ack(struct i2c *i2c, int ack) { i2c_scl(i2c, 0); udelay(5); i2c_sda(i2c, ack); udelay(5); i2c_scl(i2c, 1); udelay(5); udelay(5); i2c_scl(i2c, 0); udelay(5); }
i2c写1byte函数
/*----------------------------------------------------------------------- * Send 8 bits and look for an acknowledgement. */ int write_byte(struct i2c *i2c,unsigned char data) { int j; int nack; for (j = 0; j < 8; j++) { i2c_scl(i2c, 0); udelay(5); i2c_sda(i2c,data & 0x80); udelay(5); i2c_scl(i2c, 1); udelay(5); udelay(5); data <<= 1; } /* * Look for an <ACK>(negative logic) and return it. */ i2c_scl(i2c, 0); udelay(5); i2c_sda(i2c, 1); udelay(5); i2c_scl(i2c, 1); udelay(5); udelay(5); nack = i2c_read_sda(i2c); i2c_scl(i2c, 0); udelay(5); return(nack); /* not a nack is an ack */ }
i2c读1byte函数
/*----------------------------------------------------------------------- * if ack == I2C_ACK, ACK the byte so can continue reading, else * send I2C_NOACK to end the read. */ static unsigned char read_byte(struct i2c *i2c,int ack) { int data; int j; /* * Read 8 bits, MSB first. */ i2c_sda(i2c, 1); data = 0; for (j = 0; j < 8; j++) { i2c_scl(i2c, 0); udelay(5); i2c_scl(i2c, 1); udelay(5); data <<= 1; data |= i2c_read_sda(i2c); udelay(5); } send_ack(i2c, ack); return(data); }
i2c初始化函数
i2c->scl、i2c->sda分别为clock和data数据线的GPIO号。
/*----------------------------------------------------------------------- * Initialization */ void i2c_init(struct i2c *i2c) { gpio_request(i2c->scl, "soft_i2c"); gpio_request(i2c->sda, "soft_i2c"); gpio_direction_output(i2c->sda, 1); gpio_direction_output(i2c->scl, 1); send_reset(i2c); }
i2c读len个字节函数
参数释义
chip:从设备地址
addr: 从设备寄存器地址
alen: 从设备寄存器地址的长度
buffer: 存放读取的数据的buffer
len: 读取len个字节
/*----------------------------------------------------------------------- * Read bytes */ int i2c_read(struct i2c *i2c, unsigned char chip, unsigned int addr, int alen, unsigned char *buffer, int len) { int shift; #ifdef DEBUG printf("i2c_read: chip %x addr %x alen %d buffer %p len %d\n", chip, addr, alen, buffer, len); #endif /* * Do the addressing portion of a write cycle to set the * chip's address pointer. If the address length is zero, * don't do the normal write cycle to set the address pointer, * there is no address pointer in this chip. */ send_start(i2c); if (alen > 0) { if (write_byte(i2c,chip << 1)) { /* write cycle */ send_stop(i2c); printf("i2c_read, no chip responded %02X\n", chip); return(1); } shift = (alen-1) * 8; while(alen-- > 0) { if(write_byte(i2c,addr >> shift)) { printf("i2c_read, address not <ACK>ed\n"); return(1); } shift -= 8; } /* Some I2C chips need a stop/start sequence here, * other chips don't work with a full stop and need * only a start. Default behaviour is to send the * stop/start sequence. */ #ifdef CONFIG_SOFT_I2C_READ_REPEATED_START send_start(i2c); #else send_stop(i2c); send_start(i2c); #endif } /* * Send the chip address again, this time for a read cycle. * Then read the data. On the last byte, we do a NACK instead * of an ACK(len == 0) to terminate the read. */ write_byte(i2c,(chip << 1) | 1); /* read cycle */ while (len-- > 0) { *buffer++ = read_byte(i2c,len == 0); } send_stop(i2c); return(0); }
i2c写len个字节函数
参数释义
chip:从设备地址
addr: 从设备寄存器地址
alen: 从设备寄存器地址的长度
buffer: 存放要写入的数据
len: 写len个字节
/*----------------------------------------------------------------------- * Write bytes */ int i2c_write(struct i2c *i2c, unsigned char chip,
unsigned int addr, int alen, unsigned char *buffer, int len) { int shift, failures = 0; #ifdef DEBUG printf("i2c_write: chip %x addr %x alen %d buffer %p len %d\n", chip, addr, alen, buffer, len); #endif send_start(i2c); if (write_byte(i2c, chip << 1)) { /* write cycle */ send_stop(i2c); printf("i2c_write, no chip responded %02X\n", chip); return(1); } shift = (alen-1) * 8; while (alen-- > 0) { if (write_byte(i2c, addr >> shift)) { printf("i2c_write, address not <ACK>ed\n"); return(1); } shift -= 8; } while (len-- > 0) { if (write_byte(i2c,*buffer++)) { failures++; } } send_stop(i2c); return(failures); }
i2c探测函数
返回0代表此i2c总线上有地址为addr的设备
返回1代表此i2c总线上没侦测到从设备地址为addr的设备
int i2c_probe(struct i2c *i2c, unsigned char addr) { int rc; send_start(i2c); rc = write_byte(i2c, (addr << 1) | 0); send_stop(i2c); printf("i2c probe:%d, addr:%x\n", rc, addr); return (rc ? 1 : 0); }
本文来自博客园,作者:闹闹爸爸,转载请注明原文链接:https://www.cnblogs.com/wanglouxiaozi/p/16944487.html