wordpress Markdown编辑器 mysql安装 智慧树 security pointers neo4j safari swiper easyui视频 jq触发点击事件 office2016修复 java获取字符串 axure导出html文件 oracle存储过程返回值 python输出函数 python测试 python匹配字符串 javapackage java介绍 java时间函数 java正则替换 java集合遍历 java怎么配置 java数组排序 java定义 linuxshell java网络编程实例 磁盘分区软件 h370主板 js判断字符串相等 美国地址生成器 adobe卸载工具 原创检测工具 pr视频加速 python图片处理 视频添加水印 快手规则 a1474 ipad清理内存
当前位置: 首页 > 学习教程  > 编程语言

LINUX 系统SPI 标准接口 应用开发

2020/11/4 14:27:56 文章标签:

LINUX 系统SPI 标准接口 应用开发 Linux系统中,和I2C一样,SPI也有系统自带的设备驱动程序,位于源码目录下drivers/spi/spidev.c,以下为驱动的移植和对应应用程序编写方法 驱动代码移植 要将此设备驱动加入到内核中,要…

LINUX 系统SPI 标准接口 应用开发

Linux系统中,和I2C一样,SPI也有系统自带的设备驱动程序,位于源码目录下drivers/spi/spidev.c,以下为驱动的移植和对应应用程序编写方法

驱动代码移植
要将此设备驱动加入到内核中,要做两件事情

第一:将此驱动编译进内核
步骤:make menuconfig

        Device Drivers -> 

        <*>SPI support ->

         <*>User mode SPI device driver support

第二:在平台文件arch/arm/mach-mx6/board-mx6q_sabresd.c 中添加对spidev的设备注册
步骤:

1、准备spi_board_info变量(全局变量)

static struct spi_board_info spidev_ecspi2_board_info[] __initdata = {
{
/* The modalias must be the same as spi device driver name */
.modalias = “spidev”,
.max_speed_hz = 20000000,
.bus_num = 1,
.chip_select = 0,

},
};

2、注册spi_board_info变量到内核中,要在平台硬件初始化的函数中执行本段代码

spi_register_board_info(spidev_ecspi2_board_info,
ARRAY_SIZE(spidev_ecspi2_board_info));

应用程序编写
在对驱动代码进行修改之后,需要根据驱动的架构来完成应用程序的编写,在内核源代码Documentation/spi目录下有一个spidev_test.c文件,是内核作者提供给Linux开发人员的参考文档,笔者也是参考此文件来编写的应用程序

应用程序无非是open、close、read、write、ioctl的使用。open,close没什么好说的,下面具体说下ioctl、read和write的使用。

spi应用程序编写步骤:
第一:open
第二:ioctl ,ioctl有九种cmd,分别对应不同的arg
a、设置或获取SPI工作模式
SPI_IOC_RD_MODE //读 模式
SPI_IOC_WR_MODE //写 模式
以上两种cmd对用arg是spi_device.mode
spi_device.mode有以下几种类型
#define SPI_MODE_0 (0|0)//SCLK空闲时为低电平,第一个时间延采样
#define SPI_MODE_1 (0|SPI_CPHA)//SCLK空闲时为高电平,第一个时间延采样
#define SPI_MODE_2 (SPI_CPOL|0)//SCLK空闲时为低电平,第二个时间延采样
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)//SCLK空闲时为高电平,第二个时间延采样
#define SPI_CS_HIGH 0x04//片选为高
#define SPI_LSB_FIRST 0x08//低位数据先传输
#define SPI_3WIRE 0x10//三线式,输入输出数据线为一条线
#define SPI_LOOP 0x20//回环模式
#define SPI_NO_CS 0x40//没有片选信号
#define SPI_READY 0x80//
用法:
mode = mode | SPI_MODE_0 | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_LOOP
ioctl(fd, SPI_IOC_WR_MODE, &mode);
注意:前面四种是对SCK时钟信号空闲时的电平,和采样时刻的选择,四个只能选择其中一种,后面的五种可以用或的形式选择任意几个,使用方法如上

b、设置或获取SPI读写是从高位还是低位开始
SPI_IOC_RD_LSB_FIRST //读 LSB
SPI_IOC_WR_LSB_FIRST //写 LSB
以上两种cmd对用arg是spi_device.mode
用法:同上,但是mode类型只有SPI_LSB_FIRST一种

c、设置或获取SPI读写数据位数
SPI_IOC_RD_BITS_PER_WORD //读 每字多少位
SPI_IOC_WR_BITS_PER_WORD //写 每字多少位
以上两种cmd对用arg是spi_device.bits_per_word
用法:
bits = 8;
ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);

d、设置或获取SPI读写的最大频率
SPI_IOC_RD_MAX_SPEED_HZ //读 最大速率
SPI_IOC_WR_MAX_SPEED_HZ //写 最大速率
以上两种cmd对用arg是spi_device.max_speed_hz
用法:
speed = 50*1000;
ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);

e、传输数据
SPI_IOC_MESSAGE(n) //传输n个数据包
以上一种cmd对用arg是spi_ioc_transfer
用法:全双工传输数据
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);

第三:read或write
用法:和大多数的设备read函数一样的用法,但是每次读或者写的大小不能大于4096Byte。
char* buf[n];
read(fd,buf,sizeof(buf));或者write(fd,buf,sizeof(buf));

第四:close
应用代码:

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

static void pabort(const char *s)
{
perror(s);
abort();
}

static const char *device = “/dev/spidev1.0”;
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 50000;
static uint16_t delay;
unsigned char buf_me[1] = {0x55};

static void transfer(int fd)
{
int ret;
uint8_t tx[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
0xF0, 0x0D,
};
uint8_t rx[ARRAY_SIZE(tx)] = {0, };
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};

ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
	pabort("can't send spi message");

for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
	if (!(ret % 6))
		puts("");
	printf("%.2X ", rx[ret]);
}
puts("");

}

static void print_usage(const char *prog)
{
printf(“Usage: %s [-DsbdlHOLC3]\n”, prog);
puts(" -D --device device to use (default /dev/spidev1.1)\n"
" -s --speed max speed (Hz)\n"
" -d --delay delay (usec)\n"
" -b --bpw bits per word \n"
" -l --loop loopback\n"
" -H --cpha clock phase\n"
" -O --cpol clock polarity\n"
" -L --lsb least significant bit first\n"
" -C --cs-high chip select active high\n"
" -3 --3wire SI/SO signals shared\n");
exit(1);
}

static void parse_opts(int argc, char *argv[])
{
while (1) {
static const struct option lopts[] = {
{ “device”, 1, 0, ‘D’ },
{ “speed”, 1, 0, ‘s’ },
{ “delay”, 1, 0, ‘d’ },
{ “bpw”, 1, 0, ‘b’ },
{ “loop”, 0, 0, ‘l’ },
{ “cpha”, 0, 0, ‘H’ },
{ “cpol”, 0, 0, ‘O’ },
{ “lsb”, 0, 0, ‘L’ },
{ “cs-high”, 0, 0, ‘C’ },
{ “3wire”, 0, 0, ‘3’ },
{ “no-cs”, 0, 0, ‘N’ },
{ “ready”, 0, 0, ‘R’ },
{ NULL, 0, 0, 0 },
};
int c;

	c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);

	if (c == -1)
		break;

	switch (c) {
	case 'D':
		device = optarg;
		break;
	case 's':
		speed = atoi(optarg);
		break;
	case 'd':
		delay = atoi(optarg);
		break;
	case 'b':
		bits = atoi(optarg);
		break;
	case 'l':
		mode |= SPI_LOOP;
		break;
	case 'H':
		mode |= SPI_CPHA;
		break;
	case 'O':
		mode |= SPI_CPOL;
		break;
	case 'L':
		mode |= SPI_LSB_FIRST;
		break;
	case 'C':
		mode |= SPI_CS_HIGH;
		break;
	case '3':
		mode |= SPI_3WIRE;
		break;
	case 'N':
		mode |= SPI_NO_CS;
		break;
	case 'R':
		mode |= SPI_READY;
		break;
	default:
		print_usage(argv[0]);
		break;
	}
}

}

int main(int argc, char *argv[])
{
int ret = 0;
int fd;

parse_opts(argc, argv);

fd = open(device, O_RDWR);
if (fd < 0)
	pabort("can't open device");


    mode = mode | SPI_MODE_1 | SPI_LSB_FIRST | SPI_LOOP;

/*
 * spi mode
 */
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1)
	pabort("can't set spi mode");

ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1)
	pabort("can't get spi mode");

/*
 * bits per word
 */
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
	pabort("can't set bits per word");

ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
	pabort("can't get bits per word");

/*
 * max speed hz
 */
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
	pabort("can't set max speed hz");

ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
	pabort("can't get max speed hz");

printf("spi mode: %d\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

// transfer(fd);
while(1){
write(fd,buf_me,1);
}
close(fd);

return ret;

}


本文链接: http://www.dtmao.cc/news_show_350148.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?