I2C, SPI, USART... What are these things?

A common task for a microcontroller is to communicate with other devices, either a simpler microcontroller (such as a sensor), another microcontroller, or even a computer. For this purpuse, a few communication buses are standardized and widely used, and knowing them will allow you to talk to the vast majority of sensors and ICs that will cross your path.

Here is a comparaison of the four main standards the most widely used, and for which hardware controllers and software drivers are available in the SAM4L and libtungsten :

Typical devices Sensors High-speed sensors (accelerometers)
Data storage devices (Flash, SD card, EEPROM)
Data transmitters (wireless, ...)
Complex systems (GPS receivers, GSM transmitters...)
Other microcontrollers
Computers (as Device mode)
Simple USB devices (keyboard, mouse, ... as Host mode)
Bus type Master/slave Master/slave Symetrical Host/Device
Half/Full duplex Half duplex Full duplex Full duplex Half duplex
Number of devices Up to a few dozens Theoretically up to 4, usually 1 or 2 in practice One One
Speed Moderate Moderate to high Low to moderate High
Complexity Simple to moderate Simple Simple Complex
Reliability (error detection, ...) High Moderate Low High
Electrical lines 2 :
SDA (data)
SCL (clock)
3 + 1 per device :
MOSI (Master Out Slave In)
MISO (Master In Slave Out)
SCK (clock)
1 CS (Chip Select) per device
2 to 5 :
Rx (receiver channel)
Tx (transmitter channel)
CLK (clock, optional)
CTS (Clear To Send, optional)
RTS (Ready To send, optional)
2 (differential) :
D+/DP (Data Plus)
D-/DM (Data Minus)


I2C (eye-two-see or eye-squared-see) is a bus and a protocol widely used in a range of different ICs, including sensors, multiplexers, and as an additionnal interface to larger chipsets.

This bus uses two electrical lines : SDA (data) and SCL (clock), on which every device is collected as an open-drain, and which are permanently connected to Vcc through two pull-up resistors. An open-drain pin can only be connected to GND or be left floating, which means that a device can only pull the line to GND (logical zero) or let the line go back to Vcc (logical one) if no other device is pulling it low. This effectively leads to an implicit OR architecture, with the line being at logical state 1 by default and falling to logical state 0 if any device pulls it low, thus avoiding any possibility of line contention and short-circuit if two devices try to communicate at the same time.

I2C operates in a master/slave fashion : each device can either be a master, organising the data transfers on the bus, or a slave, which responds to a predefined address and answers to requests from the master. Even though the protocol allows for a bus to have multiple masters, this is rarely used, most I2C buses one and only one master. In most cases, only the master controls the SCL (clock) line, but the SDA (data) line is controlled in turn by the master and the slaves.

Each I2C slave has an 7-bit address, which must be unique on the bus, therefore allowing theoretically up to 127 slaves on a single bus (although line impedence issues will usually prevent you from having that many devices at the same time). The 8th bit is known as the R/W (read/write) bit and is used by the master to indicate the direction of data during a transfer. There is a small ambiguity to be careful about here : some documents will refer to the device address as the 7-bit address, ignoring the R/W bit, while other consider each device has two 8-bit addresses, one for reading and one for writing data. For example, a device can be considered to have either the 0x35 address, or both the 0x6A (write) and 0x6B (read) addresses.

The master begins a transfer by outputing a clock signal on the SCL line (typically at 100kHz) and transferring a byte on the SDA line, coding the device address on 7 bits with the R/W bit. When a device recognize its own address, it acknowledges it by pulling the SDA line low. Then, the data is transfered, either by the master or by the slave, according to the R/W bit in the address byte. A transfer can be arbitrarily long, as long as the receiver aknowledges every byte that the emitter sends.

A technique, called clock stretching, is used when a slave recognises its address on the bus but needs a bit more time to be ready to answer. To achieve this, the device can keep the clock signal low (this is the only case when a slave controls the SCK line) for the time it needs to finish its operation. The master will wait until the SCK line rises again before resuming the transfer.


SPI is also a serial bus and is often seen as a concurrent to I2C, even though they both have their pros and cons. Compared to I2C, SPI...

  • is quicker : the clock is usually between 1MHz and 5MHz, compared to 100kHz or 400kHz for I2C, there is less protocol overhead, and the transmission is full-duplex, meaning that data is sent and received at the same time
  • has a simpler protocol : there is no address, R/W and acknowledge
  • has a more complex electrical interface : two data lines instead of one, and one microcontroller select line per device
  • is less reliable : the protocol doesn't provide an acknowledge system

For these reasons, SPI is often used for data storage ICs (Flash, EEPROM,...), high-speed sensors (accelerometers, ...), and for microcontroller-to-microcontroller communication.

An SPI bus also uses a master/slave architecture, but the pins operate in push-pull mode instead of open-drain. This is the simpler case, where the line is either driven high or low (no pull-up necessary). The master controls all the pins except the MISO (Master In Slave Out) pin which is controlled by the slave.

The master begins a transfer by activating a single slave by pulling its CS pin low, while keeping the other high. The master then begins clocking the SCK line while transfering data on the MOSI line and receiving data on the MISO line at the same time. In most cases, when only one way of communication is used (only reading or only writing), the unused bits are set to zero.


An USART, or more commonly known as UART (the S stands for synchronous, which means that a clock line is used, which is rarely the case in practice), is arguably the oldest, simplest and most widely used communication interface. In its most basic form, it consists of a simple line which sends bits (voltages represents logical zeros and ones) at a predefined and constant frequency. Usually, there are two lines, one for transfering data in each direction between the two devices : the Tx line of a device is connected to the Rx line of the other. This makes the system symetrical, without a presupposed master or slave. In some cases, a clock line is used, but most of the time the bitrate is known in advance : 9600, 64800 and 115200 bps (bits per second) are common values.

In addition to the bitrate, a few other settings can be customized : the number of bits per byte (usually 8), the presence and type of parity bit (used as a very simple data integrity check) and the length of the stop bit compared to a data bit (usually 1). These settings must match between the two devices in order for the transfer to work.

To make sure that there is no data loss, the protocol provides an optional method called hardware flow control using two additional lines : CTS and RTS. RTS is an output pin, and is raised by a device when its input (Rx) buffer is full to tell the other peripheral to stop sending data. Reciprocally, when a device is transmitting data, it has to stop when its CTS line rises, and can resume when it comes back to a logical low level again.


USB doesn't really need a presentation. It is a high-level, complex protocol that is mainly used to communicate with a computer. USB uses a host/device communication mode, which is only another word to mean master/slave. Most of the protocol complexity weighs on the host, to allow for simpler and cheaper devices such as mouse and keyboards, and therefore most microcontrollers that implement the USB protocol only implement the Device side. The SAM4L however is able to operate either in Host or Device mode, which allows it to interface with a computer as a generic USB device, or with other USB devices (such as a keyboard) as a host.

The USB protocol is a lot more complex than the other protocols presented earlier. This means that the driver is heavier, but also that there are more room for customisation, for example on the side of USB descriptors. For more information, the main source of information is the USB driver documentation.