您的位置:首页 > 其它

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

2013-09-07 09:20 405 查看
因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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: