Homepage Wiki Forum Buy

SPI

From GNUBLIN

severity (level) requirement Gnublin family
Gnublin logo advanced.png Kernel compile, Toolchain All


Contents

SPI Interface

The SPI interface is simple way to connect external blocks. Both members share one clock and one serial data line for reciving and sending. Mostly 8bit blocks are tranfered.

Technical specifikation

  • Motorola SPI frame Format with a wordlength of 8/16 bits
  • Texas Instruments SSI frame Format with a wordlength from 4 upto 16 bits
  • Serial clockrate in master mode upto 45 MHz
  • Serial clockrate in slave mode upto 25 MHz
  • Support for single data access DMA
  • Full-Duplex operation
  • Maskable interrupts
  • Multiple slaves support (maximum of 3 slaves).


The SPI Interface

Gnublin board spi1.jpg

In the picture below you can see on the left, the 14-Pin connector. The next draw will explain this a little bit more exactly.

Gnublin board spi new.png

On GNUBLIN you will need 4 pins for the SPI interface:

3 - GPIO11 (this pin is the chipselect pin) 
5 - SCK    (Clock line for SPI)
7 - MISO   (Master in Slave out)
8 - MOSI   (Master out Slave in)

You can find the interfaces of the specific GNUBLIN boards here

For some slaves it may be that they don't need a chipselect(driving this pin with ground). But this can only take place when you have only one slave connected.

On the GNUBLIN standard board its only posible to connect only one SPI device because the CS and IRQ lines are used on GPIO11 and GPIO14. For every device you need your own CS and IRQ line.

Configuration in kernel

In order to use all functions you should use the community kernel.(git clone http://code.google.com/p/gnublin-develop-kernel)

The SPI drive ist compiled as built-in to the kernel. If the driver is loading successfully, you should find a spidev attribute at /sys/class/spidev:

root@gnublin-debian:~# ls /sys/class/spidev/         
spidev0.1

Here you can see the created spidev (Busnumber = 0 and chipselect = 1) and the driver works correctly.

You can also find a device file locatet at /dev/spidev0.11 .

For a fast test of the driver you can send a random value over the interface by using the echo command on the device file.

echo 100 > /dev/spidev0.11


Controll Example in C

The following shows a controll example written in C. When the driver was loaded correctly, then you have only creat a device file. The variable *device determines the device file name. If you can't the device file in the /dev/ folder then you have to create it:

mknod /dev/spi0 c 153 0

=Running the programm

In order to access directly on the device file you need the spidev module.

Note: All SPI drivers like CAN, ENC28J60, etc. have to be deloaded! (e.g. modprobe -r enc28J60)

modeprobe spidev

After that you can use the exampleprogramm in the examples directory.

./root/examples/misc/spi/spidev_test2

You can also translate it by your own:

gcc -o /root/examples/misc/spi/ spidev_test2 /root/examples/misc/spi/spidev_test2.c
#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/spi0"; // <-- Changes here static uint8_t mode; static uint8_t bits = 8; static uint32_t speed = 100000; static uint16_t delay; static void transfer(int fd) { int ret; uint8_t tx[] = { 0xF0, 0xAA, 0x0F, 0xAA, 0x55, }; 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(""); } 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); } 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' }, { NULL, 0, 0, 0 }, }; int c; c = getopt_long(argc, argv, "D:s:d:b:lHOLC3", 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; 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"); /* * 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); close(fd); return ret; }


Tek-spi.jpg

This oscilloscope picture shows the five bytes written to the SPI bus 0xF0 0XAA, 0x0F, 0xAA and 0x55. The channel above is SCK and the channel below is MOSI. The MISO Pin was left unconnected. HINWEIS:If you got the Gnublin distribution then this application is already on your rootfs(/root/examples).

In other languages