7SDevice part3

PART 3 - Protocol handshaking simulation
So far we have designed the board hardware and the software concepts. Before starting to code the firmware it is helpful to implement a protocol simulator that will allow us to test if the message mimics are correct. We will develop this as a Java multi-threaded application. We will transmit a couple of digits, tracking every step of progress of both the device and the host state machines.

There are several classes belonging to this project that are in a package I called SPI_simulator. The classes are:


 * DataBus.java       This class implements the SPI bus
 * fifo.java          This class implements a FIFO structure
 * Ansi.java          This class implements some colors for writing text
 * device_rx.java     This is the receiving state machine
 * host_tx.java       This is the transmitting state machine
 * SPI_simulator.java This is the main program

Let start with the Data bus. This, as expected, is composed of three Boolean variables as seen from the host perspective. So clk is clock line derived by host and mosi is the Master Out Slave Input signal.

Next we will define the fifo structure we will use for storing received characters.

This is a dynamic structure that handles generic objects with only three methods:


 * push(Object o);
 * pop;
 * print;

The print method is specialized for printing chars. The structure however can be used for storing any kind of object.

The Ansi class is simply a set of ANSI codes made in a clean readable format. We will only use the red and green colors but should you need other colors in your projects I provided them all for you.

Now, before starting to analyze the central parts of our simulator work (device and host) I will introduce the main flow of the program.

So, we simply declare and initialize an rx buffer of the fifo type. Then we declare and initialize a system bus of type DataBus. Then we declare a device of “device_rx” type that works on the system bus and writes on the receive buffer and then we start it. At this point of the code “device.start”, the device thread starts to run on its own in parallel with the main. We then declare a sender of “host_tx” type and initialize it attaching it to the system bus. We will use the method “send_message” to invoke the sender passing it a string that it will transfer to the listening receive device.

When finished we stop the device and invoke the print method of rxbuf to show the received string that hopefully should be equal to the one we passed to the send_message method. Pretty simple, isn't it?

In this simulation the device and host are blocking, so if we don't start the device the send_message method will hang in a loop waiting for device to be ready and the program will never terminate. The device thread, until stopped, will run forever waiting for the host transmission. In the real firmware we'll implement this as non blocking code.

Ok, let's now move on to the device state machine. We will derive it from the Thread class and we will use an enumerative type to name the machine states with easy to read labels. If you remember Part 1 where we depicted our concepts, this is where we find the states Init, WaitForClkDown,WaitForClkUp and UpdateBuffer.

In the constructor we find the definition for the bus and fifo structure passed as a parameters from the main calling method.

now, since the class is a subclass of Thread we have to implement a run method that will be executed when start is invoked.

To make a long story short, this implements the mimic of the receiving state machine. The advantage of the simulator is to use many printouts to understand what happens at every step of the algorithm. Now you see the final version so this works as we expect. But when you are in the design stage, it is very useful to have a simulator that allows you to change the mimic and see what happens on the fly.

Each bit is read and then the register ch is updated (making bit-wise OR with 0x01 or bit-wise AND with 0xFE) then ch is shifted left. When 8 bit are read the received character is pushed in the FIFO buffer. The device asserts MISO down when a bit is received successfully so the host will read a 0 byte after a successful transfer.

Look at this instruction:

This is the blocking code snippet because until the clock goes up (high), the thread will stop there. Other blocking parts are similar. When we design the actual C device pic routine we will avoid it and I will show you a technique to accomplish that task.

Note that in each printed message is written a tab and the word “receive” so when we execute the code, it will be easy to know which thread is writing on the screen, since they are running in parallel.

OK, let's move on to see the host class. As in the device class we find the machine states belonging to an enumerative type have easy to remember names. The constructor only needs to have the data bus to attach to.

This class is not subclassed from the Thread one because it operates inside the static main thread. Here the state names are device centric, and look forward to the device behavior.

So, we finally have to implement the send_message method. Note that in this simulator I will pass a long string to the sender, but in the actual host pic C routine we will be only sending two characters to the device since the hardware we built has only two digits. However the simulation is carried out in the general case.

Here is the send_message method:

Ok, so far so good. It's time to see the output of our simulation and compare it to what we've seen in Part 1. I will print the output only for the first letter of the passed string “The quick brown fox jumped over the lazy dogs back”.

Let's analyze a few rows just to see what happened. Device thread is just created and the receive state machine prints the “Init” state and then Assert Miso up (high) signaling to the host that it is ready.

In the meantime, the host thread prints “Init” and begins sending the “T” character. The Host asserts clock up (high) and passes in the state Waiting for Device Ready. Since the device just asserted the MISO line up (high) the sender sees it and passes in the state assert clock down (low), and suddenly the receive thread responds with “Got clock down” and asserts MISO down (low) signaling that it is ready to receive a bit.

The device waits for the clock to be up (high) again. The host puts the bit 0 on the MOSI line and then asserts clock up (high) and passes in the WaitForDeviceAck state. The receive thread immediately sees the clock up (high) and reads the bit, then asserts MISO up (high) and passes in the WaitForClockDown to receive the next bit. This process repeats eight times. When all bits are transferred the receiver passes in the UpdateBuffer state where it pushes the character into the receive buffer.

As you can see from the machines' state flow everything goes as we expected and we can finally say that our algorithm will work. The character to be transmitted is printed not as a character but as its ASCII code. The send method identifies itself with the send keyword so you can clearly distinguish between the host and the device messages that have the receive keyword and are indented.

At this point most of our work is completed since we only have left the C coding of the device and host routines and the device interrupt implementation. This is what we will see in Part 4

= All parts of this article =


 * Part 1 - Goals and constraints
 * Part 2 - Hardware design
 * Part 3 - Protocol Handshaking simulation
 * Part 4 - Software
 * Part 5 - Measure and testing