SPI Protocol Transaction#

Transaction Initiated by the Host#

The basic EZSP-SPI transaction is half-duplex to ensure proper framing and to give the NCP adequate response time. The basic transaction, as shown in the following figure, is composed of three sections: Command, Wait, and Response. The transaction can be considered analogous to a function call. The Command section is the function call, and the Response section is the return value.

General Timing Diagram for a SPI TransactionGeneral Timing Diagram for a SPI Transaction

Note: Silicon Labs recommends controlling nSSEL from the host to ensure that nSSEL is asserted at the beginning of the transaction, and stays asserted until the end of the transaction, instead of using the auto chip select function.

Command Section#

The Host begins the transaction by asserting the Slave Select and then sending a command to the NCP. This command can be of any length from 2 to 136 bytes and must not begin with 0xFF. During the Command section, the NCP will respond with only 0xFF. The Host should ignore data on MISO during the Command section. Once the Host has completed transmission of the entire message, the transaction moves to the Wait section.

Transmitting a command is a basic operation that simply requires asserting Slave Select and "dumping" the command bytes on the SPI in the most convenient method available (such as using a for() loop over a manual write, an interrupt-driven write, or a DMA). Once the first byte of the Response is received and the transaction has moved into the Response Section, receiving a Response is a basic, three-step operation: decode the first two bytes to determine the length of the Response, receive that precise number of bytes, and then deassert Slave Select.

The Wait section that occurs between the Command and Response sections is discussed further in the following section.

Wait Section#

The Wait section is a period of time during which the NCP may be processing the command or performing other operations. This section can be any length of time up to 350 ms. Because of the variable size of the Wait section, an interrupt-driven or polling-driven method is suggested for clocking the SPI as opposed to a DMA method. Since the NCP can require up to 350 ms to respond, as long as the Host keeps Slave Select active, the Host can perform other tasks while waiting for a Response.

How the Wait Section is implemented and handled requires some careful consideration of the two techniques available:

  • Clock the SPI until the NCP transmits a byte other than 0xFF (also known as polling on the SPI or polling for data) .

  • Interrupt on the falling edge of nHOST_INT.

Clock the SPI (Polling for Data)#

The simplest and most straightforward method for determining when a Response is ready is to continually clock the SPI until the NCP transmits a byte other than 0xFF. When the host "clocks the SPI," the host should simply transmit 0xFF, because transmitting 0xFF is considered an idle line. The NCP will also indicate that a Response is ready by asserting the nHOST_INT signal. The falling edge of nHOST_INT is the indication that a Response is ready. Once the nHOST_INT signal asserts, nHOST_INT will return to idle after the Host begins to clock data.

The major advantage of polling for data is that the simplicity of polling requires very little code space, and in most cases this can be implemented using either a while() or a do{}while loop. The disadvantage of polling for data is the blocking nature of polling. Because transactions must occur serially (meaning a transaction must complete before another transaction can begin), the blocking nature of polling for data is usually only an issue if the host needs to perform tasks not related to EmberZNet PRO.

For example, if the host captures a button press and must send a message over the network in response to the button press, blocking in a polling loop is not a critical issue because of the serial nature of the transaction. Conversely, if the host must periodically take an ADC measurement and perform calculations based on the measurement, then blocking in a polling loop might not be desirable.

Because the host is the SPI Master, there are essentially no timing requirements dictating when or how often the host should clock the SPI (the most important requirement is to keep transactions moving quickly so that messages do not back up in the NCP’s buffers). Therefore, the host can clock the SPI at its convenience, which means that a developer can choose to implement the simplest solution possible and sit in a while() loop waiting for a response. The developer can also choose a more advanced solution: for the host to poll periodically for a response while allowing other tasks to execute on the host. Knowing that the Wait Sections of many transactions can be milliseconds long, the developer may decide to clock the SPI and check for a response only once every millisecond.

Silicon Labs recommends choosing the simplest solution possible in the context of the host’s resources and other requirements. During development, starting with the simplest blocking while() loop is an easy solution that can be expanded and customized as development progresses.

Interrupt on the Falling Edge of nHOST_INT#

As detailed in Response Section, the falling edge of the signal nHOST_INT indicates that a Response is ready when the falling edge occurs while Slave Select is asserted. Instead of clocking the SPI (either by completely blocking or periodically polling) and waiting for a response, the host can be configured to interrupt on the falling edge of nHOST_INT. Once the host sees a falling edge on nHOST_INT, it must still clock the SPI until data other than 0xFF is received. The major advantage to interrupting on nHOST_INT is the ability of the host to perform other tasks while waiting for a response. The major disadvantage to interrupting on nHOST_INT is the potential for accidentally starting a new transaction before the previous transaction has completed. Remember, because a new transaction cannot begin until the previous transaction has completed, be careful not to accidentally overlap transactions.

Note: The host should not poll on the level of the nHOST_INT signal. Despite nHOST_INT remaining low until the host performs an action, only the falling edge of nHOST_INT can be trusted to properly indicate data. The NCP will carefully schedule the falling edge of nHOST_INT, but due to latency it cannot guarantee exactly when the nHOST_INT signal will return to idle after the host performs an action.

Response Section#

When the NCP transmits a byte other than 0xFF, the transaction has officially moved into the Response section. The NCP signals its readiness to enter the Response section by asserting nHOST_INT after a command from the host has been fully processed. The data format is the same format used in the Command section. The response can be of any length from 2 to 136 bytes and must not begin with 0xFF. Depending on the actual response, the length of the response is known from the first or second byte. This length should be used by the Host to clock out exactly the correct number of bytes.

Once all bytes have been clocked, the Host is allowed to deassert chip select. Since the Host is in control of clocking the SPI, no ACKs or similar signals are needed back from the Host because the NCP assumes the Host could accept the bytes being clocked on the SPI. After every transaction, the Host must hold the Slave Select high for a minimum of 1 ms. This timing requirement is called the inter-command spacing and is necessary to allow the NCP to process a command and become ready to accept a new command.

Transaction Initiated by the NCP#

When the NCP has data to send to the Host outside of a command/response transaction (Slave Select is idle), it will assert the nHOST_INT signal to indicate asynchronous data waiting in the NCP for the host. The nHOST_INT signal is designed to be an edge-triggered signal as opposed to a level-triggered signal; therefore, the falling edge of nHOST_INT is the true indicator of data availability. The Host then has the responsibility to initiate a transaction to ask the NCP for its output. The Host should initiate this transaction as soon as possible to prevent possible backup of data in the NCP. The NCP will deassert the nHOST_INT signal after receiving a byte on the SPI. Due to inherent latency in the NCP, the timing of when the nHOST_INT signal returns to idle can vary between transactions. nHOST_INT will always return to idle for a minimum of 25 µs before asserting again. If the NCP has more output available after the transaction has completed, the nHOST_INT signal will assert again after Slave Select is deasserted and the Host must make another request.

Remember, the host should not poll on the level of the nHOST_INT signal. Instead, the host should assign an interrupt to nHOST_INT and use the falling edge (the interrupt) to set a flag or some similar marker. This way, the EZSP implementation on the host can regularly poll on the flag outside of the interrupt context and trigger the EZSP Callback command.

For more advanced functionality, you can connect nHOST_INT to a pin that is capable of waking the host from sleep, and therefore enter a low power mode, while waiting for any incoming data, like a normal asynchronous callback.

Care must be taken when enabling an interrupt on nHOST_INT so that the proper piece of code is executed. nHOST_INT is capable of indicating three different situations (wake, callback, and response), and these situations are best indicated by the current state of the nSSEL and nWAKE pins.

Unexpected Resets#

The NCP is designed to protect itself against undefined behavior due to unexpected resets. The protection is based on the state of Slave Select since the inter-command spacing mandates that Slave Select must return to idle. The NCP’s internal SPI Protocol uses Slave Select returning to idle as a trigger to reinitialize its SPI Protocol. By always reinitializing, the NCP is protected against the Host unexpectedly resetting or terminating a transaction. Additionally, if Slave Select is active when the NCP powers on, the NCP will ignore SPI data until Slave Select returns to idle. By ignoring SPI traffic until idle, the NCP will not begin receiving in the middle of a transaction.

If the Host resets, in most cases it should also reset the NCP so that both devices are once again in the same state: freshly booted.

If the NCP resets during a transaction, the Host can expect either a Wait Section timeout or a missing Frame Terminator indicating an invalid Response.

If the NCP resets outside of a transaction, the Host should proceed normally.