一、目的

SPI是一种串行同步接口,可用于与外围设备进行通信。

ESP32S3自带4个SPI控制器外设(Master),其中SPI0/SPI1内部专用,共用一组信号线,通过一个仲裁器访问外部Flash和PSRAM;SPI2/3各自使用一组信号线;开发者可以使用SPI2/3控制外部SPI从设备(Slave device);其中SPI2有6个片选,数据线最多可以有八根,SPI3有3个片选,数据线最多可以有四根。

本篇主要介绍SPI主机驱动的基本知识,包括标准SPI(MISO/MOSI)/Dual SPI/Quad SPI以及Octal SPI的配置和使用。

关于标准SPI/Dual SPI/Quad SPI以及Octal SPI的区别请阅读《理解SPI/Dual SPI/Quad SPI/QPI之间的区别》。

为了方便开发者使用SPI外设,ESP-IDF SDK中将SPI外设抽象为BUS(总线),一条总线上只有一个主设备,但是可以挂接多个从设备,每个从设备各自有独立的一条片选线(CS),其他信号线共用;片选线用于选中设备进行通信。

总线框图

上图中slave A和B共用一组信号线,使用的是标准SPI模式;每个设备有自己独立的片选控制线;某个时刻只能控制一个设备,要么控制A,要么控制B;A和B分时使用SPI总线。

二、介绍

参考资料

SPI Master Driver - ESP32-S3 - — ESP-IDF Programming Guide latest documentation (espressif.com)


SPI外设框图

SPI即串行同步接口

其中FSPI即SPI2,SPI2可以通过IOMUX或者GPIO Matrix进行引脚配置,SPI3只能通过GPIO Matrix进行引脚配置。

SPI2/3都支持DMA传输。


全双工和半双工区别

模式

说明

全双工

主机与从机之间的发送线和接收线各自独立,发送数据和接收数据同时进行。

半双工

主机和从机只能有一方先发送数据,另一方接收数据。发送数据和接收数据不能同时进行。

四线全双工

四线包括:时钟线、片选线和两条数据线。其中,可使用两条数据线同时发送和接收数据。

四线半双工

四线包括:时钟线、片选线和两条数据线。其中,分时使用两条数据线,不可同时使用。

三线半双工

三线包括:时钟线、片选线和一条数据线。使用数据线分时发送和 接收数据。

专业术语

术语

描述

Host(主机)

芯片内部的SPI控制器外设,用于主动发起SPI传输

Device(设备)

SPI从设备,一条SPI总线可以连接多个从设备;每个设备分时共享信号线;每个设备都有一根独立的片选控制线;当主机需要控制某个设备时,选中对应的片选线即可(一般拉低CS线)

Bus(总线)

多个设备共享的SPI信号线

MOSI(主机输出从机输入)

主机从此信号线输出数据,从设备从此信号线接收数据;在四线/八线模式下作为Data0

MISO(主机输入从机输出)

主机从此信号线接收数据,从设备从此信号线发送数据;在四线/八线模式下作为Data1

SCLK(串行同步时钟)

串行同步时钟,数据的发送接收依赖此信号来同步

CS(片选)

片选信号,每个从设备都有一个片选线

QUADWP(写保护)

写保护信号;在四线/八线模式下作为Data2

QUADHD(保持)

保持信号;在四线/八线模式下作为Data3

DATA4

在八线模式下作为Data4

DATA5

在八线模式下作为Data5

DATA6

在八线模式下作为Data6

DATA7

在八线模式下作为Data7

Assertion

发起SPI传输(一般是拉低片选线),总线进入忙状态

De-assertion

SPI传输结束(一般是拉高片选线),总线进入空闲状态

Transaction(传输事务)

一次完整的传输事务:主机拉低从机的 CS 线,开始传输数据,然 后再拉高从机的 CS 线。传输事务为原子操作,即不可打断。

Transfer(传输)

SPI 主机与从机完成数据交换的一次完整过程。一次 SPI 传输可以 包含一个或多个 SPI 传输事务。

单次传输

在这种传输模式下,仅包含一次传输事务。

Launch edge(发射边沿)

数据源寄存器在此边沿将数据比特发送至信号线上

Latch edge(锁存边沿)

数据目的寄存器在此边沿将数据比特锁存下来


特性

  • 支持多线程环境使用

  • 支持CPU控制的传输模式以及DMA控制的传输模式

  • DMA读写过程用户无感知

  • 自动时分复用(不同时刻对不同设备进行读写)

  • 时钟最高80MHz(主机模式)


注意点

  • 同一个设备尽量在一个线程中操作

  • 同一个设备在不同线程中操作需要通过互斥锁进行保护


SPI事务描述

每次SPI传输可以包含五个阶段,包括命令、地址、空周期、写、读阶段,每个阶段都是可选的。

阶段

描述

Command(命令)

在此阶段主机可以发送命令字段,长度最多16bit

Address(地址)

在此阶段主机可以发送地址字段,长度最多32bit

Dummy(空周期)

此阶段用于适配时序要求

Write(写)

此阶段主机发送数据给从设备

Read(读)

此阶段主机读取从设备数据

传输线模式配置

模式

命令线宽度

地址线宽度

数据线宽度

Transaction Flag

Bus IO setting Flag

Normal SPI

1

1

1

0

0

Dual Output

(DOUT)

1

1

2

SPI_TRANS_MODE_DIO

SPICOMMON_BUSFLAG_DUAL

Dual I/O

(DIO)

1

2

2

SPI_TRANS_MODE_DIO | SPI_TRANS_MULTILINE_ADDR

Quad Output

(QOUT)

1

1

4

SPI_TRANS_MODE_QIO

SPICOMMON_BUSFLAG_QUAD

Quad I/O

(QIO)

1

4

4

SPI_TRANS_MODE_QIO | SPI_TRANS_MULTILINE_ADDR

Octal Output

1

1

8

SPI_TRANS_MODE_OCT

SPICOMMON_BUSFLAG_OCTAL

OPI

8

8

8

SPI_TRANS_MODE_OCT | SPI_TRANS_MULTILINE_ADDR | SPI_TRANS_MULTILINE_CMD

传输标记说明

#define SPI_TRANS_MODE_DIO            (1<<0)  ///< Transmit/receive data in 2-bit mode

收发数据阶段使用双线模式

#define SPI_TRANS_MODE_QIO            (1<<1)  ///< Transmit/receive data in 4-bit mode

收发数据阶段使用四线模式

#define SPI_TRANS_MODE_DIOQIO_ADDR    (1<<4)  ///< Also transmit address in mode selected by SPI_MODE_DIO/SPI_MODE_QIO
#define SPI_TRANS_MULTILINE_ADDR      SPI_TRANS_MODE_DIOQIO_ADDR ///< The data lines used at address phase is the same as data phase (otherwise, only one data line is used at address phase)

地址阶段使用和数据阶段一样的模式

#define SPI_TRANS_MULTILINE_CMD       (1<<9)  ///< The data lines used at command phase is the same as data phase (otherwise, only one data line is used at command phase)

命令阶段使用和数据阶段一样的模式

#define SPI_TRANS_MODE_OCT            (1<<10) ///< Transmit/receive data in 8-bit mode

收发数据阶段使用八线模式

总线的初始化

在使用SPI总线之前必须先初始化

/*** @brief Initialize a SPI bus** @warning SPI0/1 is not supported** @param host_id       SPI peripheral that controls this bus* @param bus_config    Pointer to a spi_bus_config_t struct specifying how the host should be initialized* @param dma_chan      - Selecting a DMA channel for an SPI bus allows transactions on the bus with size only limited by the amount of internal memory.*                      - Selecting SPI_DMA_DISABLED limits the size of transactions.*                      - Set to SPI_DMA_DISABLED if only the SPI flash uses this bus.*                      - Set to SPI_DMA_CH_AUTO to let the driver to allocate the DMA channel.** @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in*          DMA-capable memory.** @warning The ISR of SPI is always executed on the core which calls this*          function. Never starve the ISR on this core or the SPI transactions will not*          be handled.** @return*         - ESP_ERR_INVALID_ARG   if configuration is invalid*         - ESP_ERR_INVALID_STATE if host already is in use*         - ESP_ERR_NOT_FOUND     if there is no available DMA channel*         - ESP_ERR_NO_MEM        if out of memory*         - ESP_OK                on success*/
esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, spi_dma_chan_t dma_chan);

函数参数的说明:

host_id:SPI外设索引号

bus_config:SPI总线参数

dma_chan:是否使能DMA传输并配置使用的传输通道


使能DMA传输的注意点

  • 传输buffer需要时dma-capable的内部RAM

  • 必须32bit对齐并且长度必须是4字节对齐

如果这两个条件不满足,驱动内部会自动分配内存然后进行拷贝后再传输,故效率会降低;所以建议外部传入的buffer尽可能是DMA属性的内存


SPI外设索引号

/*** @brief Enum with the three SPI peripherals that are software-accessible in it*/
typedef enum {
//SPI1 can be used as GPSPI only on ESP32SPI1_HOST=0,    ///< SPI1SPI2_HOST=1,    ///< SPI2SPI3_HOST=2,    ///< SPI3SPI_HOST_MAX,   ///< invalid host value
} spi_host_device_t;

在ESP32S3上可以使用SPI2_HOST和SPI3_HOST


SPI总线参数说明

/*** @brief This is a configuration structure for a SPI bus.** You can use this structure to specify the GPIO pins of the bus. Normally, the driver will use the* GPIO matrix to route the signals. An exception is made when all signals either can be routed through* the IO_MUX or are -1. In that case, the IO_MUX is used, allowing for >40MHz speeds.** @note Be advised that the slave driver does not use the quadwp/quadhd lines and fields in spi_bus_config_t refering to these lines will be ignored and can thus safely be left uninitialized.*/
typedef struct {union {int mosi_io_num;    ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.int data0_io_num;   ///< GPIO pin for spi data0 signal in quad/octal mode, or -1 if not used.};union {int miso_io_num;    ///< GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used.int data1_io_num;   ///< GPIO pin for spi data1 signal in quad/octal mode, or -1 if not used.};int sclk_io_num;      ///< GPIO pin for SPI Clock signal, or -1 if not used.union {int quadwp_io_num;  ///< GPIO pin for WP (Write Protect) signal, or -1 if not used.int data2_io_num;   ///< GPIO pin for spi data2 signal in quad/octal mode, or -1 if not used.};union {int quadhd_io_num;  ///< GPIO pin for HD (Hold) signal, or -1 if not used.int data3_io_num;   ///< GPIO pin for spi data3 signal in quad/octal mode, or -1 if not used.};int data4_io_num;     ///< GPIO pin for spi data4 signal in octal mode, or -1 if not used.int data5_io_num;     ///< GPIO pin for spi data5 signal in octal mode, or -1 if not used.int data6_io_num;     ///< GPIO pin for spi data6 signal in octal mode, or -1 if not used.int data7_io_num;     ///< GPIO pin for spi data7 signal in octal mode, or -1 if not used.int max_transfer_sz;  ///< Maximum transfer size, in bytes. Defaults to 4092 if 0 when DMA enabled, or to `SOC_SPI_MAXIMUM_BUFFER_SIZE` if DMA is disabled.uint32_t flags;       ///< Abilities of bus to be checked by the driver. Or-ed value of ``SPICOMMON_BUSFLAG_*`` flags.int intr_flags;       /**< Interrupt flag for the bus to set the priority, and IRAM attribute, see*  ``esp_intr_alloc.h``. Note that the EDGE, INTRDISABLED attribute are ignored*  by the driver. Note that if ESP_INTR_FLAG_IRAM is set, ALL the callbacks of*  the driver, and their callee functions, should be put in the IRAM.*/
} spi_bus_config_t;

各个字段含义:

mosi_io_num/data0_io_num:主机输出从机输入或者data0信号线IO引脚编号

miso_io_num/data1_io_num:主机输入从机输出或者data1信号线IO引脚编号

sclk_io_num:时钟信号IO引脚编号

quadwp_io_num/data2_io_num:写保护信号或者data2信号线IO引脚编号

quadhd_io_num/data3_io_num:保持信号或者data3信号线IO引脚编号

data4_io_num:data4信号线IO引脚编号

data5_io_num:data5信号线IO引脚编号

data6_io_num:data6信号线IO引脚编号

data7_io_num:data7信号线IO引脚编号

max_transfer_size:一次SPI传输最大的长度;使能DMA传输时,如果设置为0,则默认限制为4092字节;未使能DMA时,如果设置为0,则默认限制为SOC_SPI_MAXIMUM_BUFFER_SIZE(64字节)。

flags:总线特征标志,具体说明请看下文

intr_flags:中断特征标志

其中数据线根据实际硬件需要设置,如果某些引脚不需要,设置为-1即可。

关于flags字段的说明

#define SPICOMMON_BUSFLAG_SLAVE         0          ///< Initialize I/O in slave mode

设置从设备模式,内部使用;通过spi_slave_initialize接口初始化默认为从设备模式

#define SPICOMMON_BUSFLAG_MASTER        (1<<0)     ///< Initialize I/O in master mode

设置主设备模式,内部使用;通过spi_bus_initialize接口初始化默认为主设备模式

#define SPICOMMON_BUSFLAG_IOMUX_PINS    (1<<1)     ///< Check using iomux pins. Or indicates the pins are configured through the IO mux rather than GPIO matrix.

检查是否使用IOMUX作为IO输入输出或者指示IO引脚是否是使用IOMUX进行配置的

#define SPICOMMON_BUSFLAG_GPIO_PINS     (1<<2)     ///< Force the signals to be routed through GPIO matrix. Or indicates the pins are routed through the GPIO matrix.

强制使用GPIO Matrix作为IO输入输出或者指示IO引脚是否是使用GPIO Matrix进行配置的

默认情况下,SPI主机驱动会使用GPIO矩阵来配置外设引脚;但是如果所有的信号都可以通过IOMUX进行配置(或者某些信号不需要使用,设置为-1),那么就会使用IOMUX进行引脚配置,优点是传输时钟频率可以大于40MHz。

IO引脚配置说明

如果在初始化时设置了SPICOMMON_BUSFLAG_GPIO_PINS标记,那么内部就使用IO矩阵进行IO配置(即使需要的IO引脚可以通过IOMUX配置);如果设置了SPICOMMON_BUSFLAG_IOMUX_PINS,则内部会检查设置的IO引脚编号是否可以通过IOMUX配置,如果可以则初始化成功,否则初始化失败;如果两个标记都没有设置,那么内部会检查设置的IO引脚编号是否可以通过IOMUX配置,如果可以则使用IOMUX,否则使用IO Matrix。

一般情况下SPICOMMON_BUSFLAG_GPIO_PINS和SPICOMMON_BUSFLAG_IOMUX_PINS都不需要设置,只要我们设置的IO引脚是可以通过IOMUX配置的,默认就会使用IOMUX配置;否则都是通过IO Matrix配置。

通过IOMUX配置的引脚配置

Pin Name

SPI2

SPI3

GPIO Number

CS0*

10

N/A

SCLK

12

N/A

MISO

13

N/A

MOSI

11

N/A

QUADWP

14

N/A

QUADHD

9

N/A


#define SPICOMMON_BUSFLAG_SCLK          (1<<3)     ///< Check existing of SCLK pin. Or indicates CLK line initialized.

检查是否配置SCLK引脚,一般不使用此标记;如果设置了此标志,但是sclk_io_num字段为-1,则初始化出错。

#define SPICOMMON_BUSFLAG_MISO          (1<<4)     ///< Check existing of MISO pin. Or indicates MISO line initialized.
#define SPICOMMON_BUSFLAG_MOSI          (1<<5)     ///< Check existing of MOSI pin. Or indicates MOSI line initialized.

检查是否配置MOSI/MISO引脚,一般不使用此标记;如果设置了这些标志,但是mosi_io_num/mosi_io_num字段为-1,则初始化出错。

#define SPICOMMON_BUSFLAG_DUAL          (1<<6)     ///< Check MOSI and MISO pins can output. Or indicates bus able to work under DIO mode.

检查MOSI和MISO引脚可以输出或者指示总线能够工作在DIO模式,一般不使用此标记;如果设置了这些标记,但是mosi_io_num/mosi_io_num未都设置且合法,则初始化报错。

#define SPICOMMON_BUSFLAG_WPHD          (1<<7)     ///< Check existing of WP and HD pins. Or indicates WP & HD pins initialized.

检查WP/HD信号的存在或者指示WP/HD引脚已经初始化,一般不使用此标记;如果设置了这些标记,但是quadwp_io_num/quadhd_io_num未都设置且合法,则初始化报错。

#define SPICOMMON_BUSFLAG_QUAD          (SPICOMMON_BUSFLAG_DUAL|SPICOMMON_BUSFLAG_WPHD)     ///< Check existing of MOSI/MISO/WP/HD pins as output. Or indicates bus able to work under QIO mode.

检查MOSI/MISO/WP/HD引脚可以输出或者指示总线能够工作在QIO模式

#define SPICOMMON_BUSFLAG_IO4_IO7       (1<<8)     ///< Check existing of IO4~IO7 pins. Or indicates IO4~IO7 pins initialized.

检查IO4-IO7引脚存在或者指示IO4-IO7引脚已经初始化

#define SPICOMMON_BUSFLAG_OCTAL         (SPICOMMON_BUSFLAG_QUAD|SPICOMMON_BUSFLAG_IO4_IO7)  ///< Check existing of MOSI/MISO/WP/HD/SPIIO4/SPIIO5/SPIIO6/SPIIO7 pins as output. Or indicates bus able to work under octal mode.

检查MOSI/MISO/WP/HD/SPIIO4/SPIIO5/SPIIO6/SPIIO7引脚可以输出或者指示可以工作在八线模式


SPI DMA通道说明

/*** @brief SPI DMA channels*/
typedef enum {SPI_DMA_DISABLED = 0,     ///< Do not enable DMA for SPI
#if CONFIG_IDF_TARGET_ESP32SPI_DMA_CH1      = 1,     ///< Enable DMA, select DMA Channel 1SPI_DMA_CH2      = 2,     ///< Enable DMA, select DMA Channel 2
#endifSPI_DMA_CH_AUTO  = 3,     ///< Enable DMA, channel is automatically selected by driver
} spi_common_dma_t;

使能DMA传输时传输的数据量不限制,默认为4092字节;禁用DMA传输时会限制最大可传输的数据量,默认为64字节。

往总线添加设备

总线初始化成功后,就可以往总线上添加从设备

typedef struct spi_device_t *spi_device_handle_t;  ///< Handle for a device on a SPI bus
/*** @brief Allocate a device on a SPI bus** This initializes the internal structures for a device, plus allocates a CS pin on the indicated SPI master* peripheral and routes it to the indicated GPIO. All SPI master devices have three CS pins and can thus control* up to three devices.** @note While in general, speeds up to 80MHz on the dedicated SPI pins and 40MHz on GPIO-matrix-routed pins are*       supported, full-duplex transfers routed over the GPIO matrix only support speeds up to 26MHz.** @param host_id SPI peripheral to allocate device on* @param dev_config SPI interface protocol config for the device* @param handle Pointer to variable to hold the device handle* @return*         - ESP_ERR_INVALID_ARG   if parameter is invalid*         - ESP_ERR_NOT_FOUND     if host doesn't have any free CS slots*         - ESP_ERR_NO_MEM        if out of memory*         - ESP_OK                on success*/
esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interface_config_t *dev_config, spi_device_handle_t *handle);

各个参数说明:

host_id:SPI外设索引号

dev_config:从设备配置信息

handle:从设备句柄

注意点

通过IOMUX配置外设引脚时钟最大可以为80MHz;通过GPIO Matrix的时钟只能40MHz,并且全双工通信时只能设置为26MHz.

设备配置信息

/*** @brief This is a configuration for a SPI slave device that is connected to one of the SPI buses.*/
typedef struct {uint8_t command_bits;           ///< Default amount of bits in command phase (0-16), used when ``SPI_TRANS_VARIABLE_CMD`` is not used, otherwise ignored.uint8_t address_bits;           ///< Default amount of bits in address phase (0-64), used when ``SPI_TRANS_VARIABLE_ADDR`` is not used, otherwise ignored.uint8_t dummy_bits;             ///< Amount of dummy bits to insert between address and data phaseuint8_t mode;                   /**< SPI mode, representing a pair of (CPOL, CPHA) configuration:- 0: (0, 0)- 1: (0, 1)- 2: (1, 0)- 3: (1, 1)*/uint16_t duty_cycle_pos;         ///< Duty cycle of positive clock, in 1/256th increments (128 = 50%/50% duty). Setting this to 0 (=not setting it) is equivalent to setting this to 128.uint16_t cs_ena_pretrans;        ///< Amount of SPI bit-cycles the cs should be activated before the transmission (0-16). This only works on half-duplex transactions.uint8_t cs_ena_posttrans;       ///< Amount of SPI bit-cycles the cs should stay active after the transmission (0-16)int clock_speed_hz;             ///< Clock speed, divisors of 80MHz, in Hz. See ``SPI_MASTER_FREQ_*``.int input_delay_ns;             /**< Maximum data valid time of slave. The time required between SCLK and MISOvalid, including the possible clock delay from slave to master. The driver uses this value to give an extradelay before the MISO is ready on the line. Leave at 0 unless you know you need a delay. For better timingperformance at high frequency (over 8MHz), it's suggest to have the right value.*/int spics_io_num;               ///< CS GPIO pin for this device, or -1 if not useduint32_t flags;                 ///< Bitwise OR of SPI_DEVICE_* flagsint queue_size;                 ///< Transaction queue size. This sets how many transactions can be 'in the air' (queued using spi_device_queue_trans but not yet finished using spi_device_get_trans_result) at the same timetransaction_cb_t pre_cb;   /**< Callback to be called before a transmission is started.**  This callback is called within interrupt*  context should be in IRAM for best*  performance, see "Transferring Speed"*  section in the SPI Master documentation for*  full details. If not, the callback may crash*  during flash operation when the driver is*  initialized with ESP_INTR_FLAG_IRAM.*/transaction_cb_t post_cb;  /**< Callback to be called after a transmission has completed.**  This callback is called within interrupt*  context should be in IRAM for best*  performance, see "Transferring Speed"*  section in the SPI Master documentation for*  full details. If not, the callback may crash*  during flash operation when the driver is*  initialized with ESP_INTR_FLAG_IRAM.*/
} spi_device_interface_config_t;

各个字段含义:

command_bits:命令阶段传输的bit数(可以通过SPI_TRANS_VARIABLE_CMD进行覆盖)

address_bits:地址阶段传输的bit数(可以通过SPI_TRANS_VARIABLE_ADDR进行覆盖)

dummy_bits:地址阶段和数据阶段的空周期数(可以通过SPI_TRANS_VARIABLE_DUMMY进行覆盖)

由于并不是每一个传输都需要命令、地址、空周期这些阶段,一般情况下在添加从设备时这三个字段都是设置为0,在真正发起SPI传输时通过SPI_TRANS_VARIABLE_CMD、SPI_TRANS_VARIABLE_ADDR、SPI_TRANS_VARIABLE_DUMMY这些标志位进行设置。

mode:SPI时钟的极性和相位关系,请阅读《理解SPI/Dual SPI/Quad SPI/QPI之间的区别》中的时钟极性和时钟相位章节

/**< SPI mode, representing a pair of (CPOL, CPHA) configuration:- 0: (0, 0)- 1: (0, 1)- 2: (1, 0)- 3: (1, 1)*/

duty_cycle_pos:时钟占空比,默认50%

cs_ena_pretrans:传输开始前CS信号提前有效的时间,只用在半双工传输中(0-16)

cs_ena_posttrans:传输结束后CS保持有效的时间(0-16)

clock_speed_hz:时钟频率

input_delay_ns:

spics_io_num:片选IO引脚编号,未使用时设置-1即可

flags:设备标志

queue_size:传输队列大小,使用spi_device_queue_trans接口可以将传输请求进行排队处理

pre_cb:传输开始前的回调函数,在中断中执行

post_cb:传输结束后的回调函数,在中断中执行

设备标志说明

#define SPI_DEVICE_TXBIT_LSBFIRST          (1<<0)  ///< Transmit command/address/data LSB first instead of the default MSB first

地址/命令/数据阶段发送的比特位的顺序为先发送低比特位(默认是先发送高比特位)

#define SPI_DEVICE_RXBIT_LSBFIRST          (1<<1)  ///< Receive data LSB first instead of the default MSB first

接收数据的比特位顺序为先接收低比特位(默认是先接收高比特位)

#define SPI_DEVICE_BIT_LSBFIRST            (SPI_DEVICE_TXBIT_LSBFIRST|SPI_DEVICE_RXBIT_LSBFIRST) ///< Transmit and receive LSB first

收发都使用LSB

#define SPI_DEVICE_POSITIVE_CS             (1<<3)  ///< Make CS positive during a transaction instead of negative

默认片段信号拉低有效,此标记设置为拉高为选中设备

#define SPI_DEVICE_HALFDUPLEX              (1<<4)  ///< Transmit data before receiving it, instead of simultaneously

设置为半双工模式,如果需要使用多线进行数据收发,必须在添加从设备时设置此字段


总线获取

有些情况下需要独占的使用总线,这个时候可以使用spi_device_acquire_bus()独占总线;通过spi_device_release_bus()释放总线


中断传输和轮询传输

通过spi_device_transmit()发起的传输是中断传输,会阻塞当前线程直到传输完成,此时CPU调度其他线程执行;

通过spi_device_queue_trans可以发起多个传输,每个传输进行排队,中断中一个接一个的处理。

调用此接口后,当前线程可以继续执行其他任务,通过spi_device_get_trans_result()获取传输结果。

示例代码

    esp_err_t ret;int x;//Transaction descriptors. Declared static so they're not allocated on the stack; we need this memory even when this//function is finished because the SPI driver needs access to it even while we're already calculating the next line.static spi_transaction_t trans[6];//In theory, it's better to initialize trans and data only once and hang on to the initialized//variables. We allocate them on the stack, so we need to re-init them each call.for (x=0; x<6; x++) {memset(&trans[x], 0, sizeof(spi_transaction_t));if ((x&1)==0) {//Even transfers are commandstrans[x].length=8;trans[x].user=(void*)0;} else {//Odd transfers are datatrans[x].length=8*4;trans[x].user=(void*)1;}trans[x].flags=SPI_TRANS_USE_TXDATA;}trans[0].tx_data[0]=0x2A;           //Column Address Settrans[1].tx_data[0]=0;              //Start Col Hightrans[1].tx_data[1]=0;              //Start Col Lowtrans[1].tx_data[2]=(320)>>8;       //End Col Hightrans[1].tx_data[3]=(320)&0xff;     //End Col Lowtrans[2].tx_data[0]=0x2B;           //Page address settrans[3].tx_data[0]=ypos>>8;        //Start page hightrans[3].tx_data[1]=ypos&0xff;      //start page lowtrans[3].tx_data[2]=(ypos+PARALLEL_LINES)>>8;    //end page hightrans[3].tx_data[3]=(ypos+PARALLEL_LINES)&0xff;  //end page lowtrans[4].tx_data[0]=0x2C;           //memory writetrans[5].tx_buffer=linedata;        //finally send the line datatrans[5].length=320*2*8*PARALLEL_LINES;          //Data length, in bitstrans[5].flags=0; //undo SPI_TRANS_USE_TXDATA flag//Queue all transactions.for (x=0; x<6; x++) {ret=spi_device_queue_trans(spi, &trans[x], portMAX_DELAY);assert(ret==ESP_OK);}

上述代码片段采用排队方式的中断传输,一次发起6个SPI传输事务。

轮询传输通过查询标志位判断传输是否完成,通过spi_device_polling_transmit()进行

示例代码

    spi_transaction_t t;memset(&t, 0, sizeof(t));t.length=8*3;t.flags = SPI_TRANS_USE_RXDATA;t.user = (void*)1;esp_err_t ret = spi_device_polling_transmit(spi, &t);assert( ret == ESP_OK );

至此我们介绍了SPI主机驱动的基本知识,关于spi_transaction_t结构体的具体使用细节下篇讲解。

ESP32S3系列--SPI主机驱动详解(一)相关推荐

  1. spi总线 上层调用_spi总线驱动详解

    spi总线驱动详解 spi总线驱动详解 Spi总线在实际应用得比较多,所以这篇为文章讲解以实际应用为主,bus总线类型细节不做讲解,感兴趣的读者可以分析源码,研究内核源码我觉得是一件非常有趣的事情,同 ...

  2. SPI总线以及驱动详解

    SPI总线以及驱动详解 SPI总线有四根线,一根是MISO主机输入从机输出,一根是MOSI主机输出从机输入,一根是CLK时钟线,一根是CS片选线 片选线用来选择和哪个从机进行通信 SPI总线在进行数据 ...

  3. UART, SPI, IIC的详解及三者的区别和联系

    1.UART, SPI, IIC的详解 UART.SPI.IIC是经常用到的几个数据传输标准,下面分别总结一下: UART(Universal Asynchronous Receive Transmi ...

  4. kubernetes系列10—存储卷详解

    kubernetes系列10-存储卷详解 1.认识存储卷 1.1 背景 默认情况下容器中的磁盘文件是非持久化的,容器中的磁盘的生命周期是短暂的,这就带来了一系列的问题:第一,当一个容器损坏之后,kub ...

  5. 博通wifi驱动详解

    1        WLAN技术 WLAN是英文WirelessLAN的缩写,就是无线局域网的意思.无线以太网技术是一种基于无线传输的局域网技术,与有线网络技术相比,具有灵活.建网迅速.个人化等特点.将 ...

  6. h2 不能访问localhost_SpringBoot2.x系列教程44--H2数据库详解及搭建Web控制台

    SpringBoot2.x系列教程44--H2数据库详解及搭建Web控制台 作者:一一哥 我在上一章节中讲解了Spring Boot中整合Mybatis,接下来我给大家介绍一款内存数据库--H2. H ...

  7. Pixhawk(PX4)之驱动详解篇(0)_前期准备(招贤令)

    Pixhawk(PX4)之驱动详解篇(0)_前期准备(招贤令) 原创 2017年03月01日 22:58:39 标签: 开发人员 / UAV / 软件 / 硬件 一.开篇 开源精神常在!!! 谁说软件 ...

  8. spi四种工作模式时序图_SPI总线协议及SPI时序图详解

    嵌入式linux QQ交流群:175159209,欢迎爱好者加入交流技术问题! SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种 ...

  9. 大型网站架构系列:负载均衡详解(4)

    原文:大型网站架构系列:负载均衡详解(4) 本文是负载均衡详解的第四篇,主要介绍了LVS的三种请求转发模式和八种负载均衡算法,以及Haproxy的特点和负载均衡算法.具体参考文章,详见最后的链接. 三 ...

最新文章

  1. python 中关于py2exe打包
  2. 如何写windbg高级脚本---以访问文件的windbg脚本为例说明
  3. 《众妙之门——Web用户体验设计与可用性测试》一第2章 在网页设计中通过测量数据优化情感投入2.1 情感应答和行为应答的关系...
  4. 基于CNN的性别、年龄识别及Demo实现
  5. Codeforces Round #721 (Div. 2)
  6. 对于 IE低版本不兼容问题的处理
  7. python点击按钮改变图片_单击tkinter按钮时更改图片
  8. C语言高级输出及进阶
  9. Ajax 实现在WebForm中拖动控件并即时在服务端保存状态数据 (Asp.net 2.0)(示例代码下载)...
  10. Rating Prediction——评分预测小结
  11. 23种设计模式(十六)接口隔离之中介者
  12. 关于 C# dll文件的反编译获取源码
  13. 金属重量计算机在线,金属重量计算器
  14. Linux文件系统和磁盘分区
  15. VOT 2019 RGB-TIR数据集下载教程
  16. ​Aruba 无线控制器本地账号登录密码重置
  17. latch mysql_MySQL中的latch(閂鎖)詳解——易產生的問題以及原因分析
  18. VsCode配置快速注释
  19. 如何用计算机做函数图像,用计算机画函数图像 优秀教学实录
  20. java基础--Java入门

热门文章

  1. php提取域名字符串,由字符串,提取完整子域名的方法 -php
  2. HTML5~问卷调查页面的设计与实现
  3. colorkey唇釉是否安全_colorkey唇釉成分安全吗
  4. 高效管理时间的黄金法则
  5. 5G承载网络技术发展趋势
  6. 对指针的详细认识(一)—— 指针概念+指针类型+野指针+指针运算+二级指针
  7. Unity可视化编程插件bolt1.4.15 (一)bolt下载与安装
  8. 一个简单的网页制作期末作业,学生个人html静态网页制作成品代码
  9. 2021年全球与中国椭圆形板簧行业市场规模及发展前景分析
  10. 《高效的项目和团队》