0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

ADC/DAC芯片pcf8591的linux驱动的几种实现方案

冬至子 来源:嵌入式ABC 作者:小鱼 2023-10-17 11:14 次阅读

下面是PCF8591的介绍:

PCF8591 是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591 具有 4 个模拟输入、1 个模拟输出和 1个串行 I2C 总线接口。PCF8591 的 3 个地址引脚 A0, A1 和 A2 可用于硬件地址编程,允许在同个 I2C 总线上接入 8 个 PCF8591 器件,而无需额外的硬件。在 PCF8591 器件上输入输出的地址、控制和数据信号都是通过双线双向 I2C 总线以串行的方式进行传输。

下图是PCF8591的框图

图片

本篇讨论其linux驱动的以下几种实现方式

  • Hardware Monitoring framework (hwmon)
  • 杂项字符设备 (misc)
  • 通过memmap, IOmap在用户空间直接操作processor i2c
  • Industrial IO framework (iio)

通过hwmon框架实现

在linux中已经支持通过hwmon框架方式实现pcf8591驱动的代码。

下面只贴出部分代码,具体请参见链接

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 < aurelien@aurel32.net >");
MODULE_DESCRIPTION("PCF8591 driver");
MODULE_LICENSE("GPL");


module_init(pcf8591_init);
module_exit(pcf8591_exit);

图片

在编译内核modules需要把模块添加进去,或者单独编译好模块再复制到树莓派版中。

下图为通过menuconfig配置模块: 图中“Philips PCF8591 ADC/DAC"选项

图片

安装模块驱动

sudo insmod pcf8591.ko

安装后可以在sysfs下查看,/sys/bus/i2c/drivers下多了一个pcf8591, 见下图:

图片

文中提到了hwmon设备常通过i2cbus探测的方式。但是我们却可以看到pcf8591.c中并没有detect函数:

static struct i2c_driver pcf8591_driver = {
  .driver = {
    .name  = "pcf8591",
  },
  .probe    = pcf8591_probe,
  .remove    = pcf8591_remove,
  .id_table  = pcf8591_id,
};

这是因为pcf8591没有“制造商和设备ID寄存器”。

因此我们可以通过方式1,方式2和方式4

  • 方法1:静态声明I2C设备
    • 通过devicetree声明I2C设备
    • 在板级文件中声明I2C设备
  • 方法2:显式实例化设备
  • 方法3:对某些设备进行I2C总线探测
  • 方法4:从用户空间实例化

为了避免麻烦,这里就选择方法4。

先查看地址,然后通过sysfs, new_device的方式实例化(参见上篇)

图片

图片

实例化成功后,如上图,便可以通过sysfs来获取adc的值,以及设置dac的值。

cat /sys/class/hwmon/hwmon1/device/in0_input

**misc驱动框架实现 **

misc的意思是混合、杂项的,因此MISC驱动也叫做杂项驱动,也就是当我们板子上的某些外设无法进行分类的时候就可以使用MISC驱动。misc设备也是一个字符设备,在misc的初始化函数中注册了一个字符设备,主设备号为MISC_MAJOR (10)。

驱动分为两部分:i2c设备驱动,i2c设备显式实例化

在i2c设备显示实例化中调用,i2c_new_probed_device函数

i2c_new_probed_device(i2c_adap,&i2c_info,i2c_addr_list,NULL);

在某些设备中,比如需要后期插入i2c模块板,而预先不知道I2C总线的编号,则可以显式地实例化I2C设备。这是通过填充结构体i2c_board_info并调用i2c_new_client_device()来完成。

如下图,分别将,i2c设备驱动,i2c设备显式实例化,编译成pcf8591.ko 和pcf8591_dev.ko, 然后通过Insmod加载

图片

再另外编写应用代码,open misc设备,进行读写操作。

通过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设备驱动,在应用代码中进行1ms采样时,cpu的占用率5.2%。

图片

而使用bcm2835库进行10ms周期的采样时,cpu的占用率52.1%。

图片

IIO

IIO 全称是 Industrial I/O,当你使用的传感器本质是 ADC 或 DAC 器件的时候,可以优先考虑使用 IIO 驱动框架。比如常用的陀螺仪、加速度计、电压/电流测量芯片、光照传感器、压力传感器等内部都是有个 ADC,内部 ADC 将原始的模拟数据转换为数字量,然后通过其他的通信接口,比如 IIC、SPI 等传输给 SOC。Linux 内核为了管理这些日益增多的 ADC 类传感器,特地推出了 IIO 子系统。

iio 支持多种标准的 Linux 设备访问接口:char device, sysfs, configfs, debugfs。

IIO的4种接口

1). sysfs interface

  • /sys/bus/iio/devices/iio:deviceX;
  • 可用于配置 /dev/iio:deviceX 接口的 events / data
  • 可用于轮循的方式低速地直接读/写 IIO 设备;
  • Documentation/ABI/testing/sysfs-bus-iio;

2). character device

  • /dev/iio:deviceX,该接口在 IIO 子系统里是可选非必要的;
  • 标准的文件 IO API: open(), read(), write(), close().
  • 用于读取 events 和 data;

3). configfs

  • 用于配置额外的 IIO 特性,例如:软件 triggers 或者 hrtimer triggers;
  • 详细说明:
    • Documentation/ABI/testing/configfs-iio;
    • Documentation/iio/iio_configfs.txt;

4). debugfs

  • 一些调试功能,例如 direct_reg_access 节点可用于读写寄存器;

具体的代码实现便不再花时间了,可以参考drivers下iio部分代码。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • adc
    adc
    +关注

    关注

    95

    文章

    5651

    浏览量

    539462
  • CMOS器件
    +关注

    关注

    0

    文章

    71

    浏览量

    11400
  • DAC芯片
    +关注

    关注

    1

    文章

    30

    浏览量

    14296
  • Linux驱动
    +关注

    关注

    0

    文章

    43

    浏览量

    9881
  • 树莓派
    +关注

    关注

    113

    文章

    1639

    浏览量

    104741
  • PCF8591芯片
    +关注

    关注

    2

    文章

    8

    浏览量

    7326
收藏 人收藏

    评论

    相关推荐

    PCF8591的端口地址

    PCF8591代替DAC0832做D/A转换,完成函数发生器,PCF8591的端口地址是什么?
    发表于 01-10 19:09

    PCF8591 DA转换

    想通过PCF8591芯片 进行DA转换 在1V开始 隔一秒输出加1V 应该怎么写程序 没弄懂PCF8591的工作原理还望大神赐教
    发表于 10-04 16:09

    蓝桥杯单片机——PCF8591 ADC/DAC模块 精选资料分享

    。模拟电压输入电路图:硬件上旋动Rb2旋钮,即可改变模拟电压的输入值。光强电阻电压输入电路图:光敏电阻值的改变,影响该模拟电压通道的输入值。ADC/DAC模块驱动配置PCF8591采用
    发表于 07-19 07:41

    PCF8591是什么?怎样去设计PCF8591电路?

    PCF8591是什么?怎样去设计PCF8591电路?如何去编写ADC/DAC模块函数代码?
    发表于 07-19 08:56

    单片机PCF8591DAC是怎么使用的?

    单片机PCF8591DAC是怎么使用的?
    发表于 09-29 08:13

    怎样通过pcf8591芯片实现AD/DA转换

    蓝桥杯单片机比赛系列AD/DA转换AD/DA原理相关电路pcf8591器件地址代码解释修改代码AD自写代码ADDAAD/DA原理相关电路通过pcf8591芯片实现ad转换。板子上ad采
    发表于 01-11 08:02

    PCF8591ADCDAC分别是什么意思

    PCF8591ADCDAC分别是什么意思?它们之间有何关系呢?
    发表于 02-14 07:36

    PCF8591驱动程序

    PCF8591驱动程序 51单片机程序
    发表于 08-31 16:11 27次下载

    芯片PCF8591中文带图介绍.pdf

    ADDA芯片PCF8591中文带详细图介绍 使用教程
    发表于 08-31 16:11 47次下载

    PCF8591 ADCDAC芯片的数据手册免费下载

    本文档的主要内容详细介绍的是PCF8591 ADCDAC芯片的数据手册免费下载主要内容包括了:YL-40 AD模块使用说明,四路采集串口显示程序,Commix串口调试助手,YL-40
    发表于 07-15 08:00 67次下载
    <b class='flag-5'>PCF8591</b> <b class='flag-5'>ADC</b>和<b class='flag-5'>DAC</b><b class='flag-5'>芯片</b>的数据手册免费下载

    微雪电子ADC DAC AD DA转换PCF8591 PCF8591T简介

    PCF8591 AD DA转换模块 I2C接口 8位精度 四通道AD 单通道DA 电压输出型 型号 PCF8591 AD DA Board
    的头像 发表于 12-30 09:59 2655次阅读
    微雪电子<b class='flag-5'>ADC</b> <b class='flag-5'>DAC</b> AD DA转换<b class='flag-5'>PCF8591</b> <b class='flag-5'>PCF8591</b>T简介

    蓝桥杯单片机——PCF8591 ADC/DAC模块

    。模拟电压输入电路图:硬件上旋动Rb2旋钮,即可改变模拟电压的输入值。光强电阻电压输入电路图:光敏电阻值的改变,影响该模拟电压通道的输入值。ADC/DAC模块驱动配置PCF8591采用
    发表于 11-17 11:06 10次下载
    蓝桥杯单片机——<b class='flag-5'>PCF8591</b> <b class='flag-5'>ADC</b>/<b class='flag-5'>DAC</b>模块

    PCF8591 ADC与Arduino连接的方法

    在本教程中,我们将检查 如何将 PCF8591 ADC/DAC 模块与 Arduino 连接。
    发表于 08-26 15:18 3177次阅读
    将<b class='flag-5'>PCF8591</b> <b class='flag-5'>ADC</b>与Arduino连接的方法

    如何将PCF8591 ADC模块与Raspberry Pi连接

     在本教程中,我们将学习如何将 PCF8591 ADC/DAC 模块与 Raspberry Pi 连接。
    的头像 发表于 08-26 15:58 3430次阅读
    如何将<b class='flag-5'>PCF8591</b> <b class='flag-5'>ADC</b>模块与Raspberry Pi连接

    Linux驱动开发-编写PCF8591(ADC)芯片驱动

    PCF8591是一个IIC总线接口的ADC/DAC转换芯片,功能比较强大,这篇文章就介绍在Linux系统里如何编写一个
    的头像 发表于 09-17 15:16 1576次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>驱动</b>开发-编写<b class='flag-5'>PCF8591</b>(<b class='flag-5'>ADC</b>)<b class='flag-5'>芯片</b><b class='flag-5'>驱动</b>