《RV1126 —— 配置adc並讀取adc通道上傳感器數值》


1.adc設備樹配置

  一般來說,rk中已經封裝好了標准adc的dts參數屬性,我們要做的就是添加自己的adc通道,並引用標准接口即可,不同平台,標准dts中的adc節點名有所不同,其配置屬性基本一樣。

  例如:
   1)adc: adc@ff100000 {
        compatible = "rockchip,saradc";
        ......
        };
   2)saradc: saradc@ff100000 {
        compatible = "rockchip,saradc";
        ......
        };

  添加自己的dts通道:(在系統對應的dts中添加)

adc_name{                                     //自定義節點名
      compatible = "adc_name";            //匹配驅動的屬性字符串,可以與節點名不同
      io-channels = <&saradc(&adc) 2>;   //設定我們需要讀取的adc通道,參考硬件原理圖,其中&表示應用系統封裝的標准dts配置,需要系統標准的adc節點名,保證與本系統的一致,這里我們設定的為adc通道2
      io-channel-names = "adc2"           //自己取的名字,后續iio_channel_get的第二個參數會使用到這個參數
      status = "okay";                    //設備節點狀態
      };

  

  由於我使用的是RV1109板卡,使用的是rv1126.dtsi。

   可以看到已經配置好了。

  再rv1126-evb-v10.dtsi中使能saradc,並配置基准電壓(這個根據自身硬件決定)。

 

 2.adc內核配置

  直接在kernel中make ARCH=arm menuconfig,查找saradc。

  然后編譯下載到板卡上。

 

3.編寫光敏驅動

3.1 查看光敏在adc的通道幾

   可以看到lightsensor是在通道2。

3.2 配置設備樹

 3.3 編寫light sensor驅動

  其中主要注意iio_channel_get(&(pdev->dev), "adc2")和iio_read_channel_raw(chan, &raw),作用分別是獲取adc通道以及獲取adc原始數據。

#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/moduleparam.h>
#include <linux/stat.h>
 
#include <linux/init.h>
#include <linux/module.h> 
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/adc.h>
 
#include <linux/version.h>
 
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <asm/io.h>
 
#include <linux/iio/iio.h>
#include <linux/iio/machine.h>
#include <linux/iio/driver.h>
#include <linux/iio/consumer.h>

#include <linux/uaccess.h>

#define GPIO_LOW 0
#define GPIO_HIGH 1
int major;
int count;
 
static struct class *cls;
struct iio_channel *chan;

static int light_sensor_open(struct inode *inode, struct file *file)
{
	printk(KERN_EMERG "%s-%d: enter\n",__FUNCTION__,__LINE__);
	return 0;	
}
 
static ssize_t light_sensor_read(struct file *filp,char *buf,size_t len,loff_t *off)
{
	int raw;
	int ret = -1;
	int result = 20;

	ret = iio_read_channel_raw(chan, &raw); 
	if (ret < 0) 
	{
		printk("read hook adc channel() error: %d\n", ret);
		return 0;
	}

	result = (1800*raw)/1023;
	ret = copy_to_user(buf, &result, len);	
	
	return 1;
}

static struct file_operations adc_fops = {
    .owner  =   THIS_MODULE,   
    .open   =   light_sensor_open,  
	.read   =  light_sensor_read,   	   
};
 
static int adc_probe(struct platform_device *pdev)
{
	printk(KERN_EMERG "%s-%d: enter\n",__FUNCTION__,__LINE__);
	
    major = register_chrdev(0, "light_sensor", &adc_fops);
	cls = class_create(THIS_MODULE, "light_sensor");
	device_create(cls, NULL, MKDEV(major, 0), NULL, "light_sensor"); 
	chan = iio_channel_get(&(pdev->dev), "adc2");
	if (IS_ERR(chan))
 	{
		chan = NULL;
		return -1;
	}
	return 0;  
}
 
 
static int adc_remove(struct platform_device *pdev)
{ 
	printk(KERN_INFO "Enter %s\n", __FUNCTION__);
	iio_channel_release(chan);
	device_destroy(cls, MKDEV(major, 0));
	class_destroy(cls);
	unregister_chrdev(major, "light_sensor");
    return 0;
}
static const struct of_device_id of_adc_match[] = {
	{ .compatible = "light_sensor" },
	{ /* Sentinel */ }
};
static struct platform_driver adc_driver = {
	.probe		= adc_probe,
	.remove		= adc_remove,
	.driver		= {
		.name	= "light_sensor",
		.owner	= THIS_MODULE,
		.of_match_table	= of_adc_match,
	},
};
 
static int __init adc_init(void)
{
	printk("init light_sensor driver");
    return platform_driver_register(&adc_driver);
    return 0;
}
 
static void __exit adc_exit(void)
{
	platform_driver_unregister(&adc_driver);
    printk(KERN_INFO "Exit light sensor driver\n");
}
module_init(adc_init);
module_exit(adc_exit);
MODULE_LICENSE("GPL");

  將以上源碼保存為 drivers/iio/adc/light_sensor.c ,並在 drivers/iio/adc/Makefile 后加入

obj-$(CONFIG_LIGHT_SENSOR) += light_sensor.o

  在drivers/iio/adc/Kconfig中添加:

config LIGHT_SENSOR
        tristate "light sensor config"

  最后在make ARCH=arm menuconfig配置選擇LIGHT_SENSOR。編譯下載到板卡。

   可以到對應的設備節點。

4.獲取光敏的數值

通過用戶態接口獲取adc值,其中*表示adc第多少通道:

cat /sys/bus/iio/devices/iio\:device0/in_voltage*_raw

  由於我們是使用的通道2

  其中數值就改變了。

5.adc相關api

struct iio_channel *iio_channel_get(struct device *dev, const char *consumer_channel); 
  • 功能:獲取 iio 通道描述

  • 參數:

    • dev: 使用該通道的設備描述指針

    • consumer_channel: 通道名稱

void iio_channel_release(struct iio_channel *chan); 
  • 功能:釋放 iio_channel_get 函數獲取到的通道

  • 參數:

    • chan:要被釋放的通道描述指針

int iio_read_channel_raw(struct iio_channel *chan, int *val); 
  • 功能:讀取 chan 通道 AD 采集的原始數據。

  • 參數:

    • chan:要讀取的采集通道指針

    • val:存放讀取結果的指針

 

6.計算采集到的電壓

使用標准電壓將 AD 轉換的值轉換為用戶所需要的電壓值。其計算公式如下:

Vref / (2^n-1) = Vresult / raw 

注: Vref 為標准電壓 n 為 AD 轉換的位數 Vresult 為用戶所需要的采集電壓 raw 為 AD 采集的原始數據 例如,標准電壓為 1.8V,AD 采集位數為 10 位,AD 采集到的原始數據為 568,則:

Vresult = (1800mv * 568) / 1023;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM