LINUX的IIC驅動從這開始(三)
這一篇主要是在友善的Smart210開發板上寫一個符合linux的iic驅動模型的裝置驅動程式,這樣能有一個更感性的認識。
開發環境介紹:
主機linux版本:fedora14
開發板:友善的Smart210
嵌入式linux版本:linux-3.0.8(友善光碟自帶的)
交叉編譯器:arm-linux-gcc-4.5.1(友善光碟自帶的)
硬體簡單介紹:
、
這是從友善的原理圖上截下的圖,這個圖沒有什麼複雜的,從圖可以看出來EEPROM是和s5pv210上的第0個iic介面卡連線的,但我是用第1個介面卡寫的,所以用線直接把介面卡1的引腳和EEPROM相連的,我這邊正好有這個專案需要,所以這樣寫了,你可以直接用介面卡0就行了,在寫驅動的時候我會說怎麼選iic介面卡0和iic介面卡1。
我們前面說過iic驅動模型是採用分層思想的,也即匯流排驅動和裝置驅動是分開的。那它們怎麼相互聯絡了?總得要一個什麼東西來做個匹配吧,就像以前的地下工作者,需要接頭暗號,要不然就亂套了,哈哈!iic匯流排和裝置之間是用名字做匹配的,那好了,那就先得把裝置的名字告訴匯流排吧,下面就是如何在總線上註冊裝置資訊了。
註冊裝置資訊
閱讀linux下的Documentation/i2c/instantiating-devices文件可以知道有兩種方式可以註冊,咱們只說前一種。開啟:linux-3.0.8/arch/arm/mach-s5pv210/mach-mini210.c這個.c檔案。就是在這個檔案中填寫咱們裝置的資訊的,這就是所說的bsp檔案。首先新增標頭檔案#include
<linux/i2c/at24.h>
static struct at24_platform_data at24c08 = {
.byte_len = SZ_8K / 8, //eeprom的容量大小(地址的總數)
.page_size = 16, //eeprom的一頁中包含的位元組數
};
然後新增如下的資訊,主要把eeprom的資訊包裝成符合iic模型中的裝置資訊的格式
static struct i2c_board_info i2c_devices[] __initdata = {
{
I2C_BOARD_INFO("at24c08b", 0x50), //後邊的0x50是eeprom的地址,可能有人說應該是0xa0,但linux中需要的是7bit的地址,所以向右移一位,正好是0x50。當然了,最終會在linux的iic的讀函式和寫函式中變成0xa0和0xa1的格式 .platform_data = &at24c08, }, };
最後在mini210_machine_init函式中把上面寫的資訊註冊到iic總線上
static void __init mini210_machine_init(void)
{
...
s3c_i2c2_set_platdata(&i2c2_data);
i2c_register_board_info(0, mini210_i2c_devs0,
ARRAY_SIZE(mini210_i2c_devs0));
//i2c_register_board_info(1, mini210_i2c_devs1,
//ARRAY_SIZE(mini210_i2c_devs1)); //把友善原來帶的遮蔽掉
i2c_register_board_info(1, i2c_devices, //仿照上面的新增如下的,主要這裡分為0、1和2,你可以修改介面卡0的,這樣不需要連線
ARRAY_SIZE(i2c_devices));
i2c_register_board_info(2, mini210_i2c_devs2,
ARRAY_SIZE(mini210_i2c_devs2));
...
}
這就算把裝置資訊註冊上了,重新編譯一下你的linux核心吧,然後把編譯好的核心燒進開發板,下面開始就是真真的驅動部分了。
裝置驅動編寫
首先咱們是用eeprom讀寫一些資料,資料量不會很大,所以它應該是個字元裝置,儘管它從iic驅動模型的角度說,是iic裝置,起始這並不矛盾。因為字元裝置裡包括了一部分的iic裝置,下面就是整個驅動了
#include<linux/module.h>
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/fs.h>
#include<asm/uaccess.h>
#include<linux/i2c.h>
#include<linux/miscdevice.h>
#include<linux/slab.h>
#include<linux/list.h>
#include<linux/delay.h>
#define DEVICE_NAME "at24c08"
//#define DEBUG
struct At24c08_dev
{
char name[30];
struct i2c_client *at24c08_client;
struct miscdevice at24c08_miscdev; //因為本身是一個字元裝置,所以定義成一個雜項裝置
unsigned short current_pointer;
};
struct At24c08_dev *At24c08_devp; //定義一個全域性的,因為結構體力裡面的atc08_client需要從probe函式中獲得
//open函式主要是把全域性的At24c08_devp賦給file檔案的私有資料,這樣在其他的函式中呼叫方便
static int at24c08_open(struct inode *inode,struct file *file){
file->private_data = At24c08_devp;
return 0;
}
//這就是雜項裝置的read方法,跟普通的雜項裝置的read方法沒什麼不一樣的,只是呼叫的i2c_read_byte_data用來實際傳輸資料
static ssize_t
at24c08_read(struct file *file,char *buf,size_t count,loff_t *ppos)
{
int i = 0;
int transferred = 0;
char value;
char my_buff[50];
struct At24c08_dev *dev = (struct At24c08_dev *)file->private_data;
dev->current_pointer = 0;
if(i2c_check_functionality(dev->at24c08_client->adapter,I2C_FUNC_SMBUS_READ_BYTE_DATA))
{
while(transferred < count)
{
msleep(10); //這裡一定注意,要不這個延時加上,因為cpu速度比較快,eeprom速度比較慢,所以不加會出問題,我除錯時就出問題了,後加的
value = i2c_smbus_read_byte_data(dev->at24c08_client,dev->current_pointer +i);
my_buff[i++] = value;
transferred ++;
}
if(!copy_to_user(buf,(void *)my_buff,transferred))
printk("The data copying from kernel to userspace success!\n");
else
printk("Mybe some errors has occured\n");
dev->current_pointer +=transferred;
}
return transferred;
}
//這就是註冊的雜項裝置的write方法
static ssize_t
at24c08_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
{
int i = 0;
int transferred = 0;
char my_buff[50];
struct At24c08_dev *dev = (struct At24c08_dev *)file->private_data;
dev->current_pointer = 0;
if(i2c_check_functionality(dev->at24c08_client->adapter,I2C_FUNC_SMBUS_BYTE_DATA))
{
if(!copy_from_user(my_buff,buf,count))
{
printk("The data copying from userspace to kernel success!\n");
while(transferred < count)
{
msleep(10);//與上面的read函式中的類似
i2c_smbus_write_byte_data(dev->at24c08_client,dev->current_pointer + i,my_buff[i]); //這個函式通過adapter的通訊方法把一個位元組的資料傳送 //到iic裝置中去
i ++;
transferred ++;
}
dev->current_pointer +=transferred;
}
else
printk("Mybe some errors has occured\n");
}
return transferred;
}
static const struct file_operations at24c08_fops ={
.owner = THIS_MODULE,
.open = at24c08_open,
.read = at24c08_read,
.write = at24c08_write,
};
//當把裝置掛接到總線上時,只有當at24c08b_id所起的名字和之前註冊到匯流排當中的名字一樣時,才會呼叫probe函式。在probe函式裡會分配i2c_client,通過這個//i2c_client,當呼叫註冊的字元裝置時,iic介面卡就知道把資料跟那個iic裝置互動。
static int __devinit at24c08b_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
int ret;
#ifdef DEBUG
printk("The routine of probe has started(for binding device)\n");
#endif
At24c08_devp = kmalloc(sizeof(struct At24c08_dev),GFP_KERNEL);
if(!At24c08_devp)
{
return ret = -ENOMEM;
}
memset(At24c08_devp,0,sizeof(struct At24c08_dev));
At24c08_devp->at24c08_client = client; //把分配的i2c_client賦給定義的全域性變數
At24c08_devp->at24c08_miscdev.minor = MISC_DYNAMIC_MINOR;
At24c08_devp->at24c08_miscdev.name = DEVICE_NAME;
At24c08_devp->at24c08_miscdev.fops = &at24c08_fops; //把雜項裝置的一些域用我們具體的方法定義
ret = misc_register(&At24c08_devp->at24c08_miscdev); //註冊雜項裝置
#ifdef DEBUG
printk("The driver of at24c08 has registered!\n");
#endif
return ret;
}
static int __devexit at24c08b_remove(struct i2c_client *client)
{
misc_deregister(&At24c08_devp->at24c08_miscdev);
#ifdef DEBUG
printk("The routine of remove has implemented!\n");
#endif
return 0;
}
static const struct i2c_device_id at24c08b_id[]={
{"at24c08",0},
{}
}; //當把裝置掛接到總線上時,就呼叫這裡面的名字和註冊在匯流排裡的名字比對,如果一樣就會呼叫probe函式,同時給掛接的裝置分配i2c_client結構體
MODULE_DEVICE_TABLE(i2c,at24c08b_id);
static struct i2c_driver at24c08b_driver = {
.driver = {
.name = "at24c08",
.owner=THIS_MODULE,
},
.probe = at24c08b_probe,
.remove=__devexit_p(at24c08b_remove),
.id_table =at24c08b_id,
};
static int __init at24c08b_init(void)
{
#ifdef DEBUG
printk(KERN_NOTICE"The driver of at24c08 is insmod!\n");
#endif
return i2c_add_driver(&at24c08b_driver); //把iic裝置掛接到總線上
}
void at24c08b_exit(void)
{
#ifdef DEBUG
printk(KERN_NOTICE"at24c0b is rmmod!\n");
#endif
i2c_del_driver(&at24c08b_driver); //把iic裝置移除,這時會呼叫remove函式,所以在remove函式中一般會幹一些登出裝置的工作等
}
MODULE_DESCRIPTION("at24c08b eeprom driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("xie yingdong");
module_init(at24c08b_init);
module_exit(at24c08b_exit);
上面就是完整的eeprom驅動,當然驅動寫完了,需要寫個簡單的Makefile來編譯這個驅動,好吧,下面就是Makefile檔案的內容
obj-m:=eeprom-driver.o
KDIR = /tmp/linux-3.0.8 //這裡需要你根據自己的實際的linux原始碼放的位置來設定
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
@rm -rf eeprom-driver*.o
上面的Makefile檔案很是簡單,就不做過多的解釋了。當把驅動編譯好了,用動態的方式掛載到了linux核心上後,你還得做個簡單的測試程式,來驗證咱們寫的驅動工作是否正常,下面就直接貼出來吧。
#include<stdio.h>
#include<linux/types.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/types.h>
int main(void)
{
int i;
char value[19] = "eeprom-driver test!";
char backvalue[19];
int fd;
fd = open("/dev/at24c08",O_RDWR); //這裡的名字一定要和驅動裡註冊的雜項裝置的名字一樣,但跟iic裝置的名字無關,這裡只是正好取的一樣而已
if(fd<0){
printf("Open at24c08 device failed!\n");
exit(1);
}
write(fd,value,19);
printf("The string writing to eeprom : %s\n",value);
printf("##################################################\n");
sleep(1);
read(fd,backvalue,19);
printf("The string reading from eeprom : %s\n",backvalue);
close(fd);
return 0;}
哈哈,驅動就寫完了,我自己測試了,沒問題,你可以試試,下一篇我們會分析iic匯流排驅動。
相關推薦
LINUX的IIC驅動從這開始(三)
這一篇主要是在友善的Smart210開發板上寫一個符合linux的iic驅動模型的裝置驅動程式,這樣能有一個更感性的認識。 開發環境介紹: 主機linux版本:fedora14 開發板:友善的Smart210 嵌入式linux版本:linux-3.0.8(友善光碟自帶的)
LINUX的IIC驅動從這開始(四)
轉載地址:http://blog.csdn.net/xie0812/article/details/24291153 首先這篇文章主要介紹IIC匯流排的實現過程,怎麼說了,本人也是一個小菜鳥,可能有許多錯誤在裡面,如有大神發現,請指出來,多謝多謝! 注意:平臺還是和前面的一
Git從零開始(三)
16px pop 普通 遠程服務 git clone one img 分享 模式 一、遠程倉庫管理 1、將本地內容推送到遠程庫 先關聯遠程庫,執行命令: git remote add origin https://github.com/Hollydan/gitsto
Java基礎總結從0開始(三):Java反射原理
反射:Java虛擬機器允許執行時獲取類的資訊。 2.1 反射的常用方法: a.forName(String className) : 返回與帶有給定字串名的類或介面相關聯的 Class 物件。 b.forName(String
Hyperledger Fabric 1.0 從零開始(三)——環境構建(內網/準離線)
1:環境構建與測試 在本文中用到的宿主機環境是Centos ,版本為Centos.x86_647.2,通過Docker 容器來執行Fabric的節點,版本為v1.0。因此,啟動Fabric網路中的節點需要先安裝Docker、Docker-compose和Go語言環境,然後在網上拉取相關的Docker映象
JVM從零開始(三)-常用垃圾回收器及原理
一、垃圾回收器有哪些 由於有些年輕代和老年代回收器無法相容,一般使用都是用以下四個組合。 檢視命令 java -XX:+Print
驅動開發 —— 從零開始(1) 配置vs20xx+wdkxx+winX環境並附錄常見問題解決方式
網上教程很多、如何去安裝如何去配置 但是也有些坑感覺並不是那麼的完善 wdk+vs下載連結:https://docs.microsoft.com/zh-cn/windows-hardware/drivers/download-the-wdk 只要wdk版本與sdk版本對應就行,不用在意是vs20xx 我這邊以
Kotlin開發基礎從0開始(一)
code ... 多說 lang 學習 function ria lis lac 為什麽學習kotlin kotlin在今年的Google IO 上正式被確認為Android的官方開發語言,想必原因大家也能猜到一二,一是Google與oracle關於Java相關的版權相關的
Hyperledger Fabric 1.0 從零開始(二)——公網環境構建
1.3 項目 htm move 自己 lvm2 fast 情況 tor 1:環境構建 在本文中用到的宿主機環境是Centos ,版本為Centos.x86_647.2,通過Docker 容器來運行Fabric的節點,版本為v1.0。因此,啟動Fabric網絡中的節點需要先安
Hyperledger Fabric 1.0 從零開始(六)——創建Fabric多節點集群
_id 測試 es2017 xtra 去掉 compose 多個 服務 執行命令 4:創建Fabric多節點集群 4.1、配置說明 首先可以根據官方Fabric自帶的e2e_cli列子中的集群方案來生成我們自己的集群,與案例不同的是我們需要把容器都分配到不同的服務器上,彼此
Mysql存儲過程從0開始(上)
mysql存儲過程1、首先你要明白,mysql也是一種語言,他也可以編寫程序,也是支持邏輯判斷,if,elseif,else,switch,while等等的判斷2、mysql賦值一個變量的值操作:set @a = 1; 查看這個變量為select @a;3、當你創建存儲過程的時候你要先選擇Mysql的數據庫,
[深度學習]實現一個博弈型的AI,從五子棋開始(1)
com class svm 顏色 display 深度 images += have 好久沒有寫過博客了,多久,大概8年???最近重新把寫作這事兒撿起來……最近在折騰AI,寫個AI相關的給團隊的小夥伴們看吧。 搞了這麽多年的機器學習,從分
docker從零開始(二)容器初體驗
osi build 技術分享 框架 log 註冊表 代碼 content doc 使用定義容器 Dockerfile Dockerfile定義容器內所需要的環境。對網絡接口和磁盤驅動器等資源的訪問在此環境中進行虛擬化,該環境與系統的其他部分隔離,因此您需要將端口映射到外部
docker從零開始(五)堆棧初體驗,stacks
開始 services 信息 工作 run cer cal tail int 先決條件 安裝Docker 1.13或更高版本。 獲取Docker Compose,請參考第三節 按照第四節中的描述獲取Docker Machine。 在第二節中了解如何創建容器。
【視訊】Kubernetes1.12從零開始(六):從程式碼編譯到自動部署
作者: 李佶澳 轉載請保留:原文地址 釋出時間:2018/11/10 16:14:00 說明 kubefromscratch-ansible和kubefromscratch介紹 使用前準備
Centos Docker 從零開始(2)之 mssql 的資料庫檔案儲存在主機
Docker mmsql新建資料庫如果能夠把資料庫檔案儲存在主機上就好了,centos好像可以掛載的 docker 的 run 命令: -v ~/nginx/www:/www :將主機中專案的目錄www掛載到容器的/www 準備命令一下: docker run -e
從新撿起c++,從stl開始(1)
容器包括關聯容器和順序容器。 關聯容器是通過鍵(key)儲存和讀取元素的,而順序容器則通過元素在容器中的位置順序儲存和訪問元素。 順序容器包括:vector list deque等,vector是表示一串連續的記憶體地址,基於陣列實現. list是不連續的記憶體地
從新撿起c++,從stl開始(2)
list: list類似於連結串列,它的儲存空間不是連續的,但是可以快速的插入和刪除,但是隨機訪問比較慢。 assign() 給list賦值 back()返回最後一個元素 begin()返回指向第一個元素的迭代器 clear() 清空li
Spring Cloud從0開始(二)服務治理:Spring Clound Eureka
一 . 完成一個Eureka(服務端)專案 1.登入網址 https://start.spring.io/ 選擇需要的依賴 -> Eureka Server 解壓至本地 2.通過IDEA 以Maven專案匯入。 (1)添加註解@EnableEurekaS
Hyperledger Fabric 1.0 從零開始(五)——執行測試e2e
3:執行測試e2e 3.1、執行fabric-samples的問題說明 該問題說明能夠解決6.1、平臺特定使用的二進位制檔案配置第一步的問題。可以選擇繼續閱讀該說明,或者等參考到6.1小節時再反向閱讀本說明,具體在6.1中會重新指向本步驟。 一般情況下,我們會參照官網來完成第一個網路測試,在該線上文件中會讓我