正点原子嵌入式linux驱动开发——Linux DAC驱动

上一篇笔记中学习了ADC驱动,STM32MP157 也有DAC外设,DAC也使用的IIO驱动框架。本章就来学习一下如下在Linux下使用STM32MP157上的DAC。

DAC简介

ADC是模数转换器,负责将外界的模拟信号转换为数字信号。DAC刚好相反,是数模转换器,负责将SOC的数字信号转换为模拟信号

STM32MP157的DAC模块(数字/模拟转换模块)是12位数字输入,电压输出型的DAC。DAC可以配置为8位或12位模式,也可以与DMA控制器配合使用。DAC工作在12位模式
时,数据可以设置成左对齐或右对齐。DAC模块有2个输出通道,每个通道都有独立的转换器。在双DAC模式下,2个通道可以独立地进行转换,也可以同时进行转换并同步地更新2个通道的输出。DAC可以通过引脚输入参考电压Vref+(同ADC共用)以获得更精确的转换结果。STM32MP157的DAC模块主要特点有:

  1. 1个DAC 接口,最大两个DAC输出通道。
  2. 12位模式下数据左对齐或者右对齐。
  3. 同步更新功能。
  4. 噪声波、三角波形生成。
  5. 外部触发。
  6. 双DAC通道同时或者分别转换。
  7. 每个通道都有DMA功能。
  8. 输入参考电压VREF+。
  9. ……

STM32MP157 DAC框图如下图所示:

DAC结构框图

图中VDDA和VSSA为DAC模块模拟部分的供电,而VREF+则是DAC模块的参考电压。DAC_OUT1/2就是DAC的两个输出通道了,DAC_OUT1对应PA4引脚,DAC_OUT2对应PA5引脚。正点原子STM32MP157开发板使用DAC_OUT1,引脚为PA4

DAC驱动源码分析

设备树下的DAC节点

stm32mp151.dtsi文件中的dac节点信息如下:

dac节点

第2行,compatible属性值为“st,stm32h7-dac-core”,所以在整个Linux源码里面搜索这个字符串即可找到STM32MP157的DAC驱动核心文件,这个文件就是drivers/iio/dac/stm32-dac-core.c

第11、18行,compatible属性值“st,stm32-dac”,搜索这个字符串,可以找到ADC驱动文件,这个文件就是drivers/iio/dac/stm32-dac.c

关于STM32MP157的DAC节点更为详细的信息请参考对应的绑定文档:Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt。接下来简单分析一下绑定文档,后面需要根据绑定文档修改设备树,使能DAC对应的通道。

DAC首先需要一个根节点,DAC根节点属性如下:

1、必要属性

  • compatible:兼容性属性,必须的,可以设置为“st,stm32h7-dac-core”。
  • reg:DAC控制器寄存器信息。
  • clocks:时钟。
  • clock-names:时钟名字,必须为“pclk”。
  • vref-supply:此属性对应vref参考电压句柄。
  • address-cells:设置为1。
  • size-cells:设置为0。

2、可选属性

  • :pinctrl 引脚配置信息。
  • resets:复位句柄。

STM32MP157有两个DAC通道,每个DAC通道对应一个子节点,DAC子节点相关属性
如下:

  • compatible:兼容性属性,必须的,可以设置为“st,stm32-dac”。
  • reg:不同ADC控制器寄存器地址偏移信息。
  • io-channel-cells:设置为1。

DAC驱动源码分析

STM32MP157 DAC驱动文件也有两个:stm32-dac-core.c和stm32-dac.cstm32-dac-core.c是DAC核心层,主要用于DAC时钟、电源等初始化。需要重点关注的是stm32-dac.c这个文件。stm32-adc.c主体框架是platform,配合IIO驱动框架实现DAC驱动

stm32_dac结构体

首先来看一下stm32_dac结构体,内如如下:

stm32_dac结构体

stm32_dac结构体很简单,比上一章的stm32_adc结构体要简单很多,只有一个stm32_dac_common成员变量,内容如下:

stm32_dac_common结构体

可以看出,DAC驱动也采用了regmap API。

stm32_dac_probe函数

接下来看一下stm32_dac_probe函数,内容如下(有省略):

stm32_dac_probe函数

第12行,调用devm_iio_device_alloc函数申请iio_dev,这里也连stm32_dac内存一起申请
了。

第17行,调用iio_priv函数从iio_dev里面得到stm32_dac首地址。

第19-23行,初始化iio_dev,重点是第22行的stm32_dac_iio_info,因为用户空间读取或设置DAC数据最终就是由stm32_dac_iio_info来完成的

第25行,调用stm32_dac_chan_of_init函数设置DAC通道。

第36行,调用iio_device_register函数向内核注册iio_dev。

同样的stm32_dac_probe函数核心就是初始化DAC,然后建立DAC的IIO驱动框架

stm32_dac_iio_info结构体

stm32_dac_iio_info结构体内容如下所示:

stm32_dac_iio_info结构体

第2行,stm32_dac_read_raw函数用于读取DAC信息,读取DAC原始数据值、分辨率等。

第3行,stm32_dac_write_raw函数用于设置DAC值。

stm32_dac_read_raw和stm32_dac_write_raw函数内容如下:

stm32_dac_read_raw和stm32_dac_write_raw函数

第1-17行,stm32_dac_read_raw函数,读取DAC的原始值以及分辨率,非常简单。

第19-31行,stm32_dac_write_raw函数,向DAC写入原始值,也就是设置DAC。

硬件原理图分析

DAC原理图如下:

DAC原理图

上一章讲ADC的时候,说了JP2是一个3P的排针,用来设置ADC连接可调电位器还DAC。本章学习使用DAC,因此可以使用跳线帽将JP2的1,2引脚连接起来。也就是将DAC和ADC连接在一起,如下图所示:

DAC跳线帽设置

可以编写应用程序设置DAC,然后再使用ADC采集回去。正点原子STM32MP157开发板使用了DAC通道 1,引脚为PA4

DAC驱动编写

修改设备树

DAC驱动ST已经编写好了,只需要修改设备树即可。首先在stm32mp15-pinctrl.dtsi文件中添加DAC使用的PA4引脚配置信息:

示例代码 58.4.1.1 PA4 引脚配置信息 
1 dac_ch1_pins_a: dac-ch1 {
2     pins {
3         pinmux = <STM32_PINMUX('A', 4, ANALOG)>;
4     };
5 };

接下来在stm32mp157d-atk.dts文件中向根节点添加vdd子节点信息,内容如下:

示例代码 58.4.1.2 vdd 子节点 
1 v3v3: regulator-3p3v {
2     compatible = "regulator-fixed";
3     regulator-name = "v3v3";
4     regulator-min-microvolt = <3300000>;
5     regulator-max-microvolt = <3300000>;
6     regulator-always-on;
7     regulator-boot-on;
8 };

最后在stm32mp157d-atk.dts 文件中向 adc 节点追加一些内容,内容如下:

示例代码 58.4.1.3 adc 节点
1 &dac {
2     pinctrl-names = "default";
3     pinctrl-0 = <&dac_ch1_pins_a>; 
4     vref-supply = <&v3v3>; 
5     status = "okay";
6     dac1: dac@1 {
7         status = "okay"; 
8     };
9 };

第3行,配置dac引脚。

第4行,设置电压属性。

第6-8行,dac1子节点,设置很简单,直接将status属性设置为“okay”即可。

使能DAC驱动

同样的,使能Linux内核中的ST32MP157 DAC驱动,打开Linux内核配置界面,配置路
径如下:

-> Device Drivers
-> Industrial I/O support (IIO [=y])
-> Digital to analog converters
-> <*>STMicroelectronics STM32 DAC //使能 STM32 DAC

如下图所示:

DAC配置项

编写测试APP

编译修改后的设备树,然后使用新的设备树启动系统。进入/sys/bus/iio/devices目录下,此目录下就有DAC对应的iio设备:iio:deviceX,本章例程如下图所示:

DAC iio设备

上图中有两个IIO设备:iio:device0和iio:device1,可以依次进入这两个目录查
看分别对应什么外设。教程中当前所使用的开发板中iio:device0为ADC(上一章实验使能的 ADC驱动),iio:device1为本章使能的DAC设备。

进入“iio:device1”目录,内容如下图所示:

iio:device1目录文件

标准的IIO设备文件目录,只关心三个文件:

  • out_voltage1_powerdown:DAC输出使能文件,写0打开DAC,写1关闭DAC,默认为1,也就是关闭DAC。
  • out_voltage1_raw:DAC1通道 1原始值文件。
  • out_voltage1_scale:DAC1比例文件(分辨率),单位为mV。实际输出电压值(mV)=out_voltage1_raw * out_voltage1_scale。out_voltage1_scale默认值如下图所示:

out_voltage1_scale内容

从上图可以看出,out_voltage1_scale默认为0.805664062。

DAC1默认12位,因此可设置范围为0-4095。向out_voltage1_raw写入2000,命令如下:

echo 0 > /sys/bus/iio/devices/iio:device1/out_voltage1_powerdown //开启 DAC
echo 2000 > /sys/bus/iio/devices/iio:device1/out_voltage1_raw //设置 DAC

此时DAC输出的理论电压值为2000*0.805664062≈1611.328mV。
那么DAC输出是否正确呢?直接使用上一章编写的adcAPP.c读取DAC引脚电压值就行了。这里注意,一定要先按照之前的连接示意图所示,将JP2的右边两根排针连接起来,也就是将DAC和ADC引脚连接在一起。

运行上一章的adcApp.c,结果如下图所示:

ADC采集结果

从上图可以看出,ADC采集到的电压为1.61V,和设置的DAC理论值基本一致。这里要注意,DAC1是12位的,而ADC是16位的,因此可以看到他们的原始值会不一样。

接下来编译一个简单的DAC测试APP,APP等待用户输入DAC原始值,一旦用户输入以后就调用ADC来采集DAC输出的电压值,最后将DAC理论值与ADC采集到的实际值打印出来,看一下是否正确。

这里的过程基本相似,先设置char字符数组指针file_path放置iio框架对应的文件路径,并enum对应的文件索引,然后设置dac的设备结构体,存一下raw、scale和act就可以了。

之后编写file_data_read,是一样的操作,fopen打开然后fscanf扫描,遇到EOF就fseek调到头然后fclose。

之后写dac_add_dac_read函数来获取ADC、DAC数据,这里就是file_data_read然后atoi、atof得到原始值和比例,之后经过换算把实际值存到dac_dev结构体指针dev的adc_act成员变量中;之后同样方法获取DAC的理论真实值存到dev->dac_act中。

之后编写dac_enable,里面就是system来调用控制台进而使能DAC。dac_disable也是同理。

之后编写dac_set函数,设置DAC,这里就是sprintf将传入的value转为字符串,然后fopen打开文件,fseek把文件指针调整到文件头,fwrite写入转为字符串的value,之后fclose关闭文件。

最后写main函数,argc就1个,首先要dac_enable使能DAC,之后再while中scanf获取输入的目标dac设置值,然后通过fgets来获取输入值,之后dac_set把这个值传给DAC,调用dac_add_dac_read来获取数据,成功后就打印当前dac和adc值。

运行测试

编译驱动程序和测试APP

输入如下编译dacApp.c这个测试程序:

arm-none-linux-gnueabihf-gcc -march=armv7-a -mfpu=neon -mfloat-abi=hard dacApp.c -o dacApp

编译成功以后就会生成dacApp这个应用程序。

运行测试

注意,在测试之前一定要先按照接线示意图所示,将JP2跳线帽接到右边,也就是将ADC1_CH19通道连接到开发板上DAC1引脚上!

输入如下命令,使用dacApp测试程序:

./dacApp

APP运行以后会等待输入要设置的DAC值,每输入一次就会自动打印出ADC采集到的实际ADC值以及DAC的理论值,如下图所示:

DAC测试结果

上图中设置了0、500、1000、2000、3000和4095共6个DAC原始值,可以看出DAC设置的理论值和ADC采集到的实际值基本一致。

总结

DAC和ADC总体就很接近,都是ST官方已经写好了驱动,总体就是platform驱动加上regmap配合IIO驱动来完成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/140704.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mac电脑Visio文件编辑查看软件推荐Visio Viewer for Mac

mac版Visio Viewer功能特色 在Mac OS X上查看Visio绘图和图表 在Mac OS X上轻松查看MS Visio文件 在Mac上快速方便地打开并阅读Visio文件&#xff08;.vsd&#xff0c;.vsdx&#xff09;。 支持通过放大&#xff0c;缩小&#xff0c;旋转&#xff0c;文本选择和复制&#xff0…

群晖Docker(Container Manager)中安装Home Assistant Container

群晖Docker&#xff08;Container Manager&#xff09;中安装Home Assistant Container 不要使用 套件里面的 Home Assistant&#xff0c;不利于后期拓展 方式一&#xff1a; docker run -d --name"home-assistant-1" -v /volume1/docker/homeassistant/config:/c…

华东“启明”青少年音乐艺术实践中心揭幕暨中国“启明”巴洛克合奏团首演音乐会

2023年11月11日&#xff0c;华东“启明”青少年音乐艺术实践中心在上海揭幕&#xff0c;中国“启明”巴洛克合奏团开启了首场音乐会。 华东“启明”青少年音乐艺术实践中心由中共宁波市江北区委宣传部与上音管风琴艺术中心联合指导&#xff0c;宁波音乐港、宁波市江北区洛奇音乐…

Apache APISIX 的 Admin API 默认访问令牌漏洞(CVE-2020-13945)漏洞复现

漏洞描述 Apache APISIX 是一个动态、实时、高性能的 API 网关。Apache APISIX 有一个默认的内置 API 令牌&#xff0c;可用于访问所有 admin API&#xff0c;通过 2.x 版本中添加的参数导致远程执行 LUA 代码。 漏洞环境及利用 启动docker环境 访问9080端口 通过 admin api…

利用LangChain实现RAG

检索增强生成&#xff08;Retrieval-Augmented Generation, RAG&#xff09;结合了搜寻检索生成能力和自然语言处理架构&#xff0c;透过这个架构&#xff0c;模型可以从外部知识库搜寻相关信息&#xff0c;然后使用这些信息来生成response。要完成检索增强生成主要包含四个步骤…

Java进阶(垃圾回收GC)——理论篇:JVM内存模型 垃圾回收定位清除算法 JVM中的垃圾回收器

前言 JVM作为Java进阶的知识&#xff0c;是需要Java程序员不断深度和理解的。 本篇博客介绍JVM的内存模型&#xff0c;对比了1.7和1.8的内存模型的变化&#xff1b;介绍了垃圾回收的语言发展&#xff1b;阐述了定位垃圾的方法&#xff0c;引用计数法和可达性分析发以及垃圾清…

如何实现Debian工控电脑USB接口安全管控

Debian 作为工控电脑操作系统具有稳定性、安全性、自定义性和丰富的软件包等优势&#xff0c;适用于要求高度可靠性和安全性的工控应用。 Debian 作为工控电脑操作系统在工业控制领域有很大优势&#xff0c;包括&#xff1a; 稳定性&#xff1a;Debian 的发布版以其稳定性而闻…

find和grep命令的简单使用

find和grep命令的简单使用 一、find例子--不同条件查找 二、grep正则表达式的简单说明例子--简单文本查找例子--结合管道进行查找 一、find find 命令在指定的目录下查找对应的文件。 find [path] [expression]● path 是要查找的目录路径&#xff0c;可以是一个目录或文件名…

MS321V/358V/324V低压、轨到轨输入输出运放

MS321V/MS358V/MS324V 是单个、两个和四个低压轨到轨输 入输出运放&#xff0c;可工作在幅度为 2.7V 到 5V 的单电源或者双电源条件 下。在低电源、空间节省和低成本应用方面是最有效的解决方案。 这些放大器专门设计为低压工作&#xff08; 2.7V 到 5V &#xff09;…

Electron-vue出现GET http://localhost:9080/__webpack_hmr net::ERR_ABORTED解决方案

GET http://localhost:9080/__webpack_hmr net::ERR_ABORTED解决方案 使用版本解决方案解决总结 使用版本 以下是我解决此问题时使用的electron和vue等的一些版本信息 【附】经过测试 electron 的版本为 13.1.4 时也能解决 解决方案 将项目下的 .electron-vue/dev-runner.js…

为什么要用“交叉熵”做损失函数

大家好啊&#xff0c;我是董董灿。 今天看一个在深度学习中很枯燥但很重要的概念——交叉熵损失函数。 作为一种损失函数&#xff0c;它的重要作用便是可以将“预测值”和“真实值(标签)”进行对比&#xff0c;从而输出 loss 值&#xff0c;直到 loss 值收敛&#xff0c;可以…

Python数据结构:元组(Tuple)详解

1.介绍和基础操作 Python中的元组&#xff08;Tuple&#xff09;是不可变有序序列&#xff0c;可以容纳任意数据类型&#xff08;包括数字、字符串、布尔型、列表、字典等&#xff09;的元素&#xff0c;通常用圆括号() 包裹。与列表&#xff08;List&#xff09;类似&#xff…

擎创动态 | 再获上海区政府肯定,擎创科技被评为年度优秀高新技术企业

11月6日&#xff0c;上海市静安区副区长张慧和市北高新集团总裁陈军一行来到擎创科技调研指导&#xff0c;由擎创科技高管张健和陈莹陪同交流。 陈莹女士首先向副区长一行详细介绍了擎创科技的发展现状、落地实践效益以及未来的规划布局。在公司的成长过程中&#xff0c;得到静…

Windows 10 下使用Visual Studio 2017 编译CEF SDK

1.下载CEF SDK 由于需要跑在32位的机器&#xff0c;所以选择下载32位的SDKCEF Automated Builds 选择 Current Stable Build (Preferred) &#xff0c;这是当前稳定版本&#xff0c;CEF版本118 下载成功解压 2.下载编译工具 CMake 下载地址&#xff1a;CMake 配置CMake指向…

Containerd接入Harbor仓库

在使用容器时&#xff0c;避免不了会使用到私有仓库&#xff0c;一般都是采用 harbor 作为私有仓库&#xff0c;docker 对接 harbor 仓库非常简单&#xff0c;哪 containerd 如何对接 harbor 呢&#xff1f; 在内网使用 harbor 根据个人习惯&#xff0c;一般都是非 http 并且是…

PHP 服装销售管理系统mysql数据库web结构layUI布局apache计算机软件工程网页wamp

一、源码特点 PHP 服装销售管理系统是一套完善的web设计系统mysql数据库 &#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 php服装销售管理系统1 二、功能介绍 (1)员工管理&#xff1a;对员工信息…

卷积神经网络中参数量的计算原理及方法

手动计算参数量: 1. 卷积层参数计算方法: 参数量计算公式 卷积核高度 * 卷积核宽度 * 输入层通道数 * 输出层通道数 bias(输出层通道数) 注意:池化层没有参数(只是在已知数据区域里求个最大值)输入层通道数就是上层的卷积核数量 输出层通道数等于卷积核个数:输入层通道数经过…

jenkins CSV编码导致乱码问题解决

问题&#xff1a;生产报告会乱码的问题&#xff0c;一般是有编码格式引起的。我遇到的问题是&#xff0c;jmeter需要读取csv的数据作为参数。但是我们并不知道csv保存是什么编码格式&#xff0c;有可能不是utf-8的编码格式&#xff0c;所以会导致中文乱码的问题 解决方案&#…

机器学习中的假设检验

正态性检验相关分析回归分析 所谓假设检验&#xff0c;其实就是根据原假设来构造一种已知分布的统计量来计算概率&#xff0c;根据概率值大小来判断能否拒绝原假设&#xff0c;从而得到一种结论。假设检验的过程就是&#xff0c;构造一个原假设成立条件下的事件A&#xff0c;计…

使用Nodejs搭建简单的web网页并实现公网访问

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 使用Nodejs搭建简单的web网页并实现公网访问 前言 Node.js是建立在谷歌Chrome的JavaScript引擎…