PandaBoard SPI

From OMAPpedia

Jump to: navigation, search

To start using your funny SPI slave device with PandaBoard, you have to go through several steps. I will try to outline these steps in the current how-to. Basically, the process breaks into three pieces – connecting the device, patch the kernel and initiate data exchange with your device. In this document I assume that reader has experience with soldering/connecting wires and is able to build/start a custom Linux kernel.

Contents

[edit] What is SPI, and what devices can use it?

In short, SPI is a synchronous serial data link standard, named by Motorola, that operates in full duplex mode. Devices communicate in master/slave mode where the master device initiates the data frame. Multiple slave devices are allowed with individual slave select (chip select, CS#) lines. There is a wide range of SPI slave devices - from digital-analog converters to peripherals like ethernet adapters; even SD card can be connected in "SPI mode" to SPI masters. The PandaBoard has four SPI masters, each capable to drive SPI bus up to 48Mhz. Basics of SPI subsystem in linux are well described in Documentation/spi/spi-summary - and this is strongle recommended to read before soldering anything and making changes in code.

[edit] Connecting your SPI device

So, the pandaboard has four SPI masters. Likely, you will connect your device to the MCSPI1 master via the J3 expansion connector. Here is the picture of the expansion connector that shows where SPI pins are:

Connector-A.png

Designated pins are:

pin 4 MCSPI_CS3
pin 10 MCSPI_CS1
pin 12 MCSPI_SIMO
pin 14 MCSPI_CS2
pin 16 MCSPI_CS0
pin 18 MCSPI_SOMI
pin 20 MCSPI_CLK

Here you can see that there are CS0/CS1/CS2/CS3 lines, so up to four devices can be connected to this master. You probably will connect your device to SIMO, SOMI, CLK and CS0. Don't forget to provide some power supply to it!

With device I've played with, the DS3234, please see the connection photo:

Ds3234.jpg

Also, using DS3234 with PandaBoard requires level translator(s) like PCA9306. These level shifters, provided with two reference voltages, do translation of levels bidirectionnaly: if level on SDA1 is high to VREF1, the level on SDA2 becomes high to VREF2, and vice versa. They are needed because PandaBoard provides voltage of 1.8V on control pins, and DS2334 wants voltage from 3.3 to 5V. Here is the sample schematics I used to connect the DS2334 chip:

Levelshifting.jpg

Now you should have successfully connected and powered your device.

[edit] The SPI drivers stack

In most cases, you do not need to write any kernel code and study the kernel API for SPI. The kernel already contains several sort of device drivers, namely:

SPI master drivers are device drivers that responsible to make transfers over the SPI bus; in case of PandaBoard, this is something processor-specific. You will just implicitly use functions provided by these drivers.

SPI device drivers driving the specific SPI slaves. For example, in kernel there are drivers for SPI flashes, SPI ethernet devices, SPI RTC devices and many more. These device drivers know what bytes should be sent to the slave - and how to interpret the response (and masters knows [b]how to send[/b] these bytes and receive them back). For our sample, there is rtc-ds3234 driver, that is able to control our chip. The linux kernel also provides the spidev driver, which is very useful to control the device from the userspace.

Unfortunately, it is very rarely that SPI slaves support any way to automatically discover them. So the configuration of SPI bus should be set manually, and some kernel patching is necessary. The next paragraph explains how to modify your kernel to include the information about your SPI slave device.

[edit] Configuring and patching the kernel

Pandaboard's SPI masters are fully supported by the Linux kernel's mcspi driver. That being said, one will need to make only some minor modifications to the PandaBoard's board file (arch/arm/mach-omap2/board-omap4panda.c) in order to use them. Make sure that your kernel has these drivers compiled - check that CONFIG_SPI, CONFIG_SPI_MASTER and CONFIG_SPI_OMAP_24xx (In Ubuntu 12.04 source its CONFIG_SPI_OMAP24XX) are all set to 'y' or 'm' (in case of modules, one might have to rebuild and load the modules before one will be able to play with your SPI device). Then, the arch/arm/mach-omap2/board-omap4panda.c should be changed as follows:

0. On Ubuntu 12.04 you need to also add:

  #include <linux/spi/spi.h>

1. Declare the array of structures spi_board_info that matches your device:

static const struct spi_board_info panda_spi[] __initconst = {
     {
               .modalias = "spidev",
               .bus_num = 1,
               .chip_select = 0,
               .max_speed_hz = 1000,
               .mode = SPI_MODE_1,
     }, {
               .modalias = "ds3234",
               .bus_num = 1,
               .chip_select = 1,
               .max_speed_hz = 400000,
     },
 };

2. Create the function to mux the pins and register the spi_board_info structure with SPI core:

 static void __init panda_spi_devices_init(void) {
      /* muxing pins might be only required if
       * you've connecting 
       * device to CS other than CS0
       ***  This worked for me, add:
         omap_mux_init_signal("mcspi1_cs1", OMAP_PIN_OUTPUT); // sub "mcspi1_cs2 for CS2 etc.
         to activate CS1 on header pin #10.
         Make sure your call to panda_spi_devices_init() is after omap_serial_init()
         in omap4_panda_init function.
       *** using CS[1-3] will break UART1 ***
       */
      spi_register_board_info(panda_spi, ARRAY_SIZE(panda_spi));
 }

3. Call this function from omap4_panda_init, like

 panda_spi_devices_init()

A few comments about code snippets above:

In 1, fields of the structure are:

Now everything is in place, let's compile your kernel and/or modules and try to start it on panda.

[edit] Accessing the device

If you decided to reuse a driver from the linux kernel, the access details will be hidden from you – in our example, the rtc-ds3223 driver will perform all SPI bus exchange and provide you with /dev/rtc interface. If you want to write your own device driver (are you sure that you want to do this?) please refer to samples from the kernel, and do not hesitate to ask questions. This section will be only useful if you decided to use spidev. Its interface is well-defined in Documentation/spi/spidev, however here is a simple example how to access a device (still our example, DS3224) from a python script.

 import os, sys
  
 def spidev_test(devnode):
 	#
 	# very simple. no exception handling, just five steps:
 	#
 	# 1. Open device
 	spi = os.open(devnode, os.O_RDWR, 0777)	
 	# 2. Write single zero byte
 	write_bytes = "\x00"
 	w_res = os.write(spi, write_bytes, len(write_bytes))
 	if written != len(write_bytes):
 		raise Exception("Wrote less bytes than requested")
 	# 3. read 8 bytes back
 	rd = 8
 	rd_bytes = os.read(spi, rd)
 	if len(rd_bytes) != rd:
 		raise Exception("Read less than excpected")
 	# 4. print the result
 	print ["%x" % ord(rd) for rd in rd_bytes]
 	# 5. close the handle
 	os.close(spi)
  if __name__ == "__main__":
 	spidev_test("/dev/spidev1.0")
 	sys.exit(0)
  else:
 	print "How do you want to use spidev-test?"


[edit] References

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox