mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-31 21:14:37 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			281 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			281 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
| SDIO Card Slave Driver
 | |
| ======================
 | |
| 
 | |
| Overview
 | |
| --------
 | |
| 
 | |
|     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.
 | |
| 
 | |
|     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, CMD and DAT0-3 lines should be pulled up no matter in 1-bit,
 | |
|     4-bit or SPI mode.
 | |
| 
 | |
| Connections
 | |
| ^^^^^^^^^^^
 | |
| 
 | |
| +----------+---------------+-------+-------+
 | |
| | Pin Name | Corresponding | Slot1 | Slot2 |
 | |
| +          + pins in SPI   +-------+-------+
 | |
| |          | mode          | GPIO Number   |
 | |
| +==========+===============+=======+=======+
 | |
| | CLK      | SCLK          | 6     | 14    |
 | |
| +----------+---------------+-------+-------+
 | |
| | CMD      | MOSI          | 11    | 15    |
 | |
| +----------+---------------+-------+-------+
 | |
| | DAT0     | MISO          | 7     | 2     |
 | |
| +----------+---------------+-------+-------+
 | |
| | DAT1     | Interrupt     | 8     | 4     |
 | |
| +----------+---------------+-------+-------+
 | |
| | DAT2     | N.C. (pullup) | 9     | 12    |
 | |
| +----------+---------------+-------+-------+
 | |
| | DAT3     | #CS           | 10    | 13    |
 | |
| +----------+---------------+-------+-------+
 | |
| 
 | |
| - 1-bit SD mode: Connect CLK, CMD, DAT0, DAT1 pins and the ground.
 | |
| - 4-bit SD mode: Connect all pins and the ground.
 | |
| - SPI mode: Connect SCLK, MOSI, MISO, Interrupt, #CS pins and the ground.
 | |
| 
 | |
| .. note:: Please check if CMD and DATA lines D0-D3 of the card are properly
 | |
|     pulled up by 10 KOhm resistors. This should be ensured even in 1-bit mode
 | |
|     or SPI mode. Most official modules don't offer these pullups internally.
 | |
|     If you are using official development boards, check
 | |
|     :ref:`compatibility_overview_espressif_hw_sdio` to see whether your
 | |
|     development boards have such pullups.
 | |
| 
 | |
| .. note:: Most official modules have conflicts on strapping pins with the
 | |
|     SDIO slave function. If you are using a ESP32 module with 3.3 V flash
 | |
|     inside, you have to burn the EFUSE when you are developing on the module
 | |
|     for the first time. See :ref:`compatibility_overview_espressif_hw_sdio` to
 | |
|     see how to make your modules compatible with the SDIO.
 | |
| 
 | |
|     Here is a list for modules/kits with 3.3 V flash:
 | |
| 
 | |
|     - Modules: ESP32-PICO-D4, ESP32-WROOM-32 series (including ESP32-SOLO-1),
 | |
|       ESP32-WROVER-B and ESP32-WROVER-IB
 | |
|     - Kits: ESP32-PICO-KIT, ESP32-DevKitC (till v4), ESP32-WROVER-KIT
 | |
|       (v4.1 (also known as ESP32-WROVER-KIT-VB), v2, v1 (also known as DevKitJ
 | |
|       v1))
 | |
| 
 | |
|     You can tell the version of your ESP23-WROVER-KIT version from the module
 | |
|     on it: v4.1 are with ESP32-WROVER-B modules, v3 are with ESP32-WROVER
 | |
|     modules, while v2 and v1 are with ESP32-WROOM-32 modules.
 | |
| 
 | |
| Refer to :doc:`sd_pullup_requirements` for more technical details of the pullups.
 | |
| 
 | |
| .. toctree::
 | |
|     :hidden:
 | |
| 
 | |
|     sd_pullup_requirements
 | |
| 
 | |
| The host initialize the slave into SD mode by first sending CMD0 with DAT3
 | |
| pin high, or in 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 *{IDF_TARGET_NAME} Technical Reference Manual* > *SDIO Slave Controller* 
 | |
|   [`PDF <{IDF_TARGET_TRM_EN_URL}#sdioslave>`__] 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
 | |
|   (usually via DMA). 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.
 | |
| 
 | |
| Communication with ESP SDIO Slave
 | |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | |
| 
 | |
| The host should initialize the ESP32 SDIO slave according to the standard
 | |
| SDIO initialization process (Sector 3.1.2 of `SDIO Simplified
 | |
| Specification <https://www.sdcard.org/downloads/pls/>`_), which is described
 | |
| briefly in :ref:`esp_slave_init`.
 | |
| 
 | |
| Furthermore, there's an ESP32-specific upper-level communication protocol upon the CMD52/CMD53 to
 | |
| Func 1. Please refer to :ref:`esp_slave_protocol_layer`. There is also a component
 | |
| :doc:`ESP Serial Slave Link </api-reference/protocols/esp_serial_slave_link>`
 | |
| for ESP32 master to communicate with ESP32 SDIO slave, see example :example:`peripherals/sdio`
 | |
| when programming your host.
 | |
| 
 | |
| 
 | |
| .. _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 successfully 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-file:: inc/sdio_slave_types.inc
 | |
| .. include-build-file:: inc/sdio_slave.inc
 | |
| 
 | |
| 
 | 
