mirror of
https://github.com/espressif/esp-idf.git
synced 2026-06-04 20:26:38 +03:00
spi_slave_hd: new driver for spi slave in half duplex mode
This commit is contained in:
@@ -26,6 +26,7 @@ Peripherals API
|
||||
SPI Master <spi_master>
|
||||
SPI Slave <spi_slave>
|
||||
:esp32: Secure Element <secure_element>
|
||||
:esp32s2: SPI Slave Half Duplex <spi_slave_hd>
|
||||
:esp32s2: Temp sensor <temp_sensor>
|
||||
Timer <timer>
|
||||
Touch Sensor <touch_pad>
|
||||
|
||||
@@ -133,10 +133,6 @@ Func 1. Please refer to :ref:`esp_slave_protocol_layer`. There is also a compone
|
||||
for ESP32 master to communicate with ESP32 SDIO slave, see example :example:`peripherals/sdio`
|
||||
when programming your host.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
esp_slave_protocol
|
||||
|
||||
.. _interrupts:
|
||||
|
||||
|
||||
114
docs/en/api-reference/peripherals/spi_slave_hd.rst
Normal file
114
docs/en/api-reference/peripherals/spi_slave_hd.rst
Normal file
@@ -0,0 +1,114 @@
|
||||
SPI Slave Half Duplex
|
||||
=====================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The half duplex (HD) mode is a special mode provided by ESP SPI Slave peripheral. Under this mode, the hardware provides more services than the full duplex (FD) mode (the mode for general purpose SPI transactions, see :doc:`spi_slave`). These services reduce the CPU load and the response time of SPI Slave, but the communication format is determined by the hardware. The communication format is always half duplex, so comes the name of Half Duplex Mode.
|
||||
|
||||
There are several different types of transactions, determined by the *command* phase of the transaction. Each transaction may consist of the following phases: command, address, dummy, data. The command phase is mandatory, while the other fields may be determined by the command field. During the command, address, dummy phases, the bus is always controlled by the master, while the direction of the data phase depends on the command. The data phase can be either an in phase, for the master to write data to the slave; or an out phase, for the master to read data from the slave.
|
||||
|
||||
About the details of how master should communicate with the SPI Slave, see :doc:`/api-reference/protocols/esp_spi_slave_protocol`.
|
||||
|
||||
By these different transactions, the slave provide these services to the master:
|
||||
|
||||
- A DMA channel for the master to write a great amount of data to the slave.
|
||||
- A DMA channel for the master to read a great amount of data from the slave.
|
||||
- Several general purpose registers, shard between the master and the slave.
|
||||
- Several general purpose interrupts, for the master to interrupt the SW of slave.
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
|
||||
- Transaction
|
||||
- Channel
|
||||
- Sending
|
||||
- Receiving
|
||||
- Data Descriptor
|
||||
|
||||
Driver Feature
|
||||
--------------
|
||||
|
||||
- Transaction read/write by master in segments
|
||||
|
||||
- Queues for data to send and received
|
||||
|
||||
Driver usage
|
||||
------------
|
||||
|
||||
Slave initialization
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Call :cpp:func:`spi_slave_hd_init` to initialize the SPI bus as well as the peripheral and the driver. The SPI slave will exclusively use the SPI peripheral, pins of the bus before it's deinitialized. Most configurations of the slave should be done as soon as the slave is being initialized.
|
||||
|
||||
The :cpp:type:`spi_bus_config_t` specifies how the bus should be initialized, while :cpp:type:`spi_slave_hd_slot_config_t` specifies how the SPI Slave driver should work.
|
||||
|
||||
Deinitialization (optional)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Call :cpp:func:`spi_slave_hd_deinit` to uninstall the driver. The resources, including the pins, SPI peripheral, internal memory used by the driver, interrupt sources, will be released by the deinit function.
|
||||
|
||||
Send/Receive Data by DMA Channels
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To send data to the master through the sending DMA channel, the application should properly wrap the data to send by a :cpp:type:`spi_slave_hd_data_t` descriptor structure before calling :cpp:func:`spi_slave_hd_queue_trans` with the data descriptor, and the channel argument of :cpp:enumerator:`SPI_SLAVE_CHAN_TX`. The pointers to descriptors are stored in the queue, and the data will be send to the master upon master's RDDMA command in the same order they are put into the queue by :cpp:func:`spi_slave_hd_queue_trans`.
|
||||
|
||||
The application should check the result of data sending by calling :cpp:func:`spi_slave_hd_get_trans_res` with the channel set as :cpp:enumerator:`SPI_SLAVE_CHAN_TX`. This function will block until the transaction with command RDDMA from master successfully completes (or timeout). The ``out_trans`` argument of the function will output the pointer of the data descriptor which is just finished.
|
||||
|
||||
Receiving data from the master through the receiving DMA channel is quite similar. The application calls :cpp:func:`spi_slave_hd_queue_trans` with proper data descriptor and the channel argument of :cpp:enumerator:`SPI_SLAVE_CHAN_RX`. And the application calls the :cpp:func:`spi_slave_hd_get_trans_res` later to get the descriptor to the receiving buffer, before it handles the data in the receiving buffer.
|
||||
|
||||
.. note::
|
||||
This driver itself doesn't have internal buffer for the data to send, or just received. The application should provide data descriptors for the data buffer to send to master, or to receive data from the master.
|
||||
|
||||
The application will have to properly keep the data descriptor as well as the buffer it points to, after the descriptor is successfully sent into the driver internal queue by :cpp:func:`spi_slave_hd_queue_trans`, and before returned by :cpp:func:`spi_slave_hd_get_trans_res`. During this period, the hardware as well as the driver may read or write to the buffer and the descriptor when required at any time.
|
||||
|
||||
Please note that the buffer doesn't have to be fully sent or filled before it's terminated. For example, in the segment transaction mode, the master has to send CMD7 to terminate a WRDMA transaction, or send CMD8 to terminate a RDDMA transaction (in segments), no matter the send (receive) buffer is used up (full) or not.
|
||||
|
||||
.. _spi_slave_hd_data_arguments:
|
||||
|
||||
Using Data Arguments
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Sometimes you may have initiator (sending data descriptor) and closure (handling returned descriptors) functions in different places. When you get the returned data descriptor in the closure, you may need some extra information when handle the finished data descriptor. For example, you may want to know which round it is for the returned descriptor, when you send the same piece of data for several times.
|
||||
|
||||
Set the ``arg`` member in the data descriptor to an variable indicating the transaction (by force casting), or point it to a a structure which wraps all the information you may need when handling the sending/receiving data. Then you can get what you need in your closure.
|
||||
|
||||
.. _spi_slave_hd_callbacks:
|
||||
|
||||
Using callbacks
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
.. note::
|
||||
These callbacks are called in the ISR, so that they are fast enough. However, you may need to be very careful to write the code in the ISR. The callback should return as soon as possible. No delay or blocking operations are allowed.
|
||||
|
||||
The :cpp:type:`spi_slave_hd_intr_config_t` member in the :cpp:type:`spi_slave_hd_slot_config_t` configuration structure passed when initialize the SPI Slave HD driver, allows you having callbacks for each events you may concern.
|
||||
|
||||
The corresponding interrupt for each callbacks that is not *NULL* will enabled, so that the callbacks can be called immediately when the events happen. You don't need to provide callbacks for the unconcerned events.
|
||||
|
||||
The ``arg`` member in the configuration structure can help you pass some context to the callback, or indicate which SPI Slave instance when you are using the same callbacks for several SPI Slave peripherals. Set the ``arg`` member to an variable indicating the SPI Slave instance (by force casting), or point it to a context structure. All the callbacks will be called with this ``arg`` argument you set when the callbacks are initialized.
|
||||
|
||||
There are two other arguments: the ``event`` and the ``awoken``. The ``event`` passes the information of the current event to the callback. The :cpp:type:`spi_slave_hd_event_t` type contains the information of the event, for example, event type, the data descriptor just finished (The :ref:`data argument <spi_slave_hd_data_arguments>` will be very useful in this case!). The ``awoken`` argument is an output one, telling the ISR there are tasks are awoken after this callback, and the ISR should call `portYIELD_FROM_ISR()` to do task scheduling. Just pass the ``awoken`` argument to all FreeRTOS APIs which may unblock tasks, and the awoken will be returned to the ISR.
|
||||
|
||||
Writing/Reading Shared Registers
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Call :cpp:func:`spi_slave_hd_write_buffer` to write the shared buffer, and :cpp:func:`spi_slave_hd_read_buffer` to read the shared buffer.
|
||||
|
||||
.. note::
|
||||
On {IDF_TARGET_NAME}, the shared registers are read/written in words by the application, but read/written in bytes by the master. There's no guarantee four continuous bytes read from the master are from the same word written by the slave's application. It's also possible that if the slave reads a word while the master is writing bytes of the word, the slave may get one word with half of them just written by the master, and the other half hasn't been written into.
|
||||
|
||||
The master can confirm that the word is not in transition by reading the word twice and comparing the values.
|
||||
|
||||
For the slave, it will be more difficult to ensure the word is not in transition because the process of master writing four bytes can be very long (32 SPI clocks). You can put some CRC in the last (largest address) byte of a word so that when the byte is written, the word is sure to be all written.
|
||||
|
||||
Due to the conflicts there may be among read/write from SW (worse if there are multi cores) and master, it is suggested that a word is only used in one direction (only written by master or only written by the slave).
|
||||
|
||||
Receiving General Purpose Interrupts From the Master
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When the master sends CMD 0x08, 0x09 or 0x0A, the slave corresponding will be triggered. Currently the CMD8 is permanently used to indicate the termination of RDDMA segments. To receiving general purpose interrupts, register callbacks for CMD 0x09 and 0x0A when the slave is initialized, see :ref:`spi_slave_hd_callbacks`.
|
||||
|
||||
API reference
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/spi_slave_hd.inc
|
||||
@@ -5,6 +5,30 @@ This document describes the process of initialization of an ESP SDIO Slave devic
|
||||
|
||||
The ESP SDIO Slave protocol was created to implement the communication between SDIO host and slave, because the SDIO specification only shows how to access the custom region of a card (by sending CMD52 and CMD53 to Functions 1-7) without any details regarding the underlying hardware implementation.
|
||||
|
||||
.. _esp_sdio_slave_caps:
|
||||
|
||||
SDIO Slave Capabilities of Espressif chips
|
||||
------------------------------------------
|
||||
|
||||
The services provided by SDIO Slave peripherals of Espressif chips are different. See the table below:
|
||||
|
||||
+-----------------------------------------------------------+-------+----------+
|
||||
| | ESP32 | ESP32-S2 |
|
||||
+===========================================================+=======+==========+
|
||||
| SDIO slave | Y | N |
|
||||
+-----------------------------------------------------------+-------+----------+
|
||||
| :ref:`Tohost intr <esp_sdio_slave_interrupts>` | 8 | |
|
||||
+-----------------------------------------------------------+-------+----------+
|
||||
| :ref:`Frhost intr <esp_sdio_slave_interrupts>` | 8 | |
|
||||
+-----------------------------------------------------------+-------+----------+
|
||||
| :ref:`TX DMA <esp_sdio_slave_send_fifo>` | Y | |
|
||||
+-----------------------------------------------------------+-------+----------+
|
||||
| :ref:`RX DMA <esp_sdio_slave_rcv_fifo>` | Y | |
|
||||
+-----------------------------------------------------------+-------+----------+
|
||||
| :ref:`Shared registers <esp_sdio_slave_shared_registers>` | 56\* | |
|
||||
+-----------------------------------------------------------+-------+----------+
|
||||
|
||||
- \* Not including the interrupt registers
|
||||
|
||||
.. _esp_slave_init:
|
||||
|
||||
@@ -90,6 +114,7 @@ The :doc:`ESP Serial Slave Link </api-reference/protocols/esp_serial_slave_link>
|
||||
|
||||
.. _{IDF_TARGET_NAME} Technical Reference Manual: {IDF_TARGET_TRM_EN_URL}
|
||||
|
||||
.. _esp_sdio_slave_shared_registers:
|
||||
|
||||
Slave register table
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -137,16 +162,18 @@ The slave will respond with data that has a length equal to the length field of
|
||||
1. Send CMD53 in block mode, block count=2 (1024 bytes) to address 0x1F3F9=0x1F800-**1031**.
|
||||
2. Then send CMD53 in byte mode, byte count=8 (or 7 if your controller supports that) to address 0x1F7F9=0x1F800-**7**.
|
||||
|
||||
.. _esp_sdio_slave_interrupts:
|
||||
|
||||
Interrupts
|
||||
^^^^^^^^^^
|
||||
|
||||
SDIO interrupts are "level sensitive". For host interrupts, the slave sends an interrupt by pulling the DAT1 line down at a proper time. The host detects when the interrupt line is pulled down and reads the INT_ST register to determine the source of the interrupt. After that, the host can clear the interrupt bits by writing the INT_CLR register and process the interrupt. The host can also mask unneeded sources by clearing the bits in the INT_ENA register corresponding to the sources. If all the sources are cleared (or masked), the DAT1 line goes inactive.
|
||||
|
||||
:cpp:type:`sdio_slave_hostint_t` (:doc:`sdio_slave`) shows the bit definition corresponding to host interrupt sources.
|
||||
On ESP32, the corresponding host_int bits are: bit 0 to bit 7.
|
||||
|
||||
For slave interrupts, the host sends a transfer to write the SLAVE_INT register. Once a bit is set to 1, the slave hardware and the driver will detect it and inform the application.
|
||||
|
||||
.. _esp_sdio_slave_rcv_fifo:
|
||||
|
||||
Receiving FIFO
|
||||
^^^^^^^^^^^^^^
|
||||
@@ -158,6 +185,7 @@ To write to the slave's receiving FIFO, the host should complete the following s
|
||||
3. **Write to the FIFO address with CMD53**. Note that the *requested length* should not exceed the length calculated at Step 2, and the FIFO address is related to *requested length*.
|
||||
4. **Calculate used buffers**. Note that a partially used buffer at the tail is counted as used.
|
||||
|
||||
.. _esp_sdio_slave_send_fifo:
|
||||
|
||||
Sending FIFO
|
||||
^^^^^^^^^^^^
|
||||
@@ -12,7 +12,16 @@ bus drivers.
|
||||
After an `esp_serial_slave_link` device is initialized properly, the application can use it to communicate with the ESP
|
||||
slave devices conveniently.
|
||||
|
||||
For more details about ESP32 SDIO slave protocol, see document :doc:`/api-reference/peripherals/esp_slave_protocol`.
|
||||
Espressif Device protocols
|
||||
--------------------------
|
||||
|
||||
For more details about Espressif device protocols, see the following documents.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
esp_sdio_slave_protocol
|
||||
esp_spi_slave_protocol
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
@@ -51,7 +60,7 @@ Services provided by ESP slave
|
||||
|
||||
There are some common services provided by the Espressif slaves:
|
||||
|
||||
1. Tohost Interrupts: The slave can inform the master about certain events by the interrupt line.
|
||||
1. Tohost Interrupts: The slave can inform the master about certain events by the interrupt line. (optional)
|
||||
|
||||
2. Frhost Interrupts: The master can inform the slave about certain events.
|
||||
|
||||
@@ -71,12 +80,20 @@ There are some common services provided by the Espressif slaves:
|
||||
5. Shared registers: the master can read some part of the registers on the slave, and also write
|
||||
these registers to let the slave read.
|
||||
|
||||
The services provided by the slave depends on the slave's model. See
|
||||
:ref:`esp_sdio_slave_caps` and :ref:`esp_spi_slave_caps` for more details.
|
||||
|
||||
Initialization of ESP SDIO Slave Link
|
||||
-------------------------------------
|
||||
Initialization of ESP Serial Slave Link
|
||||
---------------------------------------
|
||||
|
||||
The ESP SDIO slave link (ESSL SDIO) devices relies on the sdmmc component. The ESSL device should
|
||||
be initialized as below:
|
||||
.. _essl_sdio_slave_init:
|
||||
|
||||
ESP SDIO Slave
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The ESP SDIO slave link (ESSL SDIO) devices relies on the sdmmc component. It includes the usage
|
||||
of communicating with ESP SDIO Slave device via SDSPI feature. The ESSL device should be
|
||||
initialized as below:
|
||||
|
||||
1. Initialize a sdmmc card (see :doc:` Document of SDMMC driver </api-reference/storage/sdmmc>`)
|
||||
structure.
|
||||
@@ -91,14 +108,23 @@ be initialized as below:
|
||||
|
||||
5. Call :cpp:func:`essl_wait_for_ready` to wait for the slave to be ready.
|
||||
|
||||
ESP SPI Slave
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
.. note::
|
||||
If you are communicating with the ESP SDIO Slave device through SPI interface, you should use
|
||||
the :ref:`SDIO interface <essl_sdio_slave_init>` instead.
|
||||
|
||||
Hasn't been supported yet.
|
||||
|
||||
APIs
|
||||
----
|
||||
|
||||
After the initialization process above is performed, you can call the APIs below to make use of
|
||||
the services provided by the slave:
|
||||
|
||||
Interrupts
|
||||
^^^^^^^^^^
|
||||
Tohost Interrupts (optional)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
1. Call :cpp:func:`essl_get_intr_ena` to know which events will trigger the interrupts to the master.
|
||||
|
||||
@@ -109,7 +135,10 @@ Interrupts
|
||||
4. When interrupt is triggered, call :cpp:func:`essl_get_intr` to know which events are active,
|
||||
and call :cpp:func:`essl_clear_intr` to clear them.
|
||||
|
||||
5. Call :cpp:func:`essl_send_slave_intr` to trigger general purpose interrupt of the slave.
|
||||
Frhost Interrupts
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
1. Call :cpp:func:`essl_send_slave_intr` to trigger general purpose interrupt of the slave.
|
||||
|
||||
TX FIFO
|
||||
^^^^^^^
|
||||
@@ -152,3 +181,4 @@ API Reference
|
||||
|
||||
.. include-build-file:: inc/essl.inc
|
||||
.. include-build-file:: inc/essl_sdio.inc
|
||||
.. include-build-file:: inc/essl_spi.inc
|
||||
|
||||
170
docs/en/api-reference/protocols/esp_spi_slave_protocol.rst
Normal file
170
docs/en/api-reference/protocols/esp_spi_slave_protocol.rst
Normal file
@@ -0,0 +1,170 @@
|
||||
ESP SPI Slave HD (Half Duplex) Mode Protocol
|
||||
============================================
|
||||
|
||||
.. note::
|
||||
This protocol is only for ESP32-S2. The driver for other chip versions hasn't be developed
|
||||
yet.
|
||||
|
||||
.. _esp_spi_slave_caps:
|
||||
|
||||
SPI Slave Capabilities of Espressif chips
|
||||
-----------------------------------------
|
||||
|
||||
+--------------------+-------+----------+
|
||||
| | ESP32 | ESP32-S2 |
|
||||
+====================+=======+==========+
|
||||
| SPI Slave HD | N | Y (v2) |
|
||||
+--------------------+-------+----------+
|
||||
| Tohost intr | | N |
|
||||
+--------------------+-------+----------+
|
||||
| Frhost intr | | 2 \* |
|
||||
+--------------------+-------+----------+
|
||||
| TX DMA | | Y |
|
||||
+--------------------+-------+----------+
|
||||
| RX DMA | | Y |
|
||||
+--------------------+-------+----------+
|
||||
| Shared registers | | 72 |
|
||||
+--------------------+-------+----------+
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
In the half duplex mode, the master has to use the protocol defined by the slave to communicate
|
||||
with the slave. Each transaction may consists of the following phases (list by the order they
|
||||
should exist):
|
||||
|
||||
- Command: 8-bit, master to slave
|
||||
|
||||
This phase determines the rest phases of the transactions. See :ref:`spi_slave_hd_supported_cmds`.
|
||||
|
||||
- Address: 8-bit, master to slave, optional
|
||||
|
||||
For some commands (WRBUF, RDBUF), this phase specifies the address of shared buffer to write
|
||||
to/read from. For other commands with this phase, they are meaningless, but still have to
|
||||
exist in the transaction.
|
||||
|
||||
- Dummy: 8-bit, floating, optional
|
||||
|
||||
This phase is the turn around time between the master and the slave on the bus, and also
|
||||
provides enough time for the slave to prepare the data to send to master.
|
||||
|
||||
- Data: variable length, the direction is also determined by the command.
|
||||
|
||||
This may be a data OUT phase, in which the direction is slave to master, or a data IN phase,
|
||||
in which the direction is master to slave.
|
||||
|
||||
The *direction* means which side (master or slave) controls the MOSI, MISO, WP and HD pins.
|
||||
|
||||
Data IO Modes
|
||||
-------------
|
||||
|
||||
In some IO modes, more data wires can be use to send the data. As a result, the SPI clock cycles
|
||||
required for the same amount of data will be less than in 1-bit mode. For example, in QIO mode,
|
||||
address and data (IN and OUT) should be sent on all 4 data wires (MOSI, MISO, WP, and HD). Here's
|
||||
the modes supported by ESP32-S2 SPI slave and the wire number used in corresponding modes.
|
||||
|
||||
+-------+------------+------------+--------------+---------+
|
||||
| Mode | command WN | address WN | dummy cycles | data WN |
|
||||
+=======+============+============+==============+=========+
|
||||
| 1-bit | 1 | 1 | 1 | 1 |
|
||||
+-------+------------+------------+--------------+---------+
|
||||
| DOUT | 1 | 1 | 4 | 2 |
|
||||
+-------+------------+------------+--------------+---------+
|
||||
| DIO | 1 | 2 | 4 | 2 |
|
||||
+-------+------------+------------+--------------+---------+
|
||||
| QOUT | 1 | 1 | 4 | 4 |
|
||||
+-------+------------+------------+--------------+---------+
|
||||
| QIO | 1 | 4 | 4 | 4 |
|
||||
+-------+------------+------------+--------------+---------+
|
||||
| QPI | 4 | 4 | 4 | 4 |
|
||||
+-------+------------+------------+--------------+---------+
|
||||
|
||||
Normally, which mode is used is determined is determined by the command sent by the master (See
|
||||
:ref:`spi_slave_hd_supported_cmds`), except from the QPI mode.
|
||||
|
||||
QPI Mode
|
||||
^^^^^^^^
|
||||
|
||||
The QPI mode is a special state of the SPI Slave. The master can send ENQPI command to put the
|
||||
slave into the QPI mode state. In the QPI mode, the command is also sent in 4-bit, thus it's not
|
||||
compatible with the normal modes. The master should only send QPI commands when the slave is in
|
||||
the QPI mode. To exit form the QPI mode, master can send EXQPI command.
|
||||
|
||||
.. _spi_slave_hd_supported_cmds:
|
||||
|
||||
Supported Commands
|
||||
------------------
|
||||
|
||||
.. note::
|
||||
The command name are in a master-oriented direction. For example, WRBUF means master writes
|
||||
the buffer of slave.
|
||||
|
||||
+----------+---------------------+---------+----------+----------------------------------------------------------+
|
||||
| Name | Description | Command | Address | Data |
|
||||
+==========+=====================+=========+==========+==========================================================+
|
||||
| WRBUF | Write buffer | 0x01 | Buf addr | master to slave, no longer than buffer size |
|
||||
+----------+---------------------+---------+----------+----------------------------------------------------------+
|
||||
| RDBUF | Read buffer | 0x02 | Buf addr | slave to master, no longer than buffer size |
|
||||
+----------+---------------------+---------+----------+----------------------------------------------------------+
|
||||
| WRDMA | Write DMA | 0x03 | 8 bits | master to slave, no longer than length provided by slave |
|
||||
+----------+---------------------+---------+----------+----------------------------------------------------------+
|
||||
| RDDMA | Read DMA | 0x04 | 8 bits | slave to master, no longer than length provided by slave |
|
||||
+----------+---------------------+---------+----------+----------------------------------------------------------+
|
||||
| SEG_DONE | Segments done | 0x05 | - | - |
|
||||
+----------+---------------------+---------+----------+----------------------------------------------------------+
|
||||
| ENQPI | Enter QPI mode | 0x06 | - | - |
|
||||
+----------+---------------------+---------+----------+----------------------------------------------------------+
|
||||
| WR_DONE | Write segments done | 0x07 | - | - |
|
||||
+----------+---------------------+---------+----------+----------------------------------------------------------+
|
||||
| CMD8 | Interrupt | 0x08 | - | - |
|
||||
+----------+---------------------+---------+----------+----------------------------------------------------------+
|
||||
| CMD9 | Interrupt | 0x09 | - | - |
|
||||
+----------+---------------------+---------+----------+----------------------------------------------------------+
|
||||
| CMDA | Interrupt | 0x0A | - | - |
|
||||
+----------+---------------------+---------+----------+----------------------------------------------------------+
|
||||
| EXQPI | Exit QPI mode | 0xDD | - | - |
|
||||
+----------+---------------------+---------+----------+----------------------------------------------------------+
|
||||
|
||||
Moreover, WRBUF, RDBUF, WRDMA, RDDMA commands have their 2-bit and 4-bit version. To do
|
||||
transactions in 2-bit or 4-bit mode, send the original command ORed by the corresponding command
|
||||
mask below. For example, command 0xA1 means WRBUF in QIO mode.
|
||||
|
||||
+-------+------+
|
||||
| Mode | Mask |
|
||||
+=======+======+
|
||||
| 1-bit | 0x00 |
|
||||
+-------+------+
|
||||
| DOUT | 0x10 |
|
||||
+-------+------+
|
||||
| DIO | 0x50 |
|
||||
+-------+------+
|
||||
| QOUT | 0x20 |
|
||||
+-------+------+
|
||||
| QIO | 0xA0 |
|
||||
+-------+------+
|
||||
| QPI | 0xA0 |
|
||||
+-------+------+
|
||||
|
||||
Segment Transaction Mode
|
||||
------------------------
|
||||
|
||||
Segment transaction mode is the only mode supported by the SPI Slave HD driver for now. In this
|
||||
mode, for a transaction the slave load onto the DMA, the master is allowed to read or write in
|
||||
segments. This way the master doesn't have to prepare large buffer as the size of data provided
|
||||
by the slave. After the master finish reading/writing a buffer, it has to send corresponding
|
||||
termination command to the slave as a synchronization signal. The slave driver will update new
|
||||
data (if exist) onto the DMA upon seeing the termination command.
|
||||
|
||||
The termination command is WR_DONE (0x07) for the WRDMA, and CMD8 (0x08) for the RDDMA.
|
||||
|
||||
Here's an example for the flow the master read data from the slave DMA:
|
||||
|
||||
1. The slave loads 4092 bytes of data onto the RDDMA
|
||||
2. The master do seven RDDMA transactions, each of them are 512 bytes long, and reads the first
|
||||
3584 bytes from the slave
|
||||
3. The master do the last RDDMA transaction of 512 bytes (equal, longer or shorter than the total
|
||||
length loaded by the slave are all allowed). The first 508 bytes are valid data from the
|
||||
slave, while the last 4 bytes are meaningless bytes.
|
||||
4. The master sends CMD8 to the slave
|
||||
5. The slave loads another 4092 bytes of data onto the RDDMA
|
||||
6. The master can start new reading transactions after it sends the CMD8
|
||||
@@ -16,7 +16,7 @@ Application Protocols
|
||||
mDNS <mdns>
|
||||
Modbus <modbus>
|
||||
Websocket Client <esp_websocket_client>
|
||||
:esp32: ESP Serial Slave Link <esp_serial_slave_link>
|
||||
ESP Serial Slave Link <esp_serial_slave_link>
|
||||
Certificate Bundle <esp_crt_bundle>
|
||||
|
||||
Code examples for this API section are provided in the :example:`protocols` directory of ESP-IDF examples.
|
||||
|
||||
Reference in New Issue
Block a user