《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;

 

posted @ 2021-09-29 16:05  一个不知道干嘛的小萌新  阅读(2195)  评论(2编辑  收藏  举报