【摘要】 AT24C02是IIC接口的EEPROM存儲芯片,這顆芯片非常經典,百度搜索可以找到非常多的資料,大多都是51、STM32單片機的示例代碼,大多采用模擬時序、裸機系統運行。當前文章介紹在Linux系統里如何編寫AT24C02的驅動,并且在應用層完成驅動讀寫測試,將AT24C02的存儲空間映射成文件,在應用層,用戶可以直接將AT24C02當做一個普通文件的形式進行讀寫,偏移文件指針;在Linux內核
1. 前言
AT24C02是IIC接口的EEPROM存儲芯片,這顆芯片非常經典,百度搜索可以找到非常多的資料,大多都是51、STM32單片機的示例代碼,大多采用模擬時序、裸機系統運行。當前文章介紹在Linux系統里如何編寫AT24C02的驅動,并且在應用層完成驅動讀寫測試,將AT24C02的存儲空間映射成文件,在應用層,用戶可以直接將AT24C02當做一個普通文件的形式進行讀寫,偏移文件指針;在Linux內核里有一套標準的IIC子系統框架專門讀寫IIC接口設備,采用平臺設備模型框架,編寫驅動非常方便。
當前開發(fā)板采用友善之臂的Tiny4412,CPU是三星的EXYNOS4412,4412是三星的第一款四核處理器,主頻是1.5GHZ,穩(wěn)定頻率是1.4GHZ。
2. 硬件原理圖
當前的開發(fā)板上自帶了一顆EEPROM存儲芯片(具體型號是24AA025E48,代碼與AT24C02一樣的),原理圖如下:
自帶的內核里沒有內置EEPROM的驅動:
存儲芯片的數據手冊介紹:
設備地址:
寫字節(jié)、頁寫時序:
讀數據時序:
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 //頁字節(jié)大小
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; //記錄寫成功的字節(jié)數
//等待寫完成
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); /*驅動入口--安裝驅動的時候執(zhí)行*/
module_exit(tiny4412_drv_cleanup); /*驅動出口--卸載驅動的時候執(zhí)行*/
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); /*驅動入口--安裝驅動的時候執(zhí)行*/
module_exit(tiny4412_drv_cleanup); /*驅動出口--卸載驅動的時候執(zhí)行*/
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++)>
-
驅動
+關注
關注
12文章
1825瀏覽量
85178 -
EEPROM
+關注
關注
9文章
1010瀏覽量
81406 -
AT24C02
+關注
關注
0文章
79瀏覽量
24248
發(fā)布評論請先 登錄
相關推薦
評論