Using SPI with Linux
Last edited by aehrlich on Thu, 05/12/2011 - 11:10
Introduction
SPI (Synchronous Peripheral Interface) is a synchronous serial interface with which to connect peripheral chips like ADCs, EEPROMS, Sensors or other Micro-Controllers.
SPI works in master and slave mode, while the master provides the clock signal and each slave has a dedicated chipselect. On our AT91SAM9 based devices a Linux driver is provided. As most peripheral chips are slaves this driver only works in master mode. To connect a spi chip four signals are needed: CLK, MISO (master in, slave out), MOSI (master out, slave in) and a chipselect.
This how-to describes how to configure and use the SPI user-mode device driver (spi-dev).
SPI works in master and slave mode, while the master provides the clock signal and each slave has a dedicated chipselect. On our AT91SAM9 based devices a Linux driver is provided. As most peripheral chips are slaves this driver only works in master mode. To connect a spi chip four signals are needed: CLK, MISO (master in, slave out), MOSI (master out, slave in) and a chipselect.
This how-to describes how to configure and use the SPI user-mode device driver (spi-dev).
Preparing the Kernel
On some of our products, the driver is already activated, which are listed below:
- PortuxG20: Chipselects, which are exported on the PXB are already configured in the kernel. It is necessary to activate the driver.
- Ledato NanosG20: Chipselects, which are exported on the I/O interface are configured. The driver is also already activated. Unless you have the need to change the standard settings, you can skip this chapter
Configuring the Kernel
Activate the driver in menuconfig (make menuconfig):
Device Drivers ---> SPI Device Drivers ---> SPI ---> Atmel SPI Controller Device Drivers ---> SPI ---> User mode SPI device driver support
Add SPI board support
Add the following structure to your arch/arm/mach-at91/board-xxx.c:
static struct spi_board_info stamp9g20_spi_devices[] = { { .modalias = "spidev", .chip_select = 0, .max_speed_hz = 1 * 1000 * 1000, .bus_num = 1, .mode = SPI_MODE_3, }, { .modalias = "spidev", .chip_select = 2, .max_speed_hz = 1 * 1000 * 1000, .bus_num = 1, .mode = SPI_MODE_3, }, };
Of course this structure can be adapted according to your needs. The details of the members are explained below:
- .modalias This tells which spi-device driver to use. Setting it to "spidev" will use the spi user mode device driver, but there are other device drivers in the kernel, e.g. for the ADS7843 Touchscreen. If you want to use one of these you have to set the relevant modalias for this driver and of course activate it in your configuration.
- .chip_select This tells your device driver which chipselect to use.
- .max_speed_hz This is the maximum possible speed configured for this chip select. The speed of the SPI should be between MCK and MCK divided by 255. Take care to not use a value here which cannot be supported by your platform.
Processor MCK (Hz) SPI Min AT91SAM9261 99,993,600 392,132 AT91SAM9G20 132,096,000 518,024 AT91SAM9G10 120,000,000 471,000 AT91SAM9G45 132,096,000 518,024 - .bus_num This chooses if SPI0 or SPI1 of the AT91SAM9xx is used.
- .mode There are four different SPI modes, mode three is most commonly used by peripherals which can be only slaves. The mode of master and slave have to be the same, so when in doubt consult the datasheet of your device. There are two relevant parameters, the clock phase (CPHA) and clock polarity (CPOL). Is the phase zero (CPHA = 0), then data is sampled at rising edge with CPOL=0 and falling edge with CPOL=1. This behaviour switches with CPHA=1, then data is sampled at falling edge with CPOL=0 and rising edge with CPOL=1.
SPI Mode CPOL CPHA 0 0 0 1 0 1 2 1 0 3 1 1
Additionally to adding the structure, you have to add a call to at91_add_device_spi in your xxx_board_init function:
at91_add_device_spi(stamp9g20_spi_devices, ARRAY_SIZE(stamp9g20_spi_devices));
After compiling the kernel according to the instructions of your platform and flashing it to your board you should see these SPI devices in your /dev directory:
/dev # ls -al /dev/spi* crw-rw---- 1 root root 153, 0 Jan 1 00:20 /dev/spidev1.0 crw-rw---- 1 root root 153, 1 Jan 1 00:20 /dev/spidev1.2
user s[ace test program
#include <stdio.h> #include <fcntl.h> #include <stdlib.h> #define ARRAY_SIZE(array) sizeof(array)/sizeof(array[0]) int main(int argc, char **argv) { int i,fd; char wr_buf[]={0xff,0x00,0x1f,0x0f}; char rd_buf[10];; if (argc<2) { printf("Usage:\n%s [device]\n", argv[0]); exit(1); } fd = open(argv[1], O_RDWR); if (fd<=0) { printf("%s: Device %s not found\n", argv[0], argv[1]); exit(1); } if (write(fd, wr_buf, ARRAY_SIZE(wr_buf)) != ARRAY_SIZE(wr_buf)) perror("Write Error"); if (read(fd, rd_buf, ARRAY_SIZE(rd_buf)) != ARRAY_SIZE(rd_buf)) perror("Read Error"); else for (i=0;i<ARRAY_SIZE(rd_buf);i++) { printf("0x%02X ", rd_buf[i]); if (i%2) printf("\n"); } close(fd); return 0; }
For synchronous transfer, you can have a look at the example from Documentation/spi. It is slightly changed, as the at91-spi driver does not support to change speed or bits per word via the ioctl-transfer interface. You can cross-compile it
with
your-cross-gcc -o spidev-test -I/path-to-cross-kernel-include spidev-test.c
. Of course you can also use your compiler on the target board (Make sure you have the package linux-libc-dev installed). Later you can run it like this: spidev-test -D /dev/spidev1.0
.Ref : http://armbedded.eu/node/318
Ref : https://github.com/KnCMiner/spi-test/blob/master/spi-test.c
沒有留言:
張貼留言