SPI BBB Master, BBB 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.

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.

Yeah, this is the approach used by the I2C Slave Framework. So traditionally, the McSPI driver registers with the SPI Framework as an SPI Master. Now through DT config, we could have the McSPI driver register with the SPI Framework as an SPI Slave and then the SPI framework registers a callback with the McSPI driver (Slave Provider). On receiving event from the master, McSPI driver calls Custom Driver callback, which responds by writing to McSPI FIFO. Does that sound reasonable?

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).

I agree. In the case when the slave driver cannot respond in time, simply send a wait response and have the master retry until successful.

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.

The McSPI hardware will take care of this. From what I recall, McSPI does not process SPI signals until Slave Select is true.

<SNIP>

Yeah, this is the approach used by the I2C Slave Framework. So
traditionally, the McSPI driver registers with the SPI Framework as an SPI
Master. Now through DT config, we could have the McSPI driver register with
the SPI Framework as an SPI Slave and then the SPI framework registers a
callback with the McSPI driver (Slave Provider). On receiving event from
the master, McSPI driver calls Custom Driver callback, which responds by
writing to McSPI FIFO. Does that sound reasonable?

Sort of. I'd suggest an alternative (might be implied by what you are saying):
- Provide a fast callback that does exactly what you are saying.
- If no fast callback is registered, a slow path callback can be registered.
This slow back call back is invoked via a work queue.

Goal with something like this is to lessen the timing requirement on the
driver user.

The I2C slave side doesn't need this as I2C provides for the slave to slow
things down if needed.

> 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).

I agree. In the case when the slave driver cannot respond in time, simply
send a wait response and have the master retry until successful.
> 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.

The McSPI hardware will take care of this. From what I recall, McSPI does
not process SPI signals until Slave Select is true.

That is not sufficient for a slave. Consider the following usage scenario -
Protocol is - SS is asserted on a per transaction. First 8 bits clocked in is
a command. Additional clocks will read out data. Attempting to read out data
beyond what is appropriate for the command will return zeros. Deasserting /SS
will stop the current transaction to allow a new transaction to be started.

Something like that is often used for things that return variable amounts of
data. It can also provide a back channel for the master to resync thing.

Without propagating the /SS state back up to the driver user, the driver would
have a hard time synchronizing on the protocol level.

>>> 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.
>
>> Regards,
>> John
>>

<SNIP>

<SNIP>

Yeah, this is the approach used by the I2C Slave Framework. So
traditionally, the McSPI driver registers with the SPI Framework as an SPI
Master. Now through DT config, we could have the McSPI driver register with
the SPI Framework as an SPI Slave and then the SPI framework registers a
callback with the McSPI driver (Slave Provider). On receiving event from
the master, McSPI driver calls Custom Driver callback, which responds by
writing to McSPI FIFO. Does that sound reasonable?

Sort of. I'd suggest an alternative (might be implied by what you are saying):
- Provide a fast callback that does exactly what you are saying.
- If no fast callback is registered, a slow path callback can be registered.
This slow back call back is invoked via a work queue.

Yep, I think we are talking about the same thing. Either call the callback in interrupt context, or schedule the callback through a work queue (bottom half).

Goal with something like this is to lessen the timing requirement on the
driver user.

The I2C slave side doesn't need this as I2C provides for the slave to slow
things down if needed.

Good point because I2C can drag this out until slave does an ack. However, SPI slave could respond with a wait response until it has data available. Maybe the interrupt routing checks kfifo for a response message and it none exist, send wait command. Master retries until it gets the desired response.

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).

I agree. In the case when the slave driver cannot respond in time, simply
send a wait response and have the master retry until successful.

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.

The McSPI hardware will take care of this. From what I recall, McSPI does
not process SPI signals until Slave Select is true.

That is not sufficient for a slave. Consider the following usage scenario -
Protocol is - SS is asserted on a per transaction. First 8 bits clocked in is
a command. Additional clocks will read out data. Attempting to read out data
beyond what is appropriate for the command will return zeros. Deasserting /SS
will stop the current transaction to allow a new transaction to be started.

Something like that is often used for things that return variable amounts of
data. It can also provide a back channel for the master to resync thing.

Without propagating the /SS state back up to the driver user, the driver would
have a hard time synchronizing on the protocol level.

I see your point. Need to do some thinking on this one. So we need some sort of state machine?

Regards,
John

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.

Quite correct, so the designers of the slave interface reply with what
when the device is not ready? My suspicion is that it's 0xFF. I
think they have to deal with this gracefully.

Harvey