【摘要】 AT24C02是IIC接口的EEPROM存儲芯片,這顆芯片非常經(jīng)典,百度搜索可以找到非常多的資料,大多都是51、STM32單片機的示例代碼,大多采用模擬時序、裸機系統(tǒng)運行。當前文章介紹在Linux系統(tǒng)里如何編寫AT24C02的驅(qū)動,并且在應(yīng)用層完成驅(qū)動讀寫測試,將AT24C02的存儲空間映射成文件,在應(yīng)用層,用戶可以直接將AT24C02當做一個普通文件的形式進行讀寫,偏移文件指針;在Linux內(nèi)核
1. 前言
AT24C02是IIC接口的EEPROM存儲芯片,這顆芯片非常經(jīng)典,百度搜索可以找到非常多的資料,大多都是51、STM32單片機的示例代碼,大多采用模擬時序、裸機系統(tǒng)運行。當前文章介紹在Linux系統(tǒng)里如何編寫AT24C02的驅(qū)動,并且在應(yīng)用層完成驅(qū)動讀寫測試,將AT24C02的存儲空間映射成文件,在應(yīng)用層,用戶可以直接將AT24C02當做一個普通文件的形式進行讀寫,偏移文件指針;在Linux內(nèi)核里有一套標準的IIC子系統(tǒng)框架專門讀寫IIC接口設(shè)備,采用平臺設(shè)備模型框架,編寫驅(qū)動非常方便。
當前開發(fā)板采用友善之臂的Tiny4412,CPU是三星的EXYNOS4412,4412是三星的第一款四核處理器,主頻是1.5GHZ,穩(wěn)定頻率是1.4GHZ。
2. 硬件原理圖
當前的開發(fā)板上自帶了一顆EEPROM存儲芯片(具體型號是24AA025E48,代碼與AT24C02一樣的),原理圖如下:
自帶的內(nèi)核里沒有內(nèi)置EEPROM的驅(qū)動:
存儲芯片的數(shù)據(jù)手冊介紹:
設(shè)備地址:
寫字節(jié)、頁寫時序:
讀數(shù)據(jù)時序:
3. 示例代碼
3.1 EEPROM驅(qū)動端代碼
#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;
}
//讀取數(shù)據(jù)
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;
}
//寫數(shù)據(jù)
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é)數(shù)
//等待寫完成
msleep(10);
if(write_byte==size)break; //寫完畢
}
return write_ok_cnt;
}
/*
filp:待操作的設(shè)備文件file結(jié)構(gòu)體指針
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;//無效的參數(shù)
}
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內(nèi)核管理驅(qū)動---設(shè)備號
設(shè)備號是一個unsigned int 的變量--32位。
設(shè)備號=主設(shè)備號+次設(shè)備號
*/
static struct miscdevice misc=
{
.minor = MISC_DYNAMIC_MINOR, /*次設(shè)備號填255表示自動分配 主設(shè)備號固定為10*/
.name = "tiny4412_eeprom", /*/dev目錄下文件名稱*/
.fops = &fops, /*文件操作接口*/
};
static int tiny4412_probe(struct i2c_client *client, const struct i2c_device_id *device_id)
{
printk("probe調(diào)用成功:%#X\n",client->addr);
eeprom_client=client;
/*1. 雜項設(shè)備的注冊函數(shù)*/
misc_register(&misc);
return 0;
}
static int tiny4412_remove(struct i2c_client *client)
{
/*2. 雜項設(shè)備的注銷函數(shù)*/
misc_deregister(&misc);
printk("remove調(diào)用成功.\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驅(qū)動端*/
i2c_add_driver(&drv);
printk("IIC驅(qū)動端: 驅(qū)動安裝成功\n");
return 0;
}
static void __exit tiny4412_drv_cleanup(void)
{
/*注銷IIC驅(qū)動端*/
i2c_del_driver(&drv);
printk("IIC驅(qū)動端: 驅(qū)動卸載成功\n");
}
module_init(tiny4412_drv_init); /*驅(qū)動入口--安裝驅(qū)動的時候執(zhí)行*/
module_exit(tiny4412_drv_cleanup); /*驅(qū)動出口--卸載驅(qū)動的時候執(zhí)行*/
MODULE_LICENSE("GPL"); /*設(shè)置模塊的許可證--GPL*/
3.2 EEPROM設(shè)備端代碼
#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, /*設(shè)備地址*/
};
static int __init tiny4412_drv_init(void)
{
/*根據(jù)總線編號獲取是適配器*/
adap=i2c_get_adapter(0);
/*注冊IIC設(shè)備端*/
i2c_dev=i2c_new_device(adap,&info);
printk("IIC設(shè)備端: 驅(qū)動安裝成功\n");
return 0;
}
static void __exit tiny4412_drv_cleanup(void)
{
/*注銷IIC設(shè)備*/
i2c_unregister_device(i2c_dev);
i2c_put_adapter(adap);
printk("IIC設(shè)備端: 驅(qū)動卸載成功\n");
}
module_init(tiny4412_drv_init); /*驅(qū)動入口--安裝驅(qū)動的時候執(zhí)行*/
module_exit(tiny4412_drv_cleanup); /*驅(qū)動出口--卸載驅(qū)動的時候執(zhí)行*/
MODULE_LICENSE("GPL"); /*設(shè)置模塊的許可證--GPL*/
3.3 應(yīng)用層測試代碼
#include
#include
#include
#include
#define EEPROM_DEV "/dev/tiny4412_eeprom"
int main(int argc,char **argv)
{
/*1. 打開設(shè)備文件*/
int fd=open(EEPROM_DEV,O_RDWR);
if(fd<0)
{
printf("%s 設(shè)備驅(qū)動打開失敗.\n",EEPROM_DEV);
return 0;
}
/*3.讀寫數(shù)據(jù)*/
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++)>
-
驅(qū)動
+關(guān)注
關(guān)注
12文章
1840瀏覽量
85289 -
EEPROM
+關(guān)注
關(guān)注
9文章
1020瀏覽量
81595 -
AT24C02
+關(guān)注
關(guān)注
0文章
79瀏覽量
24299
發(fā)布評論請先 登錄
相關(guān)推薦
評論