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_types.h \
|
||||
../../components/driver/include/driver/sdspi_host.h \
|
||||
## SDIO slave
|
||||
../../components/driver/include/driver/sdio_slave.h \
|
||||
## Non-Volatile Storage
|
||||
../../components/nvs_flash/include/nvs.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>
|
||||
SDMMC Host <sdmmc_host>
|
||||
SD SPI Host <sdspi_host>
|
||||
SDIO Slave <sdio_slave>
|
||||
Sigma-delta Modulation <sigmadelta>
|
||||
SPI Master <spi_master>
|
||||
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