Thursday, April 13, 2023

Observing SPI Communication using Logic Analyser

In this article, let's try to understand how the serial peripheral interface (SPI) protocol works, which can be used to transfer data between digital electronics components. It is useful to connect various digital sensors and other peripheral modules with a microcontroller unit. As the name implies, it is a serial communication protocol. However, unlike UART, this is synchronous communication, and hence, SPI requires a clock signal. When communicating, one device acts as the master which provides the clock signal for the receiving, i.e., slave devices. The clock channel is named as SCK. We can have one master device, and one or more slave devices. The master device has to have dedicated set of channels, each connected to a particular slave device. By enabling the relevant dedicated channel, the master notifies that it wishes to communicate with the relevant slave device. These dedicated channels are called chip select or slave select (SS) channels. If there is only one slave device connected to the master device, there will be only one SS channel from the master to the slave. If there are two slave devices connected to the master, there will be two different SS pins from the master going to the two slave devices separately.

The data output from the master device is named as master-out slave-in (MOSI) channel, which is connect to the MOSI channels of all the slave devices. Similarly, the data input to the master device is named as master-in slave-out (MISO) channel, which similarly connects to the MISO pins of all the slave devices. This means, the data channels MOSI and MISO are shared about the master and all the slaves. Which slave is communicating with the master as a given moment is decided by the enabling of relevant SS channel by the master. The following diagram from Wikipedia nicely illustrates a scenario where a master device is connected to three slave devices:

Figure: SPI Connectivity between a master and three slaves (source: https://en.wikipedia.org/wiki/Serial_Peripheral_Interface)

Let's see the SPI protocol in action in a microcontroller module, particularly in an Arduino Uno device. In this scenario, our Arduino device is going to act as the master device. For the time being, we will not use a slave device since the action in MISO and MOSI are basically similar, except that they are taking data in the two directions separately. In our case, since we are only going to have a master device, we can observe some data in the MISO line when the master is sending some data out. The following is the code that we are programming the Arduino Uno device with. In this program, we are using SPI.h library from the Arduino library for SPI communication. Since we are using the pin 10 of the Arduino as the SS pin, we set it to OUTPUT mode. When initiating communication, we pull the SS pin LOW before sending data, which will go out from the MISO pin of the Arduino. After data transmission, we can set the SS pin HIGH again to signify that we are done. During the time period of SS pin is LOW, the master can both write data out (through MOSI) and also read data from the slave (through MISO) at the same time. In our case, we are only sending data out from the master.

Figure: The Arduino program to be run on the master device.

Now, it is time to wire the hardware for our observation. The MOSI, MISO, and SCK pins are hardware-defined pins. That means, we don't have a choice but to use the predefined pins of the Arduino device: MOSI is pin 11, MISO is pin 12, and SCK is pin 13. The number of SS pins we need depends on the number of slave devices we have. So, it is not hardwired. From our program code, we have set pin 10 to act as SS. When sending data from the master using SPI.h library, we can use SPI.transfer() function to specify the data we are sending. In our example code, we are sending the hexadecimal value 0xAA from the master which converts to 10101010 in binary. In order to observe SPI behaviour, let's connect the logic analyser to the SPI pins as follows:

Figure: Arduino's SPI pins connected to the logic analyser.
Channel Ground  --> GND

Channel 0 --> 10 (SS)

Channel 1 --> 11 (MOSI)

Channel 2 --> 12 (MISO)

Channel 3 --> 13 (SCK)

The following picture illustrates the Arduino Uno device pins tapped by the logic analysers channel probes. 














Now, we can observe the signals going through the relevant SPI pins of the Arduino device as captured by the logic analyser. The following screenshot illustrates the captured data by the logic analyser. Channel 0 indicates that the SS pin has been pulled LOW to enable data communication between the master and slave. When this was done, the master has immediately started sending a clock signal through the SCK pin, which is captured on Channel 3 of the logic analyser. While the clock signal is present, at every HIGH position of the clock, the MOSI and MISO channels can transmit data bits --- HIGH for 1 and LOW for 0 as data bits. In our case, the master was sending the bit pattern 10101010. Therefore, we observe the 10101010 pattern in the MOSI pin, which is captured by Channel 1 of the logic analyser. The MISO pin as captured by Channel 2 remains idle as we don't have a slave device to send anything back to the master.

Figure: Logic analyser's view of the data being transferred through SPI interface.

That's it about the SPI protocol. In contrast to the UART protocol, SPI has the advantage of connecting multiple devices together. A UART device only has Tx and Rx pins to send and receive data from only one other device. SPI achieves the capability to have more than two devices by adding an extra pin (SS) to select the intended recipient of a transmission. The cost of this is that the master device has to posses extra digital output pins as many as the number of slave devices. If there are 5 slave devices, the master should have 10 SS pins, in addition to the MISO, MOSI, and SCK pins.

Saturday, April 1, 2023

Observing UART Communication using Logic Analyser

The Universal Asynchronous Receiver / Transmitter (UART) is an embedded communication protocol, which can be used to transfer data between two electronic devices. As the name implies, this protocol is asynchronous, meaning that the sender and receiver does not have to be time synchronised through a dedicated clock signal. Instead, the signal itself is transferring a synchronisation pattern to help the receiver. For communicating from one device to the other, UART requires only one wire. However, since we need bi-directional communication, we need two wires each for sending data in a particular direction.

When you look at a microcontroller that supports UART communication, you will see that there are two dedicated pins called Tx and Rx for this purpose. The Tx pin is used to send asynchronous data from this microcontroller to the outside reicevier. Similarly the Rx pin is used to receive asynchronous data from the outside sender to the microcontroller. When the channel is idle, the UART wires are maintained at HIGH state (logic 1). When some data need to be transmitted, the transmission wire's logic level is pulled down to LOW so that the receiving device know that something is coming through the channel.

The data bits going through UART is organised into a frame structure. A UART frame consists of a start bit, data bits, parity bit, and finally a stop bit. The rate of bits is agreed between the sending and receiving devices by the programmer setting a parameter called baud rate. The are a specific set of baud rates that are usually used for this purpose. The data bits are sent in the order of least significant bit (LSB) first. The start bit is signified by a HIGH to LOW switch in the signal. Similarly, the stop bit is signified by a LOW to HIGH switch. The data bits and parity bit will be represented by either a HIGH or a LOW value depending on whether their values are 1s or 0s.

Let's see some specific real-world example of how UART works in Aruino platform. For this, we will be using a pair of Arduino Uno devices to communicate with each other through their UART ports. Arduino has a serial library to communicate through UART. The following are some specific details related to the Arduino serial library.

  • The start bit is 0 during a clock interval.
  • The end bit is 1 during a clock interval.
  • By default, there is no parity bit. If we want, we can set it to odd or even parity depending on our preference.
  • There are 8 data bits.
  • The data bits are sent in the least significant bit (LSB) first order.
Let's say we want to send the character 'A' from one Arduino device to which the second device responds with the character 'B'. First of all, let's see how these two characters would be represented in the UART.

Sending character 'A':

ASCII representation: 01000001
LSB-first order: 10000010

[ start bit | data bits | end bit ]

Frame pattern: [ 0 | 10000010 | 1 ]

Sending character 'B':

ASCII representation: 01000010
LSB-first order: 01000010

[ start bit | data bits | end bit ]

Frame pattern: [ 0 | 01000010 | 1 ]

The following two Arduino programs can be used for this purpose.



The two Arduino devices need to be connected with each other through their relevant pins. The Tx pin of the first Arduino should be connected to the Rx pin of the second device. Similarly, the Tx pin of the second Arduino device should be connected with the Rx pin of the first device. Furthermore, we should connect two GND pins of the two devices to have a common ground. The UART communication between these two devices can be observed using a logic analyser. We will connect the ground pin of the logic analyser to one of the GND pins of an Arduino. Then, channel-0 pin of the logic analyser can be connected to the Tx pin of the first Arduino. Similarly, the channel-1 pin of the logic analyser is connected to the Tx pin of the second Arduino. The following picture illustrates this wiring.


Now, let's fire up the Logic 2 program on the host computer to view the data captured by logic analyser on its channel-0 and channel-1 each representing the bits traveled in the Tx pins of each Arduino. The following screenshot illustrates the UART frames went on the two directions. If you watch carefully, you will see that the transmitted bit pattern is equal to the frame patterns that we identified previously for characters 'A' and 'B'.


Let's change the second Arduino's program to send back character '@' instead of 'B'. That means, the bit pattern it sends back has to be different.

Sending character '@':

ASCII representation: 01000000
LSB-first order: 00000010

[ start bit | data bits | end bit ]

Frame pattern: [ 0 | 00000010 | 1 ]

In the program code shown above, there is a commented line representing the way we send character '@' from the second Arduino. This time, when we observe this new response, we will see the following output on the logic analyser window.


This simple demonstration illustrates how data are included in UART communication protocol. By observing the channel using a logic analyser, it is actually possible to view the data being transferred. Let's explore how another embedded communication protocol works in another blog post.