⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spidev

📁 linux 内核源代码
💻
字号:
SPI devices have a limited userspace API, supporting basic half-duplexread() and write() access to SPI slave devices.  Using ioctl() requests,full duplex transfers and device I/O configuration are also available.	#include <fcntl.h>	#include <unistd.h>	#include <sys/ioctl.h>	#include <linux/types.h>	#include <linux/spi/spidev.h>Some reasons you might want to use this programming interface include: * Prototyping in an environment that's not crash-prone; stray pointers   in userspace won't normally bring down any Linux system. * Developing simple protocols used to talk to microcontrollers acting   as SPI slaves, which you may need to change quite often.Of course there are drivers that can never be written in userspace, becausethey need to access kernel interfaces (such as IRQ handlers or other layersof the driver stack) that are not accessible to userspace.DEVICE CREATION, DRIVER BINDING===============================The simplest way to arrange to use this driver is to just list it in thespi_board_info for a device as the driver it should use:  the "modalias"entry is "spidev", matching the name of the driver exposing this API.Set up the other device characteristics (bits per word, SPI clocking,chipselect polarity, etc) as usual, so you won't always need to overridethem later.(Sysfs also supports userspace driven binding/unbinding of drivers todevices.  That mechanism might be supported here in the future.)When you do that, the sysfs node for the SPI device will include a childdevice node with a "dev" attribute that will be understood by udev or mdev.(Larger systems will have "udev".  Smaller ones may configure "mdev" intobusybox; it's less featureful, but often enough.)  For a SPI device withchipselect C on bus B, you should see:    /dev/spidevB.C ... character special device, major number 153 with	a dynamically chosen minor device number.  This is the node	that userspace programs will open, created by "udev" or "mdev".    /sys/devices/.../spiB.C ... as usual, the SPI device node will	be a child of its SPI master controller.    /sys/class/spidev/spidevB.C ... created when the "spidev" driver	binds to that device.  (Directory or symlink, based on whether	or not you enabled the "deprecated sysfs files" Kconfig option.)Do not try to manage the /dev character device special file nodes by hand.That's error prone, and you'd need to pay careful attention to systemsecurity issues; udev/mdev should already be configured securely.If you unbind the "spidev" driver from that device, those two "spidev" nodes(in sysfs and in /dev) should automatically be removed (respectively by thekernel and by udev/mdev).  You can unbind by removing the "spidev" drivermodule, which will affect all devices using this driver.  You can also unbindby having kernel code remove the SPI device, probably by removing the driverfor its SPI controller (so its spi_master vanishes).Since this is a standard Linux device driver -- even though it just happensto expose a low level API to userspace -- it can be associated with any numberof devices at a time.  Just provide one spi_board_info record for each suchSPI device, and you'll get a /dev device node for each device.BASIC CHARACTER DEVICE API==========================Normal open() and close() operations on /dev/spidevB.D files work as youwould expect.Standard read() and write() operations are obviously only half-duplex, andthe chipselect is deactivated between those operations.  Full-duplex access,and composite operation without chipselect de-activation, is available usingthe SPI_IOC_MESSAGE(N) request.Several ioctl() requests let your driver read or override the device's currentsettings for data transfer parameters:    SPI_IOC_RD_MODE, SPI_IOC_WR_MODE ... pass a pointer to a byte which will	return (RD) or assign (WR) the SPI transfer mode.  Use the constants	SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL	(clock polarity, idle high iff this is set) or SPI_CPHA (clock phase,	sample on trailing edge iff this is set) flags.    SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte	which will return (RD) or assign (WR) the bit justification used to	transfer SPI words.  Zero indicates MSB-first; other values indicate	the less common LSB-first encoding.  In both cases the specified value	is right-justified in each word, so that unused (TX) or undefined (RX)	bits are in the MSBs.    SPI_IOC_RD_BITS_PER_WORD, SPI_IOC_WR_BITS_PER_WORD ... pass a pointer to	a byte which will return (RD) or assign (WR) the number of bits in	each SPI transfer word.  The value zero signifies eight bits.    SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ ... pass a pointer to a	u32 which will return (RD) or assign (WR) the maximum SPI transfer	speed, in Hz.  The controller can't necessarily assign that specific	clock speed.NOTES:    - At this time there is no async I/O support; everything is purely      synchronous.    - There's currently no way to report the actual bit rate used to      shift data to/from a given device.    - From userspace, you can't currently change the chip select polarity;      that could corrupt transfers to other devices sharing the SPI bus.      Each SPI device is deselected when it's not in active use, allowing      other drivers to talk to other devices.    - There's a limit on the number of bytes each I/O request can transfer      to the SPI device.  It defaults to one page, but that can be changed      using a module parameter.    - Because SPI has no low-level transfer acknowledgement, you usually      won't see any I/O errors when talking to a non-existent device.FULL DUPLEX CHARACTER DEVICE API================================See the sample program below for one example showing the use of the fullduplex programming interface.  (Although it doesn't perform a full duplextransfer.)  The model is the same as that used in the kernel spi_sync()request; the individual transfers offer the same capabilities as areavailable to kernel drivers (except that it's not asynchronous).The example shows one half-duplex RPC-style request and response message.These requests commonly require that the chip not be deselected betweenthe request and response.  Several such requests could be chained intoa single kernel request, even allowing the chip to be deselected aftereach response.  (Other protocol options include changing the word sizeand bitrate for each transfer segment.)To make a full duplex request, provide both rx_buf and tx_buf for thesame transfer.  It's even OK if those are the same buffer.SAMPLE PROGRAM==============--------------------------------	CUT HERE#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>static int verbose;static void do_read(int fd, int len){	unsigned char	buf[32], *bp;	int		status;	/* read at least 2 bytes, no more than 32 */	if (len < 2)		len = 2;	else if (len > sizeof(buf))		len = sizeof(buf);	memset(buf, 0, sizeof buf);	status = read(fd, buf, len);	if (status < 0) {		perror("read");		return;	}	if (status != len) {		fprintf(stderr, "short read\n");		return;	}	printf("read(%2d, %2d): %02x %02x,", len, status,		buf[0], buf[1]);	status -= 2;	bp = buf + 2;	while (status-- > 0)		printf(" %02x", *bp++);	printf("\n");}static void do_msg(int fd, int len){	struct spi_ioc_transfer	xfer[2];	unsigned char		buf[32], *bp;	int			status;	memset(xfer, 0, sizeof xfer);	memset(buf, 0, sizeof buf);	if (len > sizeof buf)		len = sizeof buf;	buf[0] = 0xaa;	xfer[0].tx_buf = (__u64) buf;	xfer[0].len = 1;	xfer[1].rx_buf = (__u64) buf;	xfer[1].len = len;	status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);	if (status < 0) {		perror("SPI_IOC_MESSAGE");		return;	}	printf("response(%2d, %2d): ", len, status);	for (bp = buf; len; len--)		printf(" %02x", *bp++);	printf("\n");}static void dumpstat(const char *name, int fd){	__u8	mode, lsb, bits;	__u32	speed;	if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) {		perror("SPI rd_mode");		return;	}	if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) {		perror("SPI rd_lsb_fist");		return;	}	if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) {		perror("SPI bits_per_word");		return;	}	if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) {		perror("SPI max_speed_hz");		return;	}	printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n",		name, mode, bits, lsb ? "(lsb first) " : "", speed);}int main(int argc, char **argv){	int		c;	int		readcount = 0;	int		msglen = 0;	int		fd;	const char	*name;	while ((c = getopt(argc, argv, "hm:r:v")) != EOF) {		switch (c) {		case 'm':			msglen = atoi(optarg);			if (msglen < 0)				goto usage;			continue;		case 'r':			readcount = atoi(optarg);			if (readcount < 0)				goto usage;			continue;		case 'v':			verbose++;			continue;		case 'h':		case '?':usage:			fprintf(stderr,				"usage: %s [-h] [-m N] [-r N] /dev/spidevB.D\n",				argv[0]);			return 1;		}	}	if ((optind + 1) != argc)		goto usage;	name = argv[optind];	fd = open(name, O_RDWR);	if (fd < 0) {		perror("open");		return 1;	}	dumpstat(name, fd);	if (msglen)		do_msg(fd, msglen);	if (readcount)		do_read(fd, readcount);	close(fd);	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -