当前位置: 首页 > wzjs >正文

深圳网站设计要点玉树北京网站建设

深圳网站设计要点,玉树北京网站建设,苏州建站公司 诚找苏州聚尚网络,wordpress 获取导航Linux的SPI子系统的原理和相关接口函数的介绍 关于Linux的SPI子系统的原理和相关接口函数的介绍,请参考博文 https://blog.csdn.net/wenhao_ir/article/details/146551375 SPI总线的相关知识 请参考下面两篇博文: https://blog.csdn.net/wenhao_ir/ar…

Linux的SPI子系统的原理和相关接口函数的介绍

关于Linux的SPI子系统的原理和相关接口函数的介绍,请参考博文
https://blog.csdn.net/wenhao_ir/article/details/146551375

SPI总线的相关知识

请参考下面两篇博文:
https://blog.csdn.net/wenhao_ir/article/details/146467895 【这篇主要是讲SPI总线的理论】

https://blog.csdn.net/wenhao_ir/article/details/146455604 【这篇是应用SPI总线的实例】

自己写的SPI设备(DAC模块)的驱动程序

完整源代码(dac_drv.c)

/** Simple synchronous userspace interface to SPI devices** Copyright (C) 2006 SWAPP*	Andrea Paterniani <a.paterniani@swapp-eng.it>* Copyright (C) 2007 David Brownell (simplification, cleanup)** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the* GNU General Public License for more details.*/#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 *dac;
static int major;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;memset(&xfer[0], 0, sizeof(xfer));/* copy_from_user */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;tx_buf[0] = (val>>8) & 0xff;	/* 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(dac, &msg);/* 3. 修改读到的数据的格式 */val = (rx_buf[0] << 8) | (rx_buf[1]);val >>= 2;/* copy_to_user */err = copy_to_user((void __user *)arg, &val, sizeof(int));return 0;
}static const struct file_operations spidev_fops = {.owner =	THIS_MODULE,/* REVISIT switch to aio primitives, so that userspace* gets more complete API coverage.  It'll simplify things* too, except for the locking.*/.unlocked_ioctl = spidev_ioctl,
};/*-------------------------------------------------------------------------*//* The main reason to have this class is to make mdev/udev create the* /dev/spidevB.C character device nodes exposing our userspace API.* It also simplifies memory management.*/static struct class *spidev_class;static const struct of_device_id spidev_dt_ids[] = {{ .compatible = "ti,tlc5615" },{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);/*-------------------------------------------------------------------------*/static int spidev_probe(struct spi_device *spi)
{/* 1. 记录spi_device */dac = spi;/* 2. 注册字符设备 */major = register_chrdev(0, "swh_dac_major", &spidev_fops);spidev_class = class_create(THIS_MODULE, "swh_dac_class");device_create(spidev_class, NULL, MKDEV(major, 0), NULL, "swh_spidac");	return 0;
}static int spidev_remove(struct spi_device *spi)
{/* 反注册字符设备 */device_destroy(spidev_class, MKDEV(major, 0));class_destroy(spidev_class);unregister_chrdev(major, "swh_dac_major");return 0;
}static struct spi_driver spidev_spi_driver = {.driver = {.name =		"swh_spi_dac_drv",.of_match_table = of_match_ptr(spidev_dt_ids),},.probe =	spidev_probe,.remove =	spidev_remove,/* NOTE:  suspend/resume methods are not necessary here.* We don't do anything except pass the requests to/from* the underlying controller.  The refrigerator handles* most issues; the controller driver handles the rest.*/
};/*-------------------------------------------------------------------------*/static int __init spidev_init(void)
{int status;printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);status = spi_register_driver(&spidev_spi_driver);if (status < 0) {}return status;
}
module_init(spidev_init);static void __exit spidev_exit(void)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);spi_unregister_driver(&spidev_spi_driver);
}
module_exit(spidev_exit);MODULE_LICENSE("GPL");

代码分析说明

在看完下面两篇博文:
https://blog.csdn.net/wenhao_ir/article/details/146467895 【这篇主要是讲SPI总线的理论】
https://blog.csdn.net/wenhao_ir/article/details/146455604 【这篇是应用SPI总线的实例】
并结合之前各种设备总线的学习,整个代码就很容易理解了,这里只把其中需要注意的说一下。

代码(const void __user *)arg

在这里插入图片描述

err = copy_from_user(&val, (const void __user *)arg, sizeof(int));

在Linux内核编程中,(const void __user *)arg 是用于进行用户空间与内核空间数据交换的关键操作。具体解释如下:

  1. arg 参数
    在这个驱动程序的 spidev_ioctl 函数中,arg 是一个传递给IO控制命令(ioctl)的参数,通常是用户空间传递给内核空间的数据。IO控制命令允许用户空间程序与驱动程序进行通信,而arg就是其中传递数据的载体。

  2. const void __user *

  • const:表示指针指向的内存内容不可修改。即你不能通过这个指针修改数据,通常是因为该数据来自用户空间,内核通常不直接修改用户空间的内容,而是进行读取。

  • void:表示该指针类型是泛型指针,可以指向任何类型的数据。由于函数的实际传入数据类型在此时并不确定,因此使用void *来处理所有类型的输入。

  • __user:这是Linux内核特有的标识符,用于指定该指针指向用户空间的内存区域。内核区分不同内存地址的作用,__user标签明确告诉编译器和开发者该指针指向的是用户空间,而非内核空间。这是内核编程中非常重要的一部分,因为内核空间与用户空间的内存是隔离的,不允许直接访问。

  1. (const void __user *)arg
    这一段代码的作用是将用户传递进来的arg指针(它是一个指向用户空间的地址)转换为一个指向用户空间的常量指针。
  • arg 是用户空间传递的地址,它实际上是一个指向用户空间数据的指针。
  • (const void __user *)arg 是将这个指针强制转换为一个特殊类型的指针,明确表示它指向的是用户空间的数据。

为什么需要这样转换?
Linux内核和用户空间之间有严格的内存隔离,内核不能直接访问用户空间的数据。因此,需要使用内核提供的安全机制(如copy_from_usercopy_to_user等函数)来进行数据传输。同时,为了避免非法修改用户数据,内核通过__user标记指针,这样可以在编译时捕获到潜在的错误。

总结
(const void __user *)arg 这一部分代码是将从用户空间传递来的指针(arg)转换为可以安全访问用户空间数据的指针,并且保证数据不被修改。这是内核编程中进行用户空间和内核空间数据交换的必要操作。

结构体spidev_dt_ids的第1项的内容为什么是ti,tlc5615

因为我之前在博文 https://blog.csdn.net/wenhao_ir/article/details/146455604 中写的设备树节点spidac: spidac@0的compatible属性值就为ti,tlc5615呀!
在这里插入图片描述

用户空间测试程序

完整源代码(dac_test.c)


/* 参考: 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  // 这个值随便写个就行,因为在传给驱动程序的ioctl调用函数后其实并没有用到,它对应用于驱动程序中ioctl调用函数的第2个参数cmd/* dac_test /dev/swh_spidac <val> */int main(int argc, char **argv)
{int fd;unsigned int val;int status;unsigned char tx_buf[2];	unsigned char rx_buf[2];	if (argc != 3){printf("Usage: %s /dev/swh_spidac <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); // SPI_IOC_WR在传给驱动程序的ioctl调用函数后其实并没有用到,它对应用于驱动程序中ioctl调用函数的第2个参数cmdif (status < 0) {printf("SPI_IOC_WR\n");return -1;}/* 打印 */printf("Last value is: %d\n", val);return 0;
}

代码分析说明

代码没什么好说的,对于现在的我来说,很简单了…

交叉编译出驱动模块和用户空间可执行程序

Makfile文件的书写

KERN_DIR = /home/book/100ask_imx6ull-sdk/Linux-4.9.88all:make -C $(KERN_DIR) M=`pwd` modules $(CROSS_COMPILE)gcc -o dac_test dac_test.cclean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf modules.order dac_testobj-m	+= dac_drv.o

工程目录和文件复制到Ubuntu中

在这里插入图片描述
在这里插入图片描述

执行make命令生成驱动模块和可执行文件

在这里插入图片描述

复制dac_drv.ko和可执行文件到NFS目录中

复制dac_drv.ko和可执行文件到NFS目录中以备用。
在这里插入图片描述

不带DAC模块的上板测试

短接MOSI和MISO两个引脚

带DAC模块的测试很简单,就是把MOSI和MISO两个引脚用杜邦线短接就行了,这样MOSI的数据就直接传给MISO了,如下图所示:
在这里插入图片描述

加载驱动模块dac_drv.ko

注意:在博文 https://blog.csdn.net/wenhao_ir/article/details/146455604已经写好并更新了设备树了,即内核中已经有了compatible属性值为ti,tlc5615,名字的spidac: spidac@0节点了。

接下来我们加载dac_drv.ko,并运行测试程序试一下。

打开串口终端→打开开发板→挂载网络文件系统

mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt

先加载驱动模块:

insmod /mnt/spidac_myself_write/dac_drv.ko

在这里插入图片描述

检查是否有相应的驱动和设备树文件生成

然后我们看下是否有相应的驱动和设备树文件生成:

cat /proc/devices

在这里插入图片描述

ls /dev/swh_spidac*

在这里插入图片描述
可见有相关的设备树文件了,并且也符号之前我们对设备文件名的分析,所以如果后面应用程序要使用设备文件,就用路径“/dev/swh_spidac”

运行测试程序

然后运行下面的命令执行程序

/mnt/spidac_myself_write/dac_test /dev/swh_spidac 200

后面的200代表我给DAC模块输入的数字值。
在这里插入图片描述
然后再把值改为300:

/mnt/spidac_myself_write/dac_test /dev/swh_spidac 300

发现Last value 仍然是300
在这里插入图片描述

运行结果分析

上面的结果说明我们利用spidev.c间接操作SPI控制器,至少在操作SPI控制器的MOSI和MISO两个引脚是没有问题的。
但是片选信号的操作就有问题了,详情请在博文 https://blog.csdn.net/wenhao_ir/article/details/146455604 中搜索“韦老师远程给我操作了两个小时也没有找到问题”。

上板测试自己写出的驱动程序

将DAC模块插到扩展板的J2位置

根据博文https://blog.csdn.net/wenhao_ir/article/details/146455604的记录(搜索“我们将把DAC扩展模块插到扩展板的SPI_A”),我们应该将DAC模块插到扩展板的J2的位置上:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

加载驱动模块dac_drv.ko

注意:在博文 https://blog.csdn.net/wenhao_ir/article/details/146455604已经写好并更新了设备树了,即内核中已经有了compatible属性值为ti,tlc5615,名字的spidac: spidac@0节点了。

接下来我们加载dac_drv.ko,并运行测试程序试一下。

打开串口终端→打开开发板→挂载网络文件系统

mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt

先加载驱动模块:

insmod /mnt/spidac_myself_write/dac_drv.ko

在这里插入图片描述

检查是否有相应的驱动和设备树文件生成

然后我们看下是否有相应的驱动和设备树文件生成:

cat /proc/devices

在这里插入图片描述

ls /dev/swh_spidac*

在这里插入图片描述
可见有相关的设备树文件了,并且也符号之前我们对设备文件名的分析,所以如果后面应用程序要使用设备文件,就用路径“/dev/swh_spidac”

运行测试程序

然后运行下面的命令执行程序

/mnt/spidac_myself_write/dac_test /dev/swh_spidac 200

后面的200代表我给DAC模块输入的数字值。
在这里插入图片描述然后再把值改为300:

/mnt/spidac_myself_write/dac_test /dev/swh_spidac 300

发现Last value 仍然是0
在这里插入图片描述
再把值改为1000(DAC芯片的有效位数是10位,最大值为1023)

/mnt/spidac_myself_write/dac_test /dev/swh_spidac 300

发现Last value 仍然是0
在这里插入图片描述
并且DAC模块只有电源灯在亮,如下图所示:
在这里插入图片描述
之前在博文 https://blog.csdn.net/wenhao_ir/article/details/146455604 中也是这样的情况…
韦老师帮我找到了表面的原因但无法解决问题,详情在博文 https://blog.csdn.net/wenhao_ir/article/details/146455604 中搜索“韦老师远程给我操作了两个小时也没有找到问题”

附相关文件

VScode的工程目录

在这里插入图片描述
https://pan.baidu.com/s/1rOGM-gGnGN8vc-MMRTCOIA?pwd=iwfk

经过编译的工程目录

在这里插入图片描述
https://pan.baidu.com/s/1Je8ie3d80mgS1Gz5i-XzDg?pwd=xqrd


文章转载自:

http://jQolGEp8.bdwqy.cn
http://8sUmo2fD.bdwqy.cn
http://3IaIPuME.bdwqy.cn
http://70hjUY2q.bdwqy.cn
http://jc16Ai4O.bdwqy.cn
http://pTAAxSRf.bdwqy.cn
http://rnVqhZOY.bdwqy.cn
http://rEZLqHjQ.bdwqy.cn
http://rkGOQNBQ.bdwqy.cn
http://4N5BsWdk.bdwqy.cn
http://KqWD7j3d.bdwqy.cn
http://eeV6UGoU.bdwqy.cn
http://XZTi0xOV.bdwqy.cn
http://DiqNlRTE.bdwqy.cn
http://l9rnvcHq.bdwqy.cn
http://9MIJKTfG.bdwqy.cn
http://pw8Rq2Nl.bdwqy.cn
http://8ObMjmBR.bdwqy.cn
http://D9NWGwBG.bdwqy.cn
http://TkzmWuDD.bdwqy.cn
http://JfhpNj0L.bdwqy.cn
http://J3LVeNFS.bdwqy.cn
http://1nB0Wwau.bdwqy.cn
http://uO6bgUl6.bdwqy.cn
http://i7KQzFNW.bdwqy.cn
http://9rpv9Uth.bdwqy.cn
http://bJej14Fo.bdwqy.cn
http://czERvbRN.bdwqy.cn
http://qTZniMCF.bdwqy.cn
http://4BoMReh9.bdwqy.cn
http://www.dtcms.com/wzjs/644339.html

相关文章:

  • 网站嵌入英文地图亚马逊做网站发礼物换评价
  • 金融门户网站建设wordpress 付费内容
  • 中国建设电工网站今天
  • 便宜网站开发培训制作图片下载什么软件
  • 自己搭建网站需要多少钱百度h5官网登录
  • wordpress 导出优化大师安卓版
  • 山东省住房和建设厅网站网站建设专家价格
  • 惠州做企业网站的网站开发工程师学什么区别
  • 用ip访问没有备案的网站更新网站 seo
  • 无锡商业网站建设网站空间管理平台
  • 网站建设 云计算韩雪冬网站设计
  • 佛山做网站公司有哪些网站官网怎么做
  • 网站充值 下模板全国黄页大全
  • 河源公司做网站免费查公司查老板
  • 辽宁平台网站建设公司平度网站建设公司电话
  • 网站开发哪里好未央免费做网站
  • 建设商城网站的合肥网络seo
  • 网站建设与制作 试卷与答案开发公司施工管理事业部领导如何同下属协调沟通
  • 北京网站建设seo公司哪家好wordpress禁止适应屏幕
  • 南平网站设计自己怎样做淘客网站
  • 网站建设时如何建立客户信赖感注册一个公司的流程
  • 都匀住房和城乡建设部网站体育视频网站建设
  • 容县网站开发美食网站php源码
  • 常用素材网站吉林省长春网站建设
  • 做logo找灵感的网站天宫院网站建设
  • 常州网站建设运营天津公司网站如何制作
  • 建筑网站设计大全宣传片公司哪家好
  • 美发营销型网站商服网站模板
  • c 开发手机网站开发一般做网站带宽选择多大的
  • 网站建设wix网络营销是什么?