Difference between revisions of "ECE497 SPI Project"

From eLinux.org
Jump to: navigation, search
m (Grading Template)
m (Installation Instructions)
(10 intermediate revisions by 3 users not shown)
Line 7: Line 7:
  
 
<pre style="color:red">
 
<pre style="color:red">
05 Executive Summary (Good start)
+
09 Executive Summary
02 Installation Instructions  
+
09 Installation Instructions (Too detailed to fully test at this time.)
00 User Instructions (Missing)
+
09 User Instructions
00 Highlights (Missing)
+
09 Highlights
00 Theory of Operation (Missing)
+
10 Theory of Operation (Nice details)
00 Work Breakdown
+
09 Work Breakdown
00 Future Work
+
10 Future Work
00 Conclusions
+
10 Conclusions
00 Demo
+
10 Demo
00 Late
+
10 On time
 
Comments: I'm looking forward to seeing this.
 
Comments: I'm looking forward to seeing this.
  
Score:  07/100
+
Score:  95/100
 
</pre>
 
</pre>
  
 
== Executive Summary ==
 
== Executive Summary ==
  
For this project we want to further improve documentation available for SPI with the Beagle Bone. In the process of our information gathering we will connect two different products that use SPI, one being an SPI radio interface and the other being a SPI LED strand.
+
For this project we wanted to further improve documentation available for sysfs kernel drivers with the Beagle Bone. To do this we have interfaced an [http://adafruit.com/products/306 LED light strand] by Adafruit with a sysfs kernel driver utilizing SPI. In doing so we have created an easy to use interface to the light strand while also maximizing data throughput.
  
So far there exists documentation for the [http://elinux.org/BeagleBoard/SPI BeagleBoard/SPI]. There also exists other documentation regarding the SPI specifications.
+
== Good Websites ==
  
The documentation is lacking for the current Beagle Bone platform interfacing with SPI. Additionally there exists virtually no documentation for using a Beagle device with the LPD8806 LED controller.
+
[http://elinux.org/BeagleBoard/SPI BeagleBoard and SPI]
  
In conclusion this project should help the Beagle community in general with information sharing and usable research.
+
[http://www.xml.com/ldd/chapter/book/ O'Reilly Book on Linux Device Drivers]
 +
 
 +
[http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/samples/kobject/kset-example.c Kset example for sysfs driver]
 +
 
 +
[http://elk.informatik.fh-augsburg.de/pub/elinux/ngw100-docs/AVR32743/spi/spi_example.c Example SPI device driver]
 +
 
 +
[http://www.jumpnowtek.com/index.php?option=com_content&view=article&id=57&Itemid=62 Another example SPI device driver]
 +
 
 +
== More Good Websites ==
 +
 
 +
[http://www.loadyourself.com/linux/sample-linux-driver/ Example Kernel Driver (ioctl, no sysfs)]
 +
 
 +
[http://www.freesoftwaremagazine.com/articles/drivers_linux Kernel Driver Tutorial (no sysfs/ioctl)]
  
 
== Installation Instructions ==
 
== Installation Instructions ==
  
The kernel driver for SPI is installed in the latest version  
+
All of these instructions are meant for the A6A BeagleBone running version 3.2.25+ of the kernel. Scripts and Makefiles expect that the kernel be located at <code>~/BeagleBoard/kernel/kernel</code>
<span style="color:red">(Which version, A6A?)</span> of the beagle bone.
 
  
We have integrated some code to work with a SPI radio device <span style="color:red">(What radio device?)</span>. The code is located at [https://github.com/larmorgs/ece497/tree/master/Project github].
+
Start by cloning the [https://github.com/larmoreg/FinalProject github] repository on both the bone and the host machine by running the following:
  
To get started hook up pins 30 and 11 to SPI Master and SPI clock. <span style="color:red">(Pins 30 and 11 of what?)</span>
+
both$ '''git clone git@github.com:larmoreg/FinalProject'''
  
Then echo 0 into both:
+
On the host machine, run the following:
beagle$ '''echo 0 > /sys/kernel/debug/omap_mux/spi1_d1'''
 
/sys/kernel/debug/omap_mux/spi1_sclk
 
  
to select the pin mux for SPI.
+
host$ '''cd ~/FinalProject'''
 +
host$ '''./setup.sh'''
  
<span style="color:red">(Please use my command format above)</span>
+
Make sure you only do this <b>once</b> because it is adding on our modules to the Kconfig and Makefile in <code>~/BeagleBoard/kernel/kernel/driver/char</code>. The files are backed up in the same folder with <code>.orig</code> appended.
 +
 
 +
Next run the following on the host machine:
 +
 
 +
host$ '''make kernel'''
 +
 
 +
This will copy the files <code>example.c</code> and <code>lpd8806.c</code> into the <code>~/BeagleBoard/kernel/kernel/driver/char</code> directory, make the kernel, and then scp the files to the bone.
 +
 
 +
Moving over to the bone, run the following:
 +
 
 +
bone$ '''cd /lib/modules/3.2.25+'''
 +
bone$ '''mv modules.dep.bin modules.dep.bin.orig'''
 +
 
 +
Next modify <code>modules.dep</code> to include <code>kernel/drivers/char/example.ko:</code> and <code>kernel/driver/char/lpd8806.ko:</code>
 +
 
 +
Upon successful completion, you should be able to run the following:
 +
 
 +
bone$ '''modprobe example'''
 +
bone$ '''modprobe lpd8806'''
 +
 
 +
== User Instructions ==
 +
 
 +
Run <code>dmesg</code> or <code>lsmod</code> to make sure the modules have loaded properly. You should now find two folders inside <code>/sys/firmware</code> called <code>example</code> and <code>lpd8806</code>. Feel free to play around in the example folder. If you go into this folder and then one folder further into device, you will find two files. The <code>test</code> file holds an unsigned integer, while the <code>data</code> file holds a string of length 10 (initially empty). You can read and write from these files as you would any other sysfs file.
 +
 
 +
Next we will hook up the LED strand. <b>For this make sure the beagle is powered externally</b>. The USB power supply does not have enough current to run the 5m strand at full brightness.
 +
 
 +
To get started hook up pins 30 (D12/SPI1_D1) and 31 (A13/SPI1_SCLK) to SPI data and SPI clock on the strand (see the silkscreen for guidance. Hook up the ground to ground (obviously), and the 5V wire on the strand to the <b>3.3V</b> pin on the bone. <b>Do not use the 5V pin on the bone or the suggested Adafruit 5V power supply directly connected to the strand without also adding logic level voltage shifters to the data and clock lines</b>.
 +
 
 +
[[File:Bone_P9_pinout.jpg]]
 +
 
 +
You may need to modify your muxes (if they have been changed from the default). If so, do the following:
 +
beagle$ '''echo 0 > /sys/kernel/debug/omap_mux/spi0_d1'''
 +
beagle$ '''echo 0 > /sys/kernel/debug/omap_mux/spi0_sclk'''
 +
 
 +
Now that the strand is hooked up, we can run the following:
 +
 
 +
bone$ '''cd /sys/firmware/lpd8806/device/'''
 +
bone$ '''echo "127 127 127" > grb'''
 +
 
 +
You should see the first LED (closest to the bone) light up bright white. You can also do something like the following:
 +
 
 +
bone$ '''echo "127 0 0 0 127 0 0 0 127" > data'''
 +
 
 +
The <code>data</code> file is written directly out to the strand while the <code>grb</code> file treats the strand like a big shift register. <b>Be careful with using <code>data</code></b>. Buffering problems can cause the kernel to seg fault or crash completely (see Future Work).
 +
 
 +
== Highlights ==
 +
 
 +
We have created a simple C example that uses this sysfs driver. You can run it by doing the following:
 +
 
 +
bone$ '''cd ~/FinalProject'''
 +
bone$ '''make'''
 +
bone$ '''./test'''
 +
 
 +
{{#ev:youtube|8d9n5QUyH38}}
 +
 
 +
The program shows the capabilities of the strand running in shift mode. Because of the nature of the strand's construction, it would be very simple to daisy chain many chains end to end. Also, the kset implementation means that we can have as many separate strands as there are SPI buses. Normally you could have even more, but the strand only runs 3 wire SPI (no chip select).
 +
 
 +
The speed is increased greatly when the strand is running in direct access mode by using the <code>data</code> file instead of the <code>grb</code> file. However, due to time limitations we were unable to debug the buffering issues. A good place for future work would be to figure out how the buffering problem can be alleviated.
 +
 
 +
== Theory of Operation ==
 +
 
 +
There are many layers to the implementation, so we will break them out into subsections.
 +
 
 +
=== Light Strand ===
 +
 
 +
The light strand uses the LPD8806 controller chip. Each chip controls the brightness of two 3 color GRB LEDs using PWM running at 1.2 MHz. SPI is used to communicate with the controller chips. The controller has its SPI bus rated somewhere around 20 MHz, but we are only running at 10 MHz. Each LED is 21-bit color, which leaves three bits available for latch control.
 +
 
 +
So, as you write color values out on the SPI, the first chip receives them. If the chip hasn't written a color to one of its to LEDs, it does so and thus ends the transmission. However, if it has already assigned a color to each LED then it passes the SPI along on a separate bus to the next chip. This is how the strand is able to be 5m and still run at 10 MHz.
 +
 
 +
It is still unknown how exactly the 3 latch bits are used (because the chip manufacturer has kept the interface a secret). However, if you write 6 bytes of "latch" the strand restarts at the beginning. Perhaps less bytes of "latch" can be sent and get the same effect, but due to time limitations we were unable to debug this completely. This is a simple place to start for future work.
 +
 
 +
=== SPI Bus ===
 +
 
 +
We use the default SPI controller to control the SPI lines. All we had to do is find what master is controlling the bus (2 in our case) and add a device. Initially, the SPI bus we want is being used by the default configuration of spidev. So, all we do is unregister the device from spidev and reregister it for our driver. There are a few things that go into the configuration of the device like speed, number of bits, chip select, and mode. Once these are set, you can add the device and it will then be associated with your driver.
 +
 
 +
=== Sysfs Kernel Driver ===
 +
 
 +
The sysfs kernel driver is based on the references above. It uses a kset to store kobjects (the basic building block of the kernel). Each kobject has associated with it certain attributes. These attributes are brought out to the user as files. When the files are read from or written to, the kernel calls back into the kobject's read/write routines. Here, we are able to decide which attribute is being addressed and manipulate the buffer as we see fit.
 +
 
 +
There are some alternative implementations to this that were looked into in addition to kset. The driver could have been implemented as a sysfs device driver instead of a kernel driver so that it shows up in <code>/sys/class</code> with everything else. Another option is that it could be implemented as a straight up device/kernel driver making it show up in <code>/dev</code> instead. There doesn't seem to be much of a difference though between these implementations as far as performance is concerned. However, finding where this driver fits best is another good place for future work.
  
 
== Work Breakdown ==
 
== Work Breakdown ==
  
So far we have done research on how Linux interfaces with SPI and we have integrated the SPI interface with current code that we have for an SPI radio. We also have explored methods of interfacing the SPI LED strip with a user to create a pleasant experience, such as creating a website to change the colors, or adding a possible twitter reader that would change the lights based on tweets.
+
=== Sean Richardson ===
 +
* Researched using SPI on the BeagleBone
 +
* Debugged the LED strand (the first one we received was broken)
 +
* Wrote code to interface with the strand using spidev
 +
* Helped integrate the SPI interface into the sysfs driver
 +
 
 +
=== Greg Larmore ===
 +
* Researched kernel drivers and sysfs
 +
* Helped debug the LED strand
 +
* Wrote example sysfs driver
 +
* Integrated the SPI interface into the sysfs driver
  
 
== Future Work ==
 
== Future Work ==
  
We want to develop a driver that will interface with SPI and potentially create a sysfs userspace utility for the LED strip.
+
While the strand works well as it is, there are some things that we would like to see looked into if there is future work on this project.
 +
 
 +
=== Latching and Controller Interface ===
 +
 
 +
According to Adafruit, the interface to this part has been reverse engineered. The one part that really remains unknown is how exactly the 3-bit control interface works for each LED. We were able to achieve a latching effect by sending 6 empty transmissions. The code in [github.com/adafruit/lpd8806 Adafruit's github] doesn't seem to be using this many latch transmissions.
 +
 
 +
=== Buffering Problem ===
 +
 
 +
There is a problem with buffered output going into the <code>data</code> file (because it is so big). When the output buffers it causes 2 sequential writes which weren't being handled well by the attribute's store function. This could be alleviated with a circular buffer and an index that can be controlled by the user, but really the driver should be able to handle this condition.
 +
 
 +
=== Sysfs File Location ===
 +
 
 +
The decision to have these drivers located in <code>/lib/modules/3.2.25+/kernel/drivers/char</code> and run out of <code>/sys/firmware</code> was pretty much arbitrary. It would be nice to do some research into how the kernel is supposed to be structured so that we can match it. This also applies to the example driver included in this project.
  
 
== Conclusions ==
 
== Conclusions ==
  
The SPI interface is not well developed in Linux and can use some work progressing it. We have taken on the task of getting these two devices to work in an easier manner.
+
In this project, we were able to get SPI (a lesser used interface on the bone) to work well with our LED strand. More impressively, we were able to interface with the SPI through a sysfs interface. In the process of developing this sysfs interface to the LED strand, we developed an example sysfs driver that can be used in future ECE497 classes. Lastly, we developed a sample application that uses this sysfs interface for our LED strand to show off the results.

Revision as of 00:58, 2 December 2012

Team members: Sean Richardson, Greg Larmore

Grading Template

I'm using the following template to grade. Each slot is 10 points. 0 = Missing, 5=OK, 10=Wow!

09 Executive Summary
09 Installation Instructions (Too detailed to fully test at this time.)
09 User Instructions
09 Highlights
10 Theory of Operation (Nice details)
09 Work Breakdown
10 Future Work
10 Conclusions
10 Demo
10 On time
Comments: I'm looking forward to seeing this.

Score:  95/100

Executive Summary

For this project we wanted to further improve documentation available for sysfs kernel drivers with the Beagle Bone. To do this we have interfaced an LED light strand by Adafruit with a sysfs kernel driver utilizing SPI. In doing so we have created an easy to use interface to the light strand while also maximizing data throughput.

Good Websites

BeagleBoard and SPI

O'Reilly Book on Linux Device Drivers

Kset example for sysfs driver

Example SPI device driver

Another example SPI device driver

More Good Websites

Example Kernel Driver (ioctl, no sysfs)

Kernel Driver Tutorial (no sysfs/ioctl)

Installation Instructions

All of these instructions are meant for the A6A BeagleBone running version 3.2.25+ of the kernel. Scripts and Makefiles expect that the kernel be located at ~/BeagleBoard/kernel/kernel

Start by cloning the github repository on both the bone and the host machine by running the following:

both$ git clone git@github.com:larmoreg/FinalProject

On the host machine, run the following:

host$ cd ~/FinalProject
host$ ./setup.sh

Make sure you only do this once because it is adding on our modules to the Kconfig and Makefile in ~/BeagleBoard/kernel/kernel/driver/char. The files are backed up in the same folder with .orig appended.

Next run the following on the host machine:

host$ make kernel

This will copy the files example.c and lpd8806.c into the ~/BeagleBoard/kernel/kernel/driver/char directory, make the kernel, and then scp the files to the bone.

Moving over to the bone, run the following:

bone$ cd /lib/modules/3.2.25+
bone$ mv modules.dep.bin modules.dep.bin.orig

Next modify modules.dep to include kernel/drivers/char/example.ko: and kernel/driver/char/lpd8806.ko:

Upon successful completion, you should be able to run the following:

bone$ modprobe example
bone$ modprobe lpd8806

User Instructions

Run dmesg or lsmod to make sure the modules have loaded properly. You should now find two folders inside /sys/firmware called example and lpd8806. Feel free to play around in the example folder. If you go into this folder and then one folder further into device, you will find two files. The test file holds an unsigned integer, while the data file holds a string of length 10 (initially empty). You can read and write from these files as you would any other sysfs file.

Next we will hook up the LED strand. For this make sure the beagle is powered externally. The USB power supply does not have enough current to run the 5m strand at full brightness.

To get started hook up pins 30 (D12/SPI1_D1) and 31 (A13/SPI1_SCLK) to SPI data and SPI clock on the strand (see the silkscreen for guidance. Hook up the ground to ground (obviously), and the 5V wire on the strand to the 3.3V pin on the bone. Do not use the 5V pin on the bone or the suggested Adafruit 5V power supply directly connected to the strand without also adding logic level voltage shifters to the data and clock lines.

Bone P9 pinout.jpg

You may need to modify your muxes (if they have been changed from the default). If so, do the following:

beagle$ echo 0 > /sys/kernel/debug/omap_mux/spi0_d1
beagle$ echo 0 > /sys/kernel/debug/omap_mux/spi0_sclk

Now that the strand is hooked up, we can run the following:

bone$ cd /sys/firmware/lpd8806/device/
bone$ echo "127 127 127" > grb

You should see the first LED (closest to the bone) light up bright white. You can also do something like the following:

bone$ echo "127 0 0 0 127 0 0 0 127" > data

The data file is written directly out to the strand while the grb file treats the strand like a big shift register. Be careful with using data. Buffering problems can cause the kernel to seg fault or crash completely (see Future Work).

Highlights

We have created a simple C example that uses this sysfs driver. You can run it by doing the following:

bone$ cd ~/FinalProject
bone$ make
bone$ ./test

{{#ev:youtube|8d9n5QUyH38}}

The program shows the capabilities of the strand running in shift mode. Because of the nature of the strand's construction, it would be very simple to daisy chain many chains end to end. Also, the kset implementation means that we can have as many separate strands as there are SPI buses. Normally you could have even more, but the strand only runs 3 wire SPI (no chip select).

The speed is increased greatly when the strand is running in direct access mode by using the data file instead of the grb file. However, due to time limitations we were unable to debug the buffering issues. A good place for future work would be to figure out how the buffering problem can be alleviated.

Theory of Operation

There are many layers to the implementation, so we will break them out into subsections.

Light Strand

The light strand uses the LPD8806 controller chip. Each chip controls the brightness of two 3 color GRB LEDs using PWM running at 1.2 MHz. SPI is used to communicate with the controller chips. The controller has its SPI bus rated somewhere around 20 MHz, but we are only running at 10 MHz. Each LED is 21-bit color, which leaves three bits available for latch control.

So, as you write color values out on the SPI, the first chip receives them. If the chip hasn't written a color to one of its to LEDs, it does so and thus ends the transmission. However, if it has already assigned a color to each LED then it passes the SPI along on a separate bus to the next chip. This is how the strand is able to be 5m and still run at 10 MHz.

It is still unknown how exactly the 3 latch bits are used (because the chip manufacturer has kept the interface a secret). However, if you write 6 bytes of "latch" the strand restarts at the beginning. Perhaps less bytes of "latch" can be sent and get the same effect, but due to time limitations we were unable to debug this completely. This is a simple place to start for future work.

SPI Bus

We use the default SPI controller to control the SPI lines. All we had to do is find what master is controlling the bus (2 in our case) and add a device. Initially, the SPI bus we want is being used by the default configuration of spidev. So, all we do is unregister the device from spidev and reregister it for our driver. There are a few things that go into the configuration of the device like speed, number of bits, chip select, and mode. Once these are set, you can add the device and it will then be associated with your driver.

Sysfs Kernel Driver

The sysfs kernel driver is based on the references above. It uses a kset to store kobjects (the basic building block of the kernel). Each kobject has associated with it certain attributes. These attributes are brought out to the user as files. When the files are read from or written to, the kernel calls back into the kobject's read/write routines. Here, we are able to decide which attribute is being addressed and manipulate the buffer as we see fit.

There are some alternative implementations to this that were looked into in addition to kset. The driver could have been implemented as a sysfs device driver instead of a kernel driver so that it shows up in /sys/class with everything else. Another option is that it could be implemented as a straight up device/kernel driver making it show up in /dev instead. There doesn't seem to be much of a difference though between these implementations as far as performance is concerned. However, finding where this driver fits best is another good place for future work.

Work Breakdown

Sean Richardson

  • Researched using SPI on the BeagleBone
  • Debugged the LED strand (the first one we received was broken)
  • Wrote code to interface with the strand using spidev
  • Helped integrate the SPI interface into the sysfs driver

Greg Larmore

  • Researched kernel drivers and sysfs
  • Helped debug the LED strand
  • Wrote example sysfs driver
  • Integrated the SPI interface into the sysfs driver

Future Work

While the strand works well as it is, there are some things that we would like to see looked into if there is future work on this project.

Latching and Controller Interface

According to Adafruit, the interface to this part has been reverse engineered. The one part that really remains unknown is how exactly the 3-bit control interface works for each LED. We were able to achieve a latching effect by sending 6 empty transmissions. The code in [github.com/adafruit/lpd8806 Adafruit's github] doesn't seem to be using this many latch transmissions.

Buffering Problem

There is a problem with buffered output going into the data file (because it is so big). When the output buffers it causes 2 sequential writes which weren't being handled well by the attribute's store function. This could be alleviated with a circular buffer and an index that can be controlled by the user, but really the driver should be able to handle this condition.

Sysfs File Location

The decision to have these drivers located in /lib/modules/3.2.25+/kernel/drivers/char and run out of /sys/firmware was pretty much arbitrary. It would be nice to do some research into how the kernel is supposed to be structured so that we can match it. This also applies to the example driver included in this project.

Conclusions

In this project, we were able to get SPI (a lesser used interface on the bone) to work well with our LED strand. More impressively, we were able to interface with the SPI through a sysfs interface. In the process of developing this sysfs interface to the LED strand, we developed an example sysfs driver that can be used in future ECE497 classes. Lastly, we developed a sample application that uses this sysfs interface for our LED strand to show off the results.