0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux驱动开发-编写(EEPROM)AT24C02驱动

DS小龙哥-嵌入式技术 2022-09-17 15:29 次阅读

【摘要】 AT24C02是IIC接口的EEPROM存储芯片,这颗芯片非常经典,百度搜索可以找到非常多的资料,大多都是51、STM32单片机的示例代码,大多采用模拟时序、裸机系统运行。当前文章介绍在Linux系统里如何编写AT24C02的驱动,并且在应用层完成驱动读写测试,将AT24C02的存储空间映射成文件,在应用层,用户可以直接将AT24C02当做一个普通文件的形式进行读写,偏移文件指针;在Linux内核

1. 前言

AT24C02是IIC接口的EEPROM存储芯片,这颗芯片非常经典,百度搜索可以找到非常多的资料,大多都是51、STM32单片机的示例代码,大多采用模拟时序、裸机系统运行。当前文章介绍在Linux系统里如何编写AT24C02的驱动,并且在应用层完成驱动读写测试,将AT24C02的存储空间映射成文件,在应用层,用户可以直接将AT24C02当做一个普通文件的形式进行读写,偏移文件指针;在Linux内核里有一套标准的IIC子系统框架专门读写IIC接口设备,采用平台设备模型框架,编写驱动非常方便。

当前开发板采用友善之臂的Tiny4412,CPU三星的EXYNOS4412,4412是三星的第一款四核处理器,主频是1.5GHZ,稳定频率是1.4GHZ。

2. 硬件原理图

当前的开发板上自带了一颗EEPROM存储芯片(具体型号是24AA025E48,代码与AT24C02一样的),原理图如下:

image-20220104085514044image-20220104085817035

自带的内核里没有内置EEPROM的驱动:

image-20220104085843239

存储芯片的数据手册介绍:

image-20220104090012199

设备地址:

image-20220104090059967

写字节、页写时序:

image-20220104090126403

读数据时序:

image-20220104090200161

3. 示例代码

3.1 EEPROM驱动端代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
static struct work_struct work;
static struct i2c_client *eeprom_client;

#define MAX_SIZE 255  //EEPROM大小
#define EEPROM_PAGE  16 //页字节大小

static u8 eeprom_buff[255];
static int tiny4412_open(struct inode *inode, struct file *file)
{
	printk("tiny4412_open-->ok\n");
	return 0;
}

static ssize_t tiny4412_read(struct file *file, char __user *buf, size_t size, loff_t *seek)
{	
	unsigned long err;
	//判断位置是否超出范围
	if(*seek+size>MAX_SIZE)
	{
		size=MAX_SIZE-*seek;
	}
	//读取数据
	i2c_smbus_read_i2c_block_data(eeprom_client,*seek,size,eeprom_buff);
	err=copy_to_user(buf,eeprom_buff,size);
	if(err!=0)return -1;
	*seek+=size;
	return size;
}

static ssize_t tiny4412_write(struct file *file, const char __user *buf, size_t size, loff_t *seek)
{
	size_t write_ok_cnt=0;
	unsigned long err;
	err=copy_from_user(eeprom_buff,buf,size);
	if(err!=0)return -1;
	//判断位置是否超出范围
	if(*seek+size>MAX_SIZE)
	{
		size=MAX_SIZE-*seek;
	}
	
	int write_byte=0;
	u8 *write_p=eeprom_buff;
	while(1)
	{
		if(size>EEPROM_PAGE)
		{
			write_byte=EEPROM_PAGE;
			size-=EEPROM_PAGE;
		}
		else
		{
			write_byte=size;
		}
		
		//写数据
		i2c_smbus_write_i2c_block_data(eeprom_client,*seek,write_byte,write_p);
		*seek+=write_byte;
		write_p+=write_byte;
		write_ok_cnt+=write_byte;  //记录写成功的字节数
		//等待写完成
		msleep(10);
		if(write_byte==size)break; //写完毕
	}
	return write_ok_cnt;
}

/*
filp:待操作的设备文件file结构体指针
off:待操作的定位偏移值(可正可负)
whence:待操作的定位起始位置
返回:返回移位后的新文件读、写位置,并且新位置总为正值
定位起始位置
  SEEK_SET:0,表示文件开头
  SEEK_CUR:1,表示当前位置
  SEEK_END:2,表示文件尾
*/
static loff_t tiny4412_llseek(struct file *filp, loff_t offset, int whence)
{
	loff_t newpos = 0;
	switch(whence)
	{
		case SEEK_SET:
			newpos = offset;
			break;
		case SEEK_CUR:
			newpos = filp->f_pos + offset;
			break;
		case SEEK_END:
			if(MAX_SIZE+offset>=MAX_SIZE)
			{
				newpos=MAX_SIZE;
			}
			else
			{
				newpos = MAX_SIZE + offset;
			}
			break;
		default:
			return -EINVAL;//无效的参数
	}
	filp->f_pos = newpos;
	return newpos;
}

static int tiny4412_release(struct inode *inode, struct file *file)
{
	printk("tiny4412_release-->ok\n");
	return 0;
}

static struct file_operations fops=
{
	.open=tiny4412_open,
	.read=tiny4412_read,
	.write=tiny4412_write,
	.release=tiny4412_release,
	.llseek=tiny4412_llseek
};

/*
Linux内核管理驱动---设备号
设备号是一个unsigned int 的变量--32位。
设备号=主设备号+次设备号
*/
static struct miscdevice misc=
{
	.minor = MISC_DYNAMIC_MINOR,  /*次设备号填255表示自动分配     主设备号固定为10*/
	.name = "tiny4412_eeprom",  /*/dev目录下文件名称*/
	.fops = &fops, /*文件操作接口*/
};
static int tiny4412_probe(struct i2c_client *client, const struct i2c_device_id *device_id)
{
	printk("probe调用成功:%#X\n",client->addr);
	eeprom_client=client;
	
	/*1. 杂项设备的注册函数*/
	misc_register(&misc);
	
	return 0;
}

static int tiny4412_remove(struct i2c_client *client)
{
	/*2. 杂项设备的注销函数*/
	misc_deregister(&misc);
	printk("remove调用成功.\n");
	return 0;
}

static struct i2c_device_id id_table[]=
{
	{"tiny4412_eeprom",0},
	{}
};

static struct i2c_driver drv=
{
	.probe=tiny4412_probe,
	.remove=tiny4412_remove,
	.driver=
	{
		.name="eeprom_iic"
	},
	.id_table=id_table
};

static int __init tiny4412_drv_init(void)
{	
	/*注册IIC驱动端*/
	i2c_add_driver(&drv);
    printk("IIC驱动端: 驱动安装成功\n");
    return 0;
}

static void __exit tiny4412_drv_cleanup(void)
{
	/*注销IIC驱动端*/
	i2c_del_driver(&drv);
    printk("IIC驱动端: 驱动卸载成功\n");
}

module_init(tiny4412_drv_init);    /*驱动入口--安装驱动的时候执行*/
module_exit(tiny4412_drv_cleanup); /*驱动出口--卸载驱动的时候执行*/

MODULE_LICENSE("GPL");  /*设置模块的许可证--GPL*/

3.2 EEPROM设备端代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 

static struct i2c_client *i2c_dev=NULL;
static struct i2c_adapter *adap=NULL;
static struct i2c_board_info info=
{
	.type="tiny4412_eeprom",
	.addr=0x50, /*设备地址*/
};

static int __init tiny4412_drv_init(void)
{	
	/*根据总线编号获取是适配器*/
	adap=i2c_get_adapter(0);
	/*注册IIC设备端*/
	i2c_dev=i2c_new_device(adap,&info);
    printk("IIC设备端: 驱动安装成功\n");
    return 0;
}

static void __exit tiny4412_drv_cleanup(void)
{
	/*注销IIC设备*/
	i2c_unregister_device(i2c_dev);
	i2c_put_adapter(adap);
    printk("IIC设备端: 驱动卸载成功\n");
}

module_init(tiny4412_drv_init);    /*驱动入口--安装驱动的时候执行*/
module_exit(tiny4412_drv_cleanup); /*驱动出口--卸载驱动的时候执行*/

MODULE_LICENSE("GPL");  /*设置模块的许可证--GPL*/

3.3 应用层测试代码

#include 
#include 
#include 
#include 

#define EEPROM_DEV "/dev/tiny4412_eeprom"

int main(int argc,char **argv)
{
    /*1. 打开设备文件*/
    int fd=open(EEPROM_DEV,O_RDWR);
    if(fd<0)
    {
        printf("%s 设备驱动打开失败.\n",EEPROM_DEV);
        return 0;
	}
    /*3.读写数据*/
	unsigned char buff[255];
	int cnt;
	int i;
	for(i=0;i<255;i++)buff[i]=i;
	cnt=write(fd,buff,255);
    printf("write成功:%d Byte\n",cnt);
	
	//偏移文件指针
	lseek(fd,SEEK_SET,0);
	
	unsigned char buff_r[255];
	cnt=read(fd,buff_r,255);
	printf("read成功:%d Byte\n",cnt);
	for(i=0;i;i++)>
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 驱动
    +关注

    关注

    11

    文章

    1720

    浏览量

    84389
  • EEPROM
    +关注

    关注

    9

    文章

    928

    浏览量

    80398
  • AT24C02
    +关注

    关注

    0

    文章

    79

    浏览量

    24110
收藏 人收藏

    评论

    相关推荐

    stm8s103k与AT24C02的iic通信不稳定是什么原因导致的?

    stm8s103k与AT24C02的iic通信不稳定,有时可以读取数据,有时读不出 是什么原因? 有人与ADS1110用iic通信过吗?
    发表于 04-30 07:33

    单片机IIC总线及AT24C02的应用

    电子发烧友网站提供《单片机IIC总线及AT24C02的应用.doc》资料免费下载
    发表于 11-16 09:24 2次下载
    单片机IIC总线及<b class='flag-5'>AT24C02</b>的应用

    STM32基础知识:IIC总线操作EEPROM存储模块AT24C02

    本文是IIC总线的实际应用,将带领读者一步一步阅读AT24C02数据手册,看时序图了解如何使用IIC接口EEPROM存储模块AT24C02,并编写代码使用STM32
    的头像 发表于 10-26 14:25 1133次阅读
    STM32基础知识:IIC总线操作<b class='flag-5'>EEPROM</b>存储模块<b class='flag-5'>AT24C02</b>

    STM32速成笔记(11)—EEPROM(AT24C02)

    AT24C01/02/04/08/16...是一个1K/2K/4K/8K/16K位电可擦除PROM,内部含有128/256/512/1024/2048个8位字节,AT24C01有一个8字节页写缓冲器,
    的头像 发表于 10-24 15:12 769次阅读
    STM32速成笔记(11)—<b class='flag-5'>EEPROM</b>(<b class='flag-5'>AT24C02</b>)

    一文总结linux的platform驱动

    linux设备驱动中,有许多没有特定总线的外设驱动,在实际开发中,又需要使用到总线、驱动和设备模型这三个概念,故而
    的头像 发表于 10-16 16:45 425次阅读
    一文总结<b class='flag-5'>linux</b>的platform<b class='flag-5'>驱动</b>

    STM32软件模拟IIC通信AT24C02,能读不能写?

    我在使用STM32软件模拟IIC通信,读写AT24C02的时候,出现了能读不能写的情况,一番纠结无果后,直接用上了正点原子的例程,仍然是能读不能写,我怀疑板子出问题了,但是换了一块板子也是同样的情况
    发表于 10-09 19:34

    Linux模块相关命令 Linux驱动模块的编写与挂载

    Linux模块相关命令 Linux驱动模块的编写与挂载
    发表于 10-01 12:20 205次阅读
    <b class='flag-5'>Linux</b>模块相关命令 <b class='flag-5'>Linux</b><b class='flag-5'>驱动</b>模块的<b class='flag-5'>编写</b>与挂载

    怎么用AT24C02存一个大于256的数?

    是设计一个红外计数器的,就差这个计数器计数的保存 存到AT24C02里面好像就最多就255,一到256就清零了
    发表于 09-27 06:22

    AT24C04芯片驱动程序原理

    1.芯片简介 24c02是一种串行电可擦除只读存储器(以下数据均以AT24C02为例),即eeprom存储器器件,采用的 IIC 总线技术。24c02在许多试验中都有出现。
    的头像 发表于 09-11 11:36 1302次阅读
    AT<b class='flag-5'>24</b>C04芯片<b class='flag-5'>驱动</b>程序原理

    STM32 IIC读写AT24C02(三)

    现在我们已经实现了AT24C02的单字节读写,但是对于对于2K内存来说,如果对全部数据的读取或者写入都只用单字节读写来完成,这样就会很不方便。
    发表于 07-22 10:33 556次阅读
    STM32 IIC读写<b class='flag-5'>AT24C02</b>(三)

    STM32 IIC读写AT24C02(二)

    上次已经完成了IIC读写AT24C02的协议层,现在开始编写读写AT24C02驱动函数。先从单字节的读写开始。
    发表于 07-22 10:31 776次阅读
    STM32 IIC读写<b class='flag-5'>AT24C02</b>(二)

    STM32 IIC读写AT24C02(一)

    要用IIC读写AT24C02,首先要了解IIC是什么。
    发表于 07-22 10:28 603次阅读
    STM32 IIC读写<b class='flag-5'>AT24C02</b>(一)

    24C02驱动【掉电保存】

    24C02是一个2Kbit的串行EEPROM存储芯片,可存储256个字节数据。工作电压范围为1.8V到6.0V,具有低功耗CMOS技术,自定时擦写周期,1000000次编程/擦除周期,可保存数据
    的头像 发表于 07-17 09:24 1025次阅读
    <b class='flag-5'>24C02</b><b class='flag-5'>驱动</b>【掉电保存】

    基于Linux使用spidev驱动OLED

    如果不想编写spi设备驱动,那么linux内核提供了一个通用的spidev设备驱动,提供统一的字符设备操作,那么只需要在应用层读写和控制即可。以SPI OLED为例子,使用spidev
    发表于 06-16 10:36 2805次阅读
    基于<b class='flag-5'>Linux</b>使用spidev<b class='flag-5'>驱动</b>OLED

    基于51单片机的iic--24c02EEPROM读写程序

    基于51单片机的iic--24c02EEPROM读写例程源代码
    发表于 05-12 16:44 0次下载