Success : SPI on Beagleboard xM rev C

Hi,

After much effort, here is what I did on Ubuntu :

Board : Beagleboard xM rev C
SPI : SPI-4
Distro : Angstrom Linux Demo image

1. Install the GCC - ARM Cross Compiler on Ubuntu
$sudo apt-get install gcc-arm-linux-gnueabi

2. Download the Angstrom kernel sources from and checkout the
"beagleboardXM" branch from
http://gitorious.org/angstrom/angstrom-linux

$git clone git://gitorious.org/angstrom/angstrom-linux.git
$git checkout beagleboardXM
$git checkout -b spi

The commit id that I am using : 0ae46ae93c0e0d98f96d1b58bc0590b5fc484393

2. Alternatively download the tar.gz from
http://gitorious.org/angstrom/angstrom-linux/commits/beagleboardXM on
the right hand column there is a "Download beagleboardXM as tar.gz" if
you dont want to use git in the previous step.

3. You need to do the pin multiplexing in either u-boot or the kernel
sources. I have not changed the u-boot at all. I am making all the
changes in the kernel sources. Even though the kernel is 2.6.32 you
need to apply the following patch by hand
http://elinux.org/BeagleBoard/SPI/Patch-2.6.37 (by manually adding the lines)

NOTE : Make sure that the CLOCK is set as INPUT as in the above patch,
otherwise it wont work. It is not set correctly in the
http://elinux.org/BeagleBoard/SPI/Patch-2.6.32 patch.

This will set the correct pin multiplexing mode and also register the
SPI buses with the kernel. Once you do this and also make sure to
enable the User mode SPI drivers in the kernel (as shown below)

4. Compile the kernel

$make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- mrproper
$make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- omap3_beagle_defconfig
$make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig

Here you need to make sure that the SPI options are enabled and
compiled directly into kernel and NOT as module

Device Drivers > SPI Support > Debug support for SPI drivers
Device Drivers > SPI Support > McSPI driver for OMAP24xx/OMAP34xx
Device Drivers > SPI Support > User mode SPI device driver support

Now. compile the kernel

$make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- uImage

5. Compile the SPI test program available in kernel sources at
Documentation/spi/spidev_test.c
$arm-linux-gnueabi-gcc Documentation/spi/spidev_test.c -o spitest

6. Short the SPI-4 SIMO and SOMI pins on the board so that whatever
data is sent the same is received back. These details are available in
the ref. manual of beagle board
http://beagleboard.org/static/BBxMSRM_latest.pdf

- Page no. 107 - Figure 51. Main Expansion Header Processor Connections
- Page no. 108 - Table 22. Expansion Connector Signals. In this the
EXPANSION PIN NUMBER (first column) available on the EXPANSION PORT on
board (28 pins) shown in above figure which are connected the
Processor PIN (second column) and the corresponding SPI in column
labeled "1"

In short you need to SHORT the PIN NO. 12 and 18 for SPI-4

This is done so that when you run the test program of step 5 you will
get the same data that you sent on input pins.

7. Copy the uImage generated in the Step 4 and the "spitest" generated
in the Step 5 to the beagleboard. Now boot the board and you will get
the following files.

/dev/spidev3.0
/dev/spidev3.1
/dev/spidev4.0

Now run the test program and you will see the same input as output.
$spitest -D /dev/spidev4.0

Ref links : http://elinux.org/BeagleBoard/SPI

This is just a quick guide, I will write a more detailed one shortly.

Regards.

Hi
You use this guide to make Beagleboard + Angstrom Demo image:
http://linuxdeveloper.blogspot.com/2011/09/beagleboard-angstrom-demo-image.html
?
And after that where you write the new uImage file and "spitest" file?

Thank you.
Best regards.

Hello,
I am trying to connect a device on mcsp3 for beagle board, but when i am trying to read something i am always zero only, can u kindly help me how to fix this.

Regards
Sarika

Hi

Did the change of the pinmux as I suggested in our conversation earlier (setting CLK as Input) not help?

Did you check the SOMI signal arriving at BB with an oscilloscope?

Regards
Ueli

Quoting sarika baby <sarikababy123@gmail.com>:

Hello,
Yes is et the clokc pin as OMAP_MUX_INPUT only and i tried to probe the spi read and spi write pins, i am able to see the same signal on both the pins using an oscilloscope .

Regards
Sarika

Quoting sarika baby <sarikababy123@gmail.com>:

   Yes is et the clokc pin as OMAP_MUX_INPUT only and i tried to probe the
spi read and spi write pins, i am able to see the same signal on both the
pins using an oscilloscope .

Ok, so I guess you just shortened the SOMI with the SIMO pin right?

I had a little spare time so I took a look at the code you sent me yesterday:

       spi_message_init(&msg);
       buff[0][0] =0x20;
       buff[0][1] = SPI_HI_BYTE(reg);
       xfr_addr_high.tx_buf = buff[0];
       xfr_addr_high.rx_buf = &readbyte;
       spi_message_add_tail(&xfr_addr_high, &msg);

       buff[1][0] = 0x00;
       buff[1][1] = SPI_LOW_BYTE(reg);
       xfr_addr_low.tx_buf = buff[1];
       xfr_addr_low.rx_buf = NULL;
       spi_message_add_tail(&xfr_addr_low, &msg);

       buff[2][0] = 0xC0;
       buff[2][1] = 0x00;
       xfr_data_cmd.tx_buf = buff[2];
       xfr_data_cmd.rx_buf = &readbyte; //NULL;
       spi_message_add_tail(&xfr_data_cmd, &msg); xfr_data_val.tx_buf = NULL;
       xfr_data_val.rx_buf = &readbyte;
       spi_message_add_tail(&xfr_data_val, &msg);

You are issuing four transfers, where the last transfer overwrites the value read in the first transfer, with a value read while sending "random" (in the sense of "up to the driver") data. So what you'll read is some random value or possibly zero.

Regards
Ueli

Hello Ueli,
Sorry for thr typing mistake i pasted the code here http://pastebin.com/7LGPzPBU , kindly do cross check it.

Regards
Sarika

Hi again

Quoting sarika baby <sarikababy123@gmail.com>:

       Sorry for thr typing mistake i pasted the code here
http://pastebin.com/7LGPzPBU , kindly do cross check it.

No problem. Looking closer at the code, I found a possible mistake in your code when doing this assignment:
          xfr_data_val.rx_buf = &readbyte;

What you wanted to do is to assign the address of the start of your receiving array. What you did was, assinging the address of the pointer *to beginning of* the readbyte-array instead.

The correct assignment should be
          xfr_data_val.rx_buf = readbyte;

If that's not the source of error, there is another test I'd recommend:

Remove any peripheral device from this SPI port and short SOMI and SIMO. Then do a send/receive-Test first.

Note: You are only able to receive while you are sending something. The driver framework abstracts this to you as you are not forced to sepcify a send buffer if you are about to receive data but the requirements remains in lower levels.

So if you want to read through SOMI what just wrote to SIMO, you need to specify both, send and receive buffer in the same spi_transfer. Before I go further with explainations, For the test, modify your code like this:

  buff[0][0] = 0x20;
  buff[0][1] = SPI_HI_BYTE(reg);
  xfr_addr_high.tx_buf = buff[0];
  xfr_addr_high.rx_buf = readbyte;
  spi_message_add_tail(&xfr_addr_high, &msg);

remove all other spi_message_add_tail()-Calls for this test and look what's in "readbyte" after execution. I'd expect you'll get the same data you sent through buff[0].

Regards
Ueli

Hello,
What i did was i removed my slave device and just shorted the SOMI and SIMO lines present on expansion board of beagle and tried to write a set of values and then read them back. Then i was able to read the correct values what i wrote. I write my code like this :
void spi_check(void)
{
u8 test_read=0, test_write =0xCF;
struct spi_transfer data = {
.len = 1,
.cs_change = 1,
.bits_per_word = 8,
};
test_write = reg;
xfr_addr_high.tx_buf = &test_write;
xfr_addr_high.rx_buf = &test_read;
spi_message_add_tail(&data, &msg);
ret = spi_sync(spi, &msg);
}

But when i am connecting my device i am getting the read value as zero. I have a set of doubts regarding SPI protocol.
(a) What should be the value of .len in struct spi_transfer ?
(b) Actually to my slave device has 16bir spi and for example if i want to read register 0xC500 then i should send first 0x20 then higher byte of address i.e0xC5 then again 0x00 and then lower byte of address 0x00 and finally 0xC0. Only after this i can read the 8-bit data present in the register address (16bit address). (kindly refer the images attached )
So as per http://pastebin.com/7LGPzPBU is my procedure wrong.
© whats the difference in sending all the read data’s byte by byte in different spi_transfers?
(d) Whats the difference in reading the data in a different struct spi_transfer xfr_data_val and struct spi_transfer xfr_data_cmd?

Kindly let me know these basic differences, hope this will easily solve my issue.

Screenshot1.png

Screenshot1_extension.png

Did you even try the fix that was suggested to you earlier? You were asked to change this:
xfr_data_val.rx_buf = &readbyte;

To this:
xfr_data_val.rx_buf = readbyte;

Chuck

Hello Chuck,
Yes i changed to xfr_data_val.rx_buf = readbyte;

Regards
Sarika

Hi,

Hi,

Hi,

For those still struggling with getting SPI working I’ve written up a blog for the novice users that goes step by step on how to get SPI working in Ubuntu 11.10 on the BBXm.

http://www.brianhensley.net/2012/02/spi-working-on-beagleboard-xm-rev-c.html

Cheers,
Brian Hensley