From 23e9224be6ed5e62c26d7199df0d4708f244d4a3 Mon Sep 17 00:00:00 2001 From: "GOPTIONS\\pfrost" Date: Thu, 22 Aug 2019 17:44:09 +0100 Subject: [PATCH 01/14] log: Add menuconfig option to log system time rather than RTOS time Merges https://github.com/espressif/esp-idf/pull/3958 --- components/log/Kconfig | 25 +++++++++++++++++++ components/log/include/esp_log.h | 26 ++++++++++++++++++++ components/log/log.c | 42 ++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/components/log/Kconfig b/components/log/Kconfig index 9266ccfa3..1c624a216 100644 --- a/components/log/Kconfig +++ b/components/log/Kconfig @@ -44,5 +44,30 @@ menu "Log output" In order to view these, your terminal program must support ANSI color codes. + choice LOG_TIMESTAMP_SOURCE + prompt "Log Timestamps" + default LOG_TIMESTAMP_SOURCE_RTOS + help + Choose what sort of timestamp is displayed in the log output: + + - Milliseconds since boot is calulated from the RTOS tick count multiplied + by the tick period. This time will reset after a software reboot. + e.g. (90000) + + - System time is taken from POSIX time functions which use the ESP32's + RTC and FRC1 timers to maintain an accurate time. The system time is + initialized to 0 on startup, it can be set with an SNTP sync, or with + POSIX time functions. This time will not reset after a software reboot. + e.g. (00:01:30.000) + + - NOTE: Currently this will not get used in logging from binary blobs + (i.e WiFi & Bluetooth libraries), these will always print + milliseconds since boot. + + config LOG_TIMESTAMP_SOURCE_RTOS + bool "Milliseconds Since Boot" + config LOG_TIMESTAMP_SOURCE_SYSTEM + bool "System Time" + endchoice endmenu diff --git a/components/log/include/esp_log.h b/components/log/include/esp_log.h index 21ebbdf23..c00a3b63d 100644 --- a/components/log/include/esp_log.h +++ b/components/log/include/esp_log.h @@ -86,6 +86,21 @@ vprintf_like_t esp_log_set_vprintf(vprintf_like_t func); */ uint32_t esp_log_timestamp(void); +/** + * @brief Function which returns system timestamp to be used in log output + * + * This function is used in expansion of ESP_LOGx macros to print + * the system time as "HH:MM:SS.sss". The system time is initialized to + * 0 on startup, this can be set to the correct time with an SNTP sync, + * or manually with standard POSIX time functions. + * + * Currently this will not get used in logging from binary blobs + * (i.e WiFi & Bluetooth libraries), these will still print the RTOS tick time. + * + * @return timestamp, in "HH:MM:SS.sss" + */ +char* esp_log_system_timestamp(void); + /** * @brief Function which returns timestamp to be used in log output * @@ -242,6 +257,7 @@ void esp_log_write(esp_log_level_t level, const char* tag, const char* format, . #endif //CONFIG_LOG_COLORS #define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%d) %s: " format LOG_RESET_COLOR "\n" +#define LOG_SYSTEM_TIME_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%s) %s: " format LOG_RESET_COLOR "\n" /** @endcond */ @@ -295,6 +311,7 @@ void esp_log_write(esp_log_level_t level, const char* tag, const char* format, . * * @see ``printf`` */ +#if CONFIG_LOG_TIMESTAMP_SOURCE_RTOS #define ESP_LOG_LEVEL(level, tag, format, ...) do { \ if (level==ESP_LOG_ERROR ) { esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \ else if (level==ESP_LOG_WARN ) { esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \ @@ -302,6 +319,15 @@ void esp_log_write(esp_log_level_t level, const char* tag, const char* format, . else if (level==ESP_LOG_VERBOSE ) { esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \ else { esp_log_write(ESP_LOG_INFO, tag, LOG_FORMAT(I, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \ } while(0) +#elif CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM +#define ESP_LOG_LEVEL(level, tag, format, ...) do { \ + if (level==ESP_LOG_ERROR ) { esp_log_write(ESP_LOG_ERROR, tag, LOG_SYSTEM_TIME_FORMAT(E, format), esp_log_system_timestamp(), tag, ##__VA_ARGS__); } \ + else if (level==ESP_LOG_WARN ) { esp_log_write(ESP_LOG_WARN, tag, LOG_SYSTEM_TIME_FORMAT(W, format), esp_log_system_timestamp(), tag, ##__VA_ARGS__); } \ + else if (level==ESP_LOG_DEBUG ) { esp_log_write(ESP_LOG_DEBUG, tag, LOG_SYSTEM_TIME_FORMAT(D, format), esp_log_system_timestamp(), tag, ##__VA_ARGS__); } \ + else if (level==ESP_LOG_VERBOSE ) { esp_log_write(ESP_LOG_VERBOSE, tag, LOG_SYSTEM_TIME_FORMAT(V, format), esp_log_system_timestamp(), tag, ##__VA_ARGS__); } \ + else { esp_log_write(ESP_LOG_INFO, tag, LOG_SYSTEM_TIME_FORMAT(I, format), esp_log_system_timestamp(), tag, ##__VA_ARGS__); } \ + } while(0) +#endif //CONFIG_LOG_TIMESTAMP_SOURCE_xxx /** runtime macro to output logs at a specified level. Also check the level with ``LOG_LOCAL_LEVEL``. * diff --git a/components/log/log.c b/components/log/log.c index fbbdf2406..6c71d1a07 100644 --- a/components/log/log.c +++ b/components/log/log.c @@ -53,6 +53,8 @@ #include #include #include +#include +#include #include "esp_log.h" @@ -332,6 +334,46 @@ uint32_t ATTR esp_log_early_timestamp(void) #ifndef BOOTLOADER_BUILD +char* IRAM_ATTR esp_log_system_timestamp(void) +{ + static char buffer[18] = {0}; + static _lock_t bufferLock = 0; + + if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) { + uint32_t timestamp = esp_log_early_timestamp(); + for (uint8_t i = 0; i < sizeof(buffer); i++) { + if ((timestamp > 0) || (i == 0)) { + for (uint8_t j = sizeof(buffer) - 1; j > 0; j--) { + buffer[j] = buffer[j - 1]; + } + buffer[0] = (char) (timestamp % 10) + '0'; + timestamp /= 10; + } else { + buffer[i] = 0; + break; + } + } + return buffer; + } else { + struct timeval tv; + struct tm timeinfo; + + gettimeofday(&tv, NULL); + localtime_r(&tv.tv_sec, &timeinfo); + + _lock_acquire(&bufferLock); + snprintf(buffer, sizeof(buffer), + "%02d:%02d:%02d.%03ld", + timeinfo.tm_hour, + timeinfo.tm_min, + timeinfo.tm_sec, + tv.tv_usec / 1000); + _lock_release(&bufferLock); + + return buffer; + } +} + uint32_t IRAM_ATTR esp_log_timestamp(void) { if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) { From b7bfcf3c936ac8eeb3f130abd1dc69436dfeae53 Mon Sep 17 00:00:00 2001 From: MartinValik Date: Wed, 12 Jun 2019 10:33:57 +0200 Subject: [PATCH 02/14] Revised tcp_server example. Fixed error caused by unnecessary reopening of listening socket. Extracted packet retransmit logic to separate function. Added robust implementation for sending data Closes https://github.com/espressif/esp-idf/pull/3597 --- .../sockets/tcp_server/main/tcp_server.c | 146 +++++++++--------- 1 file changed, 76 insertions(+), 70 deletions(-) diff --git a/examples/protocols/sockets/tcp_server/main/tcp_server.c b/examples/protocols/sockets/tcp_server/main/tcp_server.c index 062268ebd..bd9606e3a 100644 --- a/examples/protocols/sockets/tcp_server/main/tcp_server.c +++ b/examples/protocols/sockets/tcp_server/main/tcp_server.c @@ -28,53 +28,83 @@ static const char *TAG = "example"; +static void do_retransmit(const int sock) +{ + int len; + char rx_buffer[128]; + + do { + len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0); + if (len < 0) { + ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno); + } else if (len == 0) { + ESP_LOGW(TAG, "Connection closed"); + } else { + rx_buffer[len] = 0; // Null-terminate whatever is received and treat it like a string + ESP_LOGI(TAG, "Received %d bytes: %s", len, rx_buffer); + + // send() can return less bytes than supplied length. + // Walk-around for robust implementation. + int to_write = len; + while (to_write > 0) { + int written = send(sock, rx_buffer + (len - to_write), to_write, 0); + if (written < 0) { + ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno); + } + to_write -= written; + } + } + } while (len > 0); +} static void tcp_server_task(void *pvParameters) { - char rx_buffer[128]; char addr_str[128]; int addr_family; int ip_protocol; - while (1) { #ifdef CONFIG_EXAMPLE_IPV4 - struct sockaddr_in dest_addr; - dest_addr.sin_addr.s_addr = htonl(INADDR_ANY); - dest_addr.sin_family = AF_INET; - dest_addr.sin_port = htons(PORT); - addr_family = AF_INET; - ip_protocol = IPPROTO_IP; - inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1); + struct sockaddr_in dest_addr; + dest_addr.sin_addr.s_addr = htonl(INADDR_ANY); + dest_addr.sin_family = AF_INET; + dest_addr.sin_port = htons(PORT); + addr_family = AF_INET; + ip_protocol = IPPROTO_IP; + inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1); #else // IPV6 - struct sockaddr_in6 dest_addr; - bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un)); - dest_addr.sin6_family = AF_INET6; - dest_addr.sin6_port = htons(PORT); - addr_family = AF_INET6; - ip_protocol = IPPROTO_IPV6; - inet6_ntoa_r(dest_addr.sin6_addr, addr_str, sizeof(addr_str) - 1); + struct sockaddr_in6 dest_addr; + bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un)); + dest_addr.sin6_family = AF_INET6; + dest_addr.sin6_port = htons(PORT); + addr_family = AF_INET6; + ip_protocol = IPPROTO_IPV6; + inet6_ntoa_r(dest_addr.sin6_addr, addr_str, sizeof(addr_str) - 1); #endif - int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol); - if (listen_sock < 0) { - ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); - break; - } - ESP_LOGI(TAG, "Socket created"); + int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol); + if (listen_sock < 0) { + ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); + vTaskDelete(NULL); + return; + } + ESP_LOGI(TAG, "Socket created"); - int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); - if (err != 0) { - ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); - break; - } - ESP_LOGI(TAG, "Socket bound, port %d", PORT); + int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); + if (err != 0) { + ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); + goto CLEAN_UP; + } + ESP_LOGI(TAG, "Socket bound, port %d", PORT); + + err = listen(listen_sock, 1); + if (err != 0) { + ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno); + goto CLEAN_UP; + } + + while (1) { - err = listen(listen_sock, 1); - if (err != 0) { - ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno); - break; - } ESP_LOGI(TAG, "Socket listening"); struct sockaddr_in6 source_addr; // Large enough for both IPv4 or IPv6 @@ -84,47 +114,23 @@ static void tcp_server_task(void *pvParameters) ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno); break; } - ESP_LOGI(TAG, "Socket accepted"); - while (1) { - int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0); - // Error occurred during receiving - if (len < 0) { - ESP_LOGE(TAG, "recv failed: errno %d", errno); - break; - } - // Connection closed - else if (len == 0) { - ESP_LOGI(TAG, "Connection closed"); - break; - } - // Data received - else { - // Get the sender's ip address as string - if (source_addr.sin6_family == PF_INET) { - inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1); - } else if (source_addr.sin6_family == PF_INET6) { - inet6_ntoa_r(source_addr.sin6_addr, addr_str, sizeof(addr_str) - 1); - } - - rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string - ESP_LOGI(TAG, "Received %d bytes from %s:", len, addr_str); - ESP_LOGI(TAG, "%s", rx_buffer); - - int err = send(sock, rx_buffer, len, 0); - if (err < 0) { - ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno); - break; - } - } + // Convert ip address to string + if (source_addr.sin6_family == PF_INET) { + inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1); + } else if (source_addr.sin6_family == PF_INET6) { + inet6_ntoa_r(source_addr.sin6_addr, addr_str, sizeof(addr_str) - 1); } + ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str); - if (sock != -1) { - ESP_LOGE(TAG, "Shutting down socket and restarting..."); - shutdown(sock, 0); - close(sock); - } + do_retransmit(sock); + + shutdown(sock, 0); + close(sock); } + +CLEAN_UP: + close(listen_sock); vTaskDelete(NULL); } From f0bfd33a105959c83969c92227e915a54e552a25 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Tue, 8 Oct 2019 21:30:56 +0800 Subject: [PATCH 03/14] ethernet: fix crash in unit test --- components/esp_eth/test/test_emac.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/esp_eth/test/test_emac.c b/components/esp_eth/test/test_emac.c index f5d1557c6..405139ab4 100644 --- a/components/esp_eth/test/test_emac.c +++ b/components/esp_eth/test/test_emac.c @@ -136,6 +136,7 @@ TEST_CASE("esp32 ethernet dhcp test", "[ethernet][test_env=UT_T2_Ethernet]") test_case_uses_tcpip(); TEST_ESP_OK(esp_event_loop_create_default()); TEST_ESP_OK(tcpip_adapter_set_default_eth_handlers()); + TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, eth_event_group)); TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, eth_event_group)); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); @@ -148,9 +149,15 @@ TEST_CASE("esp32 ethernet dhcp test", "[ethernet][test_env=UT_T2_Ethernet]") bits = xEventGroupWaitBits(eth_event_group, ETH_GOT_IP_BIT, true, true, pdMS_TO_TICKS(ETH_GET_IP_TIMEOUT_MS)); TEST_ASSERT((bits & ETH_GOT_IP_BIT) == ETH_GOT_IP_BIT); TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle)); + /* wait for connection stop */ + bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS)); + TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT); + // "check link timer callback" might owned the reference of phy object, make sure it has release it + vTaskDelay(pdMS_TO_TICKS(2000)); TEST_ESP_OK(phy->del(phy)); TEST_ESP_OK(mac->del(mac)); TEST_ESP_OK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler)); + TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler)); TEST_ESP_OK(tcpip_adapter_clear_default_eth_handlers()); TEST_ESP_OK(esp_event_loop_delete_default()); vEventGroupDelete(eth_event_group); From 4e1ccd8b6f6671c47813373936ad27f7aa45a726 Mon Sep 17 00:00:00 2001 From: ronghulin Date: Wed, 21 Aug 2019 18:01:26 +0800 Subject: [PATCH 04/14] doc: add LWIP socket error usage --- docs/en/api-guides/index.rst | 1 + docs/en/api-guides/lwip.rst | 97 +++++++++++++++++++++++++++++++++ docs/zh_CN/api-guides/index.rst | 1 + docs/zh_CN/api-guides/lwip.rst | 2 + 4 files changed, 101 insertions(+) create mode 100644 docs/en/api-guides/lwip.rst create mode 100644 docs/zh_CN/api-guides/lwip.rst diff --git a/docs/en/api-guides/index.rst b/docs/en/api-guides/index.rst index fdfd58c98..e2454754c 100644 --- a/docs/en/api-guides/index.rst +++ b/docs/en/api-guides/index.rst @@ -34,4 +34,5 @@ API Guides ULP Coprocessor Unit Testing (Legacy GNU Make) Unit Testing + LwIP WiFi Driver diff --git a/docs/en/api-guides/lwip.rst b/docs/en/api-guides/lwip.rst new file mode 100644 index 000000000..f5e4e75c6 --- /dev/null +++ b/docs/en/api-guides/lwip.rst @@ -0,0 +1,97 @@ +LwIP +==== + +Overview About Socket Error Handling +------------------------------------ + +Socket error handling code is very important for robust socket applications. Normally the socket error handling involves the following aspects: + +- Detecting the error. +- Geting the error reason code. +- Handle the error according to the reason code. + +In LwIP, we have two different scenarios of handling socket errors: + +- Socket API returns an error. For more information, see <`Error Handling of Socket API`_>. +- ``select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout)`` has exception descriptor indicating that the socket has an error. For more information, see <`Error Handling of Select`_>. + +Error Handling of Socket API +++++++++++++++++++++++++++++ + +The error detection + - We can know that the socket API fails according to its return value. + +Get the error reason code + - When socket API fails, the return value doesn't contain the failure reason and the application can get the error reason code by accessing errno. Different values indicate different meanings. For more information, see <`Socket Error Reason Code`_>. + +Example:: + + int err; + int sockfd; + + if (sockfd = socket(AF_INET,SOCK_STREAM,0) < 0) { + // the error code is obtained from errno + err = errno; + return err; + } + +Error Handling of Select +++++++++++++++++++++++++ + +The error detection + - Socket error when select has exception descriptor + +Get the error reason code + - If the ``select`` indicates that the socket fails, we can't get the error reason code by accessing errno, instead we should call ``getsockopt()`` to get the failure reason code. Because ``select()`` has exception descriptor, the error code will not be given to errno. + +.. note:: ``getsockopt`` function prototype ``int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)``. Its function is to get the current value of the option of any type, any state socket, and store the result in optval. For example, when you get the error code on a socket, you can get it by ``getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &optlen)``. + +Example:: + + int err; + + if (select(sockfd + 1, NULL, NULL, &exfds, &tval) <= 0) { + err = errno; + return err; + } else { + if (FD_ISSET(sockfd, &exfds)) { + // select() exception set using getsockopt() + int optlen = sizeof(int); + getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &optlen); + return err; + } + } + +Socket Error Reason Code +++++++++++++++++++++++++ + +Below is a list of common error codes. For more detailed error codes, please query :component:`newlib/include/sys/errno.h` + ++-----------------+-------------------------------------+ +| Error code | Description | ++=================+=====================================+ +| ECONNREFUSED | Connection refused | ++-----------------+-------------------------------------+ +| EADDRINUSE | Address already in use | ++-----------------+-------------------------------------+ +| ECONNABORTED | Software caused connection abort | ++-----------------+-------------------------------------+ +| ENETUNREACH | Network is unreachable | ++-----------------+-------------------------------------+ +| ENETDOWN | Network interface is not configured | ++-----------------+-------------------------------------+ +| ETIMEDOUT | Connection timed out | ++-----------------+-------------------------------------+ +| EHOSTDOWN | Host is down | ++-----------------+-------------------------------------+ +| EHOSTUNREACH | Host is unreachable | ++-----------------+-------------------------------------+ +| EINPROGRESS | Connection already in progress | ++-----------------+-------------------------------------+ +| EALREADY | Socket already connected | ++-----------------+-------------------------------------+ +| EDESTADDRREQ | Destination address required | ++-----------------+-------------------------------------+ +| EPROTONOSUPPORT | Unknown protocol | ++-----------------+-------------------------------------+ + diff --git a/docs/zh_CN/api-guides/index.rst b/docs/zh_CN/api-guides/index.rst index c00fa330c..96d06a57e 100644 --- a/docs/zh_CN/api-guides/index.rst +++ b/docs/zh_CN/api-guides/index.rst @@ -34,4 +34,5 @@ API 指南 BluFi External SPI-connected RAM 链接脚本生成机制 + LwIP Tools diff --git a/docs/zh_CN/api-guides/lwip.rst b/docs/zh_CN/api-guides/lwip.rst new file mode 100644 index 000000000..9e512fd06 --- /dev/null +++ b/docs/zh_CN/api-guides/lwip.rst @@ -0,0 +1,2 @@ +.. include:: ../../en/api-guides/lwip.rst + From 0be585179e5bcac78c08dd20d28ce3c119ea965d Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 10 Oct 2019 14:05:46 +0200 Subject: [PATCH 05/14] spiffs: fix warning when building at release optimization level Closes https://github.com/espressif/esp-idf/issues/4144 --- components/spiffs/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/components/spiffs/CMakeLists.txt b/components/spiffs/CMakeLists.txt index dfe4643c0..0c68155dc 100644 --- a/components/spiffs/CMakeLists.txt +++ b/components/spiffs/CMakeLists.txt @@ -10,3 +10,4 @@ idf_component_register(SRCS "esp_spiffs.c" REQUIRES spi_flash PRIV_REQUIRES bootloader_support) +set_source_files_properties(spiffs/src/spiffs_nucleus.c PROPERTIES COMPILE_FLAGS -Wno-stringop-truncation) \ No newline at end of file From 6e423d5cf6e4753599b2cd8fd4216d7761be4b6f Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 10 Oct 2019 14:20:20 +0200 Subject: [PATCH 06/14] drivers/can: fix skipped function calls when assertions disabled When CONFIG_FREERTOS_ASSERT_DISABLE is set, the function calls wrapped inside the assertion macros would be removed from the code. Closes https://github.com/espressif/esp-idf/issues/4143 --- components/driver/can.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/components/driver/can.c b/components/driver/can.c index 933994b05..70768917e 100644 --- a/components/driver/can.c +++ b/components/driver/can.c @@ -453,13 +453,17 @@ static void can_intr_handler_tx(can_status_reg_t *status, int *alert_req) //Update TX message count p_can_obj->tx_msg_count--; - configASSERT(p_can_obj->tx_msg_count >= 0); //Sanity check + assert(p_can_obj->tx_msg_count >= 0); //Sanity check //Check if there are more frames to transmit if (p_can_obj->tx_msg_count > 0 && p_can_obj->tx_queue != NULL) { can_frame_t frame; - configASSERT(xQueueReceiveFromISR(p_can_obj->tx_queue, &frame, NULL) == pdTRUE); - can_set_tx_buffer_and_transmit(&frame); + int res = xQueueReceiveFromISR(p_can_obj->tx_queue, &frame, NULL); + if (res == pdTRUE) { + can_set_tx_buffer_and_transmit(&frame); + } else { + assert(false && "failed to get a frame from TX queue"); + } } else { //No more frames to transmit CAN_RESET_FLAG(p_can_obj->control_flags, CTRL_FLAG_TX_BUFF_OCCUPIED); @@ -679,7 +683,8 @@ esp_err_t can_driver_install(const can_general_config_t *g_config, const can_tim } periph_module_reset(PERIPH_CAN_MODULE); periph_module_enable(PERIPH_CAN_MODULE); //Enable APB CLK to CAN peripheral - configASSERT(can_enter_reset_mode() == ESP_OK); //Must enter reset mode to write to config registers + esp_err_t err = can_exit_reset_mode(); //Must enter reset mode to write to config registers + assert(err == ESP_OK); can_config_pelican(); //Use PeliCAN addresses /* Note: REC is allowed to increase even in reset mode. Listen only mode will freeze REC. The desired mode will be set when can_start() is called. */ @@ -734,7 +739,8 @@ esp_err_t can_driver_uninstall(void) //Check state CAN_CHECK_FROM_CRIT(p_can_obj != NULL, ESP_ERR_INVALID_STATE); CAN_CHECK_FROM_CRIT(p_can_obj->control_flags & (CTRL_FLAG_STOPPED | CTRL_FLAG_BUS_OFF), ESP_ERR_INVALID_STATE); - configASSERT(can_enter_reset_mode() == ESP_OK); //Enter reset mode to stop any CAN bus activity + esp_err_t err = can_exit_reset_mode(); //Enter reset mode to stop any CAN bus activity + assert(err == ESP_OK); //Clear registers by reading (void) can_get_interrupt_reason(); (void) can_get_arbitration_lost_capture(); @@ -772,7 +778,8 @@ esp_err_t can_start(void) //Reset RX queue, and RX message count xQueueReset(p_can_obj->rx_queue); p_can_obj->rx_msg_count = 0; - configASSERT(can_enter_reset_mode() == ESP_OK); //Should already be in bus-off mode, set again to make sure + esp_err_t err = can_exit_reset_mode(); //Should already be in bus-off mode, set again to make sure + assert(err == ESP_OK); //Currently in listen only mode, need to set to mode specified by configuration can_mode_t mode; @@ -785,7 +792,8 @@ esp_err_t can_start(void) } can_config_mode(mode); //Set mode (void) can_get_interrupt_reason(); //Clear interrupt register - configASSERT(can_exit_reset_mode() == ESP_OK); + err = can_exit_reset_mode(); + assert(err == ESP_OK); CAN_RESET_FLAG(p_can_obj->control_flags, CTRL_FLAG_STOPPED); CAN_EXIT_CRITICAL(); @@ -800,7 +808,8 @@ esp_err_t can_stop(void) CAN_CHECK_FROM_CRIT(!(p_can_obj->control_flags & (CTRL_FLAG_STOPPED | CTRL_FLAG_BUS_OFF)), ESP_ERR_INVALID_STATE); //Clear interrupts and reset flags - configASSERT(can_enter_reset_mode() == ESP_OK); + esp_err_t err = can_exit_reset_mode(); + assert(err == ESP_OK); (void) can_get_interrupt_reason(); //Read interrupt register to clear interrupts can_config_mode(CAN_MODE_LISTEN_ONLY); //Set to listen only mode to freeze REC CAN_RESET_FLAG(p_can_obj->control_flags, CTRL_FLAG_TX_BUFF_OCCUPIED); @@ -851,11 +860,13 @@ esp_err_t can_transmit(const can_message_t *message, TickType_t ticks_to_wait) CAN_ENTER_CRITICAL(); if (p_can_obj->control_flags & (CTRL_FLAG_STOPPED | CTRL_FLAG_BUS_OFF)) { //TX queue was reset (due to stop/bus_off), remove copied frame from queue to prevent transmission - configASSERT(xQueueReceive(p_can_obj->tx_queue, &tx_frame, 0) == pdTRUE); + int res = xQueueReceive(p_can_obj->tx_queue, &tx_frame, 0); + assert(res == pdTRUE); ret = ESP_ERR_INVALID_STATE; } else if ((p_can_obj->tx_msg_count == 0) && !(p_can_obj->control_flags & CTRL_FLAG_TX_BUFF_OCCUPIED)) { //TX buffer was freed during copy, manually trigger transmission - configASSERT(xQueueReceive(p_can_obj->tx_queue, &tx_frame, 0) == pdTRUE); + int res = xQueueReceive(p_can_obj->tx_queue, &tx_frame, 0); + assert(res == pdTRUE); can_set_tx_buffer_and_transmit(&tx_frame); p_can_obj->tx_msg_count++; CAN_SET_FLAG(p_can_obj->control_flags, CTRL_FLAG_TX_BUFF_OCCUPIED); @@ -946,7 +957,8 @@ esp_err_t can_initiate_recovery(void) CAN_SET_FLAG(p_can_obj->control_flags, CTRL_FLAG_RECOVERING); //Trigger start of recovery process - configASSERT(can_exit_reset_mode() == ESP_OK); + esp_err_t err = can_exit_reset_mode(); + assert(err == ESP_OK); CAN_EXIT_CRITICAL(); return ESP_OK; From e763a3a96f499b34caeb2360a33b7e6c21148a9d Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sun, 13 Oct 2019 15:37:07 +0200 Subject: [PATCH 07/14] ci: add test build with -O2 -NDEBUG, cleanup --- tools/ci/config/build.yml | 61 +++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/tools/ci/config/build.yml b/tools/ci/config/build.yml index 77802271e..46ee9fdef 100644 --- a/tools/ci/config/build.yml +++ b/tools/ci/config/build.yml @@ -22,6 +22,17 @@ - $BOT_LABEL_UNIT_TEST - $BOT_LABEL_REGULAR_TEST + +.build_with_make_and_cmake: &build_with_make_and_cmake | + echo -e "section_end:"`date +%s`":build_script\r\e[0Ksection_start:"`date +%s`":build_make\r\e[0KBuild with Make" + make defconfig + make all + make clean + echo -e "section_end:"`date +%s`":build_make\r\e[0Ksection_start:"`date +%s`":build_cmake\r\e[0KBuild with CMake" + rm -rf build sdkconfig + idf.py build + echo -e "section_end:"`date +%s`":build_cmake\r\e[0Ksection_start:"`date +%s`":build_script\r\e[0K" + build_template_app: stage: build image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG @@ -45,43 +56,37 @@ build_template_app: - export PATH="$IDF_PATH/tools:$PATH" - export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} - export EXTRA_CXXFLAGS=${PEDANTIC_CXXFLAGS} - - # CONFIG_COMPILER_OPTIMIZATION_DEFAULT with flag -Og - - echo "CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y" >> sdkconfig - - make defconfig - - make all V=1 - - make clean - # CONFIG_COMPILER_OPTIMIZATION_SIZE with flag -Os - - echo "CONFIG_COMPILER_OPTIMIZATION_SIZE=y" >> sdkconfig - - make defconfig - - make all V=1 - - make clean - - # CONFIG_COMPILER_OPTIMIZATION_PERF with flag -O2 - - echo "CONFIG_COMPILER_OPTIMIZATION_PERF=y" >> sdkconfig - - make defconfig - - make all V=1 - - make clean + # CONFIG_COMPILER_OPTIMIZATION_DEFAULT with flag -Og + - echo "CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y" > sdkconfig.defaults + - *build_with_make_and_cmake # CONFIG_COMPILER_OPTIMIZATION_NONE with flag -O0 - - echo "CONFIG_COMPILER_OPTIMIZATION_NONE=y" >> sdkconfig - - make defconfig - - make all V=1 - - make clean + - echo "CONFIG_COMPILER_OPTIMIZATION_NONE=y" > sdkconfig.defaults + - *build_with_make_and_cmake + + # CONFIG_COMPILER_OPTIMIZATION_SIZE with flag -Os + - echo "CONFIG_COMPILER_OPTIMIZATION_SIZE=y" > sdkconfig.defaults + - *build_with_make_and_cmake + + # CONFIG_COMPILER_OPTIMIZATION_PERF with flag -O2 + - echo "CONFIG_COMPILER_OPTIMIZATION_PERF=y" > sdkconfig.defaults + - *build_with_make_and_cmake + + # Same as above, but also disable assertions. + - echo "CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y" >> sdkconfig.defaults + # Don't error out on -Wunused, when assertions are disabled + - export EXTRA_CFLAGS=${PEDANTIC_CFLAGS/-Werror=unused-variable -Werror=unused-but-set-variable -Werror=unused-function/} + - export EXTRA_CXXFLAGS=${PEDANTIC_CXXFLAGS/-Werror=unused-variable -Werror=unused-but-set-variable -Werror=unused-function/} + - *build_with_make_and_cmake + - export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} + - export EXTRA_CXXFLAGS=${PEDANTIC_CXXFLAGS} # Check if there are any stray printf/ets_printf references in WiFi libs - pushd ../components/esp_wifi/lib_esp32 - test $(xtensa-esp32-elf-nm *.a | grep -w printf | wc -l) -eq 0 - test $(xtensa-esp32-elf-nm *.a | grep -w ets_printf | wc -l) -eq 0 - popd - # Repeat the build using CMake - - rm -rf build sdkconfig - # Debug build - - idf.py build - # Release build - - sed -i.bak -e's/CONFIG_OPTIMIZATION_LEVEL_DEBUG\=y/CONFIG_OPTIMIZATION_LEVEL_RELEASE=y/' sdkconfig - - idf.py build build_ssc: extends: .build_template From 31dac92e5f0daac98190fd603df213a0a25a3807 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 1 Oct 2019 18:50:34 +0200 Subject: [PATCH 08/14] ethernet: support OpenCores ethernet MAC OpenCores Ethernet MAC has a relatively simple interface, and is already supported in QEMU. This makes it a good candidate for enabling network support when running IDF apps in QEMU, compared to the relatively more complex task of writing a QEMU model of ESP32 EMAC. This driver is written with QEMU in mind: it does not implement or handle things that aren't implemented or handled in the QEMU model: error flags, error interrupts. The transmit part of the driver also assumes that the TX operation is done immediately when the TX descriptor is written (which is the case with QEMU), hence waiting for the TX operation to complete is not necessary. For simplicity, the driver assumes that the peripheral register occupy the same memory range as the ESP32 EMAC registers, and the same interrupt source number is used. --- components/esp_eth/CMakeLists.txt | 4 + components/esp_eth/Kconfig | 24 + components/esp_eth/component.mk | 4 + components/esp_eth/include/esp_eth_mac.h | 6 + components/esp_eth/src/esp_eth_mac_openeth.c | 410 ++++++++++++++++++ components/esp_eth/src/openeth.h | 216 +++++++++ .../Kconfig.projbuild | 11 + .../protocol_examples_common/connect.c | 5 + 8 files changed, 680 insertions(+) create mode 100644 components/esp_eth/src/esp_eth_mac_openeth.c create mode 100644 components/esp_eth/src/openeth.h diff --git a/components/esp_eth/CMakeLists.txt b/components/esp_eth/CMakeLists.txt index 3829df188..8547a49e3 100644 --- a/components/esp_eth/CMakeLists.txt +++ b/components/esp_eth/CMakeLists.txt @@ -13,6 +13,10 @@ if(CONFIG_ETH_SPI_ETHERNET_DM9051) "src/esp_eth_phy_dm9051.c") endif() +if(CONFIG_ETH_USE_OPENETH) + list(APPEND esp_eth_srcs "src/esp_eth_mac_openeth.c") +endif() + idf_component_register(SRCS "${esp_eth_srcs}" INCLUDE_DIRS "include" LDFRAGMENTS "linker.lf" diff --git a/components/esp_eth/Kconfig b/components/esp_eth/Kconfig index 8e894d397..63ee86936 100644 --- a/components/esp_eth/Kconfig +++ b/components/esp_eth/Kconfig @@ -153,4 +153,28 @@ menu "Ethernet" Set the GPIO number used by DM9051's Interrupt pin. endif endif + + menuconfig ETH_USE_OPENETH + bool "Support OpenCores Ethernet MAC (for use with QEMU)" + default n + help + OpenCores Ethernet MAC driver can be used when an ESP-IDF application + is executed in QEMU. This driver is not supported when running on a + real chip. + + if ETH_USE_OPENETH + config ETH_OPENETH_DMA_RX_BUFFER_NUM + int "Number of Ethernet DMA Rx buffers" + range 1 64 + default 4 + help + Number of DMA receive buffers, each buffer is 1600 bytes. + + config ETH_OPENETH_DMA_TX_BUFFER_NUM + int "Number of Ethernet DMA Tx buffers" + range 1 64 + default 1 + help + Number of DMA transmit buffers, each buffer is 1600 bytes. + endif endmenu diff --git a/components/esp_eth/component.mk b/components/esp_eth/component.mk index 3a768fdf8..252aafccf 100644 --- a/components/esp_eth/component.mk +++ b/components/esp_eth/component.mk @@ -12,3 +12,7 @@ endif ifndef CONFIG_ETH_SPI_ETHERNET_DM9051 COMPONENT_OBJEXCLUDE += src/esp_eth_mac_dm9051.o src/esp_eth_phy_dm9051.o endif + +ifndef CONFIG_ETH_USE_OPENETH + COMPONENT_OBJEXCLUDE += src/esp_eth_mac_openeth.o +endif diff --git a/components/esp_eth/include/esp_eth_mac.h b/components/esp_eth/include/esp_eth_mac.h index efcbe98d0..8ef030d8a 100644 --- a/components/esp_eth/include/esp_eth_mac.h +++ b/components/esp_eth/include/esp_eth_mac.h @@ -307,6 +307,12 @@ typedef struct { */ esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, const eth_mac_config_t *mac_config); #endif + + +#if CONFIG_ETH_USE_OPENETH +esp_eth_mac_t *esp_eth_mac_new_openeth(const eth_mac_config_t *config); +#endif // CONFIG_ETH_USE_OPENETH + #ifdef __cplusplus } #endif diff --git a/components/esp_eth/src/esp_eth_mac_openeth.c b/components/esp_eth/src/esp_eth_mac_openeth.c new file mode 100644 index 000000000..e110e405b --- /dev/null +++ b/components/esp_eth/src/esp_eth_mac_openeth.c @@ -0,0 +1,410 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This is a driver for OpenCores Ethernet MAC (https://opencores.org/projects/ethmac). +// Espressif chips do not use this MAC, but it is supported in QEMU +// (see hw/net/opencores_eth.c). Since the interface of this MAC is a relatively +// simple one, it is used for the purpose of running IDF apps in QEMU. +// The QEMU driver also emulates the DP83848C PHY, which is supported in IDF. +// Note that this driver is written with QEMU in mind. For example, it doesn't +// handle errors which QEMU will not report, and doesn't wait for TX to be +// finished, since QEMU does this instantly. + +#include +#include +#include +#include +#include "esp_log.h" +#include "esp_eth.h" +#include "esp_intr_alloc.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "openeth.h" + +static const char *TAG = "emac_opencores"; + +#define MAC_CHECK(a, str, goto_tag, ret_value, ...) \ + do \ + { \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + ret = ret_value; \ + goto goto_tag; \ + } \ + } while (0) + +// Driver state structure +typedef struct { + esp_eth_mac_t parent; + esp_eth_mediator_t *eth; + intr_handle_t intr_hdl; + TaskHandle_t rx_task_hdl; + int cur_rx_desc; + int cur_tx_desc; + uint8_t addr[6]; + uint8_t *rx_buf[RX_BUF_COUNT]; + uint8_t *tx_buf[TX_BUF_COUNT]; +} emac_opencores_t; + + +// Interrupt handler and the receive task + +static esp_err_t emac_opencores_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length); + +static IRAM_ATTR void emac_opencores_isr_handler(void *args) +{ + emac_opencores_t *emac = (emac_opencores_t*) args; + BaseType_t high_task_wakeup; + + uint32_t status = REG_READ(OPENETH_INT_SOURCE_REG); + + if (status & OPENETH_INT_RXB) { + // Notify receive task + vTaskNotifyGiveFromISR(emac->rx_task_hdl, &high_task_wakeup); + if (high_task_wakeup) { + portYIELD_FROM_ISR(); + } + } + + if (status & OPENETH_INT_BUSY) { + ESP_EARLY_LOGW(TAG, "%s: RX frame dropped (0x%x)", __func__, status); + } + + // Clear interrupt + REG_WRITE(OPENETH_INT_SOURCE_REG, status); +} + +static void emac_opencores_rx_task(void *arg) +{ + emac_opencores_t *emac = (emac_opencores_t *)arg; + uint8_t *buffer = NULL; + uint32_t length = 0; + while (1) { + if (ulTaskNotifyTake(pdFALSE, portMAX_DELAY)) { + while(true) { + buffer = (uint8_t *)malloc(ETH_MAX_PACKET_SIZE); + length = ETH_MAX_PACKET_SIZE; + if (emac_opencores_receive(&emac->parent, buffer, &length) == ESP_OK) { + // pass the buffer to the upper layer + if (length) { + emac->eth->stack_input(emac->eth, buffer, length); + } else { + free(buffer); + } + } else { + free(buffer); + break; + } + } + } + } + vTaskDelete(NULL); +} + + +// Below functions implement the driver interface + +static esp_err_t emac_opencores_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth) +{ + esp_err_t ret = ESP_OK; + MAC_CHECK(eth, "can't set mac's mediator to null", err, ESP_ERR_INVALID_ARG); + emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent); + emac->eth = eth; + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_opencores_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value) +{ + ESP_LOGV(TAG, "%s: addr=%d reg=0x%x val=0x%04x", __func__, phy_addr, phy_reg, reg_value); + REG_SET_FIELD(OPENETH_MIIADDRESS_REG, OPENETH_FIAD, phy_addr); + REG_SET_FIELD(OPENETH_MIIADDRESS_REG, OPENETH_RGAD, phy_reg); + REG_WRITE(OPENETH_MIITX_DATA_REG, reg_value & OPENETH_MII_DATA_MASK); + REG_SET_BIT(OPENETH_MIICOMMAND_REG, OPENETH_WCTRLDATA); + return ESP_OK; +} + +static esp_err_t emac_opencores_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value) +{ + esp_err_t ret = ESP_OK; + MAC_CHECK(reg_value, "can't set reg_value to null", err, ESP_ERR_INVALID_ARG); + REG_SET_FIELD(OPENETH_MIIADDRESS_REG, OPENETH_FIAD, phy_addr); + REG_SET_FIELD(OPENETH_MIIADDRESS_REG, OPENETH_RGAD, phy_reg); + REG_SET_BIT(OPENETH_MIICOMMAND_REG, OPENETH_RSTAT); + *reg_value = (REG_READ(OPENETH_MIIRX_DATA_REG) & OPENETH_MII_DATA_MASK); + ESP_LOGV(TAG, "%s: addr=%d reg=0x%x val=0x%04x", __func__, phy_addr, phy_reg, *reg_value); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_opencores_set_addr(esp_eth_mac_t *mac, uint8_t *addr) +{ + ESP_LOGV(TAG, "%s: " MACSTR, __func__, MAC2STR(addr)); + esp_err_t ret = ESP_OK; + MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG); + emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent); + memcpy(emac->addr, addr, 6); + const uint8_t mac0[4] = {addr[5], addr[4], addr[3], addr[2]}; + const uint8_t mac1[4] = {addr[1], addr[0]}; + uint32_t mac0_u32, mac1_u32; + memcpy(&mac0_u32, &mac0, 4); + memcpy(&mac1_u32, &mac1, 4); + REG_WRITE(OPENETH_MAC_ADDR0_REG, mac0_u32); + REG_WRITE(OPENETH_MAC_ADDR1_REG, mac1_u32); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_opencores_get_addr(esp_eth_mac_t *mac, uint8_t *addr) +{ + ESP_LOGV(TAG, "%s: " MACSTR, __func__, MAC2STR(addr)); + esp_err_t ret = ESP_OK; + MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG); + emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent); + memcpy(addr, emac->addr, 6); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_opencores_set_link(esp_eth_mac_t *mac, eth_link_t link) +{ + ESP_LOGV(TAG, "%s: %s", __func__, link == ETH_LINK_UP ? "up" : "down"); + esp_err_t ret = ESP_OK; + emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent); + switch (link) { + case ETH_LINK_UP: + MAC_CHECK(esp_intr_enable(emac->intr_hdl) == ESP_OK, "enable interrupt failed", err, ESP_FAIL); + openeth_enable(); + break; + case ETH_LINK_DOWN: + MAC_CHECK(esp_intr_disable(emac->intr_hdl) == ESP_OK, "disable interrupt failed", err, ESP_FAIL); + openeth_disable(); + break; + default: + MAC_CHECK(false, "unknown link status", err, ESP_ERR_INVALID_ARG); + break; + } + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_opencores_set_speed(esp_eth_mac_t *mac, eth_speed_t speed) +{ + /* QEMU doesn't emulate PHY speed, so accept any value */ + return ESP_OK; +} + +static esp_err_t emac_opencores_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex) +{ + /* QEMU doesn't emulate full/half duplex, so accept any value */ + return ESP_OK; +} + +static esp_err_t emac_opencores_set_promiscuous(esp_eth_mac_t *mac, bool enable) +{ + if (enable) { + REG_SET_BIT(OPENETH_MODER_REG, OPENETH_PRO); + } else { + REG_CLR_BIT(OPENETH_MODER_REG, OPENETH_PRO); + } + return ESP_OK; +} + +static esp_err_t emac_opencores_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length) +{ + esp_err_t ret = ESP_OK; + emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent); + MAC_CHECK(buf, "can't set buf to null", err, ESP_ERR_INVALID_ARG); + MAC_CHECK(length, "buf length can't be zero", err, ESP_ERR_INVALID_ARG); + MAC_CHECK(length < DMA_BUF_SIZE * TX_BUF_COUNT, "insufficient TX buffer size", err, ESP_ERR_INVALID_SIZE); + + uint32_t bytes_remaining = length; + // In QEMU, there never is a TX operation in progress, so start with descriptor 0. + + ESP_LOGV(TAG, "%s: len=%d", __func__, length); + while (bytes_remaining > 0) { + uint32_t will_write = MIN(bytes_remaining, DMA_BUF_SIZE); + memcpy(emac->tx_buf[emac->cur_tx_desc], buf, will_write); + openeth_tx_desc_t* desc_ptr = openeth_tx_desc(emac->cur_tx_desc); + openeth_tx_desc_t desc_val = *desc_ptr; + desc_val.wr = (emac->cur_tx_desc == TX_BUF_COUNT - 1); + desc_val.len = will_write; + desc_val.rd = 1; + // TXEN is already set, and this triggers a TX operation for the descriptor + ESP_LOGV(TAG, "%s: desc %d (%p) len=%d wr=%d", __func__, emac->cur_tx_desc, desc_ptr, will_write, desc_val.wr); + *desc_ptr = desc_val; + bytes_remaining -= will_write; + buf += will_write; + emac->cur_tx_desc = (emac->cur_tx_desc + 1) % TX_BUF_COUNT; + } + + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_opencores_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length) +{ + esp_err_t ret = ESP_OK; + emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent); + MAC_CHECK(buf && length, "can't set buf and length to null", err, ESP_ERR_INVALID_ARG); + + openeth_rx_desc_t *desc_ptr = openeth_rx_desc(emac->cur_rx_desc); + openeth_rx_desc_t desc_val = *desc_ptr; + ESP_LOGV(TAG, "%s: desc %d (%p) e=%d len=%d wr=%d", __func__, emac->cur_rx_desc, desc_ptr, desc_val.e, desc_val.len, desc_val.wr); + if (desc_val.e) { + ret = ESP_ERR_INVALID_STATE; + goto err; + } + size_t rx_length = desc_val.len; + MAC_CHECK(*length >= rx_length, "RX length too large", err, ESP_ERR_INVALID_SIZE); + *length = rx_length; + memcpy(buf, desc_val.rxpnt, *length); + desc_val.e = 1; + *desc_ptr = desc_val; + + emac->cur_rx_desc = (emac->cur_rx_desc + 1) % RX_BUF_COUNT; + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_opencores_init(esp_eth_mac_t *mac) +{ + esp_err_t ret = ESP_OK; + emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent); + esp_eth_mediator_t *eth = emac->eth; + MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL); + MAC_CHECK(esp_read_mac(emac->addr, ESP_MAC_ETH) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL); + + // Sanity check + if (REG_READ(OPENETH_MODER_REG) != OPENETH_MODER_DEFAULT) { + ESP_LOGE(TAG, "CONFIG_ETH_USE_OPENETH should only be used when running in QEMU."); + ESP_LOGE(TAG, "When running the app on the ESP32, use CONFIG_ETH_USE_ESP32_EMAC instead."); + abort(); + } + // Initialize the MAC + openeth_reset(); + openeth_set_tx_desc_cnt(TX_BUF_COUNT); + emac_opencores_set_addr(mac, emac->addr); + + return ESP_OK; +err: + eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); + return ret; +} + +static esp_err_t emac_opencores_deinit(esp_eth_mac_t *mac) +{ + emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent); + esp_eth_mediator_t *eth = emac->eth; + eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); + return ESP_OK; +} + +static esp_err_t emac_opencores_del(esp_eth_mac_t *mac) +{ + emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent); + esp_intr_free(emac->intr_hdl); + vTaskDelete(emac->rx_task_hdl); + for (int i = 0; i < RX_BUF_COUNT; i++) { + free(emac->rx_buf[i]); + } + for (int i = 0; i < TX_BUF_COUNT; i++) { + free(emac->tx_buf[i]); + } + free(emac); + return ESP_OK; +} + +esp_eth_mac_t *esp_eth_mac_new_openeth(const eth_mac_config_t *config) +{ + esp_eth_mac_t *ret = NULL; + emac_opencores_t *emac = NULL; + MAC_CHECK(config, "can't set mac config to null", out, NULL); + emac = calloc(1, sizeof(emac_opencores_t)); + MAC_CHECK(emac, "calloc emac failed", out, NULL); + + // Allocate DMA buffers + for (int i = 0; i < RX_BUF_COUNT; i++) { + emac->rx_buf[i] = heap_caps_calloc(1, DMA_BUF_SIZE, MALLOC_CAP_DMA); + if (!(emac->rx_buf[i])) { + goto out; + } + openeth_init_rx_desc(openeth_rx_desc(i), emac->rx_buf[i]); + } + openeth_rx_desc(RX_BUF_COUNT - 1)->wr = 1; + emac->cur_rx_desc = 0; + + for (int i = 0; i < TX_BUF_COUNT; i++) { + emac->tx_buf[i] = heap_caps_calloc(1, DMA_BUF_SIZE, MALLOC_CAP_DMA); + if (!(emac->tx_buf[i])) { + goto out; + } + openeth_init_tx_desc(openeth_tx_desc(i), emac->tx_buf[i]); + } + openeth_tx_desc(TX_BUF_COUNT - 1)->wr = 1; + emac->cur_tx_desc = 0; + + emac->parent.set_mediator = emac_opencores_set_mediator; + emac->parent.init = emac_opencores_init; + emac->parent.deinit = emac_opencores_deinit; + emac->parent.del = emac_opencores_del; + emac->parent.write_phy_reg = emac_opencores_write_phy_reg; + emac->parent.read_phy_reg = emac_opencores_read_phy_reg; + emac->parent.set_addr = emac_opencores_set_addr; + emac->parent.get_addr = emac_opencores_get_addr; + emac->parent.set_speed = emac_opencores_set_speed; + emac->parent.set_duplex = emac_opencores_set_duplex; + emac->parent.set_link = emac_opencores_set_link; + emac->parent.set_promiscuous = emac_opencores_set_promiscuous; + emac->parent.transmit = emac_opencores_transmit; + emac->parent.receive = emac_opencores_receive; + + // Initialize the interrupt + MAC_CHECK(esp_intr_alloc(OPENETH_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_opencores_isr_handler, + emac, &(emac->intr_hdl)) == ESP_OK, + "alloc emac interrupt failed", out, NULL); + + // Create the RX task + BaseType_t xReturned = xTaskCreate(emac_opencores_rx_task, "emac_rx", config->rx_task_stack_size, emac, + config->rx_task_prio, &emac->rx_task_hdl); + MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", out, NULL); + return &(emac->parent); + +out: + if (emac) { + if (emac->rx_task_hdl) { + vTaskDelete(emac->rx_task_hdl); + } + if (emac->intr_hdl) { + esp_intr_free(emac->intr_hdl); + } + for (int i = 0; i < TX_BUF_COUNT; i++) { + free(emac->tx_buf[i]); + } + for (int i = 0; i < RX_BUF_COUNT; i++) { + free(emac->rx_buf[i]); + } + free(emac); + } + return ret; +} diff --git a/components/esp_eth/src/openeth.h b/components/esp_eth/src/openeth.h new file mode 100644 index 000000000..ea4f48b24 --- /dev/null +++ b/components/esp_eth/src/openeth.h @@ -0,0 +1,216 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include +#include +#include +#include "sdkconfig.h" +#include "soc/soc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// These are the register definitions for the OpenCores Ethernet MAC. +// See comments in esp_eth_mac_openeth.c for more details about this driver. + +// DMA buffers configuration +#define DMA_BUF_SIZE 1600 +#define RX_BUF_COUNT CONFIG_ETH_OPENETH_DMA_RX_BUFFER_NUM +#define TX_BUF_COUNT CONFIG_ETH_OPENETH_DMA_TX_BUFFER_NUM + +// This driver uses the interrupt source number of the internal EMAC of the ESP32 chip, +// and uses the same register address base. This of course only works in QEMU, where +// the OpenCores MAC is mapped to the same register base and to the same interrupt +// source. This driver does a sanity check that it is not running on the real ESP32 +// chip, using the EMAC date register. +#define OPENETH_INTR_SOURCE ETS_ETH_MAC_INTR_SOURCE +#define OPENETH_BASE DR_REG_EMAC_BASE + +// OpenCores ethmac registers +#define OPENETH_MODER_REG (OPENETH_BASE + 0x00) +#define OPENETH_MODER_DEFAULT 0xa000 +// OPENETH_RST: reset the MAC +#define OPENETH_RST BIT(11) +// OPENETH_PRO: enable promiscuous mode +#define OPENETH_PRO BIT(5) +// OPENETH_TXEN: enable transmit +#define OPENETH_TXEN BIT(1) +// OPENETH_RXEN: enable receive +#define OPENETH_RXEN BIT(0) + +#define OPENETH_INT_SOURCE_REG (OPENETH_BASE + 0x04) +#define OPENETH_INT_MASK_REG (OPENETH_BASE + 0x08) +// These bits apply to INT_SOURCE and INT_MASK registers: +// OPENETH_INT_BUSY: Buffer was received and discarded due to lack of buffers +#define OPENETH_INT_BUSY BIT(4) +// OPENETH_INT_RXB: Frame received +#define OPENETH_INT_RXB BIT(2) +// OPENETH_INT_TXB: Frame transmitted +#define OPENETH_INT_TXB BIT(0) + +// IPGT, IPGR1, IPGR2 registers are not implemented in QEMU, hence not used here +#define OPENETH_PACKETLEN_REG (OPENETH_BASE + 0x18) +// OPENETH_MINFL: minimum frame length +#define OPENETH_MINFL_S 16 +#define OPENETH_MINFL_V 0xffff +#define OPENETH_MINFL_M (OPENETH_MINFL_V << OPENETH_MINFL_S) +// OPENETH_MAXFL: maximum frame length +#define OPENETH_MAXFL_S 0 +#define OPENETH_MAXFL_V 0xffff +#define OPENETH_MAXFL_M (OPENETH_MAXFL_V << OPENETH_MAXFL_S) + +// COLLCONF is not implemented in QEMU +#define OPENETH_TX_BD_NUM_REG (OPENETH_BASE + 0x20) +// CTRLMODER, MIIMODER are not implemented in QEMU +#define OPENETH_MIICOMMAND_REG (OPENETH_BASE + 0x2c) +// OPENETH_WCTRLDATA: write control data +#define OPENETH_WCTRLDATA BIT(2) +// OPENETH_RSTAT: read status +#define OPENETH_RSTAT BIT(1) +// OPENETH_SCANSTAT: scan status +#define OPENETH_SCANSTAT BIT(0) + +#define OPENETH_MIIADDRESS_REG (OPENETH_BASE + 0x30) +// OPENETH_RGAD: register address +#define OPENETH_RGAD_S 8 +#define OPENETH_RGAD_V 0x1f +#define OPENETH_RGAD_M (OPENETH_RGAD_V << OPENETH_RGAD_S) +// OPENETH_FIAD: PHY address +#define OPENETH_FIAD_S 0 +#define OPENETH_FIAD_V 0x1f +#define OPENETH_FIAD_N (OPENETH_FIAD_V << OPENETH_FIAD_S) + +#define OPENETH_MIITX_DATA_REG (OPENETH_BASE + 0x34) +#define OPENETH_MIIRX_DATA_REG (OPENETH_BASE + 0x38) +#define OPENETH_MII_DATA_MASK 0xffff + +#define OPENETH_MIISTATUS_REG (OPENETH_BASE + 0x3c) +// OPENETH_LINKFAIL: link is down +#define OPENETH_LINKFAIL BIT(0) + +// OPENETH_MAC_ADDR0_REG: bytes 2-5 of the MAC address (byte 5 in LSB) +#define OPENETH_MAC_ADDR0_REG (OPENETH_BASE + 0x40) +// OPENETH_MAC_ADDR1_REG: bytes 0-1 of the MAC address (byte 1 in LSB) +#define OPENETH_MAC_ADDR1_REG (OPENETH_BASE + 0x44) + +#define OPENETH_HASH0_ADR_REG (OPENETH_BASE + 0x48) +#define OPENETH_HASH1_ADR_REG (OPENETH_BASE + 0x4c) + +// Location of the DMA descriptors +#define OPENETH_DESC_BASE (OPENETH_BASE + 0x400) +// Total number of (TX + RX) DMA descriptors +#define OPENETH_DESC_CNT 128 + + +// Structures describing TX and RX descriptors. +// The field names are same as in the OpenCores ethmac documentation. +typedef struct { + uint16_t cs: 1; //!< Carrier sense lost (flag set by HW) + uint16_t df: 1; //!< Defer indication (flag set by HW) + uint16_t lc: 1; //!< Late collision occured (flag set by HW) + uint16_t rl: 1; //!< TX failed due to retransmission limit (flag set by HW) + uint16_t rtry: 4; //!< Number of retries before the frame was sent (set by HW) + uint16_t ur: 1; //!< Underrun status (flag set by HW) + uint16_t rsv: 2; //!< Reserved + uint16_t crc: 1; //!< Add CRC at the end of the packet + uint16_t pad: 1; //!< Add padding to the end of short packets + uint16_t wr: 1; //!< Wrap-around. 0: not the last descriptor in the table, 1: last descriptor. + uint16_t irq: 1; //!< Generate interrupt after this descriptor is transmitted + uint16_t rd: 1; //!< Descriptor ready. 0: descriptor owned by SW, 1: descriptor owned by HW. Cleared by HW. + + uint16_t len; //!< Number of bytes to be transmitted + void* txpnt; //!< Pointer to the data to transmit +} openeth_tx_desc_t; + +_Static_assert(sizeof(openeth_tx_desc_t) == 8, "incorrect size of openeth_tx_desc_t"); + +typedef struct { + uint16_t lc: 1; //!< Late collision flag + uint16_t crc: 1; //!< RX CRC error flag + uint16_t sf: 1; //!< Frame shorter than set in PACKETLEN register + uint16_t tl: 1; //!< Frame longer than set in PACKETLEN register + uint16_t dn: 1; //!< Dribble nibble (frame length not divisible by 8 bits) flag + uint16_t is: 1; //!< Invalid symbol flag + uint16_t or: 1; //!< Overrun flag + uint16_t m: 1; //!< Frame received because of the promiscuous mode + uint16_t rsv: 5; //!< Reserved + uint16_t wr: 1; //!< Wrap-around. 0: not the last descriptor in the table, 1: last descriptor. + uint16_t irq: 1; //!< Generate interrupt after this descriptor is transmitted + uint16_t e: 1; //!< The buffer is empty. 0: descriptor owned by SW, 1: descriptor owned by HW. + + uint16_t len; //!< Number of bytes received (filled by HW) + void* rxpnt; //!< Pointer to the receive buffer +} openeth_rx_desc_t; + +_Static_assert(sizeof(openeth_rx_desc_t) == 8, "incorrect size of openeth_rx_desc_t"); + + +static inline openeth_tx_desc_t* openeth_tx_desc(int idx) +{ + assert(idx < TX_BUF_COUNT); + return &((openeth_tx_desc_t*)OPENETH_DESC_BASE)[idx]; +} + +static inline openeth_rx_desc_t* openeth_rx_desc(int idx) +{ + assert(idx < OPENETH_DESC_CNT - TX_BUF_COUNT); + return &((openeth_rx_desc_t*)OPENETH_DESC_BASE)[idx + TX_BUF_COUNT]; +} + +static inline void openeth_enable(void) +{ + REG_SET_BIT(OPENETH_MODER_REG, OPENETH_TXEN | OPENETH_RXEN | OPENETH_PRO); + REG_SET_BIT(OPENETH_INT_MASK_REG, OPENETH_INT_RXB); +} + +static inline void openeth_disable(void) +{ + REG_CLR_BIT(OPENETH_INT_MASK_REG, OPENETH_INT_RXB); + REG_CLR_BIT(OPENETH_MODER_REG, OPENETH_TXEN | OPENETH_RXEN | OPENETH_PRO); +} + +static inline void openeth_reset(void) +{ + REG_SET_BIT(OPENETH_MODER_REG, OPENETH_RST); + REG_CLR_BIT(OPENETH_MODER_REG, OPENETH_RST); +} + +static inline void openeth_init_tx_desc(openeth_tx_desc_t* desc, void* buf) +{ + *desc = (openeth_tx_desc_t) { + .rd = 0, + .txpnt = buf + }; +} + +static inline void openeth_init_rx_desc(openeth_rx_desc_t* desc, void* buf) +{ + *desc = (openeth_rx_desc_t) { + .e = 1, + .irq = 1, + .rxpnt = buf + }; +} + +static inline void openeth_set_tx_desc_cnt(int tx_desc_cnt) +{ + assert(tx_desc_cnt <= OPENETH_DESC_CNT); + REG_WRITE(OPENETH_TX_BD_NUM_REG, tx_desc_cnt); +} + +#ifdef __cplusplus +} +#endif diff --git a/examples/common_components/protocol_examples_common/Kconfig.projbuild b/examples/common_components/protocol_examples_common/Kconfig.projbuild index f5d288e9a..e1fee9b61 100644 --- a/examples/common_components/protocol_examples_common/Kconfig.projbuild +++ b/examples/common_components/protocol_examples_common/Kconfig.projbuild @@ -49,6 +49,17 @@ menu "Example Connection Configuration" select ETH_USE_SPI_ETHERNET help Select external SPI-Ethernet module. + + config EXAMPLE_USE_OPENETH + bool "OpenCores Ethernet MAC (EXPERIMENTAL)" + select ETH_USE_OPENETH + help + When this option is enabled, the example is built with support for + OpenCores Ethernet MAC, which allows testing the example in QEMU. + Note that this option is used for internal testing purposes, and + not officially supported. Examples built with this option enabled + will not run on a real ESP32 chip. + endchoice if EXAMPLE_USE_INTERNAL_ETHERNET diff --git a/examples/common_components/protocol_examples_common/connect.c b/examples/common_components/protocol_examples_common/connect.c index 36e5326eb..1c6bd98d1 100644 --- a/examples/common_components/protocol_examples_common/connect.c +++ b/examples/common_components/protocol_examples_common/connect.c @@ -232,7 +232,12 @@ static void start(void) eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); s_mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config); s_phy = esp_eth_phy_new_dm9051(&phy_config); +#elif CONFIG_EXAMPLE_USE_OPENETH + phy_config.autonego_timeout_ms = 100; + s_mac = esp_eth_mac_new_openeth(&mac_config); + s_phy = esp_eth_phy_new_dp83848(&phy_config); #endif + esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy); ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle)); s_connection_name = "Ethernet"; From 84c72863e12b634d68bec585552af816a978d16e Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Mon, 14 Oct 2019 13:41:46 +0800 Subject: [PATCH 09/14] add netbios support in restful server example --- components/lwip/CMakeLists.txt | 1 + components/lwip/component.mk | 1 + examples/protocols/http_server/restful_server/README.md | 2 ++ .../http_server/restful_server/main/esp_rest_main.c | 5 ++++- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt index 81e8f1505..3024c65d4 100644 --- a/components/lwip/CMakeLists.txt +++ b/components/lwip/CMakeLists.txt @@ -20,6 +20,7 @@ set(srcs "lwip/src/api/sockets.c" "lwip/src/api/tcpip.c" "lwip/src/apps/sntp/sntp.c" + "lwip/src/apps/netbiosns/netbiosns.c" "lwip/src/core/def.c" "lwip/src/core/dns.c" "lwip/src/core/inet_chksum.c" diff --git a/components/lwip/component.mk b/components/lwip/component.mk index a92b88869..bea9d738f 100644 --- a/components/lwip/component.mk +++ b/components/lwip/component.mk @@ -16,6 +16,7 @@ COMPONENT_SRCDIRS := \ apps/sntp \ lwip/src/api \ lwip/src/apps/sntp \ + lwip/src/apps/netbiosns \ lwip/src/core \ lwip/src/core/ipv4 \ lwip/src/core/ipv6 \ diff --git a/examples/protocols/http_server/restful_server/README.md b/examples/protocols/http_server/restful_server/README.md index 9923d4232..84808ae2e 100644 --- a/examples/protocols/http_server/restful_server/README.md +++ b/examples/protocols/http_server/restful_server/README.md @@ -108,6 +108,8 @@ openocd-esp32/bin/openocd -s openocd-esp32/share/openocd/scripts -f interface/ft In your browser, enter the URL where the website located (e.g. `http://esp-home.local`). You can also enter the IP address that ESP32 obtained if your operating system currently don't have support for mDNS service. +Besides that, this example also enables the NetBIOS feature with the domain name `esp-home`. If your OS supports NetBIOS and has enabled it (e.g. Windows has native support for NetBIOS), then the URL `http://esp-home` should also work. + ![esp_home_local](https://dl.espressif.com/dl/esp-idf/docs/_static/esp_home_local.gif) ### ESP monitor output diff --git a/examples/protocols/http_server/restful_server/main/esp_rest_main.c b/examples/protocols/http_server/restful_server/main/esp_rest_main.c index c82711ca4..0f03f65a0 100644 --- a/examples/protocols/http_server/restful_server/main/esp_rest_main.c +++ b/examples/protocols/http_server/restful_server/main/esp_rest_main.c @@ -6,6 +6,7 @@ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +#include "sdkconfig.h" #include "driver/sdmmc_host.h" #include "driver/gpio.h" #include "esp_vfs_semihost.h" @@ -17,8 +18,8 @@ #include "esp_event.h" #include "esp_log.h" #include "mdns.h" +#include "lwip/apps/netbiosns.h" #include "protocol_examples_common.h" -#include "sdkconfig.h" #define MDNS_INSTANCE "esp home web server" @@ -126,6 +127,8 @@ void app_main(void) tcpip_adapter_init(); ESP_ERROR_CHECK(esp_event_loop_create_default()); initialise_mdns(); + netbiosns_init(); + netbiosns_set_name(CONFIG_EXAMPLE_MDNS_HOST_NAME); ESP_ERROR_CHECK(example_connect()); ESP_ERROR_CHECK(init_fs()); From 555cc11a257191fde826c752b18f9f1398e20092 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 23 Aug 2019 16:36:42 +0200 Subject: [PATCH 10/14] tcp_transport: fix possible buffer overflow in ws transport connect closes IDF-692 --- components/tcp_transport/transport_ws.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/components/tcp_transport/transport_ws.c b/components/tcp_transport/transport_ws.c index c8f3da31c..08c669d08 100644 --- a/components/tcp_transport/transport_ws.c +++ b/components/tcp_transport/transport_ws.c @@ -103,14 +103,26 @@ static int ws_connect(esp_transport_handle_t t, const char *host, int port, int ws->path, host, port, client_key); - if (ws->sub_protocol) { - len += snprintf(ws->buffer + len, DEFAULT_WS_BUFFER - len, "Sec-WebSocket-Protocol: %s\r\n", ws->sub_protocol); - } - len += snprintf(ws->buffer + len, DEFAULT_WS_BUFFER - len, "\r\n"); if (len <= 0 || len >= DEFAULT_WS_BUFFER) { ESP_LOGE(TAG, "Error in request generation, %d", len); return -1; } + if (ws->sub_protocol) { + int r = snprintf(ws->buffer + len, DEFAULT_WS_BUFFER - len, "Sec-WebSocket-Protocol: %s\r\n", ws->sub_protocol); + len += r; + if (r <= 0 || len >= DEFAULT_WS_BUFFER) { + ESP_LOGE(TAG, "Error in request generation" + "(snprintf of subprotocol returned %d, desired request len: %d, buffer size: %d", r, len, DEFAULT_WS_BUFFER); + return -1; + } + } + int r = snprintf(ws->buffer + len, DEFAULT_WS_BUFFER - len, "\r\n"); + len += r; + if (r <= 0 || len >= DEFAULT_WS_BUFFER) { + ESP_LOGE(TAG, "Error in request generation" + "(snprintf of header terminal returned %d, desired request len: %d, buffer size: %d", r, len, DEFAULT_WS_BUFFER); + return -1; + } ESP_LOGD(TAG, "Write upgrate request\r\n%s", ws->buffer); if (esp_transport_write(ws->parent, ws->buffer, len, timeout_ms) <= 0) { ESP_LOGE(TAG, "Error write Upgrade header %s", ws->buffer); From abf9345b85559f4a922e8387f48336fb09994041 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 16 Sep 2019 15:22:29 +0200 Subject: [PATCH 11/14] ws_client: fix for not sending ping responses, updated to pass events also for PING and PONG messages, added interfaces to send both binary and text data closes https://github.com/espressif/esp-idf/issues/3982 --- .../esp_websocket_client.c | 36 ++++++++++++++--- .../include/esp_websocket_client.h | 32 ++++++++++++++- .../tcp_transport/include/esp_transport_ws.h | 39 +++++++++++++++++++ components/tcp_transport/transport_ws.c | 32 +++++++++++++-- .../websocket/main/websocket_example.c | 1 + 5 files changed, 129 insertions(+), 11 deletions(-) diff --git a/components/esp_websocket_client/esp_websocket_client.c b/components/esp_websocket_client/esp_websocket_client.c index 413742d4a..fcfc86cec 100644 --- a/components/esp_websocket_client/esp_websocket_client.c +++ b/components/esp_websocket_client/esp_websocket_client.c @@ -90,6 +90,7 @@ struct esp_websocket_client { char *rx_buffer; char *tx_buffer; int buffer_size; + ws_transport_opcodes_t last_opcode; }; static uint64_t _tick_get_ms(void) @@ -106,6 +107,7 @@ static esp_err_t esp_websocket_client_dispatch_event(esp_websocket_client_handle esp_websocket_event_data_t event_data; event_data.data_ptr = data; event_data.data_len = data_len; + event_data.op_code = client->last_opcode; if ((err = esp_event_post_to(client->event_handle, WEBSOCKET_EVENTS, event, @@ -474,7 +476,7 @@ static void esp_websocket_client_task(void *pv) if (_tick_get_ms() - client->ping_tick_ms > WEBSOCKET_PING_TIMEOUT_MS) { client->ping_tick_ms = _tick_get_ms(); // Send PING - esp_transport_write(client->transport, NULL, 0, client->config->network_timeout_ms); + esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PING, NULL, 0, client->config->network_timeout_ms); } if (read_select == 0) { ESP_LOGD(TAG, "Timeout..."); @@ -488,8 +490,15 @@ static void esp_websocket_client_task(void *pv) esp_websocket_client_abort_connection(client); break; } - if (rlen > 0) { + if (rlen >= 0) { + client->last_opcode = esp_transport_ws_get_read_opcode(client->transport); esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DATA, client->rx_buffer, rlen); + // if a PING message received -> send out the PONG + if (client->last_opcode == WS_TRANSPORT_OPCODES_PING) { + const char *data = (rlen == 0) ? NULL : client->rx_buffer; + esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PONG, data, rlen, + client->config->network_timeout_ms); + } } break; case WEBSOCKET_STATE_WAIT_TIMEOUT: @@ -546,7 +555,24 @@ esp_err_t esp_websocket_client_stop(esp_websocket_client_handle_t client) return ESP_OK; } +static int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t client, ws_transport_opcodes_t opcode, const char *data, int len, TickType_t timeout); + +int esp_websocket_client_send_text(esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout) +{ + return esp_websocket_client_send_with_opcode(client, WS_TRANSPORT_OPCODES_TEXT, data, len, timeout); +} + int esp_websocket_client_send(esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout) +{ + return esp_websocket_client_send_with_opcode(client, WS_TRANSPORT_OPCODES_BINARY, data, len, timeout); +} + +int esp_websocket_client_send_bin(esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout) +{ + return esp_websocket_client_send_with_opcode(client, WS_TRANSPORT_OPCODES_BINARY, data, len, timeout); +} + +static int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t client, ws_transport_opcodes_t opcode, const char *data, int len, TickType_t timeout) { int need_write = len; int wlen = 0, widx = 0; @@ -575,10 +601,8 @@ int esp_websocket_client_send(esp_websocket_client_handle_t client, const char * need_write = client->buffer_size; } memcpy(client->tx_buffer, data + widx, need_write); - wlen = esp_transport_write(client->transport, - (char *)client->tx_buffer, - need_write, - client->config->network_timeout_ms); + // send with ws specific way and specific opcode + wlen = esp_transport_ws_send_raw(client->transport, opcode, (char *)client->tx_buffer, need_write, timeout); if (wlen <= 0) { xSemaphoreGive(client->lock); return wlen; diff --git a/components/esp_websocket_client/include/esp_websocket_client.h b/components/esp_websocket_client/include/esp_websocket_client.h index 4f1e0a3fc..444343c82 100644 --- a/components/esp_websocket_client/include/esp_websocket_client.h +++ b/components/esp_websocket_client/include/esp_websocket_client.h @@ -49,6 +49,7 @@ typedef enum { typedef struct { const char *data_ptr; /*!< Data pointer */ int data_len; /*!< Data length */ + uint8_t op_code; /*!< Received opcode */ } esp_websocket_event_data_t; /** @@ -72,7 +73,6 @@ typedef struct { } esp_websocket_event_t; typedef esp_websocket_event_t* esp_websocket_event_handle_t; -typedef esp_err_t (* websocket_event_callback_t)(esp_websocket_event_handle_t event); /** * @brief Websocket client setup configuration @@ -150,7 +150,7 @@ esp_err_t esp_websocket_client_stop(esp_websocket_client_handle_t client); esp_err_t esp_websocket_client_destroy(esp_websocket_client_handle_t client); /** - * @brief Write data to the WebSocket connection + * @brief Generic write data to the WebSocket connection; defaults to binary send * * @param[in] client The client * @param[in] data The data @@ -163,6 +163,34 @@ esp_err_t esp_websocket_client_destroy(esp_websocket_client_handle_t client); */ int esp_websocket_client_send(esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout); +/** + * @brief Write binary data to the WebSocket connection (data send with WS OPCODE=02, i.e. binary) + * + * @param[in] client The client + * @param[in] data The data + * @param[in] len The length + * @param[in] timeout Write data timeout + * + * @return + * - Number of data was sent + * - (-1) if any errors + */ +int esp_websocket_client_send_bin(esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout); + +/** + * @brief Write textual data to the WebSocket connection (data send with WS OPCODE=01, i.e. text) + * + * @param[in] client The client + * @param[in] data The data + * @param[in] len The length + * @param[in] timeout Write data timeout + * + * @return + * - Number of data was sent + * - (-1) if any errors + */ +int esp_websocket_client_send_text(esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout); + /** * @brief Check the WebSocket connection status * diff --git a/components/tcp_transport/include/esp_transport_ws.h b/components/tcp_transport/include/esp_transport_ws.h index bb4f0bc01..0876480a4 100644 --- a/components/tcp_transport/include/esp_transport_ws.h +++ b/components/tcp_transport/include/esp_transport_ws.h @@ -13,6 +13,13 @@ extern "C" { #endif +typedef enum ws_transport_opcodes { + WS_TRANSPORT_OPCODES_TEXT = 0x01, + WS_TRANSPORT_OPCODES_BINARY = 0x02, + WS_TRANSPORT_OPCODES_CLOSE = 0x08, + WS_TRANSPORT_OPCODES_PING = 0x09, + WS_TRANSPORT_OPCODES_PONG = 0x0a, +} ws_transport_opcodes_t; /** * @brief Create web socket transport @@ -43,6 +50,38 @@ void esp_transport_ws_set_path(esp_transport_handle_t t, const char *path); */ esp_err_t esp_transport_ws_set_subprotocol(esp_transport_handle_t t, const char *sub_protocol); +/** + * @brief Sends websocket raw message with custom opcode and payload + * + * Note that generic esp_transport_write for ws handle sends + * binary massages by default if size is > 0 and + * ping message if message size is set to 0. + * This API is provided to support explicit messages with arbitrary opcode, + * should it be PING, PONG or TEXT message with arbitrary data. + * + * @param[in] t Websocket transport handle + * @param[in] opcode ws operation code + * @param[in] buffer The buffer + * @param[in] len The length + * @param[in] timeout_ms The timeout milliseconds + * + * @return + * - Number of bytes was written + * - (-1) if there are any errors, should check errno + */ +int esp_transport_ws_send_raw(esp_transport_handle_t t, ws_transport_opcodes_t opcode, const char *b, int len, int timeout_ms); + +/** + * @brief Returns websocket op-code for last received data + * + * @param t websocket transport handle + * + * @return + * - Received op-code as enum + */ +ws_transport_opcodes_t esp_transport_ws_get_read_opcode(esp_transport_handle_t t); + + #ifdef __cplusplus } #endif diff --git a/components/tcp_transport/transport_ws.c b/components/tcp_transport/transport_ws.c index c8f3da31c..e444c30d6 100644 --- a/components/tcp_transport/transport_ws.c +++ b/components/tcp_transport/transport_ws.c @@ -31,9 +31,15 @@ typedef struct { char *path; char *buffer; char *sub_protocol; + uint8_t read_opcode; esp_transport_handle_t parent; } transport_ws_t; +static inline uint8_t ws_get_bin_opcode(ws_transport_opcodes_t opcode) +{ + return (uint8_t)opcode; +} + static esp_transport_handle_t ws_get_payload_transport_handle(esp_transport_handle_t t) { transport_ws_t *ws = esp_transport_get_context_data(t); @@ -219,9 +225,23 @@ static int _ws_write(esp_transport_handle_t t, int opcode, int mask_flag, const return ret; } +int esp_transport_ws_send_raw(esp_transport_handle_t t, ws_transport_opcodes_t opcode, const char *b, int len, int timeout_ms) +{ + uint8_t op_code = ws_get_bin_opcode(opcode); + if (t == NULL) { + ESP_LOGE(TAG, "Transport must be a valid ws handle"); + return ESP_ERR_INVALID_ARG; + } + ESP_LOGD(TAG, "Sending raw ws message with opcode %d", op_code); + return _ws_write(t, op_code | WS_FIN, WS_MASK, b, len, timeout_ms); +} + static int ws_write(esp_transport_handle_t t, const char *b, int len, int timeout_ms) { if (len == 0) { + // Default transport write of zero length in ws layer sends out a ping message. + // This behaviour could however be altered in IDF 5.0, since a separate API for sending + // messages with user defined opcodes has been introduced. ESP_LOGD(TAG, "Write PING message"); return _ws_write(t, WS_OPCODE_PING | WS_FIN, WS_MASK, NULL, 0, timeout_ms); } @@ -233,7 +253,7 @@ static int ws_read(esp_transport_handle_t t, char *buffer, int len, int timeout_ transport_ws_t *ws = esp_transport_get_context_data(t); int payload_len; char ws_header[MAX_WEBSOCKET_HEADER_SIZE]; - char *data_ptr = ws_header, opcode, mask, *mask_key = NULL; + char *data_ptr = ws_header, mask, *mask_key = NULL; int rlen; int poll_read; if ((poll_read = esp_transport_poll_read(ws->parent, timeout_ms)) <= 0) { @@ -246,12 +266,12 @@ static int ws_read(esp_transport_handle_t t, char *buffer, int len, int timeout_ ESP_LOGE(TAG, "Error read data"); return rlen; } - opcode = (*data_ptr & 0x0F); + ws->read_opcode = (*data_ptr & 0x0F); data_ptr ++; mask = ((*data_ptr >> 7) & 0x01); payload_len = (*data_ptr & 0x7F); data_ptr++; - ESP_LOGD(TAG, "Opcode: %d, mask: %d, len: %d\r\n", opcode, mask, payload_len); + ESP_LOGD(TAG, "Opcode: %d, mask: %d, len: %d\r\n", ws->read_opcode, mask, payload_len); if (payload_len == 126) { // headerLen += 2; if ((rlen = esp_transport_read(ws->parent, data_ptr, header, timeout_ms)) <= 0) { @@ -376,3 +396,9 @@ esp_err_t esp_transport_ws_set_subprotocol(esp_transport_handle_t t, const char } return ESP_OK; } + +ws_transport_opcodes_t esp_transport_ws_get_read_opcode(esp_transport_handle_t t) +{ + transport_ws_t *ws = esp_transport_get_context_data(t); + return ws->read_opcode; +} diff --git a/examples/protocols/websocket/main/websocket_example.c b/examples/protocols/websocket/main/websocket_example.c index 901d2ad92..f82ac9494 100644 --- a/examples/protocols/websocket/main/websocket_example.c +++ b/examples/protocols/websocket/main/websocket_example.c @@ -44,6 +44,7 @@ static void websocket_event_handler(void *handler_args, esp_event_base_t base, i case WEBSOCKET_EVENT_DATA: ESP_LOGI(TAG, "WEBSOCKET_EVENT_DATA"); + ESP_LOGI(TAG, "Received opcode=%d", data->op_code); ESP_LOGW(TAG, "Received=%.*s\r\n", data->data_len, (char*)data->data_ptr); break; case WEBSOCKET_EVENT_ERROR: From c70d234ee6c1f1708251bdacd5fc1ba211da05fa Mon Sep 17 00:00:00 2001 From: Natasha Date: Tue, 15 Oct 2019 17:15:15 +0800 Subject: [PATCH 12/14] Update board getting started guides to make cmake default --- .../hw-reference/get-started-devkitc-v2.rst | 31 +-- .../hw-reference/get-started-devkitc.rst | 39 ++-- .../hw-reference/get-started-ethernet-kit.rst | 91 ++++---- .../hw-reference/get-started-pico-kit-v3.rst | 43 ++-- .../hw-reference/get-started-pico-kit.rst | 42 ++-- .../get-started-wrover-kit-v2.rst | 86 +++---- .../get-started-wrover-kit-v3.rst | 92 ++++---- .../hw-reference/get-started-wrover-kit.rst | 218 +++++++++++------- 8 files changed, 359 insertions(+), 283 deletions(-) diff --git a/docs/zh_CN/hw-reference/get-started-devkitc-v2.rst b/docs/zh_CN/hw-reference/get-started-devkitc-v2.rst index 2cd107586..298a2245d 100644 --- a/docs/zh_CN/hw-reference/get-started-devkitc-v2.rst +++ b/docs/zh_CN/hw-reference/get-started-devkitc-v2.rst @@ -38,19 +38,22 @@ ESP32-DevKitC V2 开发板的主要组件、接口及控制方式见下。 ESP32-DevKitC V2 开发板 -+----------------+--------------------------------------------------------------------------------------------------------------------------+ -| 主要组件 | 基本介绍 | -+----------------+--------------------------------------------------------------------------------------------------------------------------+ -| ESP32-WROOM-32 | 基于 ESP32 的模组。更多详情,请见 `《ESP32-WROOM-32 技术规格书》`_。 | -+----------------+--------------------------------------------------------------------------------------------------------------------------+ -| EN | 复位按键。 | -+----------------+--------------------------------------------------------------------------------------------------------------------------+ -| Boot | 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 | -+----------------+--------------------------------------------------------------------------------------------------------------------------+ -| Micro USB 端口 | USB 接口。可用作电路板的供电电源,或连接 PC 和 ESP32-WROOM-32 模组的通信接口。 | -+----------------+--------------------------------------------------------------------------------------------------------------------------+ -| I/O | 板上模组的绝大部分管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 | -+----------------+--------------------------------------------------------------------------------------------------------------------------+ +.. list-table:: + :widths: 25 75 + :header-rows: 1 + + * - 主要组件 + - 基本介绍 + * - ESP32-WROOM-32 + - 基于 ESP32 的模组。更多详情,请见 `《ESP32-WROOM-32 技术规格书》`_。 + * - EN + - 复位按键。 + * - Boot + - 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 + * - Micro USB 端口 + - USB 接口。可用作电路板的供电电源,或连接 PC 和 ESP32-WROOM-32 模组的通信接口。 + * - I/O + - 板上模组的绝大部分管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 电源选项 -------- @@ -71,7 +74,7 @@ ESP32-DevKitC V2 开发板 ESP32-DevKitC V2 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 相关文档 diff --git a/docs/zh_CN/hw-reference/get-started-devkitc.rst b/docs/zh_CN/hw-reference/get-started-devkitc.rst index f75b5f80a..107c55d90 100644 --- a/docs/zh_CN/hw-reference/get-started-devkitc.rst +++ b/docs/zh_CN/hw-reference/get-started-devkitc.rst @@ -56,23 +56,26 @@ ESP32-DevKitC V4 开发板的主要组件、接口及控制方式见下。 ESP32-DevKitC V4(板载 ESP32-WROOM-32) -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| 主要组件 | 基本介绍 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| ESP32-WROOM-32 | 基于 ESP32 的模组。更多详情,请见 `《ESP32-WROOM-32 技术规格书》`_。 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| EN | 复位按键。 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| Boot | 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| USB-to-UART 桥接器 | 单芯片 USB-UART 桥接器,可提供高达 3 Mbps 的传输速率。 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| Micro USB 端口 | USB 接口。可用作电路板的供电电源,或连接 PC 和 ESP32-WROOM-32 模组的通信接口。 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| 5V Power On LED | 开发板通电后(USB 或外部 5 V),该指示灯将亮起。更多信息,请见 `相关文档`_ 中的原理图。 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| I/O | 板上模组的绝大部分管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ +.. list-table:: + :widths: 25 75 + :header-rows: 1 + + * - 主要组件 + - 基本介绍 + * - ESP32-WROOM-32 + - 基于 ESP32 的模组。更多详情,请见 `《ESP32-WROOM-32 技术规格书》`_。 + * - EN + - 复位按键。 + * - Boot + - 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 + * - USB-to-UART 桥接器 | 单芯片 USB-UART 桥接器,可提供高达 3 Mbps 的传输速率。 + - Micro USB 端口 + * - USB 接口。 + - 可用作电路板的供电电源,或连接 PC 和 ESP32-WROOM-32 模组的通信接口。 + * - 5V Power On LED + - 开发板通电后(USB 或外部 5 V),该指示灯将亮起。更多信息,请见 `相关文档`_ 中的原理图。 + * - I/O + - 板上模组的绝大部分管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 .. note:: @@ -121,7 +124,7 @@ C15(黄色)在 ESP32-DevKitC V4 开发板上的位置 ESP32-DevKitC V4 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 开发板尺寸 ------------- diff --git a/docs/zh_CN/hw-reference/get-started-ethernet-kit.rst b/docs/zh_CN/hw-reference/get-started-ethernet-kit.rst index f11f7862d..bbaaa072b 100644 --- a/docs/zh_CN/hw-reference/get-started-ethernet-kit.rst +++ b/docs/zh_CN/hw-reference/get-started-ethernet-kit.rst @@ -69,49 +69,52 @@ ESP32-Ethernet-Kit 开发板的主要组件、接口及控制方式见下。 下表将从图片右上角开始,以顺时针顺序介绍图中的主要组件。 -======================= ================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================== -主要组件 基本介绍 -======================= ================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================== -ESP32-WROVER-B 模组 这款 ESP32 模组内置 64-Mbit PSRAM,可提供灵活的额外存储空间和数据处理能力。 +.. list-table:: + :widths: 25 75 + :header-rows: 1 -GPIO Header 2 由 5 个未引出通孔组成,可连接至 ESP32 的部分 GPIO。具体介绍,请见 `GPIO Header 2`_。 - -流控 跳线帽,可接入开发板信号。具体介绍,请见 `流控`_。 - -功能选择开关 DIP 开关,可配置 ESP32 部分 GPIO 的功能。具体介绍,请见 `功能选择开关`_。 - -Tx/Rx LED 2 个 LED,可显示 UART 传输的状态。 - -GPIO Header 3 可连接至 ESP32 的部分 GPIO,根据 `功能选择开关`_ 的位置有不同功能。 - -FT2232 FT2232 多协议 USB 转串口桥接器。开发人员可通过 USB 接口对 FT2232 芯片进行控制和编程,与 ESP32 建立连接。FT2232 芯片可在通道 A 提供 USB-to-JTAG 接口功能,并在通道 B 提供 USB-to-Serial 接口功能,便利开发人员的应用开发与调试。见 `ESP32-Ethernet-Kit V1.0 以太网子板(A 板)原理图`_。 - -USB 端口 USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 - -电源开关 电源开关。拨向 **Boot** 按键一侧,开发板上电;拨离 **Boot** 按键一侧,开发板掉电。 - -5V Input 5V 电源接口建议仅在开发板自动运行(未连接 PC)时使用。仅用于全负荷工作下的后备电源。 - -5V Power On LED 当开发板通电后(USB 或外部 5V 供电),该红色指示灯将亮起。 - -DC/DC 转换器 直流 5 V 转 3.3 V,输出电流高达 2 A。 - -B 板连接器 1 对 2 针排针,用于连接 :ref:`PoE 子板(B 板)`。 - -IP101GRI (PHY) 物理层 (PHY) 单端口10/100 快速以太网收发器 `IP101GRI`_ ,允许开发人员实现与以太网线缆的物理层连接。PHY 与 ESP32 通过简化媒体独立接口 (RMII) 实现连接。RMII 是 `媒体独立接口 (MII)`_ 的简化版本。PHY 可在 10/100 Mbps 速率下支持 IEEE 802.3 / 802.3u 标准。 - -RJ45 端口 以太网数据传输断口。 - -网络变压器 网络变压器属于以太网物理层的一部分,可保护电路免受故障和电压瞬变影响,包括防止收发器芯片和线缆之间产生共模信号。同时它也可以在收发器与以太网设备之间提供电流隔绝。 - -Link/Activity LED 2 个 LED(绿色和红色),可分别显示 PHY 处于 "Link" 状态或 "Activity" 状态。 - -BOOT 按键 下载按键。按下 **BOOT** 键并保持,同时按一下 **EN** 键(此时不要松开 **BOOT** 键)进入“固件下载”模式,通过串口下载固件。 - -CH_PU 按键 复位按键。 - -GPIO Header 1 由 6 个未引出通孔组成,可连接至 ESP32 的备用 GPIO。具体介绍,请见 `GPIO Header 1`_。 -======================= ================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================== + * - 主要组件 + - 基本介绍 + * - ESP32-WROVER-B 模组 + - 这款 ESP32 模组内置 64-Mbit PSRAM,可提供灵活的额外存储空间和数据处理能力。 + * - GPIO Header 2 + - 由 5 个未引出通孔组成,可连接至 ESP32 的部分 GPIO。具体介绍,请见 `GPIO Header 2`_。 + * - 流控 + - 跳线帽,可接入开发板信号。具体介绍,请见 `流控`_。 + * - 功能选择开关 + - DIP 开关,可配置 ESP32 部分 GPIO 的功能。具体介绍,请见 `功能选择开关`_。 + * - Tx/Rx LED + - 2 个 LED,可显示 UART 传输的状态。 + * - GPIO Header 3 + - 可连接至 ESP32 的部分 GPIO,根据 `功能选择开关`_ 的位置有不同功能。 + * - FT2232 + - FT2232 多协议 USB 转串口桥接器。开发人员可通过 USB 接口对 FT2232 芯片进行控制和编程,与 ESP32 建立连接。FT2232 芯片可在通道 A 提供 USB-to-JTAG 接口功能,并在通道 B 提供 USB-to-Serial 接口功能,便利开发人员的应用开发与调试。见 `ESP32-Ethernet-Kit V1.0 以太网子板(A 板)原理图`_。 + * - USB 端口 + - USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 + * - 电源开关 + - 电源开关。拨向 **Boot** 按键一侧,开发板上电;拨离 **Boot** 按键一侧,开发板掉电。 + * - 5V Input + - 5V 电源接口建议仅在开发板自动运行(未连接 PC)时使用。仅用于全负荷工作下的后备电源。 + * - 5V Power On LED + - 当开发板通电后(USB 或外部 5V 供电),该红色指示灯将亮起。 + * - DC/DC 转换器 + - 直流 5 V 转 3.3 V,输出电流高达 2 A。 + * - B 板连接器 + - 1 对 2 针排针,用于连接 :ref:`PoE 子板(B 板)`。 + * - IP101GRI (PHY) + - 物理层 (PHY) 单端口10/100 快速以太网收发器 `IP101GRI`_ ,允许开发人员实现与以太网线缆的物理层连接。PHY 与 ESP32 通过简化媒体独立接口 (RMII) 实现连接。RMII 是 `媒体独立接口 (MII)`_ 的简化版本。PHY 可在 10/100 Mbps 速率下支持 IEEE 802.3 / 802.3u 标准。 + * - RJ45 端口 + - 以太网数据传输断口。 + * - 网络变压器 + - 网络变压器属于以太网物理层的一部分,可保护电路免受故障和电压瞬变影响,包括防止收发器芯片和线缆之间产生共模信号。同时它也可以在收发器与以太网设备之间提供电流隔绝。 + * - Link/Activity LED + - 2 个 LED(绿色和红色),可分别显示 PHY 处于 "Link" 状态或 "Activity" 状态。 + * - BOOT 按键 + - 下载按键。按下 **BOOT** 键并保持,同时按一下 **EN** 键(此时不要松开 **BOOT** 键)进入“固件下载”模式,通过串口下载固件。 + * - CH_PU 按键 + - 复位按键。 + * - GPIO Header 1 + - 由 6 个未引出通孔组成,可连接至 ESP32 的备用 GPIO。具体介绍,请见 `GPIO Header 1`_。 .. _get-started-esp32-ethernet-kit-b-v1.0-layout: @@ -342,9 +345,7 @@ ESP32-Ethernet-Kit 上电前,请首先确认开发板完好无损。 正式开始开发 ^^^^^^^^^^^^^^^^^^ -现在,请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - -如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 +现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 请务必在进入下一步前,确保您已完成上述所有步骤。 diff --git a/docs/zh_CN/hw-reference/get-started-pico-kit-v3.rst b/docs/zh_CN/hw-reference/get-started-pico-kit-v3.rst index a63129f83..d662f1bd8 100644 --- a/docs/zh_CN/hw-reference/get-started-pico-kit-v3.rst +++ b/docs/zh_CN/hw-reference/get-started-pico-kit-v3.rst @@ -39,25 +39,28 @@ ESP32-PICO-KIT V3 开发板的主要组件、接口及控制方式见下。 ESP32-PICO-KIT 开发板的主要组件描述见下表。 -================== ============================================================================================================================================= -主要组件 基本介绍 -================== ============================================================================================================================================= -ESP32-PICO-D4 ESP32-PICO-KIT V3 开发板上焊接的标准 ESP32-PICO-D4 模组,集成了 ESP32 芯片的完整系统,仅需连接天线、LC 匹配电路、退耦电容和一个 EN 信号上拉电阻即可正常工作。 - -LDO 5V-to-3.3V 低压差稳压器。 - -USB-to-UART 桥接器 单芯片 USB-to-UART 桥接器,可提供高达 1 Mbps 的传输速率。 - -Micro USB 端口 USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 - -Power On LED 开发板通电后,该红色指示灯将亮起。 - -I/O ESP32-PICO-D4 的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 - -BOOT 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 - -EN 复位按键。 -================== ============================================================================================================================================= +.. list-table:: + :widths: 25 75 + :header-rows: 1 + + * - 主要组件 + - 基本介绍 + * - ESP32-PICO-D4 + - ESP32-PICO-KIT V3 开发板上焊接的标准 ESP32-PICO-D4 模组,集成了 ESP32 芯片的完整系统,仅需连接天线、LC 匹配电路、退耦电容和一个 EN 信号上拉电阻即可正常工作。 + * - LDO + - 5V-to-3.3V 低压差稳压器。 + * - USB-to-UART 桥接器 + - 单芯片 USB-to-UART 桥接器,可提供高达 1 Mbps 的传输速率。 + * - Micro USB 端口 + - USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 + * - Power On LED + - 开发板通电后,该红色指示灯将亮起。 + * - I/O + - ESP32-PICO-D4 的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 + * - BOOT + - 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 + * - EN + - 复位按键。 应用程序开发 @@ -65,7 +68,7 @@ EN 复位按键。 ESP32-PICO-KIT V3 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 相关文档 diff --git a/docs/zh_CN/hw-reference/get-started-pico-kit.rst b/docs/zh_CN/hw-reference/get-started-pico-kit.rst index 10299ea2d..a7c88cd39 100644 --- a/docs/zh_CN/hw-reference/get-started-pico-kit.rst +++ b/docs/zh_CN/hw-reference/get-started-pico-kit.rst @@ -67,26 +67,28 @@ ESP32-PICO-KIT 开发板的主要组件、接口及控制方式见下。 ESP32-PICO-KIT 开发板的主要组件描述见下表(从左上角起顺时针顺序)。 -================== ============================================================================================================================================= -主要组件 基本介绍 -================== ============================================================================================================================================= -ESP32-PICO-D4 ESP32-PICO-KIT 开发板上焊接的标准 ESP32-PICO-D4 模组,集成了 ESP32 芯片的完整系统,仅需连接天线、LC 匹配电路、退耦电容和一个 EN 信号上拉电阻即可正常工作。 - -LDO 5V-to-3.3V 低压差稳压器 - -USB-to-UART 桥接器 单芯片 USB-to-UART 桥接器。V4 版本搭载的 CP2102 可提供高达 1 Mbps 的传输速率,V4.1 版本搭载的 CP2102N 可提供高达 3 Mbps 的传输速率。 - -Micro USB 端口 USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 - -5V Power On LED 开发板通电后,该红色指示灯将亮起。更多信息,请见 `相关文档`_ 中的原理图。 - -I/O ESP32-PICO-D4 的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。更多详情,请见章节 `管脚说明`_。 - -BOOT 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 - -EN 复位按键。 -================== ============================================================================================================================================= +.. list-table:: + :widths: 25 75 + :header-rows: 1 + * - 主要组件 + - 基本介绍 + * - ESP32-PICO-D4 + - ESP32-PICO-KIT 开发板上焊接的标准 ESP32-PICO-D4 模组,集成了 ESP32 芯片的完整系统,仅需连接天线、LC 匹配电路、退耦电容和一个 EN 信号上拉电阻即可正常工作。 + * - LDO + - 5V-to-3.3V 低压差稳压器 + * - USB-to-UART 桥接器 + - 单芯片 USB-to-UART 桥接器。V4 版本搭载的 CP2102 可提供高达 1 Mbps 的传输速率,V4.1 版本搭载的 CP2102N 可提供高达 3 Mbps 的传输速率。 + * - Micro USB 端口 + - USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 + * - 5V Power On LED + - 开发板通电后,该红色指示灯将亮起。更多信息,请见 `相关文档`_ 中的原理图。 + * - I/O + - ESP32-PICO-D4 的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。更多详情,请见章节 `管脚说明`_。 + * - BOOT + - 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 + * - EN + - 复位按键。 电源选项 @@ -190,7 +192,7 @@ No. Name Type Function ESP32-PICO-KIT 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 开发板尺寸 diff --git a/docs/zh_CN/hw-reference/get-started-wrover-kit-v2.rst b/docs/zh_CN/hw-reference/get-started-wrover-kit-v2.rst index c93c6f783..b606dccf9 100644 --- a/docs/zh_CN/hw-reference/get-started-wrover-kit-v2.rst +++ b/docs/zh_CN/hw-reference/get-started-wrover-kit-v2.rst @@ -73,48 +73,50 @@ ESP-WROVER-KIT 开发板的主要组件、接口及控制方式见下。 下表从图片右上角开始,以顺时针顺序介绍了图 1 中的主要组件,然后以同样的顺序介绍了图 2 中的主要组件。 +.. list-table:: + :widths: 25 75 + :header-rows: 1 -==================== ====================================================================================================================================================================================================================================================================================================================================== -主要组件 基本介绍 -==================== ====================================================================================================================================================================================================================================================================================================================================== -32.768 kHz 外接 32.768 kHz 晶振,可提供 Deep-sleep 下使用的低功耗时钟。 - -ESP32 模组 可选贴 ESP32-WROOM-32 或 ESP32-WROVER。ESP32-WROVER 模组完整集成了 ESP32-WROOM-32 的所有功能,且内置 32-Mbit PSRAM,可提供灵活的额外存储空间和数据处理能力。 - -CTS/RTS 串口流控信号。管脚默认不连接至电路。为了使能该功能,必须用跳线帽短路掉 JP14 的相应管脚。 - -UART 串口。FT2232HL 和 ESP32 的串行 TX/RX 信号已引出至 JP11 的两端。默认情况下,这两路信号由跳线帽连接。如果要跳过 FT2232 使用 ESP32 模组串口,则可移除相关跳线帽,将模组连接至其他外部串口设备。 - -SPI 默认情况下,ESP32 使用 SPI 接口访问内置 flash 和 PSRAM。使用这些引脚连接 ESP32 和其他 SPI 设备。这种情况下,需增加额外的片选 (CS) 信号。注意,选贴 ESP32-WROVER 模组时,该接口的工作电压为 1.8 V;选贴 ESP32-WROOM-32 时,该接口的工作电压为 3.3V。 - -JTAG JTAG 接口。FT2232HL 和 ESP32 的 JTAG 信号已引出至 JP8 的两端。默认情况下,这两路信号不连接。如需使能 JTAG,请按照 `设置选项`_ 的介绍,连接跳线帽。 - -FT2232 FT2232 多协议 USB 转串口桥接器。开发人员可通过 USB 接口对 FT2232 芯片进行控制和编程,与 ESP32 建立连接。FT2232 具有 USB-to-UART 和 USB-to-JTAG 功能。 - -EN 复位按键。 - -Boot 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 - -USB USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 - -电源选择开关 ESP-WROVER-KIT 开发板可通过 USB 端口或 5V 输入接口供电。用户可使用跳线帽在两种供电模式中进行选择。更多详细信息,请见章节 `设置选项`_ 中有关 JP7 连接器的描述。 - -电源开关 拨向 **USB** 按键一侧,开发板上电;拨离 **USB** 按键一侧,开发板掉电。 - -5V Input 5V 电源接口建议仅在开发板自动运行(未连接 PC)时使用。仅用于全负荷工作下的后备电源。 - -LDO 5V-to-3.3V 低压差线型稳压器 NCP1117(1A)。NCP1117 最大电流输出为 1 A。板上 LDO 为固定输出电压,但用户也可以选用具有可变输出电压的 LDO。更多信息,请见 `ESP-WROVER-KIT V2 原理图`_。 - -摄像头 摄像头接口,支持标准 OV7670 摄像头模块。 - -RGB LED 红绿蓝发光二极管,可由 PWM(脉冲宽度调制)控制。 - -I/O 板上模组的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 - -MicroSD 卡槽 MicroSD 卡槽,可扩充存储空间:当 ESP32 进入下载模式时,GPIO2 不可处于高电平。然而,为了使能 MicroSD 卡功能,需为 GPIO2 增加一个上拉电阻。默认情况下,GPIO2 和上拉电阻 R153 处于断开状态。为了使能 MicroSD 卡,请按照 `设置选项`_ 章节的要求,连接 JP1 连接器。 - -LCD 显示屏 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`get-started-esp-wrover-kit-v2-board-back`。 -==================== ====================================================================================================================================================================================================================================================================================================================================== + * - 主要组件 + - 基本介绍 + * - 32.768 kHz + - 外接 32.768 kHz 晶振,可提供 Deep-sleep 下使用的低功耗时钟。 + * - ESP32 模组 + - 可选贴 ESP32-WROOM-32 或 ESP32-WROVER。ESP32-WROVER 模组完整集成了 ESP32-WROOM-32 的所有功能,且内置 32-Mbit PSRAM,可提供灵活的额外存储空间和数据处理能力。 + * - CTS/RTS + - 串口流控信号。管脚默认不连接至电路。为了使能该功能,必须用跳线帽短路掉 JP14 的相应管脚。 + * - UART + - 串口。FT2232HL 和 ESP32 的串行 TX/RX 信号已引出至 JP11 的两端。默认情况下,这两路信号由跳线帽连接。如果要跳过 FT2232 使用 ESP32 模组串口,则可移除相关跳线帽,将模组连接至其他外部串口设备。 + * - SPI + - 默认情况下,ESP32 使用 SPI 接口访问内置 flash 和 PSRAM。使用这些引脚连接 ESP32 和其他 SPI 设备。这种情况下,需增加额外的片选 (CS) 信号。注意,选贴 ESP32-WROVER 模组时,该接口的工作电压为 1.8 V;选贴 ESP32-WROOM-32 时,该接口的工作电压为 3.3V。 + * - JTAG + - JTAG 接口。FT2232HL 和 ESP32 的 JTAG 信号已引出至 JP8 的两端。默认情况下,这两路信号不连接。如需使能 JTAG,请按照 `设置选项`_ 的介绍,连接跳线帽。 + * - FT2232 + - FT2232 多协议 USB 转串口桥接器。开发人员可通过 USB 接口对 FT2232 芯片进行控制和编程,与 ESP32 建立连接。FT2232 具有 USB-to-UART 和 USB-to-JTAG 功能。 + * - EN + - 复位按键。 + * - Boot + - 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 + * - USB + - USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 + * - 电源选择开关 + - ESP-WROVER-KIT 开发板可通过 USB 端口或 5V 输入接口供电。用户可使用跳线帽在两种供电模式中进行选择。更多详细信息,请见章节 `设置选项`_ 中有关 JP7 连接器的描述。 + * - 电源开关 + - 拨向 **USB** 按键一侧,开发板上电;拨离 **USB** 按键一侧,开发板掉电。 + * - 5V Input + - 5V 电源接口建议仅在开发板自动运行(未连接 PC)时使用。仅用于全负荷工作下的后备电源。 + * - LDO + - 5V-to-3.3V 低压差线型稳压器 NCP1117(1A)。NCP1117 最大电流输出为 1 A。板上 LDO 为固定输出电压,但用户也可以选用具有可变输出电压的 LDO。更多信息,请见 `ESP-WROVER-KIT V2 原理图`_。 + * - 摄像头 + - 摄像头接口,支持标准 OV7670 摄像头模块。 + * - RGB LED + - 红绿蓝发光二极管,可由 PWM(脉冲宽度调制)控制。 + * - I/O + - 板上模组的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 + * - MicroSD 卡槽 + - MicroSD 卡槽,可扩充存储空间:当 ESP32 进入下载模式时,GPIO2 不可处于高电平。然而,为了使能 MicroSD 卡功能,需为 GPIO2 增加一个上拉电阻。默认情况下,GPIO2 和上拉电阻 R153 处于断开状态。为了使能 MicroSD 卡,请按照 `设置选项`_ 章节的要求,连接 JP1 连接器。 + * - LCD 显示屏 + - 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`get-started-esp-wrover-kit-v2-board-back`。 .. _get-started-esp-wrover-kit-v2-setup-options: @@ -167,7 +169,7 @@ USB 供电 使能 UART 通信 正式开始开发 ^^^^^^^^^^^^^^^^^^ -请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 相关文档 diff --git a/docs/zh_CN/hw-reference/get-started-wrover-kit-v3.rst b/docs/zh_CN/hw-reference/get-started-wrover-kit-v3.rst index 0bf134939..ab8e8f753 100644 --- a/docs/zh_CN/hw-reference/get-started-wrover-kit-v3.rst +++ b/docs/zh_CN/hw-reference/get-started-wrover-kit-v3.rst @@ -73,51 +73,52 @@ ESP-WROVER-KIT 开发板的主要组件、接口及控制方式见下。 下表从图片右上角开始,以顺时针顺序介绍了图 1 中的主要组件,然后以同样的顺序介绍图 2 中的主要组件。 +.. list-table:: + :widths: 25 75 + :header-rows: 1 -==================== ====================================================================================================================================================================================================================================================================================================================================== -主要组件 基本介绍 -==================== ====================================================================================================================================================================================================================================================================================================================================== -32.768 kHz 外接 32.768 kHz 晶振,可提供 Deep-sleep 下使用的低功耗时钟。 - -0 欧电阻 ESP-WROVER-KIT 开发板设计了一个 0 欧电阻,可在测量 ESP32 系列模组在不同功耗模式下的电流时,直接移除或替换为分流器。 - -ESP32 模组 可选贴 ESP32-WROOM-32 或 ESP32-WROVER。ESP32-WROVER 模组完整集成了 ESP32-WROOM-32 的所有功能,且内置 32-Mbit PSRAM,可提供灵活的额外存储空间和数据处理能力。 - -FT2232 FT2232 多协议 USB 转串口桥接器。开发人员可通过 USB 接口对 FT2232 芯片进行控制和编程,与 ESP32 建立连接。FT2232 芯片可在通道 A 提供 USB-to-JTAG 接口功能,并在通道 B 提供 USB-to-Serial 接口功能,便利开发人员的应用开发与调试。见 `ESP-WROVER-KIT V3 原理图`_。 - -UART 串口。FT2232HL 和 ESP32 的串行 TX/RX 信号已引出至 JP11 的两端。默认情况下,这两路信号由跳线帽连接。如果要跳过 FT2232 使用 ESP32 模组串口,则可移除相关跳线帽,将模组连接至其他外部串口设备。 - -SPI 默认情况下,ESP32 使用 SPI 接口访问内置 flash 和 PSRAM。使用这些引脚连接 ESP32 和其他 SPI 设备。这种情况下,需增加额外的片选 (CS) 信号。注意,选贴 ESP32-WROVER 模组时,该接口的工作电压为 1.8 V;选贴 ESP32-WROOM-32 时,该接口的工作电压为 3.3V。 - -CTS/RTS 串口流控信号。管脚默认不连接至电路。为了使能该功能,必须用跳线帽短路掉 JP14 的相应管脚。 - -JTAG JTAG 接口。FT2232HL 和 ESP32 的 JTAG 信号已引出至 JP8 的两端。默认情况下,这两路信号不连接。如需使能 JTAG,请按照 `设置选项`_ 的介绍,连接跳线帽。 - -EN 复位按键。 - -Boot 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 - -USB USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 - -电源开关 拨向 **USB** 按键一侧,开发板上电;拨离 **USB** 按键一侧,开发板掉电。 - -电源选择开关 ESP-WROVER-KIT 开发板可通过 USB 端口或 5V 输入接口供电。用户可使用跳线帽在两种供电模式中进行选择。更多详细信息,请见章节 `设置选项`_ 中有关 JP7 连接器的描述。 - -5V Input 5V 电源接口建议仅在开发板自动运行(未连接 PC)时使用。仅用于全负荷工作下的后备电源。 - -LDO 5V-to-3.3V 低压差线型稳压器 NCP1117(1A)。NCP1117 最大电流输出为 1 A。板上 LDO 为固定输出电压,但用户也可以选用具有可变输出电压的 LDO。更多信息,请见 `ESP-WROVER-KIT V3 原理图`_。 - -摄像头 摄像头接口,支持标准 OV7670 摄像头模块。 - -RGB LED 红绿蓝发光二极管,可由 PWM(脉冲宽度调制)控制。 - -I/O 板上模组的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 - -MicroSD 卡槽 适用于需要扩充数据存储空间或进行备份的应用开发场景。 - -LCD 显示屏 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`get-started-esp-wrover-kit-v3-board-back`。 -==================== ====================================================================================================================================================================================================================================================================================================================================== - + * - 主要组件 + - 基本介绍 + * - 32.768 kHz + - 外接 32.768 kHz 晶振,可提供 Deep-sleep 下使用的低功耗时钟。 + * - 0 欧电阻 + - ESP-WROVER-KIT 开发板设计了一个 0 欧电阻,可在测量 ESP32 系列模组在不同功耗模式下的电流时,直接移除或替换为分流器。 + * - ESP32 模组 + - 可选贴 ESP32-WROOM-32 或 ESP32-WROVER。ESP32-WROVER 模组完整集成了 ESP32-WROOM-32 的所有功能,且内置 32-Mbit PSRAM,可提供灵活的额外存储空间和数据处理能力。 + * - FT2232 + - FT2232 多协议 USB 转串口桥接器。开发人员可通过 USB 接口对 FT2232 芯片进行控制和编程,与 ESP32 建立连接。FT2232 芯片可在通道 A 提供 USB-to-JTAG 接口功能,并在通道 B 提供 USB-to-Serial 接口功能,便利开发人员的应用开发与调试。见 `ESP-WROVER-KIT V3 原理图`_。 + * - UART + - 串口。FT2232HL 和 ESP32 的串行 TX/RX 信号已引出至 JP11 的两端。默认情况下,这两路信号由跳线帽连接。如果要跳过 FT2232 使用 ESP32 模组串口,则可移除相关跳线帽,将模组连接至其他外部串口设备。 + * - SPI + - 默认情况下,ESP32 使用 SPI 接口访问内置 flash 和 PSRAM。使用这些引脚连接 ESP32 和其他 SPI 设备。这种情况下,需增加额外的片选 (CS) 信号。注意,选贴 ESP32-WROVER 模组时,该接口的工作电压为 1.8 V;选贴 ESP32-WROOM-32 时,该接口的工作电压为 3.3V。 + * - CTS/RTS + - 串口流控信号。管脚默认不连接至电路。为了使能该功能,必须用跳线帽短路掉 JP14 的相应管脚。 + * - JTAG + - JTAG 接口。FT2232HL 和 ESP32 的 JTAG 信号已引出至 JP8 的两端。默认情况下,这两路信号不连接。如需使能 JTAG,请按照 `设置选项`_ 的介绍,连接跳线帽。 + * - EN + - 复位按键。 + * - Boot + - 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 + * - USB + - USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 + * - 电源开关 + - 拨向 **USB** 按键一侧,开发板上电;拨离 **USB** 按键一侧,开发板掉电。 + * - 电源选择开关 + - ESP-WROVER-KIT 开发板可通过 USB 端口或 5V 输入接口供电。用户可使用跳线帽在两种供电模式中进行选择。更多详细信息,请见章节 `设置选项`_ 中有关 JP7 连接器的描述。 + * - 5V Input + - 5V 电源接口建议仅在开发板自动运行(未连接 PC)时使用。仅用于全负荷工作下的后备电源。 + * - LDO + - 5V-to-3.3V 低压差线型稳压器 NCP1117(1A)。NCP1117 最大电流输出为 1 A。板上 LDO 为固定输出电压,但用户也可以选用具有可变输出电压的 LDO。更多信息,请见 `ESP-WROVER-KIT V3 原理图`_。 + * - 摄像头 + - 摄像头接口,支持标准 OV7670 摄像头模块。 + * - RGB LED + - 红绿蓝发光二极管,可由 PWM(脉冲宽度调制)控制。 + * - I/O + - 板上模组的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 + * - MicroSD 卡槽 + - 适用于需要扩充数据存储空间或进行备份的应用开发场景。 + * - LCD 显示屏 + - 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`get-started-esp-wrover-kit-v3-board-back`。 .. _get-started-esp-wrover-kit-v3-setup-options: @@ -351,8 +352,7 @@ USB 供电 使能 UART 通信 正式开始开发 ^^^^^^^^^^^^^^^^^^ -请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - +现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 相关文档 ----------------- diff --git a/docs/zh_CN/hw-reference/get-started-wrover-kit.rst b/docs/zh_CN/hw-reference/get-started-wrover-kit.rst index 98ffae468..2acde8430 100644 --- a/docs/zh_CN/hw-reference/get-started-wrover-kit.rst +++ b/docs/zh_CN/hw-reference/get-started-wrover-kit.rst @@ -9,8 +9,8 @@ ESP-WROVER-KIT V4.1 入门指南 ------------- * :ref:`ESP-WROVER-KIT V4.1 开发板 ` -* USB 数据线(A 转 Micro-B) -* PC(Windows、Linux 或 macOS) +* USB 2.0 数据线(A 转 Micro-B) +* PC(Windows、Linux 或 Mac OS) 您可以跳过介绍部分,直接前往 `应用程序开发`_ 章节。 @@ -74,54 +74,57 @@ ESP-WROVER-KIT 开发板的主要组件、接口及控制方式见下。 下表将从图片右上角开始,以顺时针顺序介绍图 1 中的主要组件,然后按同样顺序介绍图 2 中的主要组件。 +.. list-table:: + :widths: 25 75 + :header-rows: 1 -==================== ====================================================================================================================================================================================================================================================================================================================================== -主要组件 基本介绍 -==================== ====================================================================================================================================================================================================================================================================================================================================== -FT2232 FT2232 多协议 USB 转串口桥接器。开发人员可通过 USB 接口对 FT2232 芯片进行控制和编程,与 ESP32 建立连接。FT2232 芯片可在通道 A 提供 USB-to-JTAG 接口功能,并在通道 B 提供 USB-to-Serial 接口功能,便利开发人员的应用开发与调试。详见 `ESP-WROVER-KIT V4.1 原理图`_。 + * - 主要组件 + - 基本介绍 + * - FT2232 + - FT2232 多协议 USB 转串口桥接器。开发人员可通过 USB 接口对 FT2232 芯片进行控制和编程,与 ESP32 建立连接。FT2232 芯片可在通道 A 提供 USB-to-JTAG 接口功能,并在通道 B 提供 USB-to-Serial 接口功能,便利开发人员的应用开发与调试。详见 `ESP-WROVER-KIT V4.1 原理图`_。 + * - 32.768 kHz + - 32.768 kHz 晶振,可提供 Deep-sleep 下使用的低功耗时钟。 + * - 0 欧电阻 + - ESP-WROVER-KIT 开发板设计了一个 0 欧电阻,可在测量 ESP32 系列模组在不同功耗模式下的电流时,直接移除或替换为分流器。 + * - ESP32-WROVER-B 模组 + - 这款 ESP32 模组内置 64-Mbit PSRAM,可提供灵活的额外存储空间和数据处理能力。 + * - 诊断 LED 信号灯 + - 本开发板 FT2232 芯片的 GPIO 管脚连接了 4 个红色 LED 信号灯,以备后用。 + * - UART + - 串口。FT2232 和 ESP32 的串行 TX/RX 信号已引出至 JP2 的两端。默认情况下,这两路信号由跳线帽连接。如果仅需使用 ESP32 模组串口,则可移除相关跳线帽,将模组连接至其他外部串口设备。 + * - SPI + - 默认情况下,ESP32 使用 SPI 接口访问内置 flash 和 PSRAM。使用这些引脚连接 ESP32 和其他 SPI 设备。这种情况下,需增加额外的片选 (CS) 信号。注意,本接口的工作电压为 3.3 V。 + * - CTS/RTS + - 串口流控信号。管脚默认不连接至电路。为了使能该功能,必须用跳线帽断路掉 JP14 的相应管脚。 + * - JTAG + - JTAG 接口。FT2232 和 ESP32 的 JTAG 信号已引出至 JP2 的两端。默认情况下,这两路信号不连接。如需使能 JTAG,请按照 `设置选项`_ 的介绍,连接跳线帽。 + * - USB 端口 + - USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 + * - EN + - 复位按键。 + * - BOOT 按键 + - 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 + * - 电源开关 + - 电源开关。拨向 **Boot** 按键一侧,开发板上电;拨离 **Boot** 按键一侧,开发板掉电。 + * - 电源选择开关 + - ESP-WROVER-KIT 开发板可通过 USB 端口或 5V 输入接口供电。用户可使用跳线帽在两种供电模式中进行选择。更多详细信息,请见章节 `设置选项`_ 中有关 JP7 连接器的描述。 + * - 5V Input + - 5V 电源接口。建议仅在开发板自动运行(未连接 PC)时使用。仅用于全负荷工作下的后备电源。 + * - 5V Power On LED + - 当开发板通电后(USB 或外部 5V 供电),该红色指示灯将亮起。 + * - LDO + - 5V-to-3.3V 低压差线型稳压器 NCP1117(1A)。NCP1117 最大电流输出为 1 A。板上 LDO 为固定输出电压,但用户也可以选用具有可变输出电压的 LDO。更多信息,请见 `ESP-WROVER-KIT V4.1 原理图`_。 + * - 摄像头连接器 + - 摄像头接口,支持标准 OV7670 摄像头模块。 + * - RGB LED + - 红绿蓝发光二极管,可由 PMW 控制。 + * - I/O 连接器 + - 板上模组的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 + * - Micro SD 卡槽 + - 适用于需要扩充数据存储空间或进行备份的应用开发场景。 + * - LCD 显示器 + - 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`ESP-WROVER-KIT 开发板布局 -- 仰视图 `。 -32.768 kHz 外接 32.768 kHz 晶振,可提供 Deep-sleep 下使用的低功耗时钟。 - -0 欧电阻 ESP-WROVER-KIT 开发板设计了一个 0 欧电阻,可在测量 ESP32 系列模组在不同功耗模式下的电流时,直接移除或替换为分流器。 - -ESP32-WROVER-B 模组 ESP-WROVER 模组内置 64-Mbit PSRAM,可提供灵活的额外存储空间和数据处理能力。 - -诊断 LED 信号灯 本开发板 FT2232 芯片的 GPIO 管脚连接了 4 个红色 LED 信号灯,以备后用。 - -UART 串口。FT2232HL 和 ESP32 的串行 TX/RX 信号已引出至 JP11 的两端。默认情况下,这两路信号由跳线帽连接。如果要跳过 FT2232 使用 ESP32 模组串口,则可移除相关跳线帽,将模组连接至其他外部串口设备。 - -SPI 默认情况下,ESP32 使用 SPI 接口访问内置 flash 和 PSRAM。使用这些引脚连接 ESP32 和其他 SPI 设备。这种情况下,需增加额外的片选 (CS) 信号。注意,本接口的工作电压为 3.3 V。 - -CTS/RTS 串口流控信号。管脚默认不连接至电路。为了使能该功能,必须用跳线帽短路掉 JP14 的相应管脚。 - -JTAG JTAG 接口。FT2232HL 和 ESP32 的 JTAG 信号已引出至 JP2 的两端。默认情况下,这两路信号不连接。如需使能 JTAG,请按照 `设置选项`_ 的介绍,连接跳线帽。 - -USB 端口 USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 - -EN 复位按键。 - -Boot 按键 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 - -电源开关 拨向 **Boot** 按键一侧,开发板上电;拨离 **Boot** 按键一侧,开发板掉电。 - -电源选择开关 ESP-WROVER-KIT 开发板可通过 USB 端口或 5V 输入接口供电。用户可使用跳线帽在两种供电模式中进行选择。更多详细信息,请见章节 `设置选项`_ 中有关 JP7 连接器的描述。 - -5V Input 5V 电源接口建议仅在开发板自动运行(未连接 PC)时使用。仅用于全负荷工作下的后备电源。 - -5V Power On LED 当开发板通电后(USB 或外部 5V 供电),该红色指示灯将亮起。 - -LDO 5V-to-3.3V 低压差线型稳压器 NCP1117(1A)。NCP1117 最大电流输出为 1 A。板上 LDO 为固定输出电压,但用户也可以选用具有可变输出电压的 LDO。更多信息,请见 `ESP-WROVER-KIT V4.1 原理图`_。 - -摄像头连接器 摄像头接口,支持标准 OV7670 摄像头模块。 - -RGB LED 红绿蓝发光二极管,可由 PWM(脉冲宽度调制)控制。 - -I/O 连接器 板上模组的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 - -MicroSD 卡槽 适用于需要扩充数据存储空间或进行备份的应用开发场景。 - -LCD 显示屏 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`get-started-esp-wrover-kit-v4.1-board-back`。 -==================== ====================================================================================================================================================================================================================================================================================================================================== .. _get-started-esp-wrover-kit-v4.1-setup-options: @@ -131,15 +134,28 @@ LCD 显示屏 支持贴装一款 3.2” 的 SPI(标准四线串 用户可通过 3 组排针,设置开发板功能,其中常见功能见下表: -======= ================ ========================================================= -排针 跳线设置 功能描述 -======= ================ ========================================================= -JP7 |jp7-ext_5v| 使用外部电源为 ESP-WROVER-KIT 开发板供电 -JP7 |jp7-usb_5v| 使用 USB 端口为 ESP-WROVER-KIT 开发板供电 -JP2 |jp2-jtag| 使能 JTAG 功能 -JP2 |jp2-tx-rx| 使能 UART 通信 -JP14 |jp14| 使能 RTS/CTS 串口流控 -======= ================ ========================================================= +.. list-table:: + :widths: 25 35 40 + :header-rows: 1 + + * - 排针 + - 跳线设置 + - 功能描述 + * - JP7 + - |jp7-ext_5v| + - 使用外部电源为 ESP-WROVER-KIT 开发板供电 + * - JP7 + - |jp7-usb_5v| + - 使用 USB 端口为 ESP-WROVER-KIT 开发板供电 + * - JP2 + - |jp2-jtag| + - 使能 JTAG 功能 + * - JP2 + - |jp2-tx-rx| + - 使能 UART 通信 + * - JP14 + - |jp14| + - 使能 RTS/CTS 串口流控 ESP32 管脚分配 @@ -159,24 +175,72 @@ ESP32 模组的部分管脚/终端已被板上组件占用或用于外部硬件 JP1 连接器包括 14 x 2 个排针,具体功能可见下表中间 “I/O” 列的介绍。两侧的“共用”列则介绍了这些管脚在板上的其他用途。 -===================== ===== ===== ===================== -共用 I/O I/O 共用 -===================== ===== ===== ===================== -n/a 3.3V GND n/a -NC/XTAL IO32 IO33 NC/XTAL -JTAG,MicroSD IO12 IO13 JTAG,MicroSD -JTAG,MicroSD IO14 IO27 摄像头 -摄像头 IO26 IO25 摄像头,LCD -摄像头 IO35 IO34 摄像头 -摄像头 IO39 IO36 摄像头 -JTAG EN IO23 摄像头,LCD -摄像头,LCD IO22 IO21 摄像头,LCD,MicroSD -摄像头,LCD IO19 IO18 摄像头,LCD -摄像头,LCD IO5 IO17 PSRAM -PSRAM IO16 IO4 LED,摄像头,MicroSD -摄像头,LED,Boot IO0 IO2 LED,MicroSD -JTAG,MicroSD IO15 5V -===================== ===== ===== ===================== + +.. list-table:: + :widths: 30 20 20 30 + :header-rows: 1 + + + * - 共用 + - I/O + - I/O + - 共用 + * - n/a + - 3.3V + - GND + - n/a + * - NC/XTAL + - IO32 + - IO33 + - NC/XTAL + * - JTAG,MicroSD + - IO12 + - IO13 + - JTAG,MicroSD + * - JTAG,MicroSD + - IO14 + - IO27 + - 摄像头 + * - 摄像头 + - IO26 + - IO25 + - 摄像头,LCD + * - 摄像头 + - IO35 + - IO34 + - 摄像头 + * - 摄像头 + - IO39 + - IO36 + - 摄像头 + * - JTAG + - EN + - IO23 + - 摄像头,LCD + * - 摄像头,LCD + - IO22 + - IO21 + - 摄像头,LCD,MicroSD + * - 摄像头,LCD + - IO19 + - IO18 + - 摄像头,LCD + * - 摄像头,LCD + - IO5 + - IO17 + - PSRAM + * - PSRAM + - IO16 + - IO4 + - LED,摄像头,MicroSD + * - 摄像头,LED,Boot + - IO0 + - IO2 + - LED,MicroSD + * - JTAG,MicroSD + - IO15 + - 5V + - 说明: @@ -356,9 +420,7 @@ USB 供电 使能 UART 通信 正式开始开发 ^^^^^^^^^^^^^^^^^^ -请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - -如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 +现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 相关文档 From 820fd6447d87490844d7e4fd6a1f8c7e0e97ba89 Mon Sep 17 00:00:00 2001 From: Darian Date: Thu, 17 Oct 2019 12:33:17 +0800 Subject: [PATCH 13/14] can: Add support for lower bit rates This commit adds support for lower bit rates in the CAN Driver for ESP32 Rev 2 or later chips. --- components/driver/can.c | 30 +++++++++++++++++-- components/driver/include/driver/can.h | 9 +++++- components/soc/esp32/include/soc/can_struct.h | 2 +- docs/en/api-reference/peripherals/can.rst | 9 +++++- 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/components/driver/can.c b/components/driver/can.c index 933994b05..34d4938b3 100644 --- a/components/driver/can.c +++ b/components/driver/can.c @@ -43,12 +43,26 @@ #define CAN_RESET_FLAG(var, mask) ((var) &= ~(mask)) #define CAN_TAG "CAN" +/* + * Baud Rate Prescaler Divider config/values. The BRP_DIV bit is located in the + * CAN interrupt enable register, and is only available in ESP32 Revision 2 or + * later. Setting this bit will cause the APB clock to be prescaled (divided) by + * a factor 2, before having the BRP applied. This will allow for lower bit rates + * to be achieved. + */ +#define BRP_DIV_EN_THRESH 128 //A BRP config value large this this will need to enable brp_div +#define BRP_DIV_EN_BIT 0x10 //Bit mask for brp_div in the interrupt register +//When brp_div is enabled, the BRP config value must be any multiple of 4 between 132 and 256 +#define BRP_CHECK_WITH_DIV(brp) ((brp) >= 132 && (brp) <= 256 && ((brp) & 0x3) == 0) +//When brp_div is disabled, the BRP config value must be any even number between 2 to 128 +#define BRP_CHECK_NO_DIV(brp) ((brp) >= 2 && (brp) <= 128 && ((brp) & 0x1) == 0) + //Driver default config/values #define DRIVER_DEFAULT_EWL 96 //Default Error Warning Limit value #define DRIVER_DEFAULT_TEC 0 //TX Error Counter starting value #define DRIVER_DEFAULT_REC 0 //RX Error Counter starting value #define DRIVER_DEFAULT_CLKOUT_DIV 14 //APB CLK divided by two -#define DRIVER_DEFAULT_INTERRUPTS 0xE7 //Exclude data overrun +#define DRIVER_DEFAULT_INTERRUPTS 0xE7 //Exclude data overrun (bit[3]) and brp_div (bit[4]) #define DRIVER_DEFAULT_ERR_PASS_CNT 128 //Error counter threshold for error passive //Command Bit Masks @@ -198,7 +212,7 @@ static inline void can_config_bus_timing(uint32_t brp, uint32_t sjw, uint32_t ts - SJW (1 to 4) is number of T_scl to shorten/lengthen for bit synchronization - TSEG_1 (1 to 16) is number of T_scl in a bit time before sample point - TSEG_2 (1 to 8) is number of T_scl in a bit time after sample point - - triple_sampling will cause each bit time to be sampled 3 times*/ + - triple_sampling will cause each bit time to be sampled 3 times */ can_bus_tim_0_reg_t timing_reg_0; can_bus_tim_1_reg_t timing_reg_1; timing_reg_0.baud_rate_prescaler = (brp / 2) - 1; @@ -629,6 +643,12 @@ esp_err_t can_driver_install(const can_general_config_t *g_config, const can_tim CAN_CHECK(g_config->rx_queue_len > 0, ESP_ERR_INVALID_ARG); CAN_CHECK(g_config->tx_io >= 0 && g_config->tx_io < GPIO_NUM_MAX, ESP_ERR_INVALID_ARG); CAN_CHECK(g_config->rx_io >= 0 && g_config->rx_io < GPIO_NUM_MAX, ESP_ERR_INVALID_ARG); +#if (CONFIG_ESP32_REV_MIN >= 2) + //ESP32 revision 2 or later chips have a brp_div bit. Check that the BRP config value is valid when brp_div is enabled or disabled + CAN_CHECK(BRP_CHECK_WITH_DIV(t_config->brp) || BRP_CHECK_NO_DIV(t_config->brp), ESP_ERR_INVALID_ARG); +#else + CAN_CHECK(BRP_CHECK_NO_DIV(t_config->brp), ESP_ERR_INVALID_ARG); +#endif esp_err_t ret; can_obj_t *p_can_obj_dummy; @@ -684,8 +704,14 @@ esp_err_t can_driver_install(const can_general_config_t *g_config, const can_tim /* Note: REC is allowed to increase even in reset mode. Listen only mode will freeze REC. The desired mode will be set when can_start() is called. */ can_config_mode(CAN_MODE_LISTEN_ONLY); +#if (CONFIG_ESP32_REV_MIN >= 2) + //If the BRP config value is large enough, the brp_div bit must be enabled to achieve the same effective baud rate prescaler + can_config_interrupts((t_config->brp > BRP_DIV_EN_THRESH) ? DRIVER_DEFAULT_INTERRUPTS | BRP_DIV_EN_BIT : DRIVER_DEFAULT_INTERRUPTS); + can_config_bus_timing((t_config->brp > BRP_DIV_EN_THRESH) ? t_config->brp/2 : t_config->brp, t_config->sjw, t_config->tseg_1, t_config->tseg_2, t_config->triple_sampling); +#else can_config_interrupts(DRIVER_DEFAULT_INTERRUPTS); can_config_bus_timing(t_config->brp, t_config->sjw, t_config->tseg_1, t_config->tseg_2, t_config->triple_sampling); +#endif can_config_error(DRIVER_DEFAULT_EWL, DRIVER_DEFAULT_REC, DRIVER_DEFAULT_TEC); can_config_acceptance_filter(f_config->acceptance_code, f_config->acceptance_mask, f_config->single_filter); can_config_clk_out(g_config->clkout_divider); diff --git a/components/driver/include/driver/can.h b/components/driver/include/driver/can.h index 074ead380..45b829c40 100644 --- a/components/driver/include/driver/can.h +++ b/components/driver/include/driver/can.h @@ -45,7 +45,13 @@ extern "C" { * The following initializer macros offer commonly found bit rates. * * @note These timing values are based on the assumption APB clock is at 80MHz + * @note The 20K, 16K and 12.5K bit rates are only available from ESP32 Revision 2 onwards */ +#if (CONFIG_ESP32_REV_MIN >= 2) +#define CAN_TIMING_CONFIG_12_5KBITS() {.brp = 256, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false} +#define CAN_TIMING_CONFIG_16KBITS() {.brp = 200, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false} +#define CAN_TIMING_CONFIG_20KBITS() {.brp = 200, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false} +#endif #define CAN_TIMING_CONFIG_25KBITS() {.brp = 128, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false} #define CAN_TIMING_CONFIG_50KBITS() {.brp = 80, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false} #define CAN_TIMING_CONFIG_100KBITS() {.brp = 40, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false} @@ -153,7 +159,8 @@ typedef struct { * @note Macro initializers are available for this structure */ typedef struct { - uint8_t brp; /**< Baudrate prescaler (APB clock divider, even number from 2 to 128) */ + uint32_t brp; /**< Baudrate prescaler (i.e., APB clock divider) can be any even number from 2 to 128. + For ESP32 Rev 2 or later, multiples of 4 from 132 to 256 are also supported */ uint8_t tseg_1; /**< Timing segment 1 (Number of time quanta, between 1 to 16) */ uint8_t tseg_2; /**< Timing segment 2 (Number of time quanta, 1 to 8) */ uint8_t sjw; /**< Synchronization Jump Width (Max time quanta jump for synchronize from 1 to 4) */ diff --git a/components/soc/esp32/include/soc/can_struct.h b/components/soc/esp32/include/soc/can_struct.h index 3a7912bd4..e19196454 100644 --- a/components/soc/esp32/include/soc/can_struct.h +++ b/components/soc/esp32/include/soc/can_struct.h @@ -93,7 +93,7 @@ typedef union { uint32_t tx: 1; /* IER.1 Transmit Interrupt Enable */ uint32_t err_warn: 1; /* IER.2 Error Interrupt Enable */ uint32_t data_overrun: 1; /* IER.3 Data Overrun Interrupt Enable */ - uint32_t reserved1: 1; /* Internal Reserved (Wake-up not supported) */ + uint32_t brp_div: 1; /* THIS IS NOT AN INTERRUPT. brp_div will prescale BRP by 2. Only available on ESP32 Revision 2 or later. Reserved otherwise */ uint32_t err_passive: 1; /* IER.5 Error Passive Interrupt Enable */ uint32_t arb_lost: 1; /* IER.6 Arbitration Lost Interrupt Enable */ uint32_t bus_err: 1; /* IER.7 Bus Error Interrupt Enable */ diff --git a/docs/en/api-reference/peripherals/can.rst b/docs/en/api-reference/peripherals/can.rst index d24cbd7f6..ce190de6a 100644 --- a/docs/en/api-reference/peripherals/can.rst +++ b/docs/en/api-reference/peripherals/can.rst @@ -168,7 +168,7 @@ The operating bit rate of the CAN controller is configured using the :cpp:type:` 2. **Timing Segment 1** consists of 1 to 16 time quanta before sample point 3. **Timing Segment 2** consists of 1 to 8 time quanta after sample point -The **Baudrate Prescaler** is used to determine the period of each time quanta by dividing the CAN controller's source clock (80 MHz APB clock). The ``brp`` can be **any even number from 2 to 128**. +The **Baudrate Prescaler** is used to determine the period of each time quanta by dividing the CAN controller's source clock (80 MHz APB clock). The ``brp`` can be **any even number from 2 to 128**. If the ESP32 is a revision 2 or later chip, the ``brp`` will also support **any multiple of 4 from 132 to 256**, and can be enabled by setting the :ref:`CONFIG_ESP32_REV_MIN` to revision 2 or higher. .. packetdiag:: ../../../_static/diagrams/can/can_bit_timing.diag :caption: Bit timing configuration for 500kbit/s given BRP = 8 @@ -183,6 +183,9 @@ The **Synchronization Jump Width** is used to determined the maximum number of t Bit timing **macro initializers** are also available for commonly used CAN bus bit rates. The following macro initializers are provided by the CAN driver. + - ``CAN_TIMING_CONFIG_12_5KBITS()`` + - ``CAN_TIMING_CONFIG_16KBITS()`` + - ``CAN_TIMING_CONFIG_20KBITS()`` - ``CAN_TIMING_CONFIG_25KBITS()`` - ``CAN_TIMING_CONFIG_50KBITS()`` - ``CAN_TIMING_CONFIG_100KBITS()`` @@ -192,6 +195,10 @@ Bit timing **macro initializers** are also available for commonly used CAN bus b - ``CAN_TIMING_CONFIG_800KBITS()`` - ``CAN_TIMING_CONFIG_1MBITS()`` +.. note:: + The macro initializers for 12.5K, 16K, and 20K bit rates are only available + for ESP32 revision 2 or later. + Acceptance Filter ^^^^^^^^^^^^^^^^^ From 10fd2ae6539d9c44747e8d0ce9782401f02dcfd1 Mon Sep 17 00:00:00 2001 From: Hrishikesh Dhayagude Date: Thu, 17 Oct 2019 12:54:34 +0800 Subject: [PATCH 14/14] NimBLE: Set the default number of max connections to the controller's value Also, update the NimBLE submodule to remove unwanted logging stuff --- components/bt/host/nimble/Kconfig.in | 2 +- components/bt/host/nimble/nimble | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index f241cd047..5dce95272 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -2,7 +2,7 @@ config BT_NIMBLE_MAX_CONNECTIONS int "Maximum number of concurrent connections" range 1 9 - default 1 + default BTDM_CTRL_BLE_MAX_CONN depends on BT_NIMBLE_ENABLED help Defines maximum number of concurrent BLE connections diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 5f6348d0d..acaed3b6a 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 5f6348d0ddd7f98841e458bbc808e8f7f5f23b23 +Subproject commit acaed3b6a860457b5cf61ecddce7d7be2c61a60a