Last edited 3 months ago

How to use SPI from Linux userland with spidev


1. Article purpose[edit | edit source]

Linux® SPI framework offers several ways to access SPI peripherals. Among them, the spidev framework enables to easily control an SPI peripheral straight from Linux® user space.
Before going further in this document, the reader might be interested in having a look at the SPI overview article that describes how to use an SPI when the peripheral is assigned to Linux®:

  • How to configure an SPI device through the board device tree (example using "spidev")
  • How to perform data transfers in userland

2. SPI hardware tests (loopback MOSI / MISO)[edit | edit source]

Short-circuit the SPI bus MISO and MOSI lines to create a loopback enables the bus to receive the same data it is sending. This is an interesting solution to quickly perform basic tests as well as performance tests.

On the STM32MP157X-DKX discovery board, MOSI and MISO signals are accessible via the D12 and D11 pins of the STM32MP157x-DKx_-_hardware_description#Arduino_Uno_connector.

Similar short-circuit can also be done on other boards of other STM32 MPU families.

3. DT and kernel configuration[edit | edit source]

To be able to control the SPI device from Linux® user space, the User mode SPI device driver support must be enabled. Its configuration is described in the SPI_overview#Kernel_configuration.
In addition, the device tree must be customized to expose the SPI peripheral via the spidev framework. The overall device tree configuration is described in SPI_device_tree_configuration.

In our example of MOSI/MISO loopback on the STM32MP157X-DKX Discovery board, the stm32mp157d-dk1.dts[1] device tree, which already includes the board skeleton for spi4, must be customized as follows:

  • Activate the SPI controller by setting its status to okay.
  • Add a spidev child node.
    • Enable spidev by adding a compatible spidev.
    • Add a reg property, required for the SPI framework but not meaningful in this case since chip select is not defined and loopback is used.
    • Configure the bus speed for SPI communications by setting the spi-max-frequency property.
&spi4 {
    pinctrl-names = "default", "sleep";
    pinctrl-0 = <&spi4_pins_a>;
    pinctrl-1 = <&spi4_sleep_pins_a>;
    status = "okay";
 
    spidev@0{
        compatible = "rohm,dh2228fv";
        reg = <0>;
        spi-max-frequency = <4000000>;
    };
};

4. SPI unitary tests using spidev_test[edit | edit source]

spidev_test, available within the Linux® kernel, is a test tool enabling to perform tests via the spidev interface.

4.1. Source code[edit | edit source]

The Linux® kernel spidev_test tool source code can be found under tools/spi[2] directory:

4.2. Installation on your target[edit | edit source]

The Linux® kernel SPI tools are not embedded by default in OpenSTLinux distribution. They can be compiled independently and then installed on the target (see How to build Linux kernel user space tools).

4.3. List of spidev options[edit | edit source]

The spidev_test tool has the following options:

spidev_test -h
Usage: ./spidev_test [-2348CDFHILMNORSZbdilopsvw]
general device settings:
 -D --device         device to use (default /dev/spidev1.1)
 -s --speed          max speed (Hz)
 -d --delay          delay (usec)
 -w --word-delay     word delay (usec)
 -l --loop           loopback
spi mode:
 -H --cpha           clock phase
 -O --cpol           clock polarity
 -F --rx-cpha-flip   flip CPHA on Rx only xfer
number of wires for transmission:
 -2 --dual           dual transfer
 -4 --quad           quad transfer
 -8 --octal          octal transfer
 -3 --3wire          SI/SO signals shared
 -Z --3wire-hiz      high impedance turnaround
data:
 -i --input          input data from a file (e.g. "test.bin")
 -o --output         output data to a file (e.g. "results.bin")
 -p                  Send data (e.g. "1234\xde\xad")
 -S --size           transfer size
 -I --iter           iterations
additional parameters:
 -b --bpw            bits per word
 -L --lsb            least significant bit first
 -C --cs-high        chip select active high
 -N --no-cs          no chip select
 -R --ready          slave pulls low to pause
 -M --mosi-idle-low  leave mosi line low when idle
 -t --txonly         simplex tx transfer
 -r --rxonly         simplex rx transfer
misc:
 -v --verbose        Verbose (show tx buffer)

4.4. Example of 32-byte transfer in Full-duplex with loopback[edit | edit source]

spidev_test -D /dev/spidev0.0 -v
			spi mode: 0x0
			bits per word: 8
			max speed: 500000 Hz (500 KHz)
			TX | FF FF FF FF FF FF 40 00 00 00 00 95 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 0D  | ......@.... .................. .
			RX | FF FF FF FF FF FF 40 00 00 00 00 95 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 0D  | ......@.... .................. .

By default, spidev_test attempts to set the SPI bus speed to 500 kHz. However, this speed may not be achievable depending on the clock configuration of the system, as the SPI controller can reach up to 1/256 of its input clock speed. In cases where the default speed is not supported, the -s option of spidev_test should be used to select an appropriate speed.

5. References[edit | edit source]