0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Linux驅(qū)動開發(fā)-編寫(EEPROM)AT24C02驅(qū)動

DS小龍哥-嵌入式技術(shù) ? 2022-09-17 15:29 ? 次閱讀

【摘要】 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一樣的),原理圖如下:

image-20220104085514044image-20220104085817035

自帶的內(nèi)核里沒有內(nèi)置EEPROM的驅(qū)動:

image-20220104085843239

存儲芯片的數(shù)據(jù)手冊介紹:

image-20220104090012199

設(shè)備地址:

image-20220104090059967

寫字節(jié)、頁寫時序:

image-20220104090126403

讀數(shù)據(jù)時序:

image-20220104090200161

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++)>
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 驅(qū)動
    +關(guān)注

    關(guān)注

    12

    文章

    1840

    瀏覽量

    85289
  • EEPROM
    +關(guān)注

    關(guān)注

    9

    文章

    1020

    瀏覽量

    81595
  • AT24C02
    +關(guān)注

    關(guān)注

    0

    文章

    79

    瀏覽量

    24299
收藏 人收藏

    評論

    相關(guān)推薦

    數(shù)據(jù)保存100年!納祥科技國產(chǎn)EEPROM芯片NX24C02A,兼容替代AT24C02

    NAXIANGTECHNOLOGY納祥科技NX24C02AEEPROMEEPROM(ElectricallyErasableProgrammablereadonlymemory),帶電
    的頭像 發(fā)表于 11-14 01:08 ?434次閱讀
    數(shù)據(jù)保存100年!納祥科技國產(chǎn)<b class='flag-5'>EEPROM</b>芯片NX<b class='flag-5'>24C02</b>A,兼容替代<b class='flag-5'>AT24C02</b>

    linux內(nèi)核中通用HID觸摸驅(qū)動

    linux內(nèi)核中,為HID觸摸面板實現(xiàn)了一個通用的驅(qū)動程序,位于/drivers/hid/hid-multitouch.c文件中。hid觸摸驅(qū)動是以struct hid_driver
    的頭像 發(fā)表于 10-29 10:55 ?601次閱讀
    <b class='flag-5'>linux</b>內(nèi)核中通用HID觸摸<b class='flag-5'>驅(qū)動</b>

    用于TM4C129x器件的高耐用性EEPROM仿真驅(qū)動

    電子發(fā)燒友網(wǎng)站提供《用于TM4C129x器件的高耐用性EEPROM仿真驅(qū)動器.pdf》資料免費下載
    發(fā)表于 09-19 10:38 ?0次下載
    用于TM4<b class='flag-5'>C</b>129x器件的高耐用性<b class='flag-5'>EEPROM</b>仿真<b class='flag-5'>驅(qū)動</b>器

    英銳芯AD24C02_16-Byte(中性)

    AD24C02是一款串行電可擦除編程只讀存儲器(EEPROM)。存儲器可存儲256個字節(jié)數(shù)據(jù),分為16頁 每頁16字節(jié),隨機字尋址需要8位數(shù)據(jù)字地址,具有低功耗CMOS技術(shù),自定時編程周期
    發(fā)表于 09-09 15:08 ?0次下載

    探索存儲新未來:為何EVASH EV24C256A EEPROM成為市場新寵

    探索存儲新未來:為何EVASH EV24C256A EEPROM成為市場新寵
    的頭像 發(fā)表于 09-05 15:31 ?338次閱讀

    linux系統(tǒng)的設(shè)備驅(qū)動一般分幾類

    Linux系統(tǒng)的設(shè)備驅(qū)動是操作系統(tǒng)與硬件設(shè)備之間的橋梁,負責實現(xiàn)操作系統(tǒng)與硬件設(shè)備之間的通信和控制。Linux系統(tǒng)的設(shè)備驅(qū)動可以分為以下幾類: 字符設(shè)備
    的頭像 發(fā)表于 08-30 15:13 ?433次閱讀

    Linux設(shè)備驅(qū)動程序分類有哪些

    Linux設(shè)備驅(qū)動程序是操作系統(tǒng)與硬件設(shè)備之間的橋梁,負責實現(xiàn)硬件設(shè)備與操作系統(tǒng)之間的通信和控制。Linux設(shè)備驅(qū)動程序的分類繁多,可以根據(jù)不同的標準進行分類。 按硬件類型分類
    的頭像 發(fā)表于 08-30 15:11 ?565次閱讀

    linux驅(qū)動程序如何加載進內(nèi)核

    Linux系統(tǒng)中,驅(qū)動程序是內(nèi)核與硬件設(shè)備之間的橋梁。它們允許內(nèi)核與硬件設(shè)備進行通信,從而實現(xiàn)對硬件設(shè)備的控制和管理。 驅(qū)動程序的編寫 驅(qū)動
    的頭像 發(fā)表于 08-30 15:02 ?467次閱讀

    linux驅(qū)動程序的編譯方法有哪兩種

    Collection)或其他C/C++編譯器來編譯源代碼文件。這種方法較為原始,需要開發(fā)者手動指定編譯器選項、包含路徑、庫文件等。然而,在Linux
    的頭像 發(fā)表于 08-30 14:39 ?679次閱讀

    Linux 驅(qū)動開發(fā)與應(yīng)用開發(fā),你知道多少?

    一、Linux驅(qū)動開發(fā)與應(yīng)用開發(fā)的區(qū)別開發(fā)層次不同:Linux
    的頭像 發(fā)表于 08-30 12:16 ?789次閱讀
    <b class='flag-5'>Linux</b> <b class='flag-5'>驅(qū)動</b><b class='flag-5'>開發(fā)</b>與應(yīng)用<b class='flag-5'>開發(fā)</b>,你知道多少?

    玩轉(zhuǎn)STM32和EV24C MCU + EEPROM ST + EVASH

    STM32開發(fā)板(如STM32F103C8T6) EVASH EV24C256A EEPROM開發(fā)套件 連接線(杜邦線) 基本電子工具(烙
    的頭像 發(fā)表于 07-01 09:58 ?483次閱讀

    EVASH Ultra EEPROM 開發(fā)板使用說明書 簡介

    EVASH Ultra EEPROM 開發(fā)板使用說明書 簡介 歡迎使用EVASH Ultra EEPROM開發(fā)板使用說明書。本說明書將為您提供使用搭載EV
    的頭像 發(fā)表于 07-01 09:39 ?495次閱讀

    【GD32F303紅楓派開發(fā)板使用手冊】第二十一講 I2C-EEPROM讀寫實驗

    21.1 實驗內(nèi)容 通過本實驗主要學習以下內(nèi)容: ?AT24C16 EEPROM的工作原理; ?IIC模塊原理以及IIC驅(qū)動原理。
    的頭像 發(fā)表于 06-21 10:23 ?899次閱讀
    【GD32F303紅楓派<b class='flag-5'>開發(fā)</b>板使用手冊】第二十一講  I2<b class='flag-5'>C-EEPROM</b>讀寫實驗

    stm8s103k與AT24C02的iic通信不穩(wěn)定是什么原因?qū)е碌模?/a>

    stm8s103k與AT24C02的iic通信不穩(wěn)定,有時可以讀取數(shù)據(jù),有時讀不出 是什么原因? 有人與ADS1110用iic通信過嗎?
    發(fā)表于 04-30 07:33

    STM32F103用普通IO口驅(qū)動24C02,讀寫不正確的原因?

    以下24C02驅(qū)動好像不穩(wěn)定,不更換24C02時,讀寫都正確,但是更換一個24C02,數(shù)據(jù)就讀寫不正確,在把之前的正常的24C02重新焊上
    發(fā)表于 04-19 06:12