2016年6月22日 星期三

spi self-test


Using SPI with Linux


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).

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.
    ProcessorMCK (Hz)SPI Min
    AT91SAM926199,993,600392,132
    AT91SAM9G20132,096,000518,024
    AT91SAM9G10120,000,000471,000
    AT91SAM9G45132,096,000518,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 ModeCPOLCPHA
    000
    101
    210
    311
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

沒有留言:

張貼留言