博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
IIC的linux驱动
阅读量:4051 次
发布时间:2019-05-25

本文共 8820 字,大约阅读时间需要 29 分钟。

//---------------IIC的linux驱动------------------

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <asm/hardware.h>

#include <asm/semaphore.h>
#include <asm/uaccess.h>
#include <linux/kernel.h> 
 
#include <linux/slab.h> 
 
#include <linux/fs.h> 
 
 
 
 
 
#include <linux/errno.h> 
 
 
#include <linux/types.h> 
 
 
#include <linux/mm.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/delay.h>
//#include <linux/device.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#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 <asm/irq.h>
//#include <asm/arch/regs-adc.h>
#include <asm/arch/map.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-irq.h>
#include <asm/arch/regs-clock.h>
//#include <asm/arch/regs-iic.h>
volatile int f_nGetACK;
#define UINT unsigned int
#define I2C_MAGIC 'k'  
#define I2C_set _IO(I2C_MAGIC,1)
#define I2C_MAJOR 259
#define DEVICE_NAME "s3c2410_I2C"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("caogos");
MODULE_DESCRIPTION("s3c2410 I2C");
char data[128]="\0";
#define rGPECON 
*(volatile unsigned int *)S3C2410_GPECON
#if 0
#define S3C2410_I2C(x) (S3C2410_IICREG(x))
#define S3C2410_IICCON 
 
 
 
 
S3C2410_I2C(0x00)
#define S3C2410_IICSTAT 
 
 
 
 
S3C2410_I2C(0x04)
#define S3C2410_IICADD 
 
 
 
 
S3C2410_I2C(0x08)
#define S3C2410_IICDS 
 
 
 
 
S3C2410_I2C(0x0c)
#define rIICCON 
*(volatile unsigned int *)S3C2410_IICCON
#define rIICSTAT *(volatile unsigned int *)S3C2410_IICSTAT
#define rIICADD 
*(volatile unsigned int *)S3C2410_IICADD
#define rIICDS 
 
*(volatile unsigned int *)S3C2410_IICDS
#define rGPECON 
*(volatile unsigned int *)S3C2410_GPECON
#else
#define rIICCON 
*(volatile unsigned int *)i2c_base
#define rIICSTAT *(volatile unsigned int *)((unsigned int)i2c_base + 4)
#define rIICADD *(volatile unsigned int *)((unsigned int)i2c_base + 8)
#define rIICDS *(volatile unsigned int *)((unsigned int)i2c_base + 0xc)
static volatile void __iomem *i2c_base;
static struct resource 
 
 
 
 
 
*area = NULL;
#endif
#define CLKCON 0x4c00000c
static volatile unsigned int *clkcon;
static int I2C_major = I2C_MAJOR;
static struct cdev I2C_cdev;
// IIC interrupt handler
static irqreturn_t 
iic_int_24c04(int irq,void *dev_id,struct pt_regs *regs)
{
 
 
 
//ClearPending(BIT_IIC);
 
 
 
f_nGetACK = 1;
 
 
 
return IRQ_HANDLED ;
}
// write data to 24C040 
 
 
void iic_write_24c040(UINT unSlaveAddr,UINT unAddr,UINT ucData)
{
 
 
 
f_nGetACK = 0;
 
 
 
// Send control byte
 
 
 
rIICDS = unSlaveAddr; 
 
 
 
 
 
 
 
 
 
 
 
// 0xa0 
slave设备地址,由硬件的原理图决定
 
 
 
rIICSTAT = 0xf0; 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// Master Tx,Start
 
 
 
while(f_nGetACK == 0);// Wait ACK 
 
 
//这个标志在邋錓IC中断处理函数中被修改 
 
 
 
 
 
 
 
 
 
 
 
f_nGetACK = 0;
 
 
 
 
 
 
//Send address
 
 
 
rIICDS = unAddr; 
 
 
//数据在slave设备的存放地址
 
 
 
rIICCON = 0xaf; 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// Resumes IIC operation.
 
 
 
while(f_nGetACK == 0);// Wait ACK
 
 
 
f_nGetACK = 0;
 
 
 
 
 
 
rIICDS = ucData; 
 
 
// 向slave设备写的数据
 
 
 
rIICCON = 0xaf; 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
?/ Resumes IIC operation.
 
 
 
// printk("4444444\n");
 
 
 
while(f_nGetACK == 0);// Wait ACK
 
 
 
f_nGetACK = 0;
 
 
 
// End send
 
 
 
rIICSTAT = 0xd0; 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// Stop Master Tx condition
 
 
 
rIICCON = 0xaf; 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// Resumes IIC operation.
 
 
 
// Wait until stop condtion is in effect.
 
 
 
mdelay(10); 
 
 
 
 
 
 
 
 
 
 
 
// 这个延时时间查slave设备的资料,
 
 
 
//如果是EEPROM的话,这个延时时间被slave设备用来写数据(将通过iic传送给slave设备的数据写到EEPROM中)
}
// read data from 24C040
void iic_read_24c040(UINT unSlaveAddr,UINT unAddr,unsigned char *pData)
{
 
 
 
char cRecvByte;
 
 
 
f_nGetACK = 0;
 
 
 
//Send control byte 
 
 
 
rIICDS = unSlaveAddr; 
 
 
 
 
 
 
 
 
 
 
 
// 0xa0
 
 
 
rIICSTAT = 0xf0; 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// Master Tx,Start
 
 
 
while(f_nGetACK == 0);// Wait ACK
 
 
 
f_nGetACK = 0;
 
 
 
// Send address
 
 
 
rIICDS = unAddr;
 
 
 
rIICCON = 0xaf; 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// Resumes IIC operation.
 
 
 
//mdelay(100);
 
 
 
while(f_nGetACK == 0);// Wait ACK
 
 
 
f_nGetACK = 0;
 
 
 
//Send control byte 
 
 
 
rIICDS = unSlaveAddr; 
 
 
 
 
 
 
 
 
 
 
 
// 0xa0
 
 
 
rIICSTAT = 0xb0; 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// Master Rx,Start
 
 
 
rIICCON = 0xaf; 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// Resumes IIC operation. 
 
 
 
 
mdelay(100);
 
 
 
while(f_nGetACK == 0);// Wait ACK
 
 
 
f_nGetACK = 0;
 
 
 
//Get data 
 
 
 
// cRecvByte = rIICDS;
 
 
 
rIICCON = 0x2f;
 
 
 
mdelay(1);
 
 
 
// Get data 
 
 
 
cRecvByte = rIICDS;
 
 
 
// End receive 
 
 
 
rIICSTAT = 0x90; 
 
 
 
 
 
 
 
 
 
 
 
// Stop Master Rx condition 
 
 
 
rIICCON = 0xaf; 
 
 
 
 
 
 
 
 
 
 
 
// Resumes IIC operation.
 
 
 
mdelay(10); 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// Wait until stop condtion is in effect.
 
 
 
*pData = cRecvByte;
}
ssize_t I2C_read (struct file *filp, char *buff, size_t count, loff_t *offp)
{
 
 
 
ssize_t result = 0;
 
 
 
int i;
 
 
 
for(i=0; i<count; i++) 
 
 
 
 
 
 
data[i]=0; 
 
 
 
 
// Read 16 byte from 24C04
 
 
 
for(i=0; i<count; i++)
 
 
 
{
 
 
 
 
 
 
iic_read_24c040(0xa0, i, &(data[i])); 
 
 
//第一个参数是slave设备的地址,最后有详细解释
 
 
 
}
 
 
 
data[count]='\0';
 
 
 
// printk("rev=%s\n",data);
 
 
 
if (copy_to_user (buff, data, count)) 
 
 
 
 
 
 
result = -EFAULT;
 
 
 
//else 
 
 
 
//printk (KERN_INFO "wrote %d bytes\n", count);
 
 
 
result=count;
 
 
 
return result;
}
ssize_t I2C_write (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
 
 
 
int i;
 
 
 
ssize_t ret = 0;
 
 
 
//printk ("Writing %d bytes\n", count);
 
 
 
if (count>127) return -ENOMEM;
 
 
 
if (count<0) return -EINVAL;
 
 
 
if (copy_from_user (data, buf, count))
 
 
 
{
 
 
 
 
 
 
ret = -EFAULT;
 
 
 
}
 
 
 
else {
 
 
 
 
 
 
data[127]='\0';
 
 
 
 
 
 
//printk ("Received: %s\n", data);
 
 
 
 
 
 
// Write 0 - 16 to 24C04
 
 
 
 
 
 
for(i=0; i<count; i++)
 
 
 
 
 
 
{
 
 
 
 
 
 
 
 
 
iic_write_24c040(0xa0, i, data[i]); 
 
 
 
 
 
 
 
 
 
//mdelay(100);
 
 
 
 
 
 
}
 
 
 
 
 
 
//printk("write end\n");
 
 
 
 
 
 
ret = count;
 
 
 
}
 
 
 
return ret;
}
static int I2C_open(struct inode *inode ,struct file *file) 
 
 
{
 
 
 
int result;
 
 
 
// Initialize iic
 
 
 
rIICADD = 0x10; 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// S3C2410X slave address 
//这个地址当S3C2410X用作IIC的slave设备时用的
 
 
 
rIICCON = 0xaf; 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// Enable ACK, interrupt, SET IICCLK=MCLK/16
 
 
 
rIICSTAT = 0x10; 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// Enable TX/RX 
 
 
 
rGPECON =(rGPECON&((~0xf)<<28))+(0xa<<28);
 
 
 
//printk("rGPECON=%x\n",rGPECON);
 
 
 
result = request_irq (IRQ_IIC, iic_int_24c04, SA_INTERRUPT, DEVICE_NAME, NULL);
 
 
 
if (result) {
 
 
 
 
 
 
printk(KERN_INFO "I2C: can't get assigned irq\n");
 
 
 
}
 
 
 
//printk(KERN_NOTICE"open the I2C now!\n");
 
 
 
return 0;
}
static int I2C_release(struct inode *inode,struct file *file)
{
 
 
 
free_irq(IRQ_IIC, NULL);//释放中断资源
 
 
 
//printk("I2C closed\n");
 
 
 
return 0;
}
static int I2C_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
 
 
 
 
 
return 0; 
 
 
}
//将设备注册到系统之中
static void I2C_setup_dev(struct cdev *dev,int minor,struct file_operations *fops)
{
 
 
 
int err;
 
 
 
int devno=MKDEV(I2C_major,minor);
 
 
 
cdev_init(dev,fops); 
 
 
 
dev->owner=THIS_MODULE;
 
 
 
dev->ops=fops; 
 
 
 
err=cdev_add(dev,devno,1);
 
 
 
if(err)
 
 
 
 
 
 
printk(KERN_INFO"Error %d adding I2C %d\n",err,minor);
}
static struct file_operations I2C_remap_ops={
 
 
 
.owner=THIS_MODULE,
 
 
 
.open=I2C_open, 
 
 
 
.write = I2C_write,
 
 
 
.read = I2C_read,
 
 
 
.release=I2C_release, 
 
 
 
.ioctl=I2C_ioctl,
};
//注册设备驱动程序,主要完成主设备号的注册
static int __init s3c2410_I2C_init(void)
{
 
 
 
int result;
 
 
 
dev_t dev = MKDEV(I2C_major,0);
 
 
 
if(I2C_major)
 
 
 
 
 
 
result = register_chrdev_region(dev,1,DEVICE_NAME);
 
 
 
else
 
 
 
 
 
 
 
 
 
 
 
result = alloc_chrdev_region(&dev,0,1,DEVICE_NAME);
 
 
 
 
 
 
I2C_major = MAJOR(dev);
 
 
 
}
 
 
 
if(result<0)
 
 
 
{
 
 
 
 
 
 
printk(KERN_WARNING"I2C:unable to get major %d\n",I2C_major); 
 
 
 
 
 
 
 
 
 
 
 
return result;
 
 
 
}
 
 
 
if(I2C_major == 0)
 
 
 
 
 
 
I2C_major = result;
 
 
 
printk(KERN_NOTICE"[DEBUG] I2C device major is %d\n",I2C_major);
 
 
 
__raw_writel( (__raw_readl(S3C2410_CLKCON) | (1 << 16)), S3C2410_CLKCON);
#if 0
 
 
 
printk("\n 
S3C2410_CLKCON = %x \n", __raw_readl(S3C2410_CLKCON));
 
 
 
area = request_mem_region(0x54000000, 16,"I2C");
#endif
 
 
 
i2c_base = ioremap(0x54000000, 16);
 
 
 
clkcon = ioremap(CLKCON, 0x4);
 
 
 
printk(KERN_INFO"i2c clock = %d\n", *clkcon & (0x1 << 16));
 
 
 
*clkcon |= 0x1 << 16;
 
 
 
I2C_setup_dev(&I2C_cdev,0,&I2C_remap_ops);
 
 
 
return 0;
}
//驱动模块卸载
static void s3c2410_I2C_exit(void)
{
#if 0
 
 
 
if (area) {
 
 
 
 
 
 
release_resource(area);
 
 
 
 
 
 
kfree(area);
 
 
 
}
#endif
 
 
 
cdev_del(&I2C_cdev);
 
 
 
unregister_chrdev_region(MKDEV(I2C_major,0),1);
 
 
 
printk("I2C device uninstalled\n");
}
module_init(s3c2410_I2C_init);
module_exit(s3c2410_I2C_exit);
//---------------测试程序-------------------------
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/ioctl.h>
#define WATCHDOG_MAGIC 'k' 
#define FEED_DOG _IO(WATCHDOG_MAGIC,1)
int main(int argc,char **argv)
{
 
 
 
int fd;
 
 
 
char buff[]="farsight";
 
 
 
//打开I2C
 
 
 
fd=open("/dev/i2c",O_RDWR);
 
 
 
 
 
 
 
if(fd<0)
 
 
 
{
 
 
 
 
 
 
printf("cannot open the I2C device\n");
 
 
 
 
 
 
return -1;
 
 
 
}
 
 
 
 
 
sleep(1);
 
 
 
printf("buff_write=%s\n",buff);
 
 
 
 
 
 
 
 
 
write (fd, buff, sizeof(buff));
 
 
 
//printf(" read 
now!\n");
 
 
 
memset (buff, '\0', sizeof(buff));
 
 
 
//printf ("Read returns %d\n", read (fd, buff, sizeof(buff)));
 
 
read (fd, buff, sizeof(buff));
//read (fd, buff, 3);
 
 
 
printf ("buff_read = %s\n", buff);
 
 
 
// 
 
 
}
 
 
 
 
 
 
close(fd);
 
 
 
 
 
// 
while(1);
 
 
// 
 
printf("end\n");
 
 
 
return 0;
}

确定slave 设备地址

IIC的linux驱动

由原理图可以得到A2(即NC)为0,A1为0,A0为0,将这三个数代入下面这个图中,就可以得到slave地址为0xa0

下图是芯片资料中关于设备地址的资料

IIC的linux驱动
本例中使用的是2K的EEPROM,所以地址格式应该是

bit7 bit6  bit5  bit4  bit3  bit2  bit1 bit0

               A2    A1  A0  R/W

其中A2,A1和A0由上面的原理图已经得出了,全为0.

而最后一位,读(EEPROM)时为1,写(EEPROM)时为0

这样slave设备地址就已经确定了

 

确定EEPROM“内部”写需要的时间

IIC的linux驱动

上面用红色圈起来的,就是EEPROM内部写需要的时间twr,然后再在下面的图中查该时间是多少

IIC的linux驱动

由上图得时间最大为10ms

主机(master这里是mcu)发送详细分析

由MCU的资料得到,mcu作为master发送时的流程图为

IIC的linux驱动

由上图知,在start和stop condition之间,可以发送任意多个连续字节的数据。注意:这里把数据地址(不是设备地址)也看作是数据了。

IIC的linux驱动

由IIC的从设备(EEPROM)的资料得上图,其中对数据格式做了严格的限制,要求必须是 

起始条件->从设备地址(EEPROM自己的地址)->数据的“地址”->和真实需要被写到eeprom中的数据->停止位。

这里EEPROM(从设备)把mcu(主设备)认为是“数据”的 需要被写到eeprom中的数据 的地址 看作是地址,这里只把需要被写到EEPROM中的真实的数据 看作是数据。

要想用IIC来实现mcu(主设备)和EEPROM(从设备)的通信,必须满足主设备和从设备的数据格式。

转载地址:http://kipci.baihongyu.com/

你可能感兴趣的文章
android中对于非属性动画的整理
查看>>
一个简单的TabLayout的使用
查看>>
ReactNative使用Redux例子
查看>>
Promise的基本使用
查看>>
coursesa课程 Python 3 programming 统计文件有多少单词
查看>>
coursesa课程 Python 3 programming 输出每一行句子的第三个单词
查看>>
Returning a value from a function
查看>>
coursesa课程 Python 3 programming Functions can call other functions 函数调用另一个函数
查看>>
course_2_assessment_6
查看>>
coursesa课程 Python 3 programming course_2_assessment_7 多参数函数练习题
查看>>
coursesa课程 Python 3 programming course_2_assessment_8 sorted练习题
查看>>
在unity中建立最小的shader(Minimal Shader)
查看>>
1.3 Debugging of Shaders (调试着色器)
查看>>
关于phpcms中模块_tag.class.php中的pc_tag()方法的含义
查看>>
vsftp 配置具有匿名登录也有系统用户登录,系统用户有管理权限,匿名只有下载权限。
查看>>
linux安装usb wifi接收器
查看>>
多线程使用随机函数需要注意的一点
查看>>
getpeername,getsockname
查看>>
关于对象赋值及返回临时对象过程中的构造与析构
查看>>
VS 2005 CRT函数的安全性增强版本
查看>>