“SPI overview”的版本间的差异
Zhouyuebiao(讨论 | 贡献) |
Zhouyuebiao(讨论 | 贡献) |
||
第1行: | 第1行: | ||
− | + | This article gives basic information about the Linux<sup>®</sup> SPI framework and STM32 SPI driver installation. | |
+ | It explains how to use the SPI and more specifically: | ||
+ | * how to activate the SPI interface on a Linux<sup>®</sup> BSP | ||
+ | * how to access the SPI from kernel space | ||
+ | * how to access the SPI from user space. | ||
− | [[ | + | ==Framework purpose== |
− | + | ||
− | + | The Linux kernel provides a specific framework for SPI<ref name="More about SPI">https://en.wikipedia.org/w/index.php?title=Serial_Peripheral_Interface</ref> protocol support. | |
+ | The SPI (serial peripheral interface) is a synchronous serial communication interface used for short distance communications, mainly in embedded systems.<br /> | ||
+ | This interface was created by Motorola and has become a de facto standard. As it is not defined by a consortium such as I<sup>2</sup>C, there are different signal names and signal polarity modes.<br /> | ||
+ | SPI devices communicate either in Full duplex, Half duplex, or Simplex (rx/tx) mode using a master-slave architecture with a single master. | ||
+ | |||
+ | The Linux kernel SPI framework provides a complete support for SPI master (the Linux kernel initiates SPI messaging on the bus) and more recently for SPI slave (the Linux kernel answers to requests from the bus master). | ||
+ | |||
+ | See <ref name="SPI introduction">https://bootlin.com/doc/training/linux-kernel/</ref> for an introduction on the Linux kernel SPI framework. | ||
+ | |||
+ | ==System overview== | ||
+ | The user can add many SPI external devices around the microprocessor device, to create a custom board. Each external device can be accessed through the SPI from the user space or the kernel space. | ||
+ | |||
+ | [[File:spi-overview-new.png|center|link=]] | ||
+ | |||
+ | ===Component description=== | ||
+ | ====Board external SPI devices==== | ||
+ | Slave devices 'X' are physical devices (connected to the STM32 microprocessor via an SPI bus) that behave as slaves with respect to the STM32. <br/> The STM32 is the SPI bus master.<br/> A chip select signal allows selecting independently each slave device. | ||
+ | |||
+ | ====STM32 SPI internal peripheral controller==== | ||
+ | |||
+ | The STM32 SPI controller handles any external SPI devices connected to the same bus. <br/> | ||
+ | The STM32 microprocessor devices usually embed several instances of the [[SPI internal peripheral]] allowing to manage multiple SPI buses.<br/> | ||
+ | For more information about STM32 SPI internal peripherals, please refer to [[SPI_internal_peripheral#SPI_main_features]] | ||
+ | |||
+ | ====spi-stm32==== | ||
+ | The STM32 SPI controller driver offers an ST SPI internal peripheral abstraction layer to the spi-core.<br/> It defines all the SPI transfer methods to be used by the SPI core base.<br/> | ||
+ | The STM32 SPI controller driver only supports SPI master mode.<br/> | ||
+ | |||
+ | ====spi-core==== | ||
+ | '''{{Highlight|spi-core}}''' is the "brain of the communication": it instantiates and manages all buses and peripherals. | ||
+ | * As stated by its name, this is the SPI engine. It is also in charge of parsing device tree entries both for adapter and devices. It implements the standard SPI modes: 0, 1, 2 and 3. | ||
+ | |||
+ | ====Slave device drivers==== | ||
+ | This layer represents all the drivers associated to physical peripherals.<br/> | ||
+ | |||
+ | ====spidev==== | ||
+ | ''spidev'' is the interface between the user and the peripheral. | ||
+ | This is a kernel driver that offers a unified SPI bus access to the user space application using this dev-interface API. | ||
+ | See [[SPI overview#API_description|API Description]] for examples. | ||
+ | |||
+ | ====Application==== | ||
+ | The application can control all peripherals thanks to the ''spidev'' interface. | ||
+ | |||
+ | ===API description=== | ||
+ | ====User space application==== | ||
+ | [[#user_space_application| The user space application]] uses a kernel driver (spidev) for SPI transfers through the devfs.<br /> | ||
+ | Let's take the example of an SPI device connected to bus B with chip select C. The ''spidev'' driver provides the following interfaces: | ||
+ | * /dev/spidevB.C: character special device created by "udev" that is used by the user space application to control and transfer data to the SPI device. | ||
+ | |||
+ | '''Supported system calls : '''open(), close(), read(), write(), ioctl(), llseek(), release().<br /> | ||
+ | {| | ||
+ | |+ Supported ioctls commands | ||
+ | |- | ||
+ | !Constant | ||
+ | !Description | ||
+ | |- | ||
+ | |SPI_IOC_RD_MODE, SPI_IOC_WR_MODE | ||
+ | |Gets/sets SPI transfer mode | ||
+ | |- | ||
+ | |SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST | ||
+ | |Gets/sets bit justification used to transfer SPI words. | ||
+ | |- | ||
+ | |SPI_IOC_RD_BITS_PER_WORD, SPI_IOC_WR_BITS_PER_WORD | ||
+ | |Gets/sets the number of bits in each SPI transfer word. | ||
+ | |- | ||
+ | |SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ | ||
+ | |Gets/sets the maximum SPI transfer speed in Hz. | ||
+ | |} | ||
+ | The table above shows only the main commands. Additional commands are defined in the framework (see '''dev-interface API'''<ref name="dev-interface API">{{CodeSource | Linux kernel | Documentation/spi/spidev}} dev-interface API</ref> for a complete list). | ||
+ | |||
+ | ====Kernel space peripheral driver==== | ||
+ | The kernel space peripheral driver communicates with SPI devices and uses the following '''SPI core API''': <ref name="SPI core API">https://www.kernel.org/doc/html/latest/driver-api/spi.html</ref> | ||
+ | |||
+ | ==Configuration== | ||
+ | ===Kernel configuration=== | ||
+ | Enable SPI support (SPI framework and STM32 SPI driver) in the kernel configuration through the Linux Menuconfig tool: [[Menuconfig or how to configure kernel]]. | ||
+ | |||
+ | [x] Device Drivers | ||
+ | [x] SPI support | ||
+ | *** SPI Master Controller Drivers *** | ||
+ | [x] STMicroelectronics STM32 SPI controller | ||
+ | *** SPI Protocol Masters *** | ||
+ | [x] User mode SPI device driver support | ||
+ | |||
+ | This can be done manually in your kernel: | ||
+ | CONFIG_SPI=y | ||
+ | CONFIG_SPI_MASTER=y | ||
+ | CONFIG_SPI_STM32=y | ||
+ | CONFIG_SPI_SPIDEV=y | ||
+ | |||
+ | Drivers (controller and peripheral) can be compiled as a kernel module (selected by the 'm' kernel configuration file) or directly into the kernel (aka built-in) (selected by the 'y' kernel configuration file).<br/> | ||
+ | {{Info| If a slave device is involved in the boot process, the drivers required to support it are considered as critical and must be built into the kernel}} | ||
+ | |||
+ | ===Device tree configuration=== | ||
+ | Please refer to [[SPI device tree configuration]]. | ||
+ | |||
+ | ==How to use the framework== | ||
+ | Detailed information on how to write an SPI slave driver to control an SPI device are available in the Linux kernel documentation<ref name="Linux kernel SPI framework summary">{{CodeSource | Linux kernel | Documentation/spi/spi-summary}} Linux kernel SPI framework summary</ref>.<br/> | ||
+ | {{UnderConstruction | More examples coming soon}} | ||
+ | |||
+ | ==How to trace and debug the framework== | ||
+ | |||
+ | ===How to trace=== | ||
+ | ====Activating SPI framework debug messages==== | ||
+ | To get verbose messages from the SPI Framework, activate "Debug support for SPI drivers" in the Linux kernel via menuconfig [[Menuconfig or how to configure kernel]].<br/> | ||
+ | |||
+ | [x] Device Drivers | ||
+ | [x] SPI support | ||
+ | [x] Debug support for SPI drivers | ||
+ | |||
+ | This is done manually in your kernel .config file: | ||
+ | CONFIG_SPI=y | ||
+ | CONFIG_SPI_DEBUG=y | ||
+ | CONFIG_SPI_MASTER=y | ||
+ | ... | ||
+ | |||
+ | the debug support for SPI drivers (CONFIG_SPI_DEBUG) compiles all the SPI files located in Linux kernel drivers/spi folder with DEBUG flag.<br/> | ||
+ | |||
+ | {{Info|Reminder: ''loglevel'' needs to be increased to 8 by using either boot arguments or the ''dmesg -n 8'' command through the console}} | ||
+ | |||
+ | ====Dynamic trace==== | ||
+ | A detailed dynamic trace is available in [[How to use the kernel dynamic debug]]<br/> | ||
+ | {{Board$}} echo "file spi* +p" > /sys/kernel/debug/dynamic_debug/control | ||
+ | This command enables all the traces related to the SPI core and drivers at runtime.<br/> | ||
+ | A finer selection can be made by choosing only the files to trace.<br/> | ||
+ | |||
+ | {{Info|Reminder: ''loglevel'' needs to be increased to 8 by using either boot arguments or the ''dmesg -n 8'' command through the console}} | ||
+ | |||
+ | ===How to debug=== | ||
+ | ====Detecting SPI configuration==== | ||
+ | =====sysfs===== | ||
+ | When a peripheral is instantiated, the spi-core and the kernel export several files through the sysfs :<br /> | ||
+ | * '''/sys/class/spi_master/spix''' shows all the instantiated SPI buses, ''''x'''' being the SPI bus number. | ||
+ | {{Warning|'x' may not match the SPI internal peripheral index as it depends on device probing order.}} | ||
+ | * '''/sys/bus/spi/devices''' lists all the instantiated peripherals. For example, the repository named '''spi0.0''' corresponds to the peripheral connected to SPI bus 0 and chip select 0. Below an example representing the "TPM" device:<br /> | ||
+ | * '''/sys/bus/spi/drivers''' lists all the instantiated drivers. The '''tpm_tis_spi/''' repository is the driver of TPM 2.0. The '''spidev/''' repository is the generic driver of SPI user mode.<br/> | ||
+ | |||
+ | <pre> | ||
+ | /sys/bus/spi/devices/spi0.0/ | ||
+ | / | ||
+ | /drivers/tpm_tis_spi/spi0.0/ | ||
+ | /drivers/spidev/... | ||
+ | </pre> | ||
+ | |||
+ | <pre> | ||
+ | /sys/class/spi_master/spi0/spi0.0 | ||
+ | /spi1/ | ||
+ | /spi2/ | ||
+ | </pre> | ||
+ | |||
+ | ====devfs==== | ||
+ | If the ''spidev'' driver is compiled into the kernel, the repository '''/dev''' contains all SPI device entries. They are numbered spi'''x.y''' where: | ||
+ | * 'x' is the SPI bus number | ||
+ | * 'y' is the chip select index on the bus. | ||
+ | |||
+ | Unlike i2c-dev which allows full access to the I<sup>2</sup>C bus, the ''spidev'' offers direct access to the SPI device identified by its chip select signal defined in the device tree node.<br/> | ||
+ | |||
+ | Below example shows user mode SPI device on SPI bus 4, chipselect 2.<br/> | ||
+ | |||
+ | <pre> | ||
+ | /dev/spi4.2 | ||
+ | </pre> | ||
+ | For more information, please refer to the spidev documentation <ref name="dev-interface API">{{CodeSource | Linux kernel | Documentation/spi/spidev}} dev-interface API</ref>. | ||
+ | |||
+ | ==Source code location== | ||
+ | * The SPI framework is available under {{CodeSource | Linux kernel | drivers/spi}} | ||
+ | * The STM32 SPI driver is available under {{CodeSource | Linux kernel | drivers/spi/spi-stm32.c}} | ||
+ | * The user API for the SPI bus is available under {{CodeSource | Linux kernel | include/linux/spi/spi.h}} and SPI dev is {{CodeSource | Linux kernel | include/uapi/linux/spi/spidev.h}}. | ||
+ | |||
+ | ==References== | ||
+ | <references /> | ||
+ | |||
+ | <noinclude> | ||
+ | [[Category:SPI]] | ||
+ | {{PublicationRequestId | 10615 | 2019-02-04 | AnneJ}} | ||
+ | {{ArticleBasedOnModel | Framework overview article model}} | ||
+ | </noinclude> |
2020年5月8日 (五) 00:14的版本
This article gives basic information about the Linux® SPI framework and STM32 SPI driver installation. It explains how to use the SPI and more specifically:
- how to activate the SPI interface on a Linux® BSP
- how to access the SPI from kernel space
- how to access the SPI from user space.
目录
Framework purpose
The Linux kernel provides a specific framework for SPI[1] protocol support.
The SPI (serial peripheral interface) is a synchronous serial communication interface used for short distance communications, mainly in embedded systems.
This interface was created by Motorola and has become a de facto standard. As it is not defined by a consortium such as I2C, there are different signal names and signal polarity modes.
SPI devices communicate either in Full duplex, Half duplex, or Simplex (rx/tx) mode using a master-slave architecture with a single master.
The Linux kernel SPI framework provides a complete support for SPI master (the Linux kernel initiates SPI messaging on the bus) and more recently for SPI slave (the Linux kernel answers to requests from the bus master).
See [2] for an introduction on the Linux kernel SPI framework.
System overview
The user can add many SPI external devices around the microprocessor device, to create a custom board. Each external device can be accessed through the SPI from the user space or the kernel space.
![Spi-overview-new.png](/images/2/21/Spi-overview-new.png)
Component description
Board external SPI devices
Slave devices 'X' are physical devices (connected to the STM32 microprocessor via an SPI bus) that behave as slaves with respect to the STM32.
The STM32 is the SPI bus master.
A chip select signal allows selecting independently each slave device.
STM32 SPI internal peripheral controller
The STM32 SPI controller handles any external SPI devices connected to the same bus.
The STM32 microprocessor devices usually embed several instances of the SPI internal peripheral allowing to manage multiple SPI buses.
For more information about STM32 SPI internal peripherals, please refer to SPI_internal_peripheral#SPI_main_features
spi-stm32
The STM32 SPI controller driver offers an ST SPI internal peripheral abstraction layer to the spi-core.
It defines all the SPI transfer methods to be used by the SPI core base.
The STM32 SPI controller driver only supports SPI master mode.
spi-core
spi-core is the "brain of the communication": it instantiates and manages all buses and peripherals.
- As stated by its name, this is the SPI engine. It is also in charge of parsing device tree entries both for adapter and devices. It implements the standard SPI modes: 0, 1, 2 and 3.
Slave device drivers
This layer represents all the drivers associated to physical peripherals.
spidev
spidev is the interface between the user and the peripheral. This is a kernel driver that offers a unified SPI bus access to the user space application using this dev-interface API. See API Description for examples.
Application
The application can control all peripherals thanks to the spidev interface.
API description
User space application
The user space application uses a kernel driver (spidev) for SPI transfers through the devfs.
Let's take the example of an SPI device connected to bus B with chip select C. The spidev driver provides the following interfaces:
- /dev/spidevB.C: character special device created by "udev" that is used by the user space application to control and transfer data to the SPI device.
Supported system calls : open(), close(), read(), write(), ioctl(), llseek(), release().
Constant | Description |
---|---|
SPI_IOC_RD_MODE, SPI_IOC_WR_MODE | Gets/sets SPI transfer mode |
SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST | Gets/sets bit justification used to transfer SPI words. |
SPI_IOC_RD_BITS_PER_WORD, SPI_IOC_WR_BITS_PER_WORD | Gets/sets the number of bits in each SPI transfer word. |
SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ | Gets/sets the maximum SPI transfer speed in Hz. |
The table above shows only the main commands. Additional commands are defined in the framework (see dev-interface API[3] for a complete list).
Kernel space peripheral driver
The kernel space peripheral driver communicates with SPI devices and uses the following SPI core API: [4]
Configuration
Kernel configuration
Enable SPI support (SPI framework and STM32 SPI driver) in the kernel configuration through the Linux Menuconfig tool: Menuconfig or how to configure kernel.
[x] Device Drivers [x] SPI support *** SPI Master Controller Drivers *** [x] STMicroelectronics STM32 SPI controller *** SPI Protocol Masters *** [x] User mode SPI device driver support
This can be done manually in your kernel:
CONFIG_SPI=y CONFIG_SPI_MASTER=y CONFIG_SPI_STM32=y CONFIG_SPI_SPIDEV=y
Drivers (controller and peripheral) can be compiled as a kernel module (selected by the 'm' kernel configuration file) or directly into the kernel (aka built-in) (selected by the 'y' kernel configuration file).
![]() |
If a slave device is involved in the boot process, the drivers required to support it are considered as critical and must be built into the kernel |
Device tree configuration
Please refer to SPI device tree configuration.
How to use the framework
Detailed information on how to write an SPI slave driver to control an SPI device are available in the Linux kernel documentation[5].
![]() |
More examples coming soon |
{{#set:Has under construction messages=true}}
How to trace and debug the framework
How to trace
Activating SPI framework debug messages
To get verbose messages from the SPI Framework, activate "Debug support for SPI drivers" in the Linux kernel via menuconfig Menuconfig or how to configure kernel.
[x] Device Drivers [x] SPI support [x] Debug support for SPI drivers
This is done manually in your kernel .config file:
CONFIG_SPI=y CONFIG_SPI_DEBUG=y CONFIG_SPI_MASTER=y ...
the debug support for SPI drivers (CONFIG_SPI_DEBUG) compiles all the SPI files located in Linux kernel drivers/spi folder with DEBUG flag.
![]() |
Reminder: loglevel needs to be increased to 8 by using either boot arguments or the dmesg -n 8 command through the console |
Dynamic trace
A detailed dynamic trace is available in How to use the kernel dynamic debug
Board $> echo "file spi* +p" > /sys/kernel/debug/dynamic_debug/control
This command enables all the traces related to the SPI core and drivers at runtime.
A finer selection can be made by choosing only the files to trace.
![]() |
Reminder: loglevel needs to be increased to 8 by using either boot arguments or the dmesg -n 8 command through the console |
How to debug
Detecting SPI configuration
sysfs
When a peripheral is instantiated, the spi-core and the kernel export several files through the sysfs :
- /sys/class/spi_master/spix shows all the instantiated SPI buses, 'x' being the SPI bus number.
![]() |
'x' may not match the SPI internal peripheral index as it depends on device probing order. |
-
/sys/bus/spi/devices lists all the instantiated peripherals. For example, the repository named spi0.0 corresponds to the peripheral connected to SPI bus 0 and chip select 0. Below an example representing the "TPM" device:
-
/sys/bus/spi/drivers lists all the instantiated drivers. The tpm_tis_spi/ repository is the driver of TPM 2.0. The spidev/ repository is the generic driver of SPI user mode.
/sys/bus/spi/devices/spi0.0/ / /drivers/tpm_tis_spi/spi0.0/ /drivers/spidev/...
/sys/class/spi_master/spi0/spi0.0 /spi1/ /spi2/
devfs
If the spidev driver is compiled into the kernel, the repository /dev contains all SPI device entries. They are numbered spix.y where:
- 'x' is the SPI bus number
- 'y' is the chip select index on the bus.
Unlike i2c-dev which allows full access to the I2C bus, the spidev offers direct access to the SPI device identified by its chip select signal defined in the device tree node.
Below example shows user mode SPI device on SPI bus 4, chipselect 2.
/dev/spi4.2
For more information, please refer to the spidev documentation [3].
Source code location
- The SPI framework is available under drivers/spi| |}} drivers/spi
- The STM32 SPI driver is available under drivers/spi/spi-stm32.c| |}} drivers/spi/spi-stm32.c
- The user API for the SPI bus is available under include/linux/spi/spi.h| |}} include/linux/spi/spi.h and SPI dev is include/uapi/linux/spi/spidev.h| |}} include/uapi/linux/spi/spidev.h .
References
- ↑ https://en.wikipedia.org/w/index.php?title=Serial_Peripheral_Interface
- ↑ https://bootlin.com/doc/training/linux-kernel/
- ↑ 3.03.1 Documentation/spi/spidev| |}} Documentation/spi/spidev dev-interface API
- ↑ https://www.kernel.org/doc/html/latest/driver-api/spi.html
- ↑ Documentation/spi/spi-summary| |}} Documentation/spi/spi-summary Linux kernel SPI framework summary
<securetransclude src="ProtectedTemplate:PublicationRequestId" params="10615 | 2019-02-04 | AnneJ"></securetransclude> <securetransclude src="ProtectedTemplate:ArticleBasedOnModel" params="Framework overview article model"></securetransclude>