diff --git a/docs/en/api-reference/protocols/esp_sdio_slave_protocol.rst b/docs/en/api-reference/protocols/esp_sdio_slave_protocol.rst index 9d770c1313fd..f6720bf9b5a3 100644 --- a/docs/en/api-reference/protocols/esp_sdio_slave_protocol.rst +++ b/docs/en/api-reference/protocols/esp_sdio_slave_protocol.rst @@ -1,9 +1,11 @@ Communication with ESP SDIO Slave ================================= +:link_to_translation:`zh_CN:[中文]` + This document describes the process of initialization of an ESP SDIO Slave device and then provides details on the ESP SDIO Slave protocol - a non-standard protocol that allows an SDIO Host to communicate with an ESP SDIO slave. -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. +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: @@ -31,7 +33,7 @@ The services provided by the SDIO Slave peripheral of the {IDF_TARGET_NAME} chip * - :ref:`Shared registers ` - 56\* -- \* Not including the interrupt registers +\* Not including the interrupt registers .. _esp_slave_init: @@ -120,12 +122,12 @@ ESP SDIO Slave Protocol The ESP SDIO Slave protocol is based on the SDIO Specification's I/O Read/Write commands, i.e., CMD52 and CMD53. The protocol offers the following services: - Sending FIFO and receiving FIFO -- 52 8-bit R/W registers shared by host and slave (For details, see **{IDF_TARGET_NAME} Technical Reference Manual** > **SDIO Slave Controller** > **Register Summary** > SDIO SLC Host registers [`PDF <{IDF_TARGET_TRM_EN_URL}#sdioslave-reg-summ>`__] +- 52 8-bit R/W registers shared by host and slave (For details, see *{IDF_TARGET_NAME} Technical Reference Manual* > *SDIO Slave Controller* > *Register Summary* > SDIO SLC Host registers [`PDF <{IDF_TARGET_TRM_EN_URL}#sdioslave-reg-summ>`__]) - 16 general purpose interrupt sources, 8 from host to slave and 8 from slave to host To begin communication, the host needs to enable the I/O Function 1 in the slave and access its registers as described below. -Check the code example :example:`peripherals/sdio`. +Check the code example: :example:`peripherals/sdio` The :doc:`ESP Serial Slave Link ` component implements the logic of this protocol for ESP32 SDIO Host when communicating with an ESP32 SDIO slave. @@ -165,18 +167,18 @@ FIFO (Sending and Receiving) The address of CMD53 is related to the length requested to read from or write to the slave in a single transfer, as demonstrated by the equation below: - *requested length = 0x1F800-address* + *requested length = 0x1F800 - address* -The slave responds with data that has a length equal to the length field of CMD53. In cases where the data is longer than the **requested length**, the data will be zero filled (when sending) or discarded (when receiving). This includes both the block and the byte mode of CMD53. +The slave responds to data that has a length equal to the length field of CMD53. In cases where the data is longer than the **requested length**, the data will be zero filled (when sending) or discarded (when receiving). This includes both the block and the byte mode of CMD53. .. note:: - The function number should be set to 1, OP Code should be set to 1 (for CMD53). + The function number should be set to 1, and OP Code should be set to 1 (for CMD53). - In order to achieve higher efficiency when accessing the FIFO by an arbitrary length, the block and byte modes of CMD53 can be used in combination. For example, given that the block size is set to 512 by default, you can write/get 1031 bytes of data from the FIFO by doing the following: + In order to achieve higher efficiency when accessing the FIFO by an arbitrary length, the block and byte modes of CMD53 can be used in combination. For example, given that the block size is set to 512 by default, you can write or get 1031 bytes of data from the FIFO by doing the following: - 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**. + 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: @@ -197,9 +199,9 @@ Receiving FIFO To write to the slave's receiving FIFO, the host should complete the following steps: 1. **Read the TOKEN1 field (bits 27-16) of the register TOKEN_RDATA (0x044)**. The buffer number remaining is TOKEN1 minus the number of buffers used by host. -2. **Make sure the buffer number is sufficient** (**buffer_size** x **buffer_num** is greater than the data to write, **buffer_size** is pre-defined between the host and the slave before the communication starts). Otherwise, keep returning to Step 1 until the buffer size is sufficient. -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. +2. **Make sure the buffer number is sufficient** (*buffer_size* x *buffer_num* is greater than the data to write, *buffer_size* is pre-defined between the host and the slave before the communication starts). Otherwise, keep returning to step 1 until the buffer size is sufficient. +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: diff --git a/docs/en/api-reference/protocols/icmp_echo.rst b/docs/en/api-reference/protocols/icmp_echo.rst index 8d2bbc782c5b..7fa18f20c82d 100644 --- a/docs/en/api-reference/protocols/icmp_echo.rst +++ b/docs/en/api-reference/protocols/icmp_echo.rst @@ -1,6 +1,8 @@ ICMP Echo ========= +:link_to_translation:`zh_CN:[中文]` + Overview -------- @@ -8,7 +10,7 @@ ICMP (Internet Control Message Protocol) is used for diagnostic or control purpo During a ping session, the source host firstly sends out an ICMP echo request packet and wait for an ICMP echo reply with specific times. In this way, it also measures the round-trip time for the messages. After receiving a valid ICMP echo reply, the source host will generate statistics about the IP link layer (e.g., packet loss, elapsed time, etc). -It is common that IoT device needs to check whether a remote server is alive or not. The device should show the warnings to users when it got offline. It can be achieved by creating a ping session and sending/parsing ICMP echo packets periodically. +It is common that IoT device needs to check whether a remote server is alive or not. The device should show the warnings to users when it got offline. It can be achieved by creating a ping session and sending or parsing ICMP echo packets periodically. To make this internal procedure much easier for users, ESP-IDF provides some out-of-box APIs. @@ -24,7 +26,7 @@ Example method to create a new ping session and register callbacks: static void test_on_ping_success(esp_ping_handle_t hdl, void *args) { // optionally, get callback arguments - // const char* str = (const char*) args; + // const char* str = (const char*) args; // printf("%s\r\n", str); // "foo" uint8_t ttl; uint16_t seqno; @@ -115,6 +117,4 @@ ICMP echo example: :example:`protocols/icmp_echo` API Reference ------------- -.. include-build-file:: inc/ping_sock.inc - - +.. include-build-file:: inc/ping_sock.inc \ No newline at end of file diff --git a/docs/zh_CN/api-reference/protocols/esp_sdio_slave_protocol.rst b/docs/zh_CN/api-reference/protocols/esp_sdio_slave_protocol.rst index 8ba05341e3a3..ac877b29f111 100644 --- a/docs/zh_CN/api-reference/protocols/esp_sdio_slave_protocol.rst +++ b/docs/zh_CN/api-reference/protocols/esp_sdio_slave_protocol.rst @@ -1 +1,217 @@ -.. include:: ../../../en/api-reference/protocols/esp_sdio_slave_protocol.rst \ No newline at end of file +ESP SDIO 主从机通信 +======================== + +:link_to_translation:`en:[English]` + +本文档介绍了 ESP 数字输入输出 (Secure Digital Input and Output,SDIO) 从机设备的初始化过程,并提供 ESP SDIO 从机协议的详细信息。该协议为非标准协议,允许 SDIO 主机与 ESP SDIO 从机进行通信。 + +创建 ESP SDIO 从机协议是为了实现 SDIO 主机和从机之间的通信。 这是因为 SDIO 规范只说明了如何访问卡的自定义区(向功能 1-7 发送 CMD52 和 CMD53),却没有说明底层的硬件实现过程。 + +.. _esp_sdio_slave_caps: + +乐鑫芯片的 SDIO 从机功能 +----------------------------------- + +{IDF_TARGET_NAME} 芯片的 SDIO 从机提供以下服务: + +.. list-table:: + :widths: 70 30 + :header-rows: 1 + + * - 服务 + - {IDF_TARGET_NAME} + * - SDIO 从机 + - Y + * - :ref:`Tohost intr ` + - 8 + * - :ref:`Frhost intr ` + - 8 + * - :ref:`TX DMA ` + - Y + * - :ref:`RX DMA ` + - Y + * - :ref:`共享寄存器 ` + - 56\* + +\* 未包括中断寄存器 + + +.. _esp_slave_init: + +初始化 ESP SDIO 从机 +------------------------- + +主机需按照标准的 SDIO 初始化流程,对 {IDF_TARGET_NAME} SDIO 从机进行初始化(参考 `SDIO Simplified Specification `_ 3.1.2 章节)。下文将 SDIO 从机简称为 (SD)IO 卡。以下是 ESP SDIO 从机初始化流程的一个简单示例: + +1. SDIO 复位 + + CMD52(写入 0x6=0x8) + +2. SD 复位 + + CMD0 + +3. 检查 IO 卡(可选) + + CMD8 + +4. 发送 SDIO op cond 指令,等待 IO 卡就绪 + + CMD5 arg = 0x00000000 + + CMD5 arg = 0x00ff8000(根据以上响应进行轮询,直到 IO 卡就绪) + + **示例:** + + 首次 CMD5 (arg=0x00000000) 后 R4 的 arg 为 0xXXFFFF00。 + + 不断发送 CMD5 arg=0x00FFFF00,直到 R4 显示卡已就绪 (arg 31=1) 为止。 + +5. 设置地址 + + CMD3 + +6. 选择卡 + + CMD7(根据 CMD3 响应设置 arg) + + **示例:** + + CMD3 后 R6 的 arg 为 0x0001xxxx。 + + CMD7 的 arg 应为 0x00010000。 + +7. 选择 4-bit 模式(可选) + + CMD52(写入 0x07=0x02) + +8. 启用 Func1 + + CMD52(写入 0x02=0x02) + +9. 启用 SDIO 中断(使用中断线 (DAT1) 时必要) + + CMD52(写入 0x04=0x03) + +10. 设置 Func0 块大小(可选,默认为 512 (0x200) 字节) + + CMD52/53(读取 0x10~0x11) + + CMD52/53(写入 0x10=0x00) + + CMD52/53(写入 0x11=0x02) + + CMD52/53(再次读取 0x10~0x11, 检查最终写入的值) + +11. 设置 Func1 块大小(可选,默认为 512 (0x200) 字节) + + CMD52/53(读取 0x110~0x111) + + CMD52/53(写入 0x110=0x00) + + CMD52/53(写入 0x111=0x02) + + CMD52/53(再次读取 0x110~0x111, 检查最终写入的值) + + +.. _esp_slave_protocol_layer: + +ESP SDIO 从机协议 +-------------------------- + +ESP SDIO 从机协议基于 SDIO 规范的 I/O 读/写命令(即 CMD52 和 CMD53)创建。该协议提供以下服务: + +- 发送 FIFO 和接收 FIFO +- 52 个主从机共享的 8 位读写寄存器(要了解详细信息,请参考 *{IDF_TARGET_NAME} 技术参考手册* > *SDIO 从机控制器* > *寄存器列表* > SDIO SLC Host 寄存器 [`PDF <{IDF_TARGET_TRM_CN_URL}#sdioslave-reg-summ>`__]) +- 16 个通用中断源,其中 8 个从主机到从机的中断源,8 个自从机到主机的中断源。 + +开始通信前,主机需启用从机的 I/O Function 1,访问从机的寄存器,如下所示。 + +代码示例::example:`peripherals/sdio` + +ESP32 SDIO 用作主机与 ESP32 SDIO 从机通信时,协议中涉及的逻辑由 :doc:`/api-reference/protocols/esp_serial_slave_link` 组件实现。 + +.. _esp_sdio_slave_shared_registers: + +从机寄存器列表 +^^^^^^^^^^^^^^^^^^^^^^ + +32 位 +"""""" + +- 0x044 (TOKEN_RDATA): 第 27-16 位为接收 buffer 的数量。 +- 0x058 (INT_ST): 保存自从机到主机的中断源位。 +- 0x060 (PKT_LEN): 保存主机已读取的累计数据长度(以字节为单位),和已复制到缓冲区但尚未读取的数据。 +- 0x0D4 (INT_CLR): 写 1 清除 与 INT_ST 对应的中断位。 +- 0x0DC (INT_ENA): 从机到主机的中断屏蔽位。 + +8 位 +""""" + +共享通用寄存器: + +- 0x06C-0x077: 读/写寄存器 0-11,主机和从机都可读写。 +- 0x07A-0x07B: 读/写寄存器 14-15,主机和从机都可读写。 +- 0x07E-0x07F: 读/写寄存器 18-19,主机和从机都可读写。 +- 0x088-0x08B: 读/写寄存器 24-27,主机和从机都可读写。 +- 0x09C-0x0BB: 读/写寄存器 32-63,主机和从机都可读写。 + +中断寄存器: + +- 0x08D (SLAVE_INT):主机对从机的中断位,会自动清空。 + +FIFO(发送和接收) +"""""""""""""""""""""""""""" + +0x090 - 0x1F7FF 用作 FIFO。 + +CMD53 的地址与单次传输中从从机读取或写入从机的要求长度 (requested length) 有关。如下式所示: + + *要求长度 = 0x1F800 - 地址* + +从机返回的数据长度等于 CMD53 中定义的长度。如果数据长度大于 *requested length*,多余的数据会在发送时自动补零,或在接收时被丢弃,这一情况同时适用于 CMD53 的块模式和字节模式。 + +.. note:: + + 将功能编号设置为 1,将 OP 也设置为 1(适用于 CMD53)。 + + 为了提高以任意长度访问 FIFO 时的效率,可以将 CMD53 的块模式和字节模式结合使用。例如,如果块大小默认设置为 512 字节,则可以通过以下操作从 FIFO 中写入或获取 1031 字节的数据: + + 1. 在块模式下发送 CMD53,block count = 2(1024 字节)到 0x1F3F9=0x1F800-**1031**。 + 2. 然后在字节模式下发送 CMD53,byte count = 8(如果控制器支持也可为 7)到 0x1F7F9=0x1F800-**7**。 + +.. _esp_sdio_slave_interrupts: + +中断 +^^^^ + +SDIO 中断属于电平敏感中断。对于主机中断,从机通过在适当时间拉低 DAT1 线的方式发送中断。当该中断线被拉低后,主机会检测到变化并读取 INT_ST 寄存器,确定中断源。然后,主机写入 INT_CLR 寄存器清除中断位,并处理中断。主机也可以清除 INT_ENA 寄存器中相应位以屏蔽不需要的源。如果所有源都已清除或已屏蔽,DAT1 线状态无效。 + +{IDF_TARGET_NAME} 上对应的 host_int 位:0 至 7。 + +对于从机中断,主机发起一次传输,将数据写入 SLAVE_INT 寄存器。一旦某位被写入 1,从机硬件和驱动程序就会检测到变化,通知应用程序。 + +.. _esp_sdio_slave_rcv_fifo: + +接收 FIFO +^^^^^^^^^^^ + +要写入从机的接收 FIFO,主机应完成以下步骤: + +1. **读取 TOKEN_RDATA (0x044) 寄存器的 TOKEN1 字段(27-16 位)。** 剩余的缓冲数量为 TOKEN1 减去主机使用的缓冲数量。 +2. **确保有足够的 buffer**,(*buffer_size* x *buffer_num* 应大于要写入数据的长度,*buffer_size* 是主机和从机在开始通信前预定义的值)。如果 buffer 不够,重复步骤 1,直至满足要求为止。 +3. **用 CMD53 写入 FIFO 地址**。注意, *requested length* 不应超过步骤 2 中计算出的长度,FIFO 地址与 *requested length* 有关。 +4. **计算已使用的缓冲**。 注意,尾部的缓冲即使仅部分使用,也属于已使用的范围。 + +.. _esp_sdio_slave_send_fifo: + +发送 FIFO +^^^^^^^^^^^ + +要读取从机的发送 FIFO,主机应完成以下步骤: + +1. **等待中断线有效**。(可选,默认为低电平) +2. **读取(轮询)INT_ST 寄存器中的中断位**,以监控是否存在新数据包。 +3. **如果新数据包已准备就绪,读取 PKT_LEN 寄存器**。在读取数据包之前,确定要读取数据的长度。由于主机会保留已从从机中读取的数据的长度,因此,要从 PKT_LEN 中减去该值,得到可读取的最大数据长度。如果发送 FIFO 中尚未写入过数据,则继续等待并轮询,直到从机准备就绪,然后更新 PKT_LEN。 +4. **用 CMD53 从 FIFO 中读取数据**。注意, *要求长度* 应不大于步骤 3 中计算出的长度,FIFO 地址与 *要求长度* 相关。 +5. **更新读取长度**。 diff --git a/docs/zh_CN/api-reference/protocols/icmp_echo.rst b/docs/zh_CN/api-reference/protocols/icmp_echo.rst index 768fb7373e3f..fbe42b00e8b1 100644 --- a/docs/zh_CN/api-reference/protocols/icmp_echo.rst +++ b/docs/zh_CN/api-reference/protocols/icmp_echo.rst @@ -1 +1,120 @@ -.. include:: ../../../en/api-reference/protocols/icmp_echo.rst +ICMP 回显 +=========== + +:link_to_translation:`en:[English]` + +概述 +---- + +网际控制报文协议 (ICMP) 通常用于诊断或控制目的,或响应 IP 操作中的错误。常用的网络工具 ``ping`` 的应答,即 ``Echo Reply``,就是基于类型字段值为 0 的 ICMP 数据包实现的。 + +在 ping 会话中,首先由源主机发出请求包 (ICMP echo request),然后等待应答包 (ICMP echo reply),等待具有超时限制。通过这一过程,还能测量出信息的往返用时。收到有效的应答包后,源主机会生成 IP 链路层的统计数据(如失包率、运行时间等)。 + +IoT 设备通常需要检查远程服务器是否可用。如果服务器离线,设备应向用户发出警告。通过创建 ping 会话,定期发送或解析 ICMP echo 数据包,就能实现这一功能。 + +为简化这一过程方便用户操作,ESP-IDF 提供了一些好用的 API。 + +创建 ping 会话 +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +要创建 ping 会话,首先需填写 ``esp_ping_config_t``,指定目标芯片 IP 地址、间隔时间等配置。此外,还可以通过 ``esp_ping_callbacks_t`` 注册回调函数。 + +创建 ping 会话并注册回调函数示例: + +.. code-block:: c + + static void test_on_ping_success(esp_ping_handle_t hdl, void *args) + { + // optionally, get callback arguments + // const char* str = (const char*) args; + // printf("%s\r\n", str); // "foo" + uint8_t ttl; + uint16_t seqno; + uint32_t elapsed_time, recv_len; + ip_addr_t target_addr; + esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno)); + esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl)); + esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr)); + esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len)); + esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time)); + printf("%d bytes from %s icmp_seq=%d ttl=%d time=%d ms\n", + recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time); + } + + static void test_on_ping_timeout(esp_ping_handle_t hdl, void *args) + { + uint16_t seqno; + ip_addr_t target_addr; + esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno)); + esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr)); + printf("From %s icmp_seq=%d timeout\n", inet_ntoa(target_addr.u_addr.ip4), seqno); + } + + static void test_on_ping_end(esp_ping_handle_t hdl, void *args) + { + uint32_t transmitted; + uint32_t received; + uint32_t total_time_ms; + + esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted)); + esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received)); + esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms)); + printf("%d packets transmitted, %d received, time %dms\n", transmitted, received, total_time_ms); + } + + void initialize_ping() + { + /* convert URL to IP address */ + ip_addr_t target_addr; + struct addrinfo hint; + struct addrinfo *res = NULL; + memset(&hint, 0, sizeof(hint)); + memset(&target_addr, 0, sizeof(target_addr)); + getaddrinfo("www.espressif.com", NULL, &hint, &res); + struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr; + inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4); + freeaddrinfo(res); + + esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG(); + ping_config.target_addr = target_addr; // target IP address + ping_config.count = ESP_PING_COUNT_INFINITE; // ping in infinite mode, esp_ping_stop can stop it + + /* set callback functions */ + esp_ping_callbacks_t cbs; + cbs.on_ping_success = test_on_ping_success; + cbs.on_ping_timeout = test_on_ping_timeout; + cbs.on_ping_end = test_on_ping_end; + cbs.cb_args = "foo"; // arguments that will feed to all callback functions, can be NULL + cbs.cb_args = eth_event_group; + + esp_ping_handle_t ping; + esp_ping_new_session(&ping_config, &cbs, &ping); + } + +启动和停止 ping 会话 +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +使用 ``esp_ping_new_session`` 返回的句柄可以启动或停止 ping 会话。注意,ping 会话在创建后不会自动启动。如果 ping 会话停止后重启,ICMP 数据包的序列号会归零重新计数。 + + +删除 ping 会话 +^^^^^^^^^^^^^^^^^^^ + +如果不再使用 ping 会话,可用 ``esp_ping_delete_session`` 将其删除。在删除 ping 会话时,确保该会话已处于停止状态(即已调用了 ``esp_ping_stop`` ,或该会话已完成所有步骤)。 + + +获取运行时间数据 +^^^^^^^^^^^^^^^^^^ + +在回调函数中调用 ``esp_ping_get_profile``,可获取 ping 会话的不同运行时间数据,如上文代码示例所示。 + + +应用示例 +---------- + +ICMP echo 示例: :example:`protocols/icmp_echo` + +API 参考 +-------------- + +.. include-build-file:: inc/ping_sock.inc \ No newline at end of file