【摘要】 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一样的),原理图如下:
自带的内核里没有内置eeprom的驱动:
存储芯片的数据手册介绍:
设备地址:
写字节、页写时序:
读数据时序:
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_eepromint 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
芯片封测的主要工艺流程有哪些
不好理解的「继电器线圈电压」,本文都说清楚了
董明珠的银隆能成功吗? 能否在格力连任决定其生死
IDC产业的总体发展情况
Σ-Δ型ADC在电机控制算法设计上的应用
Linux驱动开发-编写(EEPROM)AT24C02驱动
螺杆空压机保护参数 螺杆空压机保养标准
中控智慧科技通道专用组合读头TDM03简介
数字经济时代,为什么华为云ECS能获得更多用户的青睐?
NVIDIA 创始人兼首席执行官黄仁勋将在 COMPUTEX 2023 发表主题演讲
巨头眼里的存储技术路线图
浅谈医疗器械产品数字化的未来发展
什么是拉电流和灌电流?
必达安保系统R665FM-19B门锁简介
ups电源有几种_ups电源分类
我国首条压敏传感芯片产线落户湖南
预计:2021年半导体市场将实现两位数增长
数字实现过程中的惯性延迟和传输延迟
华为路由H6开启预售 一加9R全新顶配版开售
Three ICs Produce Pure Sine Wa