SPI驱动(八) -- SPI_DAC设备驱动程序

news2025/3/16 11:07:16

文章目录

  • 参考资料:
  • 一、编写设备树
  • 二、 编写驱动程序
  • 三、编写测试APP
  • 四、Makefile
  • 五、上机实验


参考资料:

参考资料:

  • 内核头文件:include\linux\spi\spi.h
  • 内核文档:Documentation\spi\spidev
  • DAC芯片手册:TLC5615.pdf

一、编写设备树

确认最大时钟频率:参看芯片手册
在这里插入图片描述

T = 25 + 25 = 50ns
F = 20000000 = 20MHz

修改\arch\arm\boot\dts\100ask_imx6ull-14x14.dts

&ecspi1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_ecspi1>;
    
    fsl,spi-num-chipselects = <2>;
    cs-gpios = <&gpio4 26 GPIO_ACTIVE_LOW>, <&gpio4 24 GPIO_ACTIVE_LOW>;
    status = "okay";
    
    dac:dac {
		compatible = "100ask,dac";
        reg = <0>;
        spi-max-frequency = <20000000>;
    };
};

二、 编写驱动程序


#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <linux/uaccess.h>

#define SPI_IOC_WR 123

/*-------------------------------------------------------------------------*/

static struct spi_device *g_spidev_dac;
static int g_major;
static struct class *g_spidev_class;


static long
spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	int val;
	int err;
	unsigned char tx_buf[2];	
	unsigned char rx_buf[2];	

	struct spi_message	msg;
	struct spi_transfer	xfer[1];
	int status;

    /* 局部变量初始值未知,需清0 */
	memset(&xfer[0], 0, sizeof(xfer));
	
	/* 从用户层获取数据 */
	err = copy_from_user(&val, (const void __user *)arg, sizeof(int));

	printk("spidev_ioctl get val from user: %d\n", val);

	/* 发起SPI传输:     */

	/* 1. 把val修改为正确的格式 */
	val <<= 2;     /* bit0,bit1 = 0b00 */
	val &= 0xFFC;  /* 只保留10bit */

	tx_buf[1] = val & 0xff;         //低8位
	tx_buf[0] = (val>>8) & 0xff;	//高8位

	/* 2. 发起SPI传输同时写\读 */
	/* 2.1 构造transfer
	 * 2.2 加入message
	 * 2.3 调用spi_sync
	 */
	xfer[0].tx_buf = tx_buf;
	xfer[0].rx_buf = rx_buf;
	xfer[0].len = 2;

	spi_message_init(&msg);
	spi_message_add_tail(&xfer[0], &msg); 
	
	status = spi_sync(g_spidev_dac, &msg);

	/* 3. 修改读到的数据的格式 */
	val = (rx_buf[0] << 8) | (rx_buf[1]);
	val >>= 2;

	/* 返回给用户层 */
	err = copy_to_user((void __user *)arg, &val, sizeof(int));
	
	return 0;
}


/* file_operations 结构 */
static const struct file_operations spidev_fops = {
	.owner =	THIS_MODULE,
	.unlocked_ioctl = spidev_ioctl,
};


/*-------------------------------------------------------------------------*/

static int spidev_probe(struct spi_device *spi)
{
	/* 1. 记录spi_device */
	g_spidev_dac = spi;

	/* 2. 注册字符设备 */
	g_major = register_chrdev(0, "100ask_dac", &spidev_fops);
	g_spidev_class = class_create(THIS_MODULE, "100ask_dac");
	device_create(g_spidev_class, NULL, MKDEV(g_major, 0), NULL, "100ask_dac");	

	return 0;
}

static int spidev_remove(struct spi_device *spi)
{
	/* 反注册字符设备 */
	device_destroy(g_spidev_class, MKDEV(g_major, 0));
	class_destroy(g_spidev_class);
	unregister_chrdev(g_major, "100ask_dac");

	return 0;
}


static const struct of_device_id spidev_dt_ids[] = {
	{ .compatible = "100ask,dac" },
	{},
};


/* 构造一个spi_driver */
static struct spi_driver spidev_spi_driver = {
	.driver = {
		.name =	"100ask_spi_dac_drv",
		.of_match_table = of_match_ptr(spidev_dt_ids),
	},
	.probe =	spidev_probe,
	.remove =	spidev_remove,
};

/* 入口函数 */
static int __init spidev_init(void)
{
	int status;

	printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

    /* 注册spi_driver */
	status = spi_register_driver(&spidev_spi_driver);
	if (status < 0) {
	}
	return status;
}

/* 出口函数 */
static void __exit spidev_exit(void)
{
	printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	
    /* 反注册spi_driver */
	spi_unregister_driver(&spidev_spi_driver);
}

module_init(spidev_init);
module_exit(spidev_exit);

MODULE_LICENSE("GPL");

三、编写测试APP

参考: tools\spi\spidev_fdx.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>

#define SPI_IOC_WR 123

/* dac_test /dev/100ask_dac <val> */

int main(int argc, char **argv)
{
	int fd;
	unsigned int val;
	int status;
	
	if (argc != 3)
	{
		printf("Usage: %s /dev/100ask_dac <val>\n", argv[0]);
		return 0;
	}

	fd = open(argv[1], O_RDWR);
	if (fd < 0) {
		printf("can not open %s\n", argv[1]);
		return 1;
	}
	val = strtoul(argv[2], NULL, 0);

    /* 写入数据,并读回数据 */
	status = ioctl(fd, SPI_IOC_WR, &val);
	if (status < 0) {
		printf("SPI_IOC_WR\n");
		return -1;
	}
	/* 打印 */
	printf("Pre val = %d\n", val);
	return 0;
}

四、Makefile

KERN_DIR = /home/zpz/share/imx6ullsdk/repo/100ask_imx6ull-sdk/Linux-4.9.88
all:
	make -C $(KERN_DIR) M=`pwd` modules 
	$(CROSS_COMPILE)gcc -o dac_test dac_test.c
clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order dac_test
obj-m	+= dac_drv.o

五、上机实验

  1. 编译、替换设备树
  • 编译设备树
$ make dtbs 
  • 拷贝到开发板
$ mount -t nfs -o nolock 192.168.124.22:/home/zpz/share/ /mnt
$ cp /mnt/imx6ullsdk/repo/100ask_imx6ull-sdk/Linux-4.9.88/arch/arm/boot/dts/100ask_imx6ull-14x14.dtb /boot/
  • 重启开发板
  1. 编译驱动和测试程序

  2. 加载驱动

$ insmod dac_drv.ko
  1. 查看设备节点
$ ls /dev/100ask_dac -l
crw------- 1 root root 240, 0 Jan  1 01:47 /dev/100ask_dac
  1. 运行测试程序
//传入不用val,亮度不同
$ ./dac_test /dev/100ask_dac 100  
Pre val = 0 
$  ./dac_test /dev/100ask_dac 500
Pre val = 100
$ ./dac_test /dev/100ask_dac 1000
Pre val = 500

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

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

相关文章

MySQL 衍生表(Derived Tables)

在SQL的查询语句select …. from …中&#xff0c;跟在from子句后面的通常是一张拥有定义的实体表&#xff0c;而有的时候我们会用子查询来扮演实体表的角色&#xff0c;这个在from子句中的子查询会返回一个结果集&#xff0c;这个结果集可以像普通的实体表一样查询、连接&…

HarmonyOS NEXT开发进阶(十二):build-profile.json5 文件解析

文章目录 一、前言二、Hvigor脚本文件三、任务与任务依赖图四、多模块管理4.1 静态配置模块 五、分模块编译六、配置多目标产物七、配置APP多目标构建产物八、定义 product 中包含的 target九、拓展阅读 一、前言 编译构建工具DevEco Hvigor&#xff08;以下简称Hvigor&#x…

深度学习笔记(37周)

目录 摘要 Abstracts 1. 介绍 2. 相关工作 3. 模型 3.1 时序段网络TSN 3.2 学习时序段网络 4. 训练结果 5. 结论 摘要 本周阅读的论文是《Temporal Segment Networks: Towards Good Practices for Deep Action Recognition》。作者主要想通过较少的训练样本&#xff…

ELK+Filebeat+Kafka+Zookeeper安装部署

1.安装zookeeper zookpeer下载地址:apache-zookeeper-3.7.1-bin.tar.gzhttps://link.csdn.net/?targethttps%3A%2F%2Fwww.apache.org%2Fdyn%2Fcloser.lua%2Fzookeeper%2Fzookeeper-3.7.1%2Fapache-zookeeper-3.7.1-bin.tar.gz%3Flogin%3Dfrom_csdn 1.1解压安装zookeeper软件…

【软考-架构】3.3、模式分解-事务并发-封锁协议

✨资料&文章更新✨ GitHub地址&#xff1a;https://github.com/tyronczt/system_architect 文章目录 模式分解&#xff08;难点&#xff09;无损分解&#x1f4af;考试真题并发控制封锁协议&#x1f4af;考试真题第一题第二题 模式分解&#xff08;难点&#xff09; 保持函…

审批工作流系统xFlow

WorkFlow-审批流程系统 该项目为完全开源免费项目 可用于学习或搭建初始化审批流程系统 希望有用的小伙伴记得点个免费的star gitee仓库地址 仿钉钉飞书工作审批流系统 介绍 前端技术栈: vue3 ts vite arcodesign eslint 后端技术栈:springbootspring mvc mybatis mavenmysq…

【数据结构初阶第十九节】八大排序系列(下篇)—[详细动态图解+代码解析]

hello&#xff0c;好久不见&#xff01; 云边有个稻草人-CSDN博客 上篇内容&#xff0c;回顾一下吧【数据结构初阶第十八节】八大排序系列(上篇)—[详细动态图解代码解析]-CSDN博客 今天我们来学习下篇 目录 &#xff08;2&#xff09;快速排序 【挖坑法】 —思路 —思路…

定制开发开源 AI 智能名片 S2B2C 商城小程序源码在小程序直播营销中的应用与价值

摘要&#xff1a; 本文主要探讨了定制开发开源 AI 智能名片 S2B2C 商城小程序源码在小程序直播营销中的应用与价值。首先详细阐述了小程序直播的基本概念、特点、发展历程及营销意义&#xff0c;包括其便捷性、广泛的受众连接能力以及对企业推广的重要作用。接着深入剖析了定制…

蓝桥杯Python赛道备赛——Day3:排序算法(二)(归并排序、堆排序、桶排序)

本博客是蓝桥杯备赛系列中排序算法的第二期&#xff0c;包括&#xff1a;归并排序、堆排序和桶排序。每一个算法都在给出概念解释的同时&#xff0c;给出了示例代码&#xff0c;以供低年级师弟师妹们学习和练习。 由于本期的三个算法的复杂度相对来说要高于上一期的三个算法&am…

Type-C:智能家居的电力革命与空间美学重构

在万物互联的时代浪潮中&#xff0c;家居空间正经历着从功能容器到智慧终端的蜕变。当意大利设计师安东尼奥奇特里奥提出"消失的设计"理念二十年后&#xff0c;Type-C充电技术正以润物无声的方式重塑着现代家居的形态与内核&#xff0c;开启了一场静默的居住革命。 【…

第十五届蓝桥杯C/C++组:宝石组合题目(从小学奥数到编程题详解)

这道题目真的一看就不好做&#xff0c;如果直接暴力去做百分之90必挂掉&#xff0c;那么这道题目到底应该怎么去做呢&#xff1f;这我们就得从小学奥数开始聊了。&#xff08;闲话&#xff1a;自从开始蓝桥杯备赛后&#xff0c;每天都在被小学奥数震惊&#xff0c;为什么我小的…

ECharts中Map(地图)样式配置、渐变色生成

前言 ECharts是我们常用的图表控件&#xff0c;功能特别强大&#xff0c;每次使用都要查API比较繁琐&#xff0c;这里就记录开发中常用的配置。 官网&#xff1a;https://echarts.apache.org/handbook/zh/get-started 配置项&#xff1a;https://echarts.apache.org/zh/opti…

MySQL | MySQL表的增删改查(CRUD)

目录 前言&#xff1a;什么是 CRUD ?一、Creat 新增1.1 语法1.2 示例1.2.1 单行数据全列插入1.2.2 单行数据指定列插入1.2.3 多行数据指定列插入 二、Retrieve 检索2.1 语法2.2 示例2.2.1 全列查询2.2.2 指定列查询2.2.3 查询字段为表达式2.2.4 结果去重查询2.2.5 where条件查…

电子电气架构 --- 分布到集中的动カ系统及基于域控制器的架构

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧,都是来源于自己的想象,只有你真的去做了,才会发现有多快乐。…

基于SpringBoot的“考研互助平台”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“考研互助平台”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统整体功能图 局部E-R图 系统首页界面 系统注册…

基于javaweb的SpringBoot足球俱乐部管理系统设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…

DQN 玩 2048 实战|第一期!搭建游戏环境(附 PyGame 可视化源码)

视频讲解&#xff1a; DQN 玩 2048 实战&#xff5c;第一期&#xff01;搭建游戏环境&#xff08;附 PyGame 可视化源码&#xff09; 代码仓库&#xff1a;GitHub - LitchiCheng/DRL-learning: 深度强化学习 2048游戏介绍&#xff0c;引用维基百科 《2048》在44的网格上进行。…

高频面试题(含笔试高频算法整理)基本总结回顾24

干货分享&#xff0c;感谢您的阅读&#xff01; &#xff08;暂存篇---后续会删除&#xff0c;完整版和持续更新见高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09;&#xff09; 备注&#xff1a;引用请标注出处&#xff0c;同时存在的问题请在相关博客留言…

第八节:红黑树(初阶)

【本节要点】 红黑树概念红黑树性质红黑树结点定义红黑树结构红黑树插入操作的分析 一、红黑树的概念与性质 1.1 红黑树的概念 红黑树 &#xff0c;是一种 二叉搜索树 &#xff0c;但 在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是 Red和 Black 。 通过对 任何…

Webpack vs Rollup vs Parcel:构建工具深度对比

文章目录 1. 核心特性对比1.1 功能定位1.2 技术架构对比 2. 配置与使用2.1 Webpack 配置示例2.2 Rollup 配置示例2.3 Parcel 使用示例 3. 性能对比3.1 构建速度3.2 输出质量 4. 生态系统4.1 插件生态4.2 学习曲线 5. 适用场景分析5.1 Webpack 适用场景5.2 Rollup 适用场景5.3 P…