To communicate with the MCU, ASR uses Afero Serial Protocol (afPro) over a Serial Peripheral Interface (SPI) bus. Note that we require use of SPI Mode 0 (CPOL and CPHA are both ‘0’; data is sampled at the leading rising edge of the clock).
To illustrate, we’ve provided some examples below. These examples assume:
We use timing diagrams from a logic analyzer to show the traffic.
Because all SPI transactions are driven by the master, and because afPro supports bi-directional communications, two problems must be solved:
To solve problem 1, we use a sync message to communicate the number of bytes to be sent from the master or the slave. This message can be sent at any time to make sure the master stays in sync with the slave. It is also used to recognize collisions (i.e., both master and slave want to send at the same time).
To solve problem 2, we add an interrupt line to the standard SPI signals. The slave can pulse the interrupt line when it wants the master to communicate with it. The master can then send a sync message to begin the transaction.
Whenever the MCU reboots, it must then force ASR to reboot as well, thus canceling any unresolved transactions between master and slave. The MCU does this by sending a Reset signal to ASR. But first the MCU must be ready to receive a request from ASR:
This sequence forces ASR to start from a known (initial) state. ASR will initiate the zero sync right after it reboots, as described below in Example 1.
A sync message is the first thing sent for every afPro transaction. There are two types of sync messages: Sync Request and Sync Acknowledge. Both messages have the same format; the only difference is the message type.
uint8_t | uint16_t | uint16_t | uint8_t |
---|---|---|---|
Message Type | MOSI byte count | MISO byte count | Checksum |
The message type is 0x30 for a Sync Request and 0x31 for a Sync Acknowledge. The checksum is simply the unsigned sum of all the other bytes in the message.
The simplest form of sync is when the master sends a Sync Request with both byte counts set to zero. If the slave also has no bytes to send, the master sends a Sync Acknowledge and the transaction is complete.
For all the timing diagrams in the examples below, the byte counts are little-endian and the signal order is:
Let’s look at these examples:
The INT line shows the ASR module starting transactions with the MCU:
Click image to enlarge:It follows this order:
Now let’s look at the individual messages.
After the MCU receives an interrupt from ASR, the MCU sends a Sync Request message:
Click image to enlarge:As the message is being clocked out, data from ASR is being clocked in. In the example above, the data clocked in exactly matches the data clocked out. The message type and checksum bytes are 0x30, and the two 16-bit byte counts are 0.
Since neither the MCU nor ASR has any bytes to send, the MCU can respond with a Sync Acknowledge.
It first waits for an interrupt from ASR, then sends the Sync Acknowledge message:
Click image to enlarge:The Sync Acknowledge looks just like the Sync Request except the message type is 0x31. The MCU ignores the data returned from ASR at this point.
Finally, the MCU waits for a final interrupt from ASR to know the transaction is complete.
At this point the master and slave are in sync. Neither one has anything to send.
Now let’s look at a more realistic example. Let’s look at a Set Attribute transaction, which sets the value of an attribute, then the subsequent Update Attribute transaction.
In this example, the Afero Cloud is requesting that the MCU change the value of one of its attributes using a Set Attribute transaction. The MCU makes the change and then responds with an Update Attribute transaction. Let’s start with an overview of the Set/Update Attribute transaction as a whole:
Click image to enlarge:The transaction starts with ASR pulsing the interrupt line to let the MCU know there is something to send. The transaction ends with ASR pulsing the interrupt line to signal the operation has completed. There are 13 distinct events here:
Set Attribute Transaction
Update Attribute Transaction
Let’s look at each event in more detail.
Receive Request
The transaction begins with ASR pulsing the interrupt to signal the MCU it has something to send. The MCU responds by sending a Sync Request message:
Click image to enlarge:As the MCU is clocking out the Sync Request saying that it has 0 bytes to send, it is clocking in the ASR response, which says it has 9 bytes to send. The MCU sees that ASR wants to send data and responds with a Sync Acknowledge.
Receive Acknowledge
The MCU now sends a Sync Acknowledge message that includes the byte count from the ASR Sync Request. The MCU is telling ASR it is ready to receive 9 bytes:
Click image to enlarge:Receive Data
Next, the MCU clocks out 9 bytes of zeros and clocks in the actual Set Attribute command from ASR:
Click image to enlarge:Finally, ASR pulses the interrupt line to let the MCU know it is ready to receive data again.
Now the MCU changes the attribute value locally and then starts an Update Attribute transaction to ASR. As always, it begins with a Sync Request. The MCU message is 11 bytes, so it sends 0x0B in the Sync Request message:
Click image to enlarge:Next is the Sync Acknowledge message:
Click image to enlarge:The Sync Acknowledge message confirms that we are going to send 11 bytes. On the next interrupt from ASR we send the actual data:
Click image to enlarge:After the final interrupt from ASR, the transaction is complete.
So now let’s look at what happens when both sides want to send something. Let’s say that at the exact same time the MCU wants to send something to ASR, ASR wants to send something to the MCU. We call this a “collision”. The protocol is designed to handle this case.
The first thing that happens is the MCU sends its Sync Request:
Click image to enlarge:In the example above, the MCU wants to send 10 bytes to ASR. As it clocks out its request, it clocks in the request from ASR that wants to send the MCU 12 bytes. At this point there is a collision. The protocol dictates that whenever there is a collision, the MCU wins. Both the MCU and ASR notice the collision. ASR queues its request and prepares to handle the MCU request. The MCU just waits for the next interrupt from ASR and then resends the Sync Request:
Click image to enlarge:At this point, ASR has queued its request and we are back in sync. After this message, the MCU sends the Sync Acknowledge followed by the data, just like in the examples above.
In general, the protocol is designed so that whenever there is an unexpected result, the MCU can resend the Sync Request to get things back in sync. You may need to send the Sync Request a couple of times, but ASR will eventually respond with the correct result.