通用i2c驱动

了解I2C的同志都知道,常规I2C驱动中的最重点就是这4个结构体:i2c_driver、i2c_client、i2c_adapter 和i2c_algorithm,而且他们之间的关系错综复杂,我看了好长一段时间,也没看出多少头绪来,而且代码的可移植性很差劲,换个平台,要该的地方一大堆,改了之后还不一定对呢委屈,所以,下面介绍的通用I2C驱动就很必要了。

    大家都知道, I2C总线仅仅使用SCL、SDA这两根信号线就实现了设备之间的数据交互,极大地简化了对硬件资源和PCB板布线空间的占用。因此,I2C总线应用非常的广泛。而工作中,我需要通过I2C实现Hi35XX控制视频芯片CX25828,我是这样做的,首先,把I2C当做一个字符设备,然后用2个GPIO管脚模拟数据线和时钟线,一个管脚控制方向,实现电平的高低控制,这样就可以模拟I2C通信了(CPU与设备间的通信)。

 

 

1.当做一个字符设备

     看到这个,相信大家一定很熟悉了,对了,这就是我们入门时再熟悉不过的东东了,上层可直接对dev下的“gpioi2c”的这个节点open、write、read、close(不过,就目前这个,无read、write接口,只有ioctl了),接下来,你懂的。(在网上有很多比较成熟的I2C驱动,也是同我这个原理实现的,改改GPIO口地址就可以了大笑)。

  1. <SPAN style="FONT-SIZE: 14px">//打开和关闭设备   
  2. int gpioi2c_open(struct inode * inode, struct file * file)  
  3. {  
  4.     return 0;  
  5. }  
  6. int gpioi2c_close(struct inode * inode, struct file * file)  
  7. {  
  8.     return 0;  
  9. }  
  10.   
  11. //最重要的结构体,文件描述符指针,上层直接ioctl就可通过底层调用gpioi2c_ioctl函数。   
  12. //当然,可以有其他的成员,如read、write等。   
  13. static struct file_operations gpioi2c_fops =  
  14. {  
  15.     .owner      = THIS_MODULE,  
  16.     .ioctl      = gpioi2c_ioctl,  
  17.     .open       = gpioi2c_open,  
  18.     .release    = gpioi2c_close  
  19. };  
  20.   
  21. static struct miscdevice gpioi2c_dev =  
  22. {  
  23.     .minor       = MISC_DYNAMIC_MINOR,  
  24.     .name        = "gpioi2c",//在dev下可以找到这个节点,上层就是通过open、read/write这个节点而对设备操作的。   
  25.      .fops  = &gpioi2c_fops,  
  26. };  
  27.   
  28. //导入导出   
  29. static int __init gpio_i2c_init(void)  
  30. {  
  31.     int ret;  
  32.     printk("hello dvr iic\n");  
  33.     //注册设备   
  34.      ret = misc_register(&gpioi2c_dev);  
  35.     if(0 != ret)  
  36.         return -1;  
  37.   
  38.     i2c_set(SCL | SDA);  
  39.   
  40.     return 0;  
  41. }  
  42. static void __exit gpio_i2c_exit(void)  
  43. {  
  44.     //卸载设备   
  45.      misc_deregister(&gpioi2c_dev);  
  46. }  
  47.   
  48. //导入导出内核设备   
  49. module_init(gpio_i2c_init);  
  50. module_exit(gpio_i2c_exit);  
  51.   
  52. MODULE_INFO(build, UTS_VERSION);  
  53. MODULE_LICENSE("GPL");</SPAN>  
//打开和关闭设备
int gpioi2c_open(struct inode * inode, struct file * file)
{
    return 0;
}
int gpioi2c_close(struct inode * inode, struct file * file)
{
    return 0;
}

//最重要的结构体,文件描述符指针,上层直接ioctl就可通过底层调用gpioi2c_ioctl函数。
//当然,可以有其他的成员,如read、write等。
static struct file_operations gpioi2c_fops =
{
    .owner      = THIS_MODULE,
    .ioctl      = gpioi2c_ioctl,
    .open       = gpioi2c_open,
    .release    = gpioi2c_close
};

static struct miscdevice gpioi2c_dev =
{
    .minor       = MISC_DYNAMIC_MINOR,
    .name        = "gpioi2c",//在dev下可以找到这个节点,上层就是通过open、read/write这个节点而对设备操作的。
     .fops  = &gpioi2c_fops,
};

//导入导出
static int __init gpio_i2c_init(void)
{
    int ret;
    printk("hello dvr iic\n");
    //注册设备
     ret = misc_register(&gpioi2c_dev);
    if(0 != ret)
        return -1;

    i2c_set(SCL | SDA);

    return 0;
}
static void __exit gpio_i2c_exit(void)
{
    //卸载设备
     misc_deregister(&gpioi2c_dev);
}

//导入导出内核设备
module_init(gpio_i2c_init);
module_exit(gpio_i2c_exit);

MODULE_INFO(build, UTS_VERSION);
MODULE_LICENSE("GPL");

杂项设备(misc device):
    在 Linux 内核的include\linux\miscdevice.h文件,要把自己定义的misc device从设备定义在这里。其实是因为这些字符设备不符合预先确定的字符设备范畴,所有这些设备采用主设备号10 ,一起归于misc device,其实misc_register就是用主设备号10调用register_chrdev()的。也就是说,misc设备其实也就是特殊的字符设备。
    misc_device是特殊的字符设备。注册驱动程序时采用misc_register函数注册,此函数中会自动创建设备节点,即设备文件。无需mknod指令创建设备文件。因为misc_register()会调用class_device_create()或者device_create()。

 

2.对字符设备的控制:ioctl函数

     提供给上层的接口,arg参数其实是一个地址,这个地址里面必须存放三个信息:设备地址+寄存器地址+data。通过设备地址找到设备,然后通过寄存器地址配置相应的寄存器。关于每次通信的信息量,这要看上层接口函数ioctl:int ioctl(int file_operations, int cmd, void *addr)时arg地址内存放的内容了,如果内容是int类型即4个字节,就如下。如果这个地址内存放的是结构体,而且sizeof这个结构体的大小为12byte(即设备地址、寄存器地址、以及数据各占4个字节),就不需要移动了,直接填进去。

  1. <SPAN style="FONT-SIZE: 14px">int gpioi2c_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)  
  2. {  
  3.     unsigned int val;  
  4.     char device_addr, reg_addr;  
  5.     short reg_val;  
  6.   
  7.     switch(cmd)  
  8.     {  
  9.         case GPIO_I2C_READ:  
  10.             val = *(unsigned int *)arg;  
  11.             device_addr = (val&0xff000000)>>24;  
  12.             reg_addr = (val&0xffff00)>>8;  
  13.   
  14.             reg_val = gpio_i2c_read(device_addr, reg_addr);  
  15.             *(unsigned int *)arg = (val&0xffffff00)|reg_val;  
  16.             break;  
  17.   
  18.         case GPIO_I2C_WRITE:  
  19.             val = *(unsigned int *)arg;  
  20.             device_addr = (val&0xff000000)>>24;  
  21.             reg_addr = (val&0xffff00)>>8;  
  22.   
  23.             reg_val = val&0xff;  
  24.             gpio_i2c_write(device_addr, reg_addr, reg_val);  
  25.             break;  
  26.   
  27.         default:  
  28.             return -1;  
  29.     }  
  30.     return 0;  
  31. }  
  32. </SPAN>  
int gpioi2c_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
    unsigned int val;
    char device_addr, reg_addr;
    short reg_val;

    switch(cmd)
    {
        case GPIO_I2C_READ:
            val = *(unsigned int *)arg;
            device_addr = (val&0xff000000)>>24;
            reg_addr = (val&0xffff00)>>8;

            reg_val = gpio_i2c_read(device_addr, reg_addr);
            *(unsigned int *)arg = (val&0xffffff00)|reg_val;
            break;

        case GPIO_I2C_WRITE:
            val = *(unsigned int *)arg;
            device_addr = (val&0xff000000)>>24;
            reg_addr = (val&0xffff00)>>8;

            reg_val = val&0xff;
            gpio_i2c_write(device_addr, reg_addr, reg_val);
            break;

        default:
            return -1;
    }
    return 0;
}

 

 

3.对设备的读写:read、write

     CX25828中,寄存器的地址为16位,设备地址为8位,所有,I2C每次只能read、write1个字节的数据。。总线空闲时,上拉电阻使SDA和SCL线都保持高电平。当 SCL 稳定在高电平时,SDA 由高到低的变化将产生一个开始位,而由低到高的变化则产生一个停止位。开始位和停止位都由 I2C 主设备产生。在选择从设备时,如果从设备采用 7 位地址,则主设备在发起传输过程前,需先发送1字节的地址信息,前 7 位为设备地址,最后 1 位为读写标志。之后,每次传输的数据也是 1 个字节,从 MSB 位开始传输。每个字节传完后,在SCL的第9个上升沿到来之前,接收方应该发出 1 个 ACK 位。SCL上的时钟脉冲由I2C主控方发出, 在第8个时钟周期之后。

                 

  1. <SPAN style="FONT-SIZE: 14px">//读1个字节(其实可以2,或者4个字节,这个地方是实现读写功能以及决定字节数的,IIC支持)   
  2. unsigned short  gpio_i2c_read(unsigned char devaddress, unsigned int address)  
  3. {  
  4.     unsigned short rxdata=0  
  5.     unsigned int tmp=0;  
  6.     int dev_addr=devaddress;  
  7.   
  8.    //发送设备地址:8位   
  9.     i2c_start_bit();  
  10.     i2c_send_byte((unsigned char)(dev_addr));  
  11.     i2c_receive_ack();  
  12.   
  13.     //寄存器地址:16位   
  14.      tmp=address&0xff00;  
  15.     tmp=tmp>>8;  
  16.     i2c_send_byte((unsigned char)tmp);  
  17.     i2c_receive_ack();  
  18.     tmp=address&0xff;  
  19.     i2c_send_byte((unsigned char)tmp);  
  20.     i2c_receive_ack();  
  21.   
  22.      //发送:读状态   
  23.      i2c_start_bit();  
  24.     i2c_send_byte((unsigned char)(dev_addr) | 1);  
  25.     i2c_receive_ack();  
  26.   
  27.     //接收数据:8bit   
  28.     rxdata = i2c_receive_byte();  
  29.   
  30.     //停止接收数据   
  31.     i2c_stop_bit();  
  32.     rxdata=rxdata&0xff;  
  33.   
  34.     return rxdata;  
  35. }  
  36.   
  37. //写一个字节   
  38. void gpio_i2c_write(unsigned char devaddress, unsigned int address, unsigned int data)  
  39. {  
  40.     int tmp;  
  41.     unsigned short devaddr=devaddress&0xfe;//在手册中可以看到,读写状态占1bit,读为1,写为0.   
  42.   
  43.     //设备地址:8bit   
  44.     i2c_start_bit();  
  45.     i2c_send_byte((unsigned char)(devaddr));  
  46.     i2c_receive_ack();//ACK   
  47.   
  48.     //寄存器地址:16bit   
  49.     tmp=address&0xff00;  
  50.     tmp=tmp>>8;  
  51.     i2c_send_byte((unsigned char)tmp);  
  52.     i2c_receive_ack();  
  53.     tmp=address&0xff;   
  54.     i2c_send_byte((unsigned char)tmp);  
  55.     i2c_receive_ack();  
  56.   
  57.     //发送数据:8bit   
  58.     tmp=data&0xff;  
  59.     i2c_send_byte((unsigned char)tmp);  
  60.     i2c_receive_ack();  
  61.   
  62.     //停止接收数据    
  63.     i2c_stop_bit();  
  64. }</SPAN>  
//读1个字节(其实可以2,或者4个字节,这个地方是实现读写功能以及决定字节数的,IIC支持)
unsigned short  gpio_i2c_read(unsigned char devaddress, unsigned int address)
{
    unsigned short rxdata=0
    unsigned int tmp=0;
    int dev_addr=devaddress;

   //发送设备地址:8位
    i2c_start_bit();
    i2c_send_byte((unsigned char)(dev_addr));
    i2c_receive_ack();

    //寄存器地址:16位
     tmp=address&0xff00;
    tmp=tmp>>8;
    i2c_send_byte((unsigned char)tmp);
    i2c_receive_ack();
    tmp=address&0xff;
    i2c_send_byte((unsigned char)tmp);
    i2c_receive_ack();

     //发送:读状态
     i2c_start_bit();
    i2c_send_byte((unsigned char)(dev_addr) | 1);
    i2c_receive_ack();

    //接收数据:8bit
    rxdata = i2c_receive_byte();

    //停止接收数据
    i2c_stop_bit();
    rxdata=rxdata&0xff;

    return rxdata;
}

//写一个字节
void gpio_i2c_write(unsigned char devaddress, unsigned int address, unsigned int data)
{
    int tmp;
    unsigned short devaddr=devaddress&0xfe;//在手册中可以看到,读写状态占1bit,读为1,写为0.

    //设备地址:8bit
    i2c_start_bit();
    i2c_send_byte((unsigned char)(devaddr));
    i2c_receive_ack();//ACK

    //寄存器地址:16bit
    tmp=address&0xff00;
    tmp=tmp>>8;
    i2c_send_byte((unsigned char)tmp);
    i2c_receive_ack();
    tmp=address&0xff; 
    i2c_send_byte((unsigned char)tmp);
    i2c_receive_ack();

    //发送数据:8bit
    tmp=data&0xff;
    i2c_send_byte((unsigned char)tmp);
    i2c_receive_ack();

    //停止接收数据 
    i2c_stop_bit();
}

 

4.模拟数据线时钟线以及需要调用的一些函数

  1. <SPAN style="FONT-SIZE: 14px">#include "gpio_i2c.h"  
  2. #define GPIO_0_BASE 0x20150000  
  3. #define GPIO_0_DIR IO_ADDRESS(GPIO_0_BASE + 0x400)  //GPIO方向控制  
  4.   
  5. #define SCL                 (1 << 1)    /* GPIO 0_1 */  
  6. #define SDA                 (1 << 0)    /* GPIO 0_0 */  
  7. #define GPIO_I2C_SDA_REG    IO_ADDRESS(GPIO_0_BASE + 0x4)//数据线GPIO管脚  
  8. #define GPIO_I2C_SCL_REG    IO_ADDRESS(GPIO_0_BASE + 0x8)//时钟线GPIO管脚  
  9. #define GPIO_I2C_SCLSDA_REG IO_ADDRESS(GPIO_0_BASE + 0xc)  
  10. #define HW_REG(reg)         *((volatile unsigned int *)(reg))  
  11. #define DELAY(us)           time_delay_us(us)  
  12.   
  13. //拉低数据线/时钟线  
  14. static void i2c_clr(unsigned char whichline)  
  15. {  
  16.     unsigned char regvalue;  
  17.       
  18.     //拉低时钟线  
  19.      if(whichline == SCL)  
  20.     {  
  21.       //方向:输入/输出  
  22.           regvalue = HW_REG(GPIO_0_DIR);  
  23.         regvalue |= SCL;  
  24.         HW_REG(GPIO_0_DIR) = regvalue;  
  25.           
  26.     //置零  
  27.         HW_REG(GPIO_I2C_SCL_REG) = 0;  
  28.       return;  
  29.     }  
  30.     else if(whichline == SDA)  
  31.     {  
  32.         regvalue = HW_REG(GPIO_0_DIR);  
  33.         regvalue |= SDA;  
  34.         HW_REG(GPIO_0_DIR) = regvalue;  
  35.   
  36.         HW_REG(GPIO_I2C_SDA_REG) = 0;  
  37.         return;  
  38.     }  
  39.     else if(whichline == (SDA|SCL))  
  40.     {  
  41.         regvalue = HW_REG(GPIO_0_DIR);  
  42.         regvalue |= (SDA|SCL);  
  43.         HW_REG(GPIO_0_DIR) = regvalue;  
  44.   
  45.         HW_REG(GPIO_I2C_SCLSDA_REG) = 0;  
  46.         return;  
  47.     }  
  48.     else  
  49.     {  
  50.         printk("Error input.\n");  
  51.         return;  
  52.     }  
  53.   
  54. }  
  55.   
  56. //拉高数据线/时钟线  
  57. static void  i2c_set(unsigned char whichline)  
  58. {  
  59.     unsigned char regvalue;  
  60.     //拉高时钟线  
  61.      if(whichline == SCL)  
  62.     {  
  63.         regvalue = HW_REG(GPIO_0_DIR);  
  64.         regvalue |= SCL;  
  65.         HW_REG(GPIO_0_DIR) = regvalue;  
  66.           
  67.         HW_REG(GPIO_I2C_SCL_REG) = SCL;  
  68.         return;  
  69.     }  
  70.     else if(whichline == SDA)  
  71.     {  
  72.         regvalue = HW_REG(GPIO_0_DIR);  
  73.         regvalue |= SDA;  
  74.         HW_REG(GPIO_0_DIR) = regvalue;  
  75.   
  76.         HW_REG(GPIO_I2C_SDA_REG) = SDA;  
  77.         return;  
  78.     }  
  79.     else if(whichline == (SDA|SCL))  
  80.     {  
  81.         regvalue = HW_REG(GPIO_0_DIR);  
  82.         regvalue |= (SDA|SCL);  
  83.         HW_REG(GPIO_0_DIR) = regvalue;  
  84.   
  85.         HW_REG(GPIO_I2C_SCLSDA_REG) = (SDA|SCL);  
  86.         return;  
  87.     }  
  88.     else  
  89.     {  
  90.         printk("Error input.\n");  
  91.         return;  
  92.     }  
  93. }  
  94.   
  95. //延时usec微秒  
  96. void time_delay_us(unsigned int usec)  
  97. {  
  98.     int i,j;  
  99.   
  100.     for(i=0; i<usec * 5; i++)  
  101.     {  
  102.         for(j=0; j<64; j++)  
  103.         {  
  104.             ;  
  105.         }  
  106.     }  
  107. }  
  108.   
  109. //开始IIC通信  
  110. static void i2c_start_bit(void)  
  111. {  
  112.     DELAY(1);  
  113.     //拉高双线,拉低数据线,开始发送数据。  
  114.      i2c_set(SDA | SCL);  
  115.     DELAY(1);  
  116.     i2c_clr(SDA);  
  117.     DELAY(2);  
  118. }  
  119.   
  120. //停止IIC通信  
  121. static void i2c_stop_bit(void)  
  122. {  
  123.     //时钟响应  
  124.     DELAY(1);  
  125.     i2c_set(SCL);  
  126.     DELAY(1);  
  127.     i2c_clr(SCL);  
  128.   
  129.     //数据线为高,数据线由低->高:结束通信  
  130.     DELAY(1);  
  131.     i2c_clr(SDA);  
  132.     DELAY(1);  
  133.     i2c_set(SCL);  
  134.     DELAY(1);  
  135.     i2c_set(SDA);  
  136.     DELAY(1);  
  137. }  
  138.   
  139. //读取数据:1bit  
  140. static unsigned char i2c_data_read(void)  
  141. {  
  142.     unsigned char regvalue;  
  143.   
  144.     regvalue = HW_REG(GPIO_0_DIR);  
  145.     regvalue &= (~SDA);  
  146.     HW_REG(GPIO_0_DIR) = regvalue;  
  147.     DELAY(1);  
  148.   
  149.     regvalue = HW_REG(GPIO_I2C_SDA_REG);  
  150.     if((regvalue&SDA) != 0)  
  151.         return 1;  
  152.     else  
  153.         return 0;  
  154. }  
  155.   
  156. //发送数据:1byte  
  157. static void i2c_send_byte(unsigned char c)  
  158. {  
  159.     int i;  
  160.     //屏蔽中断  
  161.     local_irq_disable();  
  162.     for(i=0; i<8; i++)  
  163.     {  
  164.         DELAY(1);  
  165.         i2c_clr(SCL);  
  166.         DELAY(1);  
  167.           
  168.       //发送1(这个是重点哦<IMG alt=大笑 src="http://static.blog.csdn.net/xheditor/xheditor_emot/default/laugh.gif">)  
  169.         if(c & (1<<(7-i)))  
  170.             i2c_set(SDA);  
  171.         else//发送0  
  172.             i2c_clr(SDA);  
  173.   
  174.         DELAY(1);  
  175.         i2c_set(SCL);  
  176.         DELAY(1);  
  177.         i2c_clr(SCL);  
  178.     }  
  179.     DELAY(1);  
  180.     local_irq_enable();  
  181. }  
  182.   
  183. //接收数据:1byte  
  184. static unsigned char i2c_receive_byte(void)  
  185. {  
  186.     int j=0;  
  187.     int i;  
  188.     unsigned char regvalue;  
  189.   
  190.     local_irq_disable();  
  191.     for(i=0; i<8; i++)  
  192.     {  
  193.         DELAY(1);  
  194.         i2c_clr(SCL);  
  195.         DELAY(2);  
  196.         i2c_set(SCL);  
  197.   
  198.         regvalue = HW_REG(GPIO_0_DIR);  
  199.         regvalue &= (~SDA);  
  200.         HW_REG(GPIO_0_DIR) = regvalue;  
  201.         DELAY(1);  
  202.   
  203.         if(i2c_data_read())  
  204.             j+=(1<<(7-i));  
  205.   
  206.         DELAY(1);  
  207.         i2c_clr(SCL);  
  208.     }  
  209.     local_irq_enable();  
  210.     DELAY(1);  
  211.   
  212.   
  213.     return j;  
  214. }  
  215.   
  216. //响应(每发送一个字节,都要响应),返回值为0:成功。  
  217. static int i2c_receive_ack(void)  
  218. {  
  219.     int nack;  
  220.     unsigned char regvalue;  
  221.   
  222.     DELAY(1);  
  223.     regvalue = HW_REG(GPIO_0_DIR);  
  224.     regvalue &= (~SDA);//数据线置零  
  225.     HW_REG(GPIO_0_DIR) = regvalue;  
  226.     DELAY(1);  
  227.     i2c_clr(SCL);  
  228.     DELAY(1);  
  229.     i2c_set(SCL);  
  230.     DELAY(1);  
  231.     nack = i2c_data_read();  
  232.     DELAY(1);  
  233.     i2c_clr(SCL);  
  234.     DELAY(1);  
  235.     if(nack == 0)  
  236.         return 1;  
  237.   
  238.     return 0;  
  239. }</SPAN>  
#include "gpio_i2c.h"
#define GPIO_0_BASE 0x20150000
#define GPIO_0_DIR IO_ADDRESS(GPIO_0_BASE + 0x400)  //GPIO方向控制

#define SCL                 (1 << 1)    /* GPIO 0_1 */
#define SDA                 (1 << 0)    /* GPIO 0_0 */
#define GPIO_I2C_SDA_REG    IO_ADDRESS(GPIO_0_BASE + 0x4)//数据线GPIO管脚
#define GPIO_I2C_SCL_REG    IO_ADDRESS(GPIO_0_BASE + 0x8)//时钟线GPIO管脚
#define GPIO_I2C_SCLSDA_REG IO_ADDRESS(GPIO_0_BASE + 0xc)
#define HW_REG(reg)         *((volatile unsigned int *)(reg))
#define DELAY(us)           time_delay_us(us)

//拉低数据线/时钟线
static void i2c_clr(unsigned char whichline)
{
    unsigned char regvalue;
	
    //拉低时钟线
     if(whichline == SCL)
    {
	  //方向:输入/输出
          regvalue = HW_REG(GPIO_0_DIR);
        regvalue |= SCL;
        HW_REG(GPIO_0_DIR) = regvalue;
		
	//置零
        HW_REG(GPIO_I2C_SCL_REG) = 0;
      return;
    }
    else if(whichline == SDA)
    {
        regvalue = HW_REG(GPIO_0_DIR);
        regvalue |= SDA;
        HW_REG(GPIO_0_DIR) = regvalue;

        HW_REG(GPIO_I2C_SDA_REG) = 0;
        return;
    }
    else if(whichline == (SDA|SCL))
    {
        regvalue = HW_REG(GPIO_0_DIR);
        regvalue |= (SDA|SCL);
        HW_REG(GPIO_0_DIR) = regvalue;

        HW_REG(GPIO_I2C_SCLSDA_REG) = 0;
        return;
    }
    else
    {
        printk("Error input.\n");
        return;
    }

}

//拉高数据线/时钟线
static void  i2c_set(unsigned char whichline)
{
    unsigned char regvalue;
    //拉高时钟线
     if(whichline == SCL)
    {
        regvalue = HW_REG(GPIO_0_DIR);
        regvalue |= SCL;
        HW_REG(GPIO_0_DIR) = regvalue;
		
        HW_REG(GPIO_I2C_SCL_REG) = SCL;
        return;
    }
    else if(whichline == SDA)
    {
        regvalue = HW_REG(GPIO_0_DIR);
        regvalue |= SDA;
        HW_REG(GPIO_0_DIR) = regvalue;

        HW_REG(GPIO_I2C_SDA_REG) = SDA;
        return;
    }
    else if(whichline == (SDA|SCL))
    {
        regvalue = HW_REG(GPIO_0_DIR);
        regvalue |= (SDA|SCL);
        HW_REG(GPIO_0_DIR) = regvalue;

        HW_REG(GPIO_I2C_SCLSDA_REG) = (SDA|SCL);
        return;
    }
    else
    {
        printk("Error input.\n");
        return;
    }
}

//延时usec微秒
void time_delay_us(unsigned int usec)
{
    int i,j;

    for(i=0; i<usec * 5; i++)
    {
        for(j=0; j<64; j++)
        {
            ;
        }
    }
}

//开始IIC通信
static void i2c_start_bit(void)
{
    DELAY(1);
    //拉高双线,拉低数据线,开始发送数据。
     i2c_set(SDA | SCL);
    DELAY(1);
    i2c_clr(SDA);
    DELAY(2);
}

//停止IIC通信
static void i2c_stop_bit(void)
{
    //时钟响应
    DELAY(1);
    i2c_set(SCL);
    DELAY(1);
    i2c_clr(SCL);

    //数据线为高,数据线由低->高:结束通信
    DELAY(1);
    i2c_clr(SDA);
    DELAY(1);
    i2c_set(SCL);
    DELAY(1);
    i2c_set(SDA);
    DELAY(1);
}

//读取数据:1bit
static unsigned char i2c_data_read(void)
{
    unsigned char regvalue;

    regvalue = HW_REG(GPIO_0_DIR);
    regvalue &= (~SDA);
    HW_REG(GPIO_0_DIR) = regvalue;
    DELAY(1);

    regvalue = HW_REG(GPIO_I2C_SDA_REG);
    if((regvalue&SDA) != 0)
        return 1;
    else
        return 0;
}

//发送数据:1byte
static void i2c_send_byte(unsigned char c)
{
    int i;
	//屏蔽中断
    local_irq_disable();
    for(i=0; i<8; i++)
    {
        DELAY(1);
        i2c_clr(SCL);
        DELAY(1);
		
	  //发送1(这个是重点哦大笑)
        if(c & (1<<(7-i)))
            i2c_set(SDA);
        else//发送0
            i2c_clr(SDA);

        DELAY(1);
        i2c_set(SCL);
        DELAY(1);
        i2c_clr(SCL);
    }
    DELAY(1);
    local_irq_enable();
}

//接收数据:1byte
static unsigned char i2c_receive_byte(void)
{
    int j=0;
    int i;
    unsigned char regvalue;

    local_irq_disable();
    for(i=0; i<8; i++)
    {
        DELAY(1);
        i2c_clr(SCL);
        DELAY(2);
        i2c_set(SCL);

        regvalue = HW_REG(GPIO_0_DIR);
        regvalue &= (~SDA);
        HW_REG(GPIO_0_DIR) = regvalue;
        DELAY(1);

        if(i2c_data_read())
            j+=(1<<(7-i));

        DELAY(1);
        i2c_clr(SCL);
    }
    local_irq_enable();
    DELAY(1);


    return j;
}

//响应(每发送一个字节,都要响应),返回值为0:成功。
static int i2c_receive_ack(void)
{
    int nack;
    unsigned char regvalue;

    DELAY(1);
    regvalue = HW_REG(GPIO_0_DIR);
    regvalue &= (~SDA);//数据线置零
    HW_REG(GPIO_0_DIR) = regvalue;
    DELAY(1);
    i2c_clr(SCL);
    DELAY(1);
    i2c_set(SCL);
    DELAY(1);
    nack = i2c_data_read();
    DELAY(1);
    i2c_clr(SCL);
    DELAY(1);
    if(nack == 0)
        return 1;

    return 0;
}

 

5.上层调用

  1. /***** IIC写数据 ********************************************************************************************/  
/***** IIC写数据 ********************************************************************************************/
  1. //参数分别为设备地址、寄存器地址、值。  
//参数分别为设备地址、寄存器地址、值。
  1. //如果writeval为结构体(最好12字节),而非unsiged long类型,就不需要移动了(底层驱动支持情况下)   
  2. void IIC_Write(int devAddr, int regAddr, int val)  
  3. {  
  4.     unsigned long writeval, ret;      
  5.     writeval = (((devAddr & 0xff) << 24) | ((regAddr & 0xffff) << 8) | (val & 0xff));  
  6.     ret = ioctl(i2cfd, I2C_WRITE, &writeval);  
  7.     if(0 > ret)  
  8.     {  
  9.         _ERROR("write iic ERROR");  
  10.     }         
  11. }  
  12.   
  13. /***** IIC读数据 ********************************************************************************************/  
  14. unsigned int IIC_Read(int devAddr, int regAddr)  
  15. {  
  16.     unsigned long readval, ret;  
  17.       
  18.     readval = (((devAddr & 0xff) << 24) | ((regAddr & 0xffff) << 8));  
  19.     ret = ioctl(i2cfd, I2C_READ, &readval);  
  20.     if(0 > ret)  
  21.     {  
  22.         _ERROR("read iic ERROR");  
  23.     }     
  24.       
  25.     readval &= 0xff;  
  26.     return readval;  
  27. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值