下面是PCF8591的介紹:
PCF8591 是一個單片集成、單獨供電、低功耗、8-bit CMOS數(shù)據(jù)獲取器件。PCF8591 具有 4 個模擬輸入、1 個模擬輸出和 1個串行 I2C 總線接口。PCF8591 的 3 個地址引腳 A0, A1 和 A2 可用于硬件地址編程,允許在同個 I2C 總線上接入 8 個 PCF8591 器件,而無需額外的硬件。在 PCF8591 器件上輸入輸出的地址、控制和數(shù)據(jù)信號都是通過雙線雙向 I2C 總線以串行的方式進(jìn)行傳輸。
下圖是PCF8591的框圖
本篇討論其linux驅(qū)動的以下幾種實現(xiàn)方式
- Hardware Monitoring framework (hwmon)
- 雜項字符設(shè)備 (misc)
- 通過memmap, IOmap在用戶空間直接操作processor i2c
- Industrial IO framework (iio)
通過hwmon框架實現(xiàn)
在linux中已經(jīng)支持通過hwmon框架方式實現(xiàn)pcf8591驅(qū)動的代碼。
下面只貼出部分代碼,具體請參見鏈接
static int pcf8591_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pcf8591_data *data;
int err;
data = devm_kzalloc(&client- >dev, sizeof(struct pcf8591_data),
GFP_KERNEL);
if (!data)
return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data- >update_lock);
/* Initialize the PCF8591 chip */
pcf8591_init_client(client);
/* Register sysfs hooks */
err = sysfs_create_group(&client- >dev.kobj, &pcf8591_attr_group);
if (err)
return err;
/* Register input2 if not in "two differential inputs" mode */
if (input_mode != 3) {
err = device_create_file(&client- >dev, &dev_attr_in2_input);
if (err)
goto exit_sysfs_remove;
}
/* Register input3 only in "four single ended inputs" mode */
if (input_mode == 0) {
err = device_create_file(&client- >dev, &dev_attr_in3_input);
if (err)
goto exit_sysfs_remove;
}
data- >hwmon_dev = hwmon_device_register(&client- >dev);
if (IS_ERR(data- >hwmon_dev)) {
err = PTR_ERR(data- >hwmon_dev);
goto exit_sysfs_remove;
}
return 0;
exit_sysfs_remove:
sysfs_remove_group(&client- >dev.kobj, &pcf8591_attr_group_opt);
sysfs_remove_group(&client- >dev.kobj, &pcf8591_attr_group);
return err;
}
static const struct i2c_device_id pcf8591_id[] = {
{ "pcf8591", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8591_id);
static struct i2c_driver pcf8591_driver = {
.driver = {
.name = "pcf8591",
},
.probe = pcf8591_probe,
.remove = pcf8591_remove,
.id_table = pcf8591_id,
};
static int __init pcf8591_init(void)
{
if (input_mode < 0 || input_mode > 3) {
pr_warn("invalid input_mode (%d)n", input_mode);
input_mode = 0;
}
return i2c_add_driver(&pcf8591_driver);
}
static void __exit pcf8591_exit(void)
{
i2c_del_driver(&pcf8591_driver);
}
MODULE_AUTHOR("Aurelien Jarno < [email protected] >");
MODULE_DESCRIPTION("PCF8591 driver");
MODULE_LICENSE("GPL");
module_init(pcf8591_init);
module_exit(pcf8591_exit);
在編譯內(nèi)核modules需要把模塊添加進(jìn)去,或者單獨編譯好模塊再復(fù)制到樹莓派版中。
下圖為通過menuconfig配置模塊: 圖中“Philips PCF8591 ADC/DAC"選項
安裝模塊驅(qū)動
sudo insmod pcf8591.ko
安裝后可以在sysfs下查看,/sys/bus/i2c/drivers下多了一個pcf8591, 見下圖:
文中提到了hwmon設(shè)備常通過i2cbus探測的方式。但是我們卻可以看到pcf8591.c中并沒有detect函數(shù):
static struct i2c_driver pcf8591_driver = {
.driver = {
.name = "pcf8591",
},
.probe = pcf8591_probe,
.remove = pcf8591_remove,
.id_table = pcf8591_id,
};
這是因為pcf8591沒有“制造商和設(shè)備ID寄存器”。
因此我們可以通過方式1,方式2和方式4
- 方法1:靜態(tài)聲明I2C設(shè)備
- 通過devicetree聲明I2C設(shè)備
- 在板級文件中聲明I2C設(shè)備
- 方法2:顯式實例化設(shè)備
- 方法3:對某些設(shè)備進(jìn)行I2C總線探測
- 方法4:從用戶空間實例化
為了避免麻煩,這里就選擇方法4。
先查看地址,然后通過sysfs, new_device的方式實例化(參見上篇)
實例化成功后,如上圖,便可以通過sysfs來獲取adc的值,以及設(shè)置dac的值。
cat /sys/class/hwmon/hwmon1/device/in0_input
**misc驅(qū)動框架實現(xiàn) **
misc的意思是混合、雜項的,因此MISC驅(qū)動也叫做雜項驅(qū)動,也就是當(dāng)我們板子上的某些外設(shè)無法進(jìn)行分類的時候就可以使用MISC驅(qū)動。misc設(shè)備也是一個字符設(shè)備,在misc的初始化函數(shù)中注冊了一個字符設(shè)備,主設(shè)備號為MISC_MAJOR (10)。
驅(qū)動分為兩部分:i2c設(shè)備驅(qū)動,i2c設(shè)備顯式實例化
在i2c設(shè)備顯示實例化中調(diào)用,i2c_new_probed_device函數(shù)
i2c_new_probed_device(i2c_adap,&i2c_info,i2c_addr_list,NULL);
在某些設(shè)備中,比如需要后期插入i2c模塊板,而預(yù)先不知道I2C總線的編號,則可以顯式地實例化I2C設(shè)備。這是通過填充結(jié)構(gòu)體i2c_board_info并調(diào)用i2c_new_client_device()來完成。
如下圖,分別將,i2c設(shè)備驅(qū)動,i2c設(shè)備顯式實例化,編譯成pcf8591.ko 和pcf8591_dev.ko, 然后通過Insmod加載
再另外編寫應(yīng)用代碼,open misc設(shè)備,進(jìn)行讀寫操作。
通過memmap, IOmap在用戶空間直接操作processor i2c
樹莓派的一些庫,如bcm2835, wiringpi等
/* Open the master /dev/mem device */
if ((memfd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0)
{
fprintf(stderr, "bcm2835_init: Unable to open /dev/mem: %sn",
strerror(errno)) ;
goto exit;
}
/* Base of the peripherals block is mapped to VM */
bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd, (off_t)bcm2835_peripherals_base);
if (bcm2835_peripherals == MAP_FAILED) goto exit;
/* Now compute the base addresses of various peripherals,
// which are at fixed offsets within the mapped peripherals block
// Caution: bcm2835_peripherals is uint32_t*, so divide offsets by 4
*/
bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE/4;
bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM/4;
bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE/4;
bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS/4;
bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE/4;
bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4; /* I2C */
bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; /* I2C */
bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4;
bcm2835_aux = bcm2835_peripherals + BCM2835_AUX_BASE/4;
bcm2835_spi1 = bcm2835_peripherals + BCM2835_SPI1_BASE/4;
效率比較
下圖為使用misc設(shè)備驅(qū)動,在應(yīng)用代碼中進(jìn)行1ms采樣時,cpu的占用率5.2%。
而使用bcm2835庫進(jìn)行10ms周期的采樣時,cpu的占用率52.1%。
IIO
IIO 全稱是 Industrial I/O,當(dāng)你使用的傳感器本質(zhì)是 ADC 或 DAC 器件的時候,可以優(yōu)先考慮使用 IIO 驅(qū)動框架。比如常用的陀螺儀、加速度計、電壓/電流測量芯片、光照傳感器、壓力傳感器等內(nèi)部都是有個 ADC,內(nèi)部 ADC 將原始的模擬數(shù)據(jù)轉(zhuǎn)換為數(shù)字量,然后通過其他的通信接口,比如 IIC、SPI 等傳輸給 SOC。Linux 內(nèi)核為了管理這些日益增多的 ADC 類傳感器,特地推出了 IIO 子系統(tǒng)。
iio 支持多種標(biāo)準(zhǔn)的 Linux 設(shè)備訪問接口:char device, sysfs, configfs, debugfs。
IIO的4種接口
1). sysfs interface
- /sys/bus/iio/devices/iio:deviceX;
- 可用于配置 /dev/iio:deviceX 接口的 events / data
- 可用于輪循的方式低速地直接讀/寫 IIO 設(shè)備;
- Documentation/ABI/testing/sysfs-bus-iio;
2). character device
- /dev/iio:deviceX,該接口在 IIO 子系統(tǒng)里是可選非必要的;
- 標(biāo)準(zhǔn)的文件 IO API: open(), read(), write(), close().
- 用于讀取 events 和 data;
3). configfs
- 用于配置額外的 IIO 特性,例如:軟件 triggers 或者 hrtimer triggers;
- 詳細(xì)說明:
- Documentation/ABI/testing/configfs-iio;
- Documentation/iio/iio_configfs.txt;
4). debugfs
- 一些調(diào)試功能,例如 direct_reg_access 節(jié)點可用于讀寫寄存器;
具體的代碼實現(xiàn)便不再花時間了,可以參考drivers下iio部分代碼。
-
adc
+關(guān)注
關(guān)注
99文章
6537瀏覽量
545880 -
CMOS器件
+關(guān)注
關(guān)注
0文章
71瀏覽量
11575 -
DAC芯片
+關(guān)注
關(guān)注
1文章
32瀏覽量
14719 -
Linux驅(qū)動
+關(guān)注
關(guān)注
0文章
43瀏覽量
10026 -
樹莓派
+關(guān)注
關(guān)注
117文章
1710瀏覽量
105897 -
PCF8591芯片
+關(guān)注
關(guān)注
2文章
8瀏覽量
7395
發(fā)布評論請先 登錄
相關(guān)推薦
PCF8591 DA轉(zhuǎn)換
藍(lán)橋杯單片機(jī)——PCF8591 ADC/DAC模塊 精選資料分享
PCF8591是什么?怎樣去設(shè)計PCF8591電路?
怎樣通過pcf8591芯片實現(xiàn)AD/DA轉(zhuǎn)換
PCF8591 ADC和DAC芯片的數(shù)據(jù)手冊免費下載
![<b class='flag-5'>PCF8591</b> <b class='flag-5'>ADC</b>和<b class='flag-5'>DAC</b><b class='flag-5'>芯片</b>的數(shù)據(jù)手冊免費下載](https://file.elecfans.com/web1/M00/9C/FA/pIYBAF0sH6CAADs6AADde0L-3pE499.png)
微雪電子ADC DAC AD DA轉(zhuǎn)換PCF8591 PCF8591T簡介
![微雪電子<b class='flag-5'>ADC</b> <b class='flag-5'>DAC</b> AD DA轉(zhuǎn)換<b class='flag-5'>PCF8591</b> <b class='flag-5'>PCF8591</b>T簡介](https://file.elecfans.com/web1/M00/AC/7D/o4YBAF3CyICAThueAAD2PWM0dXQ952.jpg)
藍(lán)橋杯單片機(jī)——PCF8591 ADC/DAC模塊
![藍(lán)橋杯單片機(jī)——<b class='flag-5'>PCF8591</b> <b class='flag-5'>ADC</b>/<b class='flag-5'>DAC</b>模塊](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
將PCF8591 ADC與Arduino連接的方法
![將<b class='flag-5'>PCF8591</b> <b class='flag-5'>ADC</b>與Arduino連接的方法](https://file.elecfans.com/web2/M00/65/57/pYYBAGMIc0WAfJd_AAJ9DnUtkdw274.png)
Linux驅(qū)動開發(fā)-編寫PCF8591(ADC)芯片驅(qū)動
![<b class='flag-5'>Linux</b><b class='flag-5'>驅(qū)動</b>開發(fā)-編寫<b class='flag-5'>PCF8591</b>(<b class='flag-5'>ADC</b>)<b class='flag-5'>芯片</b><b class='flag-5'>驅(qū)動</b>](https://file.elecfans.com//web2/M00/6A/5A/poYBAGMlQ2uAMeYsAAiIJeXIEL0907.png)
評論