00025-----GPIO模拟IIC总线程序

来源:互联网 发布:雀巢咖啡好处坏处知乎 编辑:程序博客网 时间:2024/05/24 06:30
因2440自带的IIC控制器本人用它作为从机使用,所以用GPIO模拟了IIC总线的主机模式。以下列出驱动代码和应用试验程序
总线模拟读写EEPROM
 
1.底层驱动
 

/*********************************
** EEPROM模拟IIC总线 驱动程序   **
**        日期:2012.8.30       **
**        版本: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_data    200
#define write_at24c32_addr   0xa0
#define read_at24c32_addr    0xa1
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;
}
原创粉丝点击