首页 > 其他分享 >GPIO软件模拟i2c

GPIO软件模拟i2c

时间:2022-12-02 15:22:50浏览次数:31  
标签:scl int udelay send sda 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);
}

 

标签:scl,int,udelay,send,sda,GPIO,i2c,模拟
From: https://www.cnblogs.com/wanglouxiaozi/p/16944487.html

相关文章

  • 学习随笔-到底什么是终端、终端模拟器和伪终端
    什么是终端一般来说终端是指用于输入输出的物理设备计算机=主机+终端终端=输入终端+输出终端简单解释他们之间的联系电传打字机(TTY)是物理设备,最初是为电......
  • python实操案例__02—利用prettytable库模拟高铁售票系统
    1问题描述设计一个简易售票系统,可循环购票并显示余票。2功能拆解2.1什么是prettytable?PrettyTable是python中的一个第三方库,可用来生成美观的ASCII格式的表格,本实操......
  • COMSOL物理场的模拟和仿真软件安装
    COMSOL6.1WIN1064位安装步骤:1、先使用“百度网盘客户端”下载CMSL61_CN_x64安装包到电脑磁盘英文路径文件夹下,并鼠标右击进行解压缩,安装前先断开电脑网络,然后找到_SolidS......
  • golang 模拟byte数组
    packagemainimport("fmt")typeBytes[]bytefuncmain(){ fmt.Println("hello") fmt.Println("--------------") //ascii字符=============================......
  • 「模拟」找到最近的有相同 X 或 Y 坐标的点(力扣第1779题)
    本题为12月1日力扣每日一题题目来源:力扣第1779题题目tag:模拟题面题目描述给你两个整数 x和 y ,表示你在一个笛卡尔坐标系下的 (x,y) 处。同时,在同一个坐标......
  • 每日一抄 Go语言模拟远程调用
    packagemainimport( "errors" "fmt" "time")//客户端请求和接收封装/*下面代码封装了向服务器请求数据,等待服务器返回数据,如果请求超时该函数还会处理超时逻辑......
  • 1779. 找到最近的有相同 X 或 Y 坐标的点 ----- 模拟
    给你两个整数 x和 y ,表示你在一个笛卡尔坐标系下的 (x,y) 处。同时,在同一个坐标系下给你一个数组 points ,其中 points[i]=[ai,bi] 表示在 (ai,bi) 处有一......
  • 双栈排序——二分图+模拟
    二分图建模-双栈排序题目描述Tom最近在研究一个有趣的排序问题。如图所示,通过\(2\)个栈\(S_1\)和\(S_2\),Tom希望借助以下\(4\)种操作实现将输入序列升序排序。......
  • 模拟Promise的功能
    模拟Promise的功能, 按照下面的步骤,一步一步1.新建是个构造函数2.传入一个可执行函数函数的入参第一个为fullFill函数第二个为reject函数;函数立即执行,参数......
  • 模拟栈
    实现一个栈,栈初始为空,支持四种操作:pushx –向栈顶插入一个数 xx;pop –从栈顶弹出一个数;empty –判断栈是否为空;query –查询栈顶元素。现在要对栈进行 M......