mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
doc(sdio_slave): documentation for SDIO slave driver
This commit is contained in:
parent
f613859e29
commit
1b45e1117b
@ -107,6 +107,8 @@ INPUT = \
|
|||||||
../../components/driver/include/driver/sdmmc_host.h \
|
../../components/driver/include/driver/sdmmc_host.h \
|
||||||
../../components/driver/include/driver/sdmmc_types.h \
|
../../components/driver/include/driver/sdmmc_types.h \
|
||||||
../../components/driver/include/driver/sdspi_host.h \
|
../../components/driver/include/driver/sdspi_host.h \
|
||||||
|
## SDIO slave
|
||||||
|
../../components/driver/include/driver/sdio_slave.h \
|
||||||
## Non-Volatile Storage
|
## Non-Volatile Storage
|
||||||
../../components/nvs_flash/include/nvs.h \
|
../../components/nvs_flash/include/nvs.h \
|
||||||
../../components/nvs_flash/include/nvs_flash.h \
|
../../components/nvs_flash/include/nvs_flash.h \
|
||||||
|
85
docs/en/api-reference/peripherals/esp_slave_protocol.rst
Normal file
85
docs/en/api-reference/peripherals/esp_slave_protocol.rst
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
ESP SDIO slave protocol
|
||||||
|
=======================
|
||||||
|
|
||||||
|
The protocol is based on Function 1 access by CMD52 and CMD53, offering 3 services: (1) sending and receiving FIFO, (2) 52 8-bit R/W
|
||||||
|
register shared by host and slave, (3) 8 general purpose interrupt sources from host to slave and 8 in the oppsite direction.
|
||||||
|
|
||||||
|
The host should access the registers below as described to communicate with slave.
|
||||||
|
|
||||||
|
Slave register table
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
32-bit
|
||||||
|
^^^^^^^
|
||||||
|
- 0x044 (TOKEN_RDATA): in which bit 27-16 holds the receiving buffer number.
|
||||||
|
- 0x058 (INT_ST): holds the interrupt source bits from slave to host.
|
||||||
|
- 0x060 (PKT_LEN): holds the accumulated length (by byte) to be sent from slave to host.
|
||||||
|
- 0x0D4 (INT_CLR): write 1 to clear interrupt bits corresponding to INT_ST.
|
||||||
|
- 0x0DC (INT_ENA): mask bits for interrupts from slave to host.
|
||||||
|
|
||||||
|
8-bit
|
||||||
|
^^^^^
|
||||||
|
Shared general purpose registers:
|
||||||
|
|
||||||
|
- 0x06C-0x077: R/W registers 0-11 shared by slave and host.
|
||||||
|
- 0x07A-0x07B: R/W registers 14-15 shared by slave and host.
|
||||||
|
- 0x07E-0x07F: R/W registers 18-19 shared by slave and host.
|
||||||
|
- 0x088-0x08B: R/W registers 24-27 shared by slave and host.
|
||||||
|
- 0x09C-0x0BB: R/W registers 32-63 shared by slave and host.
|
||||||
|
|
||||||
|
Interrupt Registers:
|
||||||
|
- 0x08D (SLAVE_INT): bits for host to interrupt slave. auto clear.
|
||||||
|
|
||||||
|
FIFO (sending and receiving)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
0x090 - 0x1F7FF are reserved for FIFOs.
|
||||||
|
|
||||||
|
.. note:: This includes the CMD52 and CMD53 (block mode or byte mode).
|
||||||
|
|
||||||
|
The function number should be set to 1, OP Code should be set to 1 (for CMD53).
|
||||||
|
|
||||||
|
The slave will respond with the length according to the length field in CMD53 (1 of CMD52), with the data longer
|
||||||
|
than *requested length* filled with 0 (sending) or discard (receiving).
|
||||||
|
|
||||||
|
Interrupts
|
||||||
|
----------
|
||||||
|
|
||||||
|
For the host interrupts, the slave raise the interrupt by pulling DAT1 line down at a proper time (level sensitive).
|
||||||
|
The host detect this and read the INT_ST register to see the source. Then the host can clear it by writing the INT_CLR
|
||||||
|
register and do something with the interrupt. The host can also mask unneeded sources by clearing the bits in INT_ENA
|
||||||
|
register corresponding to the sources. If all the sources are cleared (or masked), the DAT1 line goes inactive.
|
||||||
|
|
||||||
|
``sdio_slave_hostint_t`` (:doc:`sdio_slave`) shows the bit definition corresponding to host interrupt sources.
|
||||||
|
|
||||||
|
For the slave interrupts, the host send transfers to write the SLAVE_INT register. Once a bit is written from 0 to 1,
|
||||||
|
the slave hardware and driver will detect it and inform the app.
|
||||||
|
|
||||||
|
Receiving FIFO
|
||||||
|
--------------
|
||||||
|
|
||||||
|
To write the receiving FIFO in the slave, host should work in the following steps:
|
||||||
|
|
||||||
|
1. Read the TOKEN1 field (bits 27-16) of TOKEN_RDATA (0x044) register. The buffer number remaining is TOKEN1 minus
|
||||||
|
the number of buffers used by host.
|
||||||
|
2. Make sure the buffer number is sufficient (*buffer_size* * *buffer_num* is greater than data to write, *buffer_size*
|
||||||
|
is pre-defined between the host and the slave before the communication starts). Or go back to step 1 until the buffer
|
||||||
|
is enough.
|
||||||
|
3. Write to the FIFO address with CMD53. Note that the *requested length* should not be larger than calculated in step 2,
|
||||||
|
and the FIFO address is related to *rquested length*.
|
||||||
|
4. Calculate used buffers, note that non-full buffer at the tail should be seen as one that is used.
|
||||||
|
|
||||||
|
Sending FIFO
|
||||||
|
------------
|
||||||
|
|
||||||
|
To read the sending FIFO in the slave, host should work in the following steps:
|
||||||
|
|
||||||
|
1. Wait for the interrupt line to be active (optional, low by default).
|
||||||
|
2. Read (poll) the interrupt bits in INT_ST register to see whether new packets exists.
|
||||||
|
3. If new packets are ready, reads the PKT_LEN reg. The data length to read from slave is PKT_LEN minuses the length
|
||||||
|
that has been read from the host. If the PKT_LEN is not larger than used, wait and poll until the slave is ready and
|
||||||
|
update the PKT_LEN.
|
||||||
|
4. Read from the FIFO with CMD53. Note that the *requested length* should not be larger than calculated in step3, and
|
||||||
|
the FIFO address is related to *requested length*.
|
||||||
|
5. Recored read length.
|
||||||
|
|
@ -15,6 +15,7 @@ Peripherals API
|
|||||||
Remote Control <rmt>
|
Remote Control <rmt>
|
||||||
SDMMC Host <sdmmc_host>
|
SDMMC Host <sdmmc_host>
|
||||||
SD SPI Host <sdspi_host>
|
SD SPI Host <sdspi_host>
|
||||||
|
SDIO Slave <sdio_slave>
|
||||||
Sigma-delta Modulation <sigmadelta>
|
Sigma-delta Modulation <sigmadelta>
|
||||||
SPI Master <spi_master>
|
SPI Master <spi_master>
|
||||||
SPI Slave <spi_slave>
|
SPI Slave <spi_slave>
|
||||||
|
227
docs/en/api-reference/peripherals/sdio_slave.rst
Normal file
227
docs/en/api-reference/peripherals/sdio_slave.rst
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
SDIO Card Slave Driver
|
||||||
|
======================
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
.. note:: At the moment, this code has been proven to work on the Wrover-Kit V3. Earlier versions of the Wrover-Kit
|
||||||
|
and other development kits are electrically incompatible with this code. Functionality on other devboards is untested.
|
||||||
|
|
||||||
|
The ESP32 SDIO Card peripherals (Host, Slave) shares two sets of pins as below table.
|
||||||
|
The first set is usually occupied by SPI0 bus which is responsible for the SPI flash holding the code to run.
|
||||||
|
This means SDIO slave driver can only runs on the second set of pins while SDIO host is not using it.
|
||||||
|
|
||||||
|
+----------+-------+-------+
|
||||||
|
| Pin Name | Slot1 | Slot2 |
|
||||||
|
+ +-------+-------+
|
||||||
|
| | GPIO Number |
|
||||||
|
+==========+=======+=======+
|
||||||
|
| CLK | 6 | 14 |
|
||||||
|
+----------+-------+-------+
|
||||||
|
| CMD | 11 | 15 |
|
||||||
|
+----------+-------+-------+
|
||||||
|
| DAT0 | 7 | 2 |
|
||||||
|
+----------+-------+-------+
|
||||||
|
| DAT1 | 8 | 4 |
|
||||||
|
+----------+-------+-------+
|
||||||
|
| DAT2 | 9 | 12 |
|
||||||
|
+----------+-------+-------+
|
||||||
|
| DAT3 | 10 | 13 |
|
||||||
|
+----------+-------+-------+
|
||||||
|
|
||||||
|
The SDIO slave can run under 3 modes: SPI, 1-bit SD and 4-bit SD modes, which is detected automatically by the
|
||||||
|
hardware. According to the SDIO specification, the host initialize the slave into SD mode by first sending CMD0 with
|
||||||
|
DAT3 pin high, while initialize the slave into SPI mode by sending CMD0 with CS pin (the same pin as DAT3) low. After the
|
||||||
|
initialization, the host can enable the 4-bit SD mode by writing CCCR register 0x07 by CMD52. All the bus detection
|
||||||
|
process are handled by the slave peripheral.
|
||||||
|
|
||||||
|
The host has to communicate with the slave by an ESP-slave-specific protocol. The slave driver offers 3 services over
|
||||||
|
Function 1 access by CMD52 and CMD53: (1) a sending FIFO and a receiving FIFO, (2) 52 8-bit R/W registers shared by
|
||||||
|
host and slave, (3) 16 interrupt sources (8 from host to slave, and 8 from slave to host).
|
||||||
|
|
||||||
|
Terminology
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
|
The SDIO slave driver uses the following terms:
|
||||||
|
|
||||||
|
- Transfer: a transfer is always started by a command token from the host, and may contain a reply and several data
|
||||||
|
blocks. ESP32 slave software is based on transfers.
|
||||||
|
- Sending: slave to host transfers.
|
||||||
|
- Receiving: host to slave transfers.
|
||||||
|
|
||||||
|
.. note:: Register names in ESP Rechnical Reference Manual are oriented from the point of view of the host, i.e. 'rx'
|
||||||
|
registers refer to sending, while 'tx' registers refer to receiving. We're not using `tx` or `rx` in the driver to
|
||||||
|
avoid ambiguities.
|
||||||
|
|
||||||
|
- FIFO: specific address in Function 1 that can be access by CMD53 to read/write large amount of data. The address is
|
||||||
|
related to the length requested to read from/write to the slave in a single transfer:
|
||||||
|
*requested length* = 0x1F800-address.
|
||||||
|
- Ownership: When the driver takes ownership of a buffer, it means the driver can randomly read/write the buffer
|
||||||
|
(mostly by the hardware). The application should not read/write the buffer until the ownership is returned to the
|
||||||
|
application. If the application reads from a buffer owned by a receiving driver, the data read can be random; if
|
||||||
|
the application writes to a buffer owned by a sending driver, the data sent may be corrupted.
|
||||||
|
- Requested length: The length requested in one transfer determined by the FIFO address.
|
||||||
|
- Transfer length: The length requested in one transfer determined by the CMD53 byte/block count field.
|
||||||
|
|
||||||
|
.. note:: Requested length is different from the transfer length. ESP32 slave DMA base on the *requested length* rather
|
||||||
|
than the *transfer length*. The *transfer length* should be no shorter than the *requested length*, and the rest
|
||||||
|
part will be filled with 0 (sending) or discard (receiving).
|
||||||
|
|
||||||
|
- Receiving buffer size: The buffer size is pre-defined between the host and the slave before communication starts.
|
||||||
|
Slave application has to set the buffer size during initialization by the ``recv_buffer_size`` member of
|
||||||
|
``sdio_slave_config_t``.
|
||||||
|
- Interrupts: the esp32 slave support interrupts in two directions: from host to slave (called slave interrupts below)
|
||||||
|
and from slave to host (called host interrupts below). See more in :ref:`interrupts`.
|
||||||
|
- Registers: specific address in Function 1 access by CMD52 or CMD53.
|
||||||
|
|
||||||
|
ESP SDIO Slave Protocol
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The communication protocol slave used to communicate with the host is ESP32 specific, please refer to
|
||||||
|
:doc:`esp_slave_protocol`, or example :example:`peripherals/sdio` for designing a host.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
esp_slave_protocol
|
||||||
|
|
||||||
|
.. _interrupts:
|
||||||
|
|
||||||
|
Interrupts
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
There are interrupts from host to slave, and from slave to host to help communicating conveniently.
|
||||||
|
|
||||||
|
Slave Interrupts
|
||||||
|
""""""""""""""""
|
||||||
|
|
||||||
|
The host can interrupt the slave by writing any one bit in the register 0x08D. Once any bit of the register is
|
||||||
|
set, an interrupt is raised and the SDIO slave driver calls the callback function defined in the ``slave_intr_cb`` member
|
||||||
|
in the ``sdio_slave_config_t`` structure.
|
||||||
|
|
||||||
|
.. note:: The callback function is called in the ISR, do not use any delay, loop or spinlock in the callback.
|
||||||
|
|
||||||
|
There's another set of functions can be used. You can call ``sdio_slave_wait_int`` to wait for an interrupt within a
|
||||||
|
certain time, or call ``sdio_slave_clear_int`` to clear interrupts from host. The callback function can work with the
|
||||||
|
wait functions perfectly.
|
||||||
|
|
||||||
|
Host Interrupts
|
||||||
|
"""""""""""""""
|
||||||
|
|
||||||
|
The slave can interrupt the host by an interrupt line (at certain time) which is level sensitive. When the host see the
|
||||||
|
interrupt line pulled down, it may read the slave interrupt status register, to see the interrupt source. Host can clear
|
||||||
|
interrupt bits, or choose to disable a interrupt source. The interrupt line will hold active until all the sources are
|
||||||
|
cleared or disabled.
|
||||||
|
|
||||||
|
There are several dedicated interrupt sources as well as general purpose sources. see ``sdio_slave_hostint_t`` for
|
||||||
|
more information.
|
||||||
|
|
||||||
|
Shared Registers
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
There are 52 8-bit R/W shared registers to share information between host and slave. The slave can write or read the
|
||||||
|
registers at any time by ``sdio_slave_read_reg`` and ``sdio_slave_write_reg``. The host can access (R/W) the register by CMD52 or CMD53.
|
||||||
|
|
||||||
|
Receiving FIFO
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
When the host is going to send the slave some packets, it has to check whether the slave is ready to receive by reading
|
||||||
|
the buffer number of slave.
|
||||||
|
|
||||||
|
To allow the host sending data to the slave, the application has to load buffers to the slave driver by the following steps:
|
||||||
|
|
||||||
|
1. Register the buffer by calling ``sdio_slave_recv_register_buf``, and get the handle of the registered buffer. The driver
|
||||||
|
will allocate memory for the linked-list descriptor needed to link the buffer onto the hardware.
|
||||||
|
2. Load buffers onto the driver by passing the buffer handle to ``sdio_slave_recv_load_buf``.
|
||||||
|
3. Call ``sdio_slave_recv`` to get the received data. If non-blocking call is needed, set ``wait=0``.
|
||||||
|
4. Pass the handle of processed buffer back to the driver by ``sdio_recv_load_buf`` again.
|
||||||
|
|
||||||
|
.. note:: To avoid overhead from copying data, the driver itself doesn't have any buffer inside, the application is
|
||||||
|
responsible to offer new buffers in time. The DMA will automatically store received data to the buffer.
|
||||||
|
|
||||||
|
Sending FIFO
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Each time the slave has data to send, it raises an interrupt and the host will request for the packet length. There are
|
||||||
|
two sending modes:
|
||||||
|
|
||||||
|
- Stream Mode: when a buffer is loaded to the driver, the buffer length will be counted into the packet length requested
|
||||||
|
by host in the incoming communications. Regardless previous packets are sent or not. This means the host can get data
|
||||||
|
of several buffers in one transfer.
|
||||||
|
- Packet Mode: the packet length is updated packet by packet, and only when previous packet is sent. This means that the
|
||||||
|
host can only get data of one buffer in one transfer.
|
||||||
|
|
||||||
|
.. note:: To avoid overhead from copying data, the driver itself doesn't have any buffer inside. Namely, the DMA takes
|
||||||
|
data directly from the buffer provided by the application. The application should not touch the buffer until the
|
||||||
|
sending is finished.
|
||||||
|
|
||||||
|
The sending mode can be set in the ``sending_mode`` member of ``sdio_slave_config_t``, and the buffer numbers can be
|
||||||
|
set in the ``send_queue_size``. All the buffers are restricted to be no larger than 4092 bytes. Though in the stream
|
||||||
|
mode several buffers can be sent in one transfer, each buffer is still counted as one in the queue.
|
||||||
|
|
||||||
|
The application can call ``sdio_slave_transmit`` to send packets. In this case the function returns when the transfer
|
||||||
|
is sucessfully done, so the queue is not fully used. When higher effeciency is required, the application can use the
|
||||||
|
following functions instead:
|
||||||
|
|
||||||
|
1. Pass buffer information (address, length, as well as an ``arg`` indicating the buffer) to ``sdio_slave_send_queue``.
|
||||||
|
If non-blocking call is needed, set ``wait=0``. If the ``wait`` is not ``portMAX_DELAY`` (wait until success),
|
||||||
|
application has to check the result to know whether the data is put in to the queue or discard.
|
||||||
|
|
||||||
|
2. Call ``sdio_slave_send_get_finished`` to get and deal with a finished transfer. A buffer should be keep unmodified
|
||||||
|
until returned from ``sdio_slave_send_get_finished``. This means the buffer is actually sent to the host, rather
|
||||||
|
than just staying in the queue.
|
||||||
|
|
||||||
|
There are several ways to use the ``arg`` in the queue parameter:
|
||||||
|
|
||||||
|
1. Directly point ``arg`` to a dynamic-allocated buffer, and use the ``arg`` to free it when transfer finished.
|
||||||
|
2. Wrap transfer informations in a transfer structure, and point ``arg`` to the structure. You can use the
|
||||||
|
structure to do more things like::
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t* buffer;
|
||||||
|
size_t size;
|
||||||
|
int id;
|
||||||
|
}sdio_transfer_t;
|
||||||
|
|
||||||
|
//and send as:
|
||||||
|
sdio_transfer_t trans = {
|
||||||
|
.buffer = ADDRESS_TO_SEND,
|
||||||
|
.size = 8,
|
||||||
|
.id = 3, //the 3rd transfer so far
|
||||||
|
};
|
||||||
|
sdio_slave_send_queue(trans.buffer, trans.size, &trans, portMAX_DELAY);
|
||||||
|
|
||||||
|
//... maybe more transfers are sent here
|
||||||
|
|
||||||
|
//and deal with finished transfer as:
|
||||||
|
sdio_transfer_t* arg = NULL;
|
||||||
|
sdio_slave_send_get_finished((void**)&arg, portMAX_DELAY);
|
||||||
|
ESP_LOGI("tag", "(%d) successfully send %d bytes of %p", arg->id, arg->size, arg->buffer);
|
||||||
|
some_post_callback(arg); //do more things
|
||||||
|
|
||||||
|
3. Working with the receiving part of this driver, point ``arg`` to the receive buffer handle of this buffer. So
|
||||||
|
that we can directly use the buffer to receive data when it's sent::
|
||||||
|
|
||||||
|
uint8_t buffer[256]={1,2,3,4,5,6,7,8};
|
||||||
|
sdio_slave_buf_handle_t handle = sdio_slave_recv_register_buf(buffer);
|
||||||
|
sdio_slave_send_queue(buffer, 8, handle, portMAX_DELAY);
|
||||||
|
|
||||||
|
//... maybe more transfers are sent here
|
||||||
|
|
||||||
|
//and load finished buffer to receive as
|
||||||
|
sdio_slave_buf_handle_t handle = NULL;
|
||||||
|
sdio_slave_send_get_finished((void**)&handle, portMAX_DELAY);
|
||||||
|
sdio_slave_recv_load_buf(handle);
|
||||||
|
|
||||||
|
More about this, see :example:`peripherals/sdio`.
|
||||||
|
|
||||||
|
Application Example
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Slave/master communication: :example:`peripherals/sdio`.
|
||||||
|
|
||||||
|
API Reference
|
||||||
|
-------------
|
||||||
|
|
||||||
|
.. include:: /_build/inc/sdio_slave.inc
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
.. include:: ../../../en/api-reference/peripherals/esp_slave_protocol.rst
|
1
docs/zh_CN/api-reference/peripherals/sdio_slave.rst
Normal file
1
docs/zh_CN/api-reference/peripherals/sdio_slave.rst
Normal file
@ -0,0 +1 @@
|
|||||||
|
.. include:: ../../../en/api-reference/peripherals/sdio_slave.rst
|
Loading…
x
Reference in New Issue
Block a user