Merge branch 'master' into feature/esp32s2beta_merge

This commit is contained in:
Angus Gratton 2019-10-17 18:22:08 +11:00 committed by Angus Gratton
commit ae21d669b9
42 changed files with 1575 additions and 415 deletions

View file

@ -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

@ -1 +1 @@
Subproject commit 5f6348d0ddd7f98841e458bbc808e8f7f5f23b23
Subproject commit acaed3b6a860457b5cf61ecddce7d7be2c61a60a

View file

@ -44,12 +44,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
@ -199,7 +213,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;
@ -454,13 +468,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);
@ -630,6 +648,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;
@ -680,13 +704,20 @@ 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. */
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);
@ -735,7 +766,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();
@ -773,7 +805,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;
@ -786,7 +819,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();
@ -801,7 +835,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);
@ -852,11 +887,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);
@ -947,7 +984,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;

View file

@ -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) */

View file

@ -22,6 +22,10 @@ if(CONFIG_ETH_ENABLED)
endif()
endif()
if(CONFIG_ETH_USE_OPENETH)
list(APPEND srcs "src/esp_eth_mac_openeth.c")
endif()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS ${include}
LDFRAGMENTS ${linker}

View file

@ -160,4 +160,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

View file

@ -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

View file

@ -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

View file

@ -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 <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include <sys/param.h>
#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;
}

View file

@ -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 <stdint.h>
#include <stddef.h>
#include <assert.h>
#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

View file

@ -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, &eth_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);

View file

@ -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;

View file

@ -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
*

View file

@ -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

View file

@ -90,6 +90,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
*
@ -246,6 +261,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 */
@ -299,6 +315,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__); } \
@ -306,6 +323,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``.
*

View file

@ -53,6 +53,8 @@
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
#include <time.h>
#include <sys/time.h>
#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) {

View file

@ -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"

View file

@ -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 \

View file

@ -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 */

View file

@ -9,3 +9,6 @@ idf_component_register(SRCS "esp_spiffs.c"
PRIV_INCLUDE_DIRS "." "spiffs/src"
REQUIRES spi_flash
PRIV_REQUIRES bootloader_support)
set_source_files_properties(spiffs/src/spiffs_nucleus.c PROPERTIES COMPILE_FLAGS -Wno-stringop-truncation)

View file

@ -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

View file

@ -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);
@ -103,14 +109,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);
@ -219,9 +237,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 +265,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 +278,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 +408,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;
}

View file

@ -34,4 +34,5 @@ API Guides
ULP Coprocessor <ulp>
Unit Testing (Legacy GNU Make) <unit-tests-legacy>
Unit Testing <unit-tests>
LwIP <lwip>
WiFi Driver <wifi>

View file

@ -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 |
+-----------------+-------------------------------------+

View file

@ -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
^^^^^^^^^^^^^^^^^

View file

@ -34,4 +34,5 @@ API 指南
BluFi <blufi>
External SPI-connected RAM <external-ram>
链接脚本生成机制 <linker-script-generation>
LwIP <lwip>
Tools <tools/index>

View file

@ -0,0 +1,2 @@
.. include:: ../../en/api-guides/lwip.rst

View file

@ -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` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。
相关文档

View file

@ -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` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。
开发板尺寸
-------------

View file

@ -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 板)<get-started-esp32-ethernet-kit-b-v1.0-layout>`
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 板)<get-started-esp32-ethernet-kit-b-v1.0-layout>`
* - 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` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。
请务必在进入下一步前,确保您已完成上述所有步骤。

View file

@ -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` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。
相关文档

View file

@ -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` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。
开发板尺寸

View file

@ -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` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。
相关文档

View file

@ -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` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。
相关文档
-----------------

View file

@ -9,8 +9,8 @@ ESP-WROVER-KIT V4.1 入门指南
-------------
* :ref:`ESP-WROVER-KIT V4.1 开发板 <get-started-esp-wrover-kit-v4.1-board-front>`
* USB 数据线A 转 Micro-B
* PCWindows、Linux 或 macOS
* USB 2.0 数据线A 转 Micro-B
* PCWindows、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 开发板布局 -- 仰视图 <get-started-esp-wrover-kit-v4.1-board-back>`
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
JTAGMicroSD IO12 IO13 JTAGMicroSD
JTAGMicroSD IO14 IO27 摄像头
摄像头 IO26 IO25 摄像头LCD
摄像头 IO35 IO34 摄像头
摄像头 IO39 IO36 摄像头
JTAG EN IO23 摄像头LCD
摄像头LCD IO22 IO21 摄像头LCDMicroSD
摄像头LCD IO19 IO18 摄像头LCD
摄像头LCD IO5 IO17 PSRAM
PSRAM IO16 IO4 LED摄像头MicroSD
摄像头LEDBoot IO0 IO2 LEDMicroSD
JTAGMicroSD 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
* - JTAGMicroSD
- IO12
- IO13
- JTAGMicroSD
* - JTAGMicroSD
- IO14
- IO27
- 摄像头
* - 摄像头
- IO26
- IO25
- 摄像头LCD
* - 摄像头
- IO35
- IO34
- 摄像头
* - 摄像头
- IO39
- IO36
- 摄像头
* - JTAG
- EN
- IO23
- 摄像头LCD
* - 摄像头LCD
- IO22
- IO21
- 摄像头LCDMicroSD
* - 摄像头LCD
- IO19
- IO18
- 摄像头LCD
* - 摄像头LCD
- IO5
- IO17
- PSRAM
* - PSRAM
- IO16
- IO4
- LED摄像头MicroSD
* - 摄像头LEDBoot
- IO0
- IO2
- LEDMicroSD
* - JTAGMicroSD
- 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` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。
相关文档

View file

@ -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

View file

@ -234,7 +234,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";

View file

@ -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

View file

@ -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());

View file

@ -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);
}

View file

@ -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:

View file

@ -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