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

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

文章目录

  • 参考资料:
  • 一、编写设备树
  • 二、 编写驱动程序
  • 三、编写测试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

相关文章:

  • 农作物病害数据集
  • 单片机农业大棚浇花系统
  • prometheus-helm的使用
  • 立体匹配的问题及基本解决思路与流程
  • 我的创作纪念日:技术成长的脚印
  • 【Linux内核系列】:文件系统收尾以及软硬链接详解
  • LVGL移植到6818开发板
  • 洛谷P1200 [USACO1.1] 你的飞碟在这儿 Your Ride Is Here
  • 设计模式学习记录
  • docker后台运行,便于后期用命令行进入它的终端
  • 【知识迁移的底层逻辑:从符号到语义的升维】
  • 按钮权限的设计及实现
  • 13. Pandas :使用 to_excel 方法写入 Excel文件
  • 【TMS570LC4357】之相关问题及解决
  • Jupyter Notebook的介绍和使用
  • 正则表达式全解析 + Java常用示例
  • uniapp-x web 开发警告提示以及解决方法
  • 以太坊生态中有代币标准和协议,针对不同场景设计了丰富的功能
  • 深度学习-服务器训练SparseDrive过程记录
  • 【6】树状数组学习笔记
  • 巴基斯坦军方:印度向巴本土及巴控克什米尔发射导弹
  • 《中国医药指南》就“宫颈癌等论文出现男性病例”致歉:辞退涉事编辑
  • 南方地区强降雨或致部分河流发生超警洪水,水利部部署防范
  • “五一”假期全社会跨区域人员流动量超14.65亿人次
  • 联合国秘书长古特雷斯呼吁印巴保持最大克制
  • 甘肃临夏州政协委员马全成涉嫌诈骗罪,被撤销政协委员资格