]> granicus.if.org Git - esp-idf/commitdiff
doc(sdio_slave): documentation for SDIO slave driver
authormichael <xiaoxufeng@espressif.com>
Mon, 4 Dec 2017 12:05:09 +0000 (20:05 +0800)
committerMichael (XIAO Xufeng) <xiaoxufeng@espressif.com>
Mon, 21 May 2018 15:48:56 +0000 (23:48 +0800)
docs/Doxyfile
docs/en/api-reference/peripherals/esp_slave_protocol.rst [new file with mode: 0644]
docs/en/api-reference/peripherals/index.rst
docs/en/api-reference/peripherals/sdio_slave.rst [new file with mode: 0644]
docs/zh_CN/api-reference/peripherals/esp_slave_protocol.rst [new file with mode: 0644]
docs/zh_CN/api-reference/peripherals/sdio_slave.rst [new file with mode: 0644]

index 481eaa3fe5b7e0d25acf95a0619ad097fc474b98..53b31af2b6f344948c93be8403a121850e923363 100644 (file)
@@ -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 \
diff --git a/docs/en/api-reference/peripherals/esp_slave_protocol.rst b/docs/en/api-reference/peripherals/esp_slave_protocol.rst
new file mode 100644 (file)
index 0000000..04cecca
--- /dev/null
@@ -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.
+
index 0b0d18a8ad8f4211c832c70a09f277c8592d74c1..930e12a7b3cdb059af08e4eb420f4b818942689a 100644 (file)
@@ -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>
diff --git a/docs/en/api-reference/peripherals/sdio_slave.rst b/docs/en/api-reference/peripherals/sdio_slave.rst
new file mode 100644 (file)
index 0000000..9e9b222
--- /dev/null
@@ -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
+
diff --git a/docs/zh_CN/api-reference/peripherals/esp_slave_protocol.rst b/docs/zh_CN/api-reference/peripherals/esp_slave_protocol.rst
new file mode 100644 (file)
index 0000000..6fc80e9
--- /dev/null
@@ -0,0 +1 @@
+.. include:: ../../../en/api-reference/peripherals/esp_slave_protocol.rst
\ No newline at end of file
diff --git a/docs/zh_CN/api-reference/peripherals/sdio_slave.rst b/docs/zh_CN/api-reference/peripherals/sdio_slave.rst
new file mode 100644 (file)
index 0000000..98a10bd
--- /dev/null
@@ -0,0 +1 @@
+.. include:: ../../../en/api-reference/peripherals/sdio_slave.rst
\ No newline at end of file