SPI BBB Master, BBB Slave

I am having issues with SPI between two BBB that may be simple to solve. I have spidev_test loopback working on each board but am having problems connecting the two.

spi0 master dts:

0x150 0x10 /* spi0_sclk, OUTPUT_PULLUP | MODE0 /
0x154 0x30 /
spi0_d0, INPUT_PULLUP | MODE0 /
0x158 0x10 /
spi0_d1, OUTPUT_PULLUP | MODE0 /
0x15c 0x10 /
spi0_cs0, OUTPUT_PULLUP | MODE0 */

spi slave dts:

0x150 0x30 /* spi0_sclk, INPUT_PULLUP | MODE0 /
0x154 0x10 /
spi0_d0, OUTPUT_PULLUP | MODE0 /
0x158 0x30 /
spi0_d1, INPUT_PULLUP | MODE0 /
0x15c 0x30 /
spi0_cs0, INPUT_PULLUP | MODE0 */

The oscilloscope shows activity when spi0_sckl (P9_17) is not connected but nothing when P9_17 is connected between both boards.
I am sending bytes from master with the command: echo 1 > /dev/spidev1.0

I need 4-8mbit/sec transfer, is this achievable by bit banging over GPIO and would that be a viable alternative to getting SPI working?

Hi,

I’m trying to setup SPI slave mode with same above method and changed OMAP2_MCSPI_MODULCTRL_MS set to 0 for slave mode.

i’m facing issue in master mode and slave both on sckl pin configuration.

http://elinux.org/BeagleBone_Black_Enable_SPIDEV in this link why sckl pin is configured as INPUT 0x33 but it will work with same configuration if i change it to OUTPUT it doesn’t work with any slave device and no clock on that pin.

Please anyone clarify this doubt and issues.

For slave mode i tried to change OMAP2_MCSPI_MODULCTRL_MS bit in driver file spi_omap2_mcspi.c but no use. still its master only.

Please provide any suggestion or exact procedure.

Thank you in advance.

Regard s
Ravi

As far as I know Linux still only supports the master side of SPI.
You will have to bitbang it if you want a bbb SPI slave.

Hi Ravi,

This is something I’m currently working on. However, for your application, why do you need to use SPI? Surely you could use IP Sockets or UART to achieve the same thing. Also, McASP has both master and slave support through the sound subsystem. Specifically you can use spdif_receiver.c and spdif_transmitter.c codecs to do what you need as show in[1]. Thereafter, implement something similar to alsa arecord and aplay to send and receive data from a user space app.

[1] http://processors.wiki.ti.com/index.php/Sitara_Linux_Audio_DAC_Example

Regards,
John

Hi John,

Yes I can use UART or other protocol to achieve same data communication.
But I’m working for client . They should require spi slave in kernel. So struggling to get it up. We asked TI also regarding this but they also don’t have any sample code for testing spi slave…

Regards
Ravi

Hi,

Is there any resolution about this ? Since I’m having the same consideration

Thanks !

What exactly are you trying to do? Please explain your application so that we can propose a solution.

Regards,
John

John Hi,

Thank you for coming back on this.

I’m trying to connect 2 SPI busses on the BBB (HDMI disabled) and configure SPI1 as SPI slave so that I can sent messages from SPI0 to SPI1 - this allows me my application development and laterone I’ll connect the respective SPI slave and master devices

Thank you
Yaron

Ah, what you are trying to do cannot be done with the current SPI driver because Linux SPI framework does not support SPI slave mode. Recently someone added I2C slave support to the I2C framework and that might be your first place to look. My approach would be to create a custom SPI driver that does not use the SPI framework. The length and frequency of messages will define the driver design. For example, if the message length is smaller than the SPI receive FIFO size, I would do this with interrupts, but the interrupt would occur only when exceeding the FIFO threshold and then dump the full FIFO in the bottom half interrupt handler. This way, you would get an interrupt on every say every 32 receive bytes, which will reduce the interrupt overhead and improve throughput.

If the message length is more than the FIFO length, or if the message is cyclical, then I would use DMA to copy the SPI data into a ping-pong buffer arrangement. From the use space app, you would use poll to wait for a complete buffer, and then read that buffer via read or mmap.

Question is, how experienced are you at writing Linux drivers? This isn’t a trivial task.

Regards,
John

I’d actually look into using the McSPI module. Which is hardware, and does support slave mode.

The McSPI needs a driver and there is currently no Linux Driver that supports SPI slave mode. The current driver /drivers/spi/spi-omap2-mcspi.c does not support slave mode. The Linux kernel SPI framework uses spi-omap2-mcspi driver on TI processors.

Regards,
John

Thank you very much about clarifying this point !

I don’t think that I can allocate enough time to dive into what John described - I assume that at some stage there will be such a driver or other form of such support

Thanks for now

Thank you very much about clarifying this point !

I don’t think that I can allocate enough time to dive into what John described - I assume that at some stage there will be such a driver or other form of such support

Thanks for now

People have been discussing this since ~2009, and 2013, one person on the TI e2e forums claimed to have it working. One way to get it working however, would be to use a PRU to enable, and monitor the McSPI module. Passed that, I’d probably use uio to communicate between the McPSI module, and Linux. Would it be a simple task to get all this working properly ? I’m afraid that this would be over my head too, for now, but I had considered taking this on as a project at some point. Something that’s a challenge always appeals to me . . .

Getting it to work is not hard. (Had it working for a project.) To get to work
reliably at a high clock rate requires debugging the DMA or working out a
protocol where timing isn't as tricky. As a slave the master can start
clocking at anytime and unless the FIFO (or DMA) is preloaded with the entire
packet the master wants, you will need to respond to the interrupt before an
underrun occurs.

The bigger barrier is a framework for SPI slave.

I’m not sure that is correct. The master will normally send a command and then your slave driver will have to respond with relevant packet. The protocol will have to be well defined. However, you are correct that the SPI slave must be preconfigured and waiting for the master to start clocking the interface. The problem with the SPI framework and in particular the McSPI driver is that they is written around a master implementation and adding slave support is almost impossible. It would be easier to write a slave McSPI from scratch. The I2C slave framework might be a good guide on how to make this work.

Regards,
John

I’m not sure that is correct. The master will normally send a command and
then your slave driver will have to respond with relevant packet. The
protocol will have to be well defined.

None of that is required by SPI (in the most basic form it is just a shift
register). What I was alluding it protocol games that be played like Master
writes byte to slave and waits for an active GPIO before anymore clocking. Or
even a dumb (unidirectional) protocol where the master waits for a GPIO to go
active before clocking out data.

In contrast, doing it like a lot of common devices where you can clock in a
byte (i.e. register address or a command) and expect data after another 8
clocks could impose some very tight timing requirements.

However, you are correct that the
SPI slave must be preconfigured and waiting for the master to start
clocking the interface. The problem with the SPI framework and in
particular the McSPI driver is that they is written around a master
implementation and adding slave support is almost impossible. It would be
easier to write a slave McSPI from scratch. The I2C slave framework might
be a good guide on how to make this work.

There are 2 things being mixed up here -
Merely grafting on slave functionality isn't too difficult with the current
McSPI driver (that's what I did). The main thing this gets you is a lot of the
driver registration and McSPI init is reused; this is a big hack but it gets
data flowing.

Getting it as a clean interface would definitely benefit from a rewrite as you
described.

I’m not sure that is correct. The master will normally send a command and
then your slave driver will have to respond with relevant packet. The
protocol will have to be well defined.

None of that is required by SPI (in the most basic form it is just a shift
register). What I was alluding it protocol games that be played like Master
writes byte to slave and waits for an active GPIO before anymore clocking. Or
even a dumb (unidirectional) protocol where the master waits for a GPIO to go
active before clocking out data.

Well, technically, that is correct, because data is shifted in and out at the same time, using the same clock. However, when the master hasn’t requested a specific data, what do you respond with? Random data? Perhaps if it was just streaming channel data, then I can see your point.

In contrast, doing it like a lot of common devices where you can clock in a
byte (i.e. register address or a command) and expect data after another 8
clocks could impose some very tight timing requirements.

I agree, this could be very difficult to achieve using interrupts, but using DMA that should be pretty simple. That presupposes that the data is already in the DMA buffer and this is some streaming interface I spoke of previously. Streaming channel data into the BBB using DMA would also be pretty simple. Exchanging of short master/slave command/response would need interrupt processing. Maybe using fixed size messages and using fifo watermark might limit the interrupt overhead.

However, you are correct that the
SPI slave must be preconfigured and waiting for the master to start
clocking the interface. The problem with the SPI framework and in
particular the McSPI driver is that they is written around a master
implementation and adding slave support is almost impossible. It would be
easier to write a slave McSPI from scratch. The I2C slave framework might
be a good guide on how to make this work.

There are 2 things being mixed up here -
Merely grafting on slave functionality isn't too difficult with the current
McSPI driver (that's what I did). The main thing this gets you is a lot of the
driver registration and McSPI init is reused; this is a big hack but it gets
data flowing.

Can you share that with me? I would be interested to see how you managed to do this. I’ve looked at this several times and each time my head wants to explode.

Getting it as a clean interface would definitely benefit from a rewrite as you
described.

If you are willing, perhaps this is a project we can work on together.

Regards,
John

I’m not sure that is correct. The master will normally send a command and
then your slave driver will have to respond with relevant packet. The
protocol will have to be well defined.

None of that is required by SPI (in the most basic form it is just a shift
register). What I was alluding it protocol games that be played like Master
writes byte to slave and waits for an active GPIO before anymore clocking. Or
even a dumb (unidirectional) protocol where the master waits for a GPIO to go
active before clocking out data.

Well, technically, that is correct, because data is shifted in and out at the same time, using the same clock. However, when the master hasn’t requested a specific data, what do you respond with? Random data? Perhaps if it was just streaming channel data, then I can see your point.

Data that is shifted back into the master is generally a known
quantity, generally 0xFF.

I haven't run into a device that requires data to be sent within a
certain amount of time. Generally, you don't have to always run at
the maximum, although there's sometimes a minimum.

I've been debugging SPI stuff on another platform, and the time
between bytes did not seem to be significant if it were held up by the
debugger.

In contrast, doing it like a lot of common devices where you can clock in a
byte (i.e. register address or a command) and expect data after another 8
clocks could impose some very tight timing requirements.

I agree, this could be very difficult to achieve using interrupts, but using DMA that should be pretty simple. That presupposes that the data is already in the DMA buffer and this is some streaming interface I spoke of previously. Streaming channel data into the BBB using DMA would also be pretty simple. Exchanging of short master/slave command/response would need interrupt processing. Maybe using fixed size messages and using fifo watermark might limit the interrupt overhead.

IF you're dealing with a streaming interface, then the timing is
imposed by the data stream output, and all the timing relaxations have
limits.

Harvey

However, you are correct that the
SPI slave must be preconfigured and waiting for the master to start
clocking the interface. The problem with the SPI framework and in
particular the McSPI driver is that they is written around a master
implementation and adding slave support is almost impossible. It would be
easier to write a slave McSPI from scratch. The I2C slave framework might
be a good guide on how to make this work.

There are 2 things being mixed up here -
Merely grafting on slave functionality isn't too difficult with the current
McSPI driver (that's what I did). The main thing this gets you is a lot of the
driver registration and McSPI init is reused; this is a big hack but it gets
data flowing.

Can you share that with me? I would be interested to see how you managed to do this. I’ve looked at this several times and each time my head wants to explode.

Getting it as a clean interface would definitely benefit from a rewrite as you
described.

If you are willing, perhaps this is a project we can work on together.

Regards,
John

Regards,
John

<snip>

I’m not sure that is correct. The master will normally send a command and
then your slave driver will have to respond with relevant packet. The
protocol will have to be well defined.

None of that is required by SPI (in the most basic form it is just a shift
register). What I was alluding it protocol games that be played like Master
writes byte to slave and waits for an active GPIO before anymore clocking. Or
even a dumb (unidirectional) protocol where the master waits for a GPIO to go
active before clocking out data.

Well, technically, that is correct, because data is shifted in and out at the same time, using the same clock. However, when the master hasn’t requested a specific data, what do you respond with? Random data? Perhaps if it was just streaming channel data, then I can see your point.

Data that is shifted back into the master is generally a known
quantity, generally 0xFF.

I haven't run into a device that requires data to be sent within a
certain amount of time. Generally, you don't have to always run at
the maximum, although there's sometimes a minimum.

I've been debugging SPI stuff on another platform, and the time
between bytes did not seem to be significant if it were held up by the
debugger.

If you are using an SPI master, then what you say is correct, but if you are a SPI slave, then some other device is controlling the clock, which means you have to have data available before the clock starts. If there is no delay between packets, then timing is critical.

Regards,
John

>
>> I’m not sure that is correct. The master will normally send a command and
>> then your slave driver will have to respond with relevant packet. The
>> protocol will have to be well defined.
>
> None of that is required by SPI (in the most basic form it is just a
> shift
> register). What I was alluding it protocol games that be played like
> Master
> writes byte to slave and waits for an active GPIO before anymore clocking.
> Or even a dumb (unidirectional) protocol where the master waits for a
> GPIO to go active before clocking out data.

Well, technically, that is correct, because data is shifted in and out at
the same time, using the same clock. However, when the master hasn’t
requested a specific data, what do you respond with? Random data? Perhaps
if it was just streaming channel data, then I can see your point.

Since SPI is always full duplex, it comes down to protocol definition. It
could be a fixed pattern, 0, 0xff, or random, or undefined data during the
initial clock out for the command byte.

> In contrast, doing it like a lot of common devices where you can clock in
> a
> byte (i.e. register address or a command) and expect data after another 8
> clocks could impose some very tight timing requirements.

I agree, this could be very difficult to achieve using interrupts, but using
DMA that should be pretty simple. That presupposes that the data is already
in the DMA buffer and this is some streaming interface I spoke of
previously. Streaming channel data into the BBB using DMA would also be
pretty simple. Exchanging of short master/slave command/response would need
interrupt processing. Maybe using fixed size messages and using fifo
watermark might limit the interrupt overhead.
>> However, you are correct that the
>> SPI slave must be preconfigured and waiting for the master to start
>> clocking the interface. The problem with the SPI framework and in
>> particular the McSPI driver is that they is written around a master
>> implementation and adding slave support is almost impossible. It would be
>> easier to write a slave McSPI from scratch. The I2C slave framework might
>> be a good guide on how to make this work.
>
> There are 2 things being mixed up here -
> Merely grafting on slave functionality isn't too difficult with the
> current
> McSPI driver (that's what I did). The main thing this gets you is a lot of
> the driver registration and McSPI init is reused; this is a big hack but
> it gets data flowing.

Can you share that with me? I would be interested to see how you managed to
do this. I’ve looked at this several times and each time my head wants to
explode.

Unfortunately, I cannot share that code (paperwork reasons, owned by
customer). The differences between slave/master from a pure driver's point of
view is a few register settings. A naive way of doing this is -

Initialize as slave
Have a callback in the driver that queue's data for transmission.
Driver user (aka data consumer) registers a receive callback that is invoked
when data comes in. Driver user is responsible for ignoring data when
appropriate.

On receive, queue more data for xfer to avoid underruns on the MISO end. If
nothing is queued by the driver user, put in fix data to keep the McSPI happy
(avoid underruns).

A better implementation may be to use a work queue arrangement to limit the
exposure of the driver user to time criticality. Probally need to propagate
the CS (SS) signal up to the driver user to help synchronize things.

> Getting it as a clean interface would definitely benefit from a rewrite as
> you described.

If you are willing, perhaps this is a project we can work on together.

We can talk about it.