红联Linux门户
Linux帮助

linux模拟iic代码

发布时间:2016-07-09 15:05:33来源:linux网站作者:shareinfo2018
因2440自带的IIC控制器本人用它作为从机使用,所以用GPIO模拟了IIC总线的主机模式。以下列出驱动代码和应用试验程序,总线模拟读写EEPROM。
 
1.底层驱动
/********************************* 
** EEPROM模拟IIC总线 驱动程序   **
**版本:V1_0** 
*********************************/  
#include <linux/errno.h>  
#include <linux/kernel.h>  
#include <linux/module.h>  
#include <linux/slab.h>  
#include <linux/input.h>  
#include <linux/init.h>  
#include <linux/serio.h>  
#include <linux/delay.h>  
#include <linux/clk.h>  
#include <linux/wait.h>  
#include <linux/sched.h>  
#include <asm/io.h>  
#include <asm/irq.h>  
#include <asm/uaccess.h>  
#include <asm/delay.h>  
#include <mach/regs-clock.h>  
#include <plat/regs-timer.h>
#include <plat/regs-adc.h>  
#include <mach/regs-gpio.h>  
#include <linux/cdev.h>  
#include <linux/miscdevice.h>  
#include "s3c24xx-adc.h"  
static void __iomem *base_addr;  
#define GPJCON  (*(volatile unsigned long *)(base_addr + 0))   
#define GPJDAT  (*(volatile unsigned long *)(base_addr + 0x04))   
#define GPJUP   (*(volatile unsigned long *)(base_addr + 0x08))
#define DEVICE_NAME "eeprom_micro2440_drv"  
static struct semaphore lock;  
#define I2CSDA_HIGH   (GPJDAT=GPJDAT|(0x01<<4))  
#define I2CSDA_LOW(GPJDAT=GPJDAT&(~(0x01<<4)))  
#define I2CSCL_HIGH   (GPJDAT=GPJDAT|(0x01<<3))  
#define I2CSCL_LOW(GPJDAT=GPJDAT&(~(0x01<<3)))  
#define delay_data200  
#define write_at24c32_addr   0xa0  
#define read_at24c32_addr0xa1  
static void iicstart(void)  
{  
I2CSDA_HIGH;  
__udelay(delay_data);  
I2CSCL_HIGH;  
__udelay(delay_data);  
I2CSDA_LOW;  
__udelay(delay_data);  
}   
static void iicstop(void)  
{  
I2CSDA_LOW;  
__udelay(delay_data);  
I2CSCL_HIGH;  
__udelay(delay_data);  
I2CSDA_HIGH;  
__udelay(delay_data);
}  
static unsigned char waitack(void)  
{ //将SDA改为输入
GPJCON=GPJCON&(~(0x03<<8));  
__udelay(delay_data);  
I2CSCL_HIGH;  
__udelay(delay_data);  
while((GPJDAT&(0x01<<4))!=0);  
I2CSCL_LOW;  
__udelay(delay_data);  
GPJCON=GPJCON|(0x01<<8);  
I2CSDA_HIGH;  
__udelay(delay_data);  
return 1;  
}  
static void sendack(void)  
{  
I2CSDA_LOW;  
__udelay(delay_data);  
I2CSCL_HIGH;  
__udelay(delay_data);  
I2CSCL_LOW;  
__udelay(delay_data);
}  
static void sendnotack(void)  
{  
I2CSDA_HIGH;  
__udelay(delay_data);  
I2CSCL_HIGH;  
__udelay(delay_data);  
I2CSCL_LOW;  
__udelay(delay_data);  
I2CSDA_LOW;  
__udelay(delay_data);  
}  
static void iicsendbyte(unsigned char ch)  
{  
unsigned char i=8;  
while(i--)  
{  
  I2CSCL_LOW;  
  __udelay(delay_data);  
  if((ch&0x80)==0)  
  {  
  I2CSDA_LOW;   
  }   
  else  
  {  
  I2CSDA_HIGH;  
  }  
  ch=ch<<1;  
  __udelay(delay_data);  
  I2CSCL_HIGH;  
  __udelay(delay_data);  
 
 }   
 I2CSCL_LOW;  
 __udelay(delay_data);  
 I2CSDA_HIGH;  
 __udelay(delay_data);  
}  
static unsigned char iicreceivebyte(void)  
{  
unsigned char i=8;  
unsigned char ddata=0;  
I2CSDA_HIGH;  
//将数据线改为输入  
GPJCON=GPJCON&(~(0x03<<8));  
__udelay(delay_data);  
  
while(i--)  
{  
 ddata<<=1;  
 I2CSCL_LOW;  
 __udelay(delay_data);  
 I2CSCL_HIGH;  
 __udelay(delay_data);   
 if((GPJDAT&(0x01<<4))==0)  
 {  
ddata|=0;  
printk("%d=0\n",i);  
 }  
 else  
 {  
ddata|=1;  
printk("%d=1\n",i);  
 }
}  
__udelay(delay_data);  
I2CSCL_LOW;  
__udelay(delay_data);  
GPJCON=GPJCON|(0x01<<8);  
GPJDAT=GPJDAT|(0x01<<4);  
__udelay(delay_data);  
return ddata;  
}  
static void write_at24c32(unsigned int addr,unsigned char dat)  
{  
  iicstart();  
  __udelay(delay_data);  
  iicsendbyte(write_at24c32_addr);  
  __udelay(delay_data);  
 waitack();  
  __udelay(delay_data);  
  iicsendbyte((unsigned char)(addr>>8));  
  __udelay(delay_data);  
  waitack();  
  __udelay(delay_data);  
  iicsendbyte((unsigned char)(addr&0x00ff));  
  __udelay(delay_data);  
  waitack();  
  iicsendbyte(dat);  
  __udelay(delay_data);  
  waitack();  
  iicstop();  
  __udelay(delay_data);   
}  
static unsigned char read_at24c32(unsigned int addr)  
{  
 unsigned char dat=0;  
 iicstart();  
 __udelay(delay_data);  
 iicsendbyte(write_at24c32_addr);  
 __udelay(delay_data);  
 waitack();  
 __udelay(delay_data);  
 iicsendbyte((unsigned char)(addr>>8));  
 __udelay(delay_data);  
 waitack();  
 __udelay(delay_data);  
 iicsendbyte((unsigned char)(addr&0x00ff));  
 __udelay(delay_data);  
 waitack();  
 __udelay(delay_data);  
 iicstart();  
 __udelay(delay_data);  
 iicsendbyte(read_at24c32_addr);  
 __udelay(delay_data);  
 waitack();  
 __udelay(delay_data);  
 dat=iicreceivebyte();  
 __udelay(delay_data);  
 sendnotack();  
 __udelay(delay_data);  
 iicstop();  
 __udelay(delay_data);  
 return dat;  
}  
static ssize_t eeprom_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)  
{  
   unsigned char data_temp=0;  
   unsigned long ret=0;  
   data_temp=read_at24c32((unsigned int)count);  
   printk("read data_temp=%d",data_temp);  
   ret=copy_to_user(buffer, &data_temp, 1);  
   return ret;  
}  
static ssize_t eeprom_write(struct file *file,char *buf,size_t count,loff_t *ppos)  
{  
 unsigned long ret=0;  
 unsigned char data_temp=0;  
 ret=copy_from_user(&data_temp,buf,1);  
 printk("write data_temp=%d",data_temp);  
 write_at24c32((unsigned int)count,data_temp);  
 return ret;
}  
static int eeprom_open(struct inode *inode,struct file *file)  
{  
  //尝试打开互斥锁  
   int ret;  
   ret=down_trylock(&lock);  
   if(ret!=0)  
return -EBUSY;  
  //映射IO口  
  base_addr=ioremap(0x560000d0,0x1c);  
  //初始化IO口  
  GPJCON=GPJCON&(~(0x0f<<6));  
  GPJCON=GPJCON|(0x05<<6);  
  GPJDAT=GPJDAT|(0x01<<4)|(0x01<<3);  
   printk("eeprom init ok!\n");  
  return 0;
 }   
static int eeprom_close(struct inode *inodep,struct file *file)  
{  
  up(&lock);//释放互斥锁  
 return 0;  
}  
static struct file_operations dev_fops={  
 .owner=THIS_MODULE,  
 .open=eeprom_open,  
 .release=eeprom_close,  
 .write=eeprom_write,  
 .read=eeprom_read,  
};  
static struct miscdevice misc={  
 .name=DEVICE_NAME,  
 .minor=MISC_DYNAMIC_MINOR,  
 .fops=&dev_fops,  
};  
static int __init eeprom_micro2440_init(void)  
{  
 int ret;  
 //初始化锁  
 init_MUTEX(&lock);   
 //注册混杂设备  
 ret=misc_register(&misc);   
 return ret;  
}  
void __exit eeprom_micro2440_exit(void)  
{  
//1.取消寄存器映射  
iounmap(base_addr);  
//2.注销混杂设备  
misc_deregister(&misc);//注销混杂设备   
}  
MODULE_LICENSE("GPL");  
MODULE_AUTHOR("xubin");  
module_init(eeprom_micro2440_init);  
module_exit(eeprom_micro2440_exit);  
 
2.应用程序
#include <stdio.h>  
#include <fcntl.h>  
#include <linux/types.h>  
#include <unistd.h>  
#include <sys/types.h>  
#include <stdlib.h>  
int main(int argc,char **argv)  
{  
int i;  
unsigned char value[512];  
int fd;  
value[0]=0x01;   
fd=open("/dev/eeprom_micro2440_drv",O_RDWR);  
if(fd<0)  
{  
printf("error\n");  
exit(1);  
}  
while(1)  
{  
write(fd,value,1);  
printf("write reg[0]data:%x to at24lc04\n",value[0]);  
sleep(1);  
value[0]=0;   
read(fd,value,1);  
printf("read reg[0]data:%x to at24lc04\n",value[0]);  
value[0]+=1;  
}  
return 0;  
}
 
本文永久更新地址://m.ajphoenix.com/linux/22214.html