使用SPIDE操作SPI_DAC模块

249 阅读2分钟

本文已参与【新人创作礼】活动,一起开启掘金创作之路。

一、硬件

IMX6ULL: 在这里插入图片描述 原理图: 在这里插入图片描述接线图: 请添加图片描述

二、DAC操作原理

2.1 内部框图

在这里插入图片描述 操作过程:

  • CS为低:
  • 在SCLK的上升沿,从DIN采集16位数据,存入上图中的16-Bit Shift Register
  • 在CS的上升沿,把16-Bit Shift Register中的10位数据传入10-Bit DAC Register,作为模拟量在OUT引脚输出

注意:

  • 传输的16位数据中,高4位是无意义的
  • 中间10位才被转换为模拟量
  • 最低2位必须是0

2.2 时序图

在这里插入图片描述

使用SPI传输的细节:

  • SCLK初始电平为低
  • 使用16个SCLK周期来传输16位数据
  • 在SCLK上升沿读取DIN电平
  • 在SCLK上升沿发出DOUT信号
  • DOUT数据来自16-Bit Shift Register
    • 低1个数据是上次数据遗留下的LSB位
    • 其余16个数据来自16-Bit Shift Register的高15位
    • 16-Bit Shift Register的LSB在下一个周期的第1个时钟传输
    • LSB必定是0,所以当前的周期里读出16-Bit Shift Register的15位数据也足够了

2.3 DAC公式

在这里插入图片描述

输出电压 = 2 * VREFIN * n / 1024 = 2 * 2.048 * n / 1024
其中:n为10位数值

2.3 编写设备树

确认SPI时钟最大频率 在这里插入图片描述 在这里插入图片描述

这里一个周期的时间就是TW(CL)+TW(CH)=25+25=50nsT_W(CL)+T_W(CH) = 25 + 25 = 50ns 对应的频率就是1/50ns=20106=20MHz1/50ns=20*10^6=20MHz

设备树如下:

dac: dac@00 {
	compatible = "spidev";
	reg = <0>;
	spi-max-frequency = <20000000>;		//从DAC芯片手册获得
};	

2.4 编写内核支持SPI_DEV模块

需要开启user spi support

-> Device Drivers
  -> SPI support (SPI [=y]) 
    < >   User mode SPI device driver support  

2.5 编写APP

#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>
#include <linux/spi/spidev.h>

/* dac_test /dev/spidevB.D <val> */

int main(int argc, char **argv)
{
	int fd;
	unsigned int val;
	struct spi_ioc_transfer	xfer[1];
	unsigned char tx_buf[2];
	unsigned char rx_buf[2];
	int	status;

	if(argc != 3) {
		printf("Usage: %s /dev/spidevB.D <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);
	val <<= 2;		/* bit0, bit1 = 0b00 */
	val &= 0xFFC;	/* only reserve 10 bit */

	tx_buf[0] = (val>>8) & 0xff;
	tx_buf[1] = val & 0xff;

	memset(xfer, 0, sizeof xfer);

	xfer[0].len = 2;
	xfer[0].tx_buf = (unsigned long) tx_buf;
	xfer[0].rx_buf = (unsigned long) rx_buf;

	status = ioctl(fd, SPI_IOC_MESSAGE(1), xfer);
	if (status < 0) {
		printf("SPI_IOC_MESSAGE\n");
		return -1;
	}

	/* print result */
	val = (rx_buf[0] <<8)|(rx_buf[1]);
	val >>= 2;
	printf("pre val = %d\n", val);

	return 0;
}

2.6 实验结果

[root@firefly-rk3288:/home/picture/spi]# ./dac_test /dev/spidev0.0 0
pre val = 0
[root@firefly-rk3288:/home/picture/spi]# ./dac_test /dev/spidev0.0 100
pre val = 0
[root@firefly-rk3288:/home/picture/spi]# ./dac_test /dev/spidev0.0 100         0
pre val = 100
[root@firefly-rk3288:/home/picture/spi]# ./dac_test /dev/spidev0.0 100
^C
[root@firefly-rk3288:/home/picture/spi]# ./dac_test /dev/spidev0.0 100       100
0
pre val = 100
[root@firefly-rk3288:/home/picture/spi]# ./dac_test /dev/spidev0.0 100      ^C
[root@firefly-rk3288:/home/picture/spi]# ./dac_test /dev/spidev0.0 200
0
pre val = 1000
[root@firefly-rk3288:/home/picture/spi]# ./dac_test /dev/spidev0.0 200      1500
Usage: ./dac_test /dev/spidevB.D <val>
[root@firefly-rk3288:/home/picture/spi]# ./dac_test /dev/spidev0.0 100
0
pre val = 976
[root@firefly-rk3288:/home/picture/spi]# ./dac_test /dev/spidev0.0 100       500
pre val = 1000