8BIT wrote:
An SPI command interpreter, with a few simple commands:
Get Status, Get Data, Send Data, set parameter. The SPI receiver should have an interrupt so the controller does not miss an incoming request.
1) The SPI Master sends a Get Status command, waits for x amount of time for slave to be ready, the clocks the status back (two SPI transfers total)
2) If slave has data to be passed to master, master sends get data command that tells slave to send it. At this point, the time needed for the slave to respond needs to be defined so we won't miss it by starting the next transfer too soon. (two SPI transfers total)
3) Master sends Send Data command to slave, which is a command byte to tell the slave to go process something and return a value when done. The slave should acknowlege the command, then go do the task. The time needed to acknowlege the command will be variable depending upon how many commands it must decode. We need a method to ensure the ack is received by the master. (two spi transfers minimum)
When the task is done, the slave sets a status flag and waits for Master to execute task 2.
I ran into all this with the SBC-3's ATMega8 running the PC keyboard and RS-232 port. For every transmission, at least one more is needed for feedback.
Has anyone else created an SPI slave device? How did you handle it?
I have already addressed this during the construction of the SerBus preliminary protocol. This issue came about before even for dumb device construction too.
The solution is that the SPI controller
must exist as a self-contained functional unit with demonstrable resiliancy against failure of the intended peripheral.
What this means can best be explained by way of example.
Assume you're implementing a simple pen plotter, using the following commands: Q, W, E, A, D, Z, X, and C are used to move the carriage in the compass directions implied by their relative placement on the QWERTY keyboard. 1 is used for "pen-down", 2 for "pen-up".
Driving a stepper motor obviously takes MUCH longer than it'll take to transfer even a single byte plus status on the SPI bus, let alone an entire buffer full of commands. How, then, can we not only make the plotter asynchronous from the host PC, but also give it the ability to synchronize?
This is a clear-cut case where experience in writing multi-threaded software gives benefits to hardware design. The solution in software is to create a
separate thread, whose sole purpose is to keep an eye on the desired slave thread,
on behalf of the master thread.
In hardware terms, we apply the same principle by using
two microcontrollers: one whose
sole purpose is to baby-sit the SPI bus, and the other to drive the plotter. They're certainly cheap enough now -- about $0.50 each for the smaller microcontrollers. Except for PCB layout issues, there's no reason to use a single microcontroller anymore.
Due to the decoupling of functionality, the SPI controller runs independently of driven peripheral. If the intended peripheral ever crashes or malfunctions, you can at least still contact the SPI interface for telemetry
The plotter's SPI controller maintains a (
note: not necessarily
the) command queue, as viewed by the PC, along with knowledge of how deep the command queue currently is. It also knows (via its parallel I/O pins) the relevant status information of the slave peripheral as well. Thus, when the PC queries the device, it may receive information of both the front command buffer and the current operational status of the plotter.
Seeing that the front queue is empty, the PC may transmit a block of data to the SPI controller. Stuffing bytes is trivially simple, so it's able to maintain these bytes in the front queue.
When the plotter controller is ready, the SPI controller sends a byte to the plotter controller using its parallel I/O lines. Will the SPI device need to deal with interrupts? Absolutely! But, because everything is decoupled, your latencies at most are measured in microseconds, which will prove plenty fast enough for SPI interfaces, even if the plotter controller itself takes milliseconds or longer.
Ignoring cosmic ray interference, it is entirely possible to write the SPI controller to be crash-free under every input scenario. Some might argue that this takes a lot of effort; while it certainly does require more attention to detail, using formal design methodologies as simple as "Hoare triples" and deriving what are called Hoare's "weakest preconditions", a feat which requires neither formal training nor education in discrete mathematics, I would hardly call this a lot of effort.
Consider the effort in debugging the system under all possible input combinations!