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);
}

 

posted @ 2022-12-02 15:10  闹闹爸爸  阅读(1173)  评论(0编辑  收藏  举报