diff --git a/components/ethernet/Kconfig b/components/ethernet/Kconfig index cbd3bfbe4..9eb897cbb 100644 --- a/components/ethernet/Kconfig +++ b/components/ethernet/Kconfig @@ -3,18 +3,32 @@ menuconfig ETHERNET default n help Enable this option to enable ethernet driver and show the menu with ethernet features. - config DMA_RX_BUF_NUM - int "Dma Rx Buf Num" + int "DMA Rx Buf Num" default 10 depends on ETHERNET help Dma rx buf num ,can not be 0 . config DMA_TX_BUF_NUM - int "Dma Tx Buf Num" + int "DMA Tx Buf Num" default 10 depends on ETHERNET help Dma tx Buf num ,can not be 0. + +config EMAC_L2_TO_L3_RX_BUF_MODE + bool "L2 To L3 RX BUF COPY MODE" + default n + depends on ETHERNET + help + Receive Buf user copy mode or pointer mode. + +config EMAC_TASK_PRIORITY + int "EMAC_TASK_PRIORITY" + default 20 + depends on ETHERNET + help + Emac task priority ,suggest 3 ~ 23. + diff --git a/components/ethernet/emac_common.h b/components/ethernet/emac_common.h index 48f71fd90..774c287ad 100644 --- a/components/ethernet/emac_common.h +++ b/components/ethernet/emac_common.h @@ -19,6 +19,7 @@ #include "esp_err.h" #include "emac_dev.h" +#include "esp_eth.h" #ifdef __cplusplus extern "C" { @@ -32,11 +33,6 @@ typedef struct { emac_par_t par; } emac_event_t; -enum emac_mode { - EMAC_MODE_RMII = 0, - EMAC_MDOE_MII, -}; - enum emac_runtime_status { EMAC_RUNTIME_NOT_INIT = 0, EMAC_RUNTIME_INIT, @@ -45,36 +41,37 @@ enum emac_runtime_status { }; enum { + SIG_EMAC_RX_UNAVAIL, SIG_EMAC_TX_DONE, SIG_EMAC_RX_DONE, - SIG_EMAC_TX, SIG_EMAC_START, SIG_EMAC_STOP, + SIG_EMAC_CHECK_LINK, SIG_EMAC_MAX }; -typedef void (*emac_phy_fun)(void); -typedef esp_err_t (*emac_tcpip_input_fun)(void *buffer, uint16_t len, void *eb); -typedef void (*emac_gpio_config_func)(void); - struct emac_config_data { - unsigned int phy_addr; - enum emac_mode mac_mode; + eth_phy_base_t phy_addr; + eth_mode_t mac_mode; struct dma_extended_desc *dma_etx; - unsigned int cur_tx; - unsigned int dirty_tx; - signed int cnt_tx; + uint32_t cur_tx; + uint32_t dirty_tx; + int32_t cnt_tx; struct dma_extended_desc *dma_erx; - unsigned int cur_rx; - unsigned int dirty_rx; - signed int cnt_rx; - unsigned int rx_need_poll; + uint32_t cur_rx; + uint32_t dirty_rx; + int32_t cnt_rx; + uint32_t rx_need_poll; bool phy_link_up; enum emac_runtime_status emac_status; uint8_t macaddr[6]; - emac_phy_fun phy_init; - emac_tcpip_input_fun emac_tcpip_input; - emac_gpio_config_func emac_gpio_config; + eth_phy_func phy_init; + eth_tcpip_input_func emac_tcpip_input; + eth_gpio_config_func emac_gpio_config; + eth_phy_check_link_func emac_phy_check_link; + eth_phy_check_init_func emac_phy_check_init; + eth_phy_get_speed_mode_func emac_phy_get_speed_mode; + eth_phy_get_duplex_mode_func emac_phy_get_duplex_mode; }; enum emac_post_type { @@ -103,18 +100,15 @@ struct emac_close_cmd { #if CONFIG_ETHERNET #define DMA_RX_BUF_NUM CONFIG_DMA_RX_BUF_NUM #define DMA_TX_BUF_NUM CONFIG_DMA_TX_BUF_NUM +#define EMAC_TASK_PRIORITY CONFIG_EMAC_TASK_PRIORITY #else #define DMA_RX_BUF_NUM 1 #define DMA_TX_BUF_NUM 1 +#define EMAC_TASK_PRIORITY 10 #endif #define DMA_RX_BUF_SIZE 1600 #define DMA_TX_BUF_SIZE 1600 -//lwip err -#define ERR_OK 0 -#define ERR_MEM -1 -#define ERR_IF -16 - #define EMAC_CMD_OK 0 #define EMAC_CMD_FAIL -1 diff --git a/components/ethernet/emac_dev.c b/components/ethernet/emac_dev.c index a8095fecb..244da0843 100644 --- a/components/ethernet/emac_dev.c +++ b/components/ethernet/emac_dev.c @@ -34,18 +34,6 @@ static const char *TAG = "emac"; -void emac_poll_tx_cmd(void) -{ - //write any to wake up dma - REG_WRITE(EMAC_DMATXPOLLDEMAND_REG, 1); -} - -void emac_poll_rx_cmd(void) -{ - //write any to wake up dma - REG_WRITE(EMAC_DMARXPOLLDEMAND_REG, 1); -} - void emac_enable_dma_tx(void) { REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_START_STOP_TRANSMISSION_COMMAND); @@ -66,15 +54,6 @@ void emac_disable_dma_rx(void) REG_CLR_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_START_STOP_RECEIVE); } -uint32_t emac_read_tx_cur_reg(void) -{ - return REG_READ(EMAC_DMATXCURRDESC_REG); -} - -uint32_t emac_read_rx_cur_reg(void) -{ - return REG_READ(EMAC_DMARXCURRDESC_REG); -} uint32_t emac_read_mac_version(void) { @@ -121,16 +100,18 @@ void emac_dma_init(void) REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_FORWARD_UNDERSIZED_GOOD_FRAMES); REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_OPERATE_SECOND_FRAME); REG_SET_FIELD(EMAC_DMABUSMODE_REG, EMAC_PROG_BURST_LEN, 4); + REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG,EMAC_DMAOPERATION_MODE_REG); } void emac_mac_init(void) { - REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACRX); - REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACTX); REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACDUPLEX); REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACMIIGMII); REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED); REG_SET_BIT(EMAC_GMACFRAMEFILTER_REG, EMAC_PROMISCUOUS_MODE); + + REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACRX); + REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACTX); } void emac_set_clk_rmii(void) diff --git a/components/ethernet/emac_dev.h b/components/ethernet/emac_dev.h index ede15271e..bc04d8d9e 100644 --- a/components/ethernet/emac_dev.h +++ b/components/ethernet/emac_dev.h @@ -49,14 +49,52 @@ uint32_t emac_read_mac_version(void); void emac_dma_init(void); void emac_mac_init(void); void emac_enable_dma_tx(void); -void emac_poll_tx_cmd(void); -uint32_t emac_read_tx_cur_reg(void); void emac_enable_dma_rx(void); -uint32_t emac_read_rx_cur_reg(void); -void emac_poll_rx_cmd(void); void emac_disable_dma_tx(void); void emac_disable_dma_rx(void); +uint32_t inline emac_read_tx_cur_reg(void) +{ + return REG_READ(EMAC_DMATXCURRDESC_REG); +} + +uint32_t inline emac_read_rx_cur_reg(void) +{ + return REG_READ(EMAC_DMARXCURRDESC_REG); +} + +void inline emac_poll_tx_cmd(void) +{ + //write any to wake up dma + REG_WRITE(EMAC_DMATXPOLLDEMAND_REG, 1); +} + +void inline emac_poll_rx_cmd(void) +{ + //write any to wake up dma + REG_WRITE(EMAC_DMARXPOLLDEMAND_REG, 1); +} + +void inline emac_disable_rx_intr(void) +{ + REG_CLR_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_INTERRUPT_ENABLE); +} + +void inline emac_enable_rx_intr(void) +{ + REG_SET_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_INTERRUPT_ENABLE); +} + +void inline emac_disable_rx_unavail_intr(void) +{ + REG_CLR_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_BUFFER_UNAVAILABLE_ENABLE); +} + +void inline emac_enable_rx_unavail_intr(void) +{ + REG_SET_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_BUFFER_UNAVAILABLE_ENABLE); +} + #ifdef __cplusplus } #endif diff --git a/components/ethernet/emac_main.c b/components/ethernet/emac_main.c index 3dc61d809..ab2ca8964 100644 --- a/components/ethernet/emac_main.c +++ b/components/ethernet/emac_main.c @@ -47,6 +47,8 @@ #include "freertos/semphr.h" #include "freertos/timers.h" +#include "lwip/err.h" + #define EMAC_EVT_QNUM 200 #define EMAC_SIG_MAX 50 @@ -63,7 +65,8 @@ static xTaskHandle emac_task_hdl; static xQueueHandle emac_xqueue; static uint8_t emac_sig_cnt[EMAC_SIG_MAX] = {0}; static TimerHandle_t emac_timer = NULL; - +static SemaphoreHandle_t emac_rx_xMutex = NULL; +static SemaphoreHandle_t emac_tx_xMutex = NULL; static const char *TAG = "emac"; static esp_err_t emac_ioctl(emac_sig_t sig, emac_par_t par); @@ -82,20 +85,24 @@ void esp_eth_get_mac(uint8_t mac[6]) static void emac_setup_tx_desc(struct dma_extended_desc *tx_desc , uint32_t size) { - tx_desc->basic.desc0 = EMAC_DESC_TX_OWN | EMAC_DESC_INT_COMPL | EMAC_DESC_LAST_SEGMENT | EMAC_DESC_FIRST_SEGMENT | EMAC_DESC_SECOND_ADDR_CHAIN; tx_desc->basic.desc1 = size & 0xfff; + tx_desc->basic.desc0 = EMAC_DESC_INT_COMPL | EMAC_DESC_LAST_SEGMENT | EMAC_DESC_FIRST_SEGMENT | EMAC_DESC_SECOND_ADDR_CHAIN; + tx_desc->basic.desc0 = EMAC_DESC_TX_OWN | EMAC_DESC_INT_COMPL | EMAC_DESC_LAST_SEGMENT | EMAC_DESC_FIRST_SEGMENT | EMAC_DESC_SECOND_ADDR_CHAIN; } static void emac_clean_tx_desc(struct dma_extended_desc *tx_desc) { - tx_desc->basic.desc0 = 0; tx_desc->basic.desc1 = 0; + tx_desc->basic.desc0 = 0; } -static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc) +static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc ,uint32_t buf_ptr) { - rx_desc->basic.desc0 = EMAC_DESC_RX_OWN; + if(buf_ptr != 0) { + rx_desc->basic.desc2 = buf_ptr; + } rx_desc->basic.desc1 = EMAC_DESC_RX_SECOND_ADDR_CHAIN | DMA_RX_BUF_SIZE; + rx_desc->basic.desc0 = EMAC_DESC_RX_OWN; } static void emac_set_tx_base_reg(void) @@ -156,18 +163,15 @@ static void emac_init_dma_chain(void) dma_phy = (uint32_t)(emac_config.dma_erx); p = emac_config.dma_erx; - for (i = 0; i < (DMA_TX_BUF_NUM - 1); i++ ) { + for (i = 0; i < (DMA_RX_BUF_NUM - 1); i++ ) { dma_phy += sizeof(struct dma_extended_desc); - emac_clean_rx_desc(p); + emac_clean_rx_desc(p, (uint32_t)(&emac_dma_rx_buf[0]) + (i * DMA_RX_BUF_SIZE)); p->basic.desc3 = dma_phy; - p->basic.desc2 = (uint32_t)(&emac_dma_rx_buf[0]) + (i * DMA_RX_BUF_SIZE); p++; } - p->basic.desc3 = (uint32_t)(emac_config.dma_erx); - p->basic.desc2 = (uint32_t)(&emac_dma_rx_buf[0]) + (i * DMA_RX_BUF_SIZE); - //init desc0 desc1 - emac_clean_rx_desc(p); + emac_clean_rx_desc(p, (uint32_t)(&emac_dma_rx_buf[0]) + (i * DMA_RX_BUF_SIZE)); + p->basic.desc3 = (uint32_t)(emac_config.dma_erx); } void esp_eth_smi_write(uint32_t reg_num, uint16_t value) @@ -207,18 +211,32 @@ static void emac_set_user_config_data(eth_config_t *config ) emac_config.phy_init = config->phy_init; emac_config.emac_tcpip_input = config->tcpip_input; emac_config.emac_gpio_config = config->gpio_config; + emac_config.emac_phy_check_link = config->phy_check_link; + emac_config.emac_phy_check_init = config->phy_check_init; + emac_config.emac_phy_get_speed_mode = config->phy_get_speed_mode; + emac_config.emac_phy_get_duplex_mode = config->phy_get_duplex_mode; +} + +static void emac_enable_intr() +{ + REG_WRITE(EMAC_DMAINTERRUPT_EN_REG, EMAC_INTR_ENABLE_BIT); +} + +static void emac_disable_intr() +{ + REG_WRITE(EMAC_DMAINTERRUPT_EN_REG, 0); } static esp_err_t emac_verify_args(void) { esp_err_t ret = ESP_OK; - if (emac_config.phy_addr > 31) { + if (emac_config.phy_addr > PHY31) { ESP_LOGE(TAG, "phy addr err"); ret = ESP_FAIL; } - if (emac_config.mac_mode != EMAC_MODE_RMII) { + if (emac_config.mac_mode != ETH_MODE_RMII) { ESP_LOGE(TAG, "mac mode err,now only support RMII"); ret = ESP_FAIL; } @@ -238,6 +256,26 @@ static esp_err_t emac_verify_args(void) ret = ESP_FAIL; } + if (emac_config.emac_phy_check_link == NULL) { + ESP_LOGE(TAG, "phy check link func is null"); + ret = ESP_FAIL; + } + + if (emac_config.emac_phy_check_init == NULL) { + ESP_LOGE(TAG, "phy check init func is null"); + ret = ESP_FAIL; + } + + if (emac_config.emac_phy_get_speed_mode == NULL) { + ESP_LOGE(TAG, "phy get speed mode func is null"); + ret = ESP_FAIL; + } + + if (emac_config.emac_phy_get_duplex_mode == NULL) { + ESP_LOGE(TAG, "phy get duplex mode func is null"); + ret = ESP_FAIL; + } + return ret; } @@ -255,7 +293,13 @@ static void emac_process_tx(void) { uint32_t cur_tx_desc = emac_read_tx_cur_reg(); - while (((uint32_t) & (emac_config.dma_etx[emac_config.dirty_tx].basic.desc0) != cur_tx_desc)) { + if(emac_config.emac_status == EMAC_RUNTIME_STOP) { + return; + } + + xSemaphoreTakeRecursive( emac_tx_xMutex, ( TickType_t ) portMAX_DELAY ); + + while (((uint32_t) &(emac_config.dma_etx[emac_config.dirty_tx].basic.desc0) != cur_tx_desc)) { emac_clean_tx_desc(&(emac_config.dma_etx[emac_config.dirty_tx])); emac_config.dirty_tx = (emac_config.dirty_tx + 1) % DMA_TX_BUF_NUM; emac_config.cnt_tx --; @@ -263,11 +307,33 @@ static void emac_process_tx(void) if (emac_config.cnt_tx < 0) { ESP_LOGE(TAG, "emac tx chain err"); } + cur_tx_desc = emac_read_tx_cur_reg(); } + + xSemaphoreGiveRecursive( emac_tx_xMutex ); } +void esp_eth_free_rx_buf(void *buf) +{ + xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY ); + + emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.cur_rx]),(uint32_t) buf); + emac_config.cur_rx = (emac_config.cur_rx + 1) % DMA_RX_BUF_NUM; + emac_config.cnt_rx--; + if(emac_config.cnt_rx < 0) { + ESP_LOGE(TAG, "emac rx buf err!!\n"); + } + emac_poll_rx_cmd(); + + xSemaphoreGiveRecursive( emac_rx_xMutex ); +} + +#if CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE static void emac_process_rx(void) { + if(emac_config.emac_status == EMAC_RUNTIME_STOP) { + return; + } uint32_t cur_rx_desc = emac_read_rx_cur_reg(); while (((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc)) { @@ -275,17 +341,116 @@ static void emac_process_rx(void) emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2), (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL); - emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx])); + emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]),(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2)); emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; - if (emac_config.rx_need_poll != 0) { - emac_poll_rx_cmd(); - emac_config.rx_need_poll = 0; - } + //if open this ,one intr can do many intrs ? - //cur_rx_desc = emac_read_rx_cur_reg(); + cur_rx_desc = emac_read_rx_cur_reg(); } + + emac_enable_rx_intr(); } +static void emac_process_rx_unavail(void) +{ + if(emac_config.emac_status == EMAC_RUNTIME_STOP) { + return; + } + + uint32_t dirty_cnt = 0; + while (dirty_cnt < DMA_RX_BUF_NUM) { + + if(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 == EMAC_DESC_RX_OWN) { + break; + } + + dirty_cnt ++; + //copy data to lwip + emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2), + (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL); + + emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]),(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2)); + emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; + } + emac_enable_rx_intr(); + emac_enable_rx_unavail_intr(); + emac_poll_rx_cmd(); +} + +#else +static void emac_process_rx_unavail(void) +{ + if(emac_config.emac_status == EMAC_RUNTIME_STOP) { + return; + } + + xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY ); + + while (emac_config.cnt_rx < DMA_RX_BUF_NUM) { + + //copy data to lwip + emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2), + (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL); + emac_config.cnt_rx++; + if(emac_config.cnt_rx > DMA_RX_BUF_NUM) { + ESP_LOGE(TAG, "emac rx unavail buf err !!\n"); + } + emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; + } + emac_enable_rx_intr(); + emac_enable_rx_unavail_intr(); + xSemaphoreGiveRecursive( emac_rx_xMutex ); +} + +static void emac_process_rx(void) +{ + if(emac_config.emac_status == EMAC_RUNTIME_STOP) { + return; + } + + uint32_t cur_rx_desc = emac_read_rx_cur_reg(); + + xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY ); + + if(((uint32_t) &(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc)) { + + while (((uint32_t) &(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc) && emac_config.cnt_rx < DMA_RX_BUF_NUM ) { + //copy data to lwip + emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2), + (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL); + + emac_config.cnt_rx++; + + if(emac_config.cnt_rx > DMA_RX_BUF_NUM ) { + ESP_LOGE(TAG, "emac rx buf err!!\n"); + } + emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; + + cur_rx_desc = emac_read_rx_cur_reg(); + } + } else { + if(emac_config.cnt_rx < DMA_RX_BUF_NUM) { + if((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) == 0) { + while (emac_config.cnt_rx < DMA_RX_BUF_NUM) { + + //copy data to lwip + emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2), + (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL); + emac_config.cnt_rx++; + if(emac_config.cnt_rx > DMA_RX_BUF_NUM) { + ESP_LOGE(TAG,"emac rx buf err!!!\n"); + } + + emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; + } + } + } + } + emac_enable_rx_intr(); + xSemaphoreGiveRecursive( emac_rx_xMutex ); +} +#endif + //TODO other events need to do something static void IRAM_ATTR emac_process_intr(void *arg) { @@ -295,35 +460,37 @@ static void IRAM_ATTR emac_process_intr(void *arg) //clr intrs REG_WRITE(EMAC_DMASTATUS_REG, event); - if (event & EMAC_RECV_BUF_UNAVAIL) { - emac_config.rx_need_poll = 1; - } else if (event & EMAC_TRANS_INT) { - emac_post(SIG_EMAC_TX_DONE, 0); - } else if (event & EMAC_RECV_INT) { + if (event & EMAC_RECV_INT) { + emac_disable_rx_intr(); emac_post(SIG_EMAC_RX_DONE, 0); - } else { - //other events + } + + if (event & EMAC_RECV_BUF_UNAVAIL) { + emac_disable_rx_unavail_intr(); + emac_post(SIG_EMAC_RX_UNAVAIL,0); + } + + if (event & EMAC_TRANS_INT) { + emac_post(SIG_EMAC_TX_DONE, 0); } } -//ToDo: this should only be called once because this allocates the interrupt as well. -static void emac_enable_intr() +static void emac_check_phy_init(void) { - //init emac intr - esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, emac_process_intr, NULL, NULL); - REG_WRITE(EMAC_DMAINTERRUPT_EN_REG, EMAC_INTR_ENABLE_BIT); -} + emac_config.emac_phy_check_init(); + if(emac_config.emac_phy_get_duplex_mode() == ETH_MDOE_FULLDUPLEX) { + REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACDUPLEX); + } else { + REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACDUPLEX); + } + if(emac_config.emac_phy_get_speed_mode() == ETH_SPEED_MODE_100M) { + REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED); + } else { + REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED); + } -static void emac_disable_intr() -{ - REG_WRITE(EMAC_DMAINTERRUPT_EN_REG, 0); + emac_mac_init(); } - -static bool emac_check_phy_link_status(void) -{ - return ((esp_eth_smi_read(1) & 0x4) == 0x4 ); -} - static void emac_process_link_updown(bool link_status) { system_event_t evt; @@ -331,10 +498,10 @@ static void emac_process_link_updown(bool link_status) emac_config.phy_link_up = link_status; if (link_status == true) { + emac_check_phy_init(); ESP_LOGI(TAG, "eth link_up!!!"); emac_enable_dma_tx(); emac_enable_dma_rx(); - ets_delay_us(200000); evt.event_id = SYSTEM_EVENT_ETH_CONNECTED; } else { ESP_LOGI(TAG, "eth link_down!!!"); @@ -356,26 +523,20 @@ static void emac_hw_init(void) //ipc TODO } -static esp_err_t emac_xmit(void *param) +esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size) { - struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)param; - struct emac_tx_cmd *cmd = (struct emac_tx_cmd *)(post_cmd->cmd); esp_err_t ret = ESP_OK; - void *buf = cmd->buf; - uint16_t size = cmd->size; - if (emac_config.emac_status != EMAC_RUNTIME_START || emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) { ESP_LOGI(TAG, "tx netif close"); - cmd->err = ERR_IF; - ret = ESP_FAIL; + ret = ERR_IF; goto _exit; } - if (emac_config.cnt_tx == DMA_TX_BUF_NUM) { - ESP_LOGI(TAG, "tx buf full"); - cmd->err = ERR_MEM; - ret = ESP_FAIL; + xSemaphoreTakeRecursive( emac_tx_xMutex, ( TickType_t ) portMAX_DELAY ); + if (emac_config.cnt_tx == DMA_TX_BUF_NUM -1) { + ESP_LOGD(TAG, "tx buf full"); + ret = ERR_MEM; goto _exit; } @@ -390,26 +551,23 @@ static esp_err_t emac_xmit(void *param) _exit: - if (post_cmd->post_type == EMAC_POST_SYNC) { - xSemaphoreGive(emac_g_sem); - } - + xSemaphoreGiveRecursive( emac_tx_xMutex ); return ret; } static void emac_init_default_data(void) { - emac_config.rx_need_poll = 0; + memset((uint8_t *)&emac_config, 0,sizeof(struct emac_config_data)); } -void emac_link_check_func(void *pv_parameters) +void emac_process_link_check(void) { if (emac_config.emac_status != EMAC_RUNTIME_START || emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) { return; } - if (emac_check_phy_link_status() == true ) { + if (emac_config.emac_phy_check_link() == true ) { if (emac_config.phy_link_up == false) { emac_process_link_updown(true); } @@ -420,9 +578,14 @@ void emac_link_check_func(void *pv_parameters) } } +void emac_link_check_func(void *pv_parameters) +{ + emac_post(SIG_EMAC_CHECK_LINK,0); +} + static bool emac_link_check_timer_init(void) { - emac_timer = xTimerCreate("emac_timer", (1000 / portTICK_RATE_MS), + emac_timer = xTimerCreate("emac_timer", (2000 / portTICK_RATE_MS), pdTRUE, (void *)rand(), emac_link_check_func); if (emac_timer == NULL) { return false; @@ -473,18 +636,11 @@ static void emac_start(void *param) emac_set_tx_base_reg(); emac_set_rx_base_reg(); - emac_mac_init(); emac_config.phy_init(); - //for test - //emac_wait_linkup(); - - //mmc not support - //ptp TODO - //enable emac intr emac_enable_intr(); emac_config.emac_status = EMAC_RUNTIME_START; @@ -573,7 +729,7 @@ esp_err_t esp_eth_disable(void) return close_cmd.err; } - if (emac_config.emac_status != EMAC_RUNTIME_NOT_INIT) { + if (emac_config.emac_status == EMAC_RUNTIME_START) { if (emac_ioctl(SIG_EMAC_STOP, (emac_par_t)(&post_cmd)) != 0) { close_cmd.err = EMAC_CMD_FAIL; } @@ -608,9 +764,6 @@ static esp_err_t emac_ioctl(emac_sig_t sig, emac_par_t par) case SIG_EMAC_TX_DONE: emac_process_tx(); break; - case SIG_EMAC_TX: - emac_xmit((void *)par); - break; case SIG_EMAC_START: emac_start((void *)par); break; @@ -626,29 +779,6 @@ static esp_err_t emac_ioctl(emac_sig_t sig, emac_par_t par) return ret; } -esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size) -{ - struct emac_post_cmd post_cmd; - struct emac_tx_cmd tx_cmd; - - post_cmd.cmd = (void *)(&tx_cmd); - - if (emac_check_phy_link_status() == false) { - emac_process_link_updown(false); - tx_cmd.err = ERR_IF; - } else { - tx_cmd.buf = buf; - tx_cmd.size = size; - tx_cmd.err = ERR_OK; - - if (emac_ioctl(SIG_EMAC_TX, (emac_par_t)(&post_cmd)) != 0) { - tx_cmd.err = ERR_MEM; - } - } - - return tx_cmd.err; -} - void emac_task(void *pv) { emac_event_t e; @@ -662,18 +792,21 @@ void emac_task(void *pv) case SIG_EMAC_RX_DONE: emac_process_rx(); break; + case SIG_EMAC_RX_UNAVAIL: + emac_process_rx_unavail(); + break; case SIG_EMAC_TX_DONE: emac_process_tx(); break; - case SIG_EMAC_TX: - emac_xmit((void *)e.par); - break; case SIG_EMAC_START: emac_start((void *)e.par); break; case SIG_EMAC_STOP: emac_stop((void *)e.par); break; + case SIG_EMAC_CHECK_LINK: + emac_process_link_check(); + break; default: ESP_LOGE(TAG, "unexpect sig %d", e.sig); break; @@ -684,27 +817,35 @@ void emac_task(void *pv) esp_err_t IRAM_ATTR emac_post(emac_sig_t sig, emac_par_t par) { - portENTER_CRITICAL(&g_emac_mux); + if(sig <= SIG_EMAC_RX_DONE) { + if (emac_sig_cnt[sig]) { + return ESP_OK; + } else { + emac_sig_cnt[sig]++; + emac_event_t evt; + signed portBASE_TYPE ret; + evt.sig = sig; + evt.par = par; + portBASE_TYPE tmp; - if (emac_sig_cnt[sig] && sig != SIG_EMAC_TX) { - portEXIT_CRITICAL(&g_emac_mux); - return ESP_OK; + ret = xQueueSendFromISR(emac_xqueue, &evt, &tmp); + + if(tmp != pdFALSE) { + portYIELD_FROM_ISR(); + } + + if(ret != pdPASS) { + return ESP_FAIL; + } + } } else { emac_sig_cnt[sig]++; - portEXIT_CRITICAL(&g_emac_mux); emac_event_t evt; evt.sig = sig; evt.par = par; - if (sig <= SIG_EMAC_RX_DONE) { - portBASE_TYPE tmp; - if (xQueueSendFromISR(emac_xqueue, &evt, &tmp) != pdPASS) { - return ESP_FAIL; - } - } else { - if (xQueueSend(emac_xqueue, &evt, 10 / portTICK_RATE_MS) != pdTRUE) { - return ESP_FAIL; - } + if (xQueueSend(emac_xqueue, &evt, 10 / portTICK_RATE_MS) != pdTRUE) { + return ESP_FAIL; } } @@ -737,7 +878,7 @@ esp_err_t esp_eth_init(eth_config_t *config) REG_SET_FIELD(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_PHY_INTF_SEL, EMAC_EX_PHY_INTF_RMII); emac_dma_init(); - if (emac_config.mac_mode == EMAC_MODE_RMII) { + if (emac_config.mac_mode == ETH_MODE_RMII) { emac_set_clk_rmii(); } else { emac_set_clk_mii(); @@ -752,8 +893,12 @@ esp_err_t esp_eth_init(eth_config_t *config) //init task for emac emac_g_sem = xSemaphoreCreateBinary(); + emac_rx_xMutex = xSemaphoreCreateRecursiveMutex(); + emac_tx_xMutex = xSemaphoreCreateRecursiveMutex(); emac_xqueue = xQueueCreate(EMAC_EVT_QNUM, sizeof(emac_event_t)); - xTaskCreate(emac_task, "emacT", 2048 * 4, NULL, (19), &emac_task_hdl); + xTaskCreate(emac_task, "emacT", 2048, NULL, EMAC_TASK_PRIORITY, &emac_task_hdl); + + esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, emac_process_intr, NULL, NULL); emac_reset(); emac_enable_clk(false); diff --git a/components/ethernet/include/esp_eth.h b/components/ethernet/include/esp_eth.h index b97289dd2..2aae9d202 100644 --- a/components/ethernet/include/esp_eth.h +++ b/components/ethernet/include/esp_eth.h @@ -22,15 +22,21 @@ extern "C" { #endif -typedef void (*eth_phy_fun)(void); -typedef esp_err_t (*eth_tcpip_input_fun)(void *buffer, uint16_t len, void *eb); -typedef void (*eth_gpio_config_func)(void); - typedef enum { ETH_MODE_RMII = 0, ETH_MDOE_MII, } eth_mode_t; +typedef enum { + ETH_SPEED_MODE_10M = 0, + ETH_SPEED_MODE_100M, +} eth_speed_mode_t; + +typedef enum { + ETH_MODE_HALFDUPLEX = 0, + ETH_MDOE_FULLDUPLEX, +} eth_duplex_mode_t; + typedef enum { PHY0 = 0, PHY1, @@ -66,6 +72,15 @@ typedef enum { PHY31, } eth_phy_base_t; +typedef bool (*eth_phy_check_link_func)(void); +typedef void (*eth_phy_check_init_func)(void); +typedef eth_speed_mode_t (*eth_phy_get_speed_mode_func)(void); +typedef eth_duplex_mode_t (*eth_phy_get_duplex_mode_func)(void); +typedef void (*eth_phy_func)(void); +typedef esp_err_t (*eth_tcpip_input_func)(void *buffer, uint16_t len, void *eb); +typedef void (*eth_gpio_config_func)(void); + + /** * @brief ethernet configuration * @@ -73,8 +88,12 @@ typedef enum { typedef struct { eth_phy_base_t phy_addr; /*!< phy base addr (0~31) */ eth_mode_t mac_mode; /*!< mac mode only support RMII now */ - eth_tcpip_input_fun tcpip_input; /*!< tcpip input func */ - eth_phy_fun phy_init; /*!< phy init func */ + eth_tcpip_input_func tcpip_input; /*!< tcpip input func */ + eth_phy_func phy_init; /*!< phy init func */ + eth_phy_check_link_func phy_check_link; /*!< phy check link func */ + eth_phy_check_init_func phy_check_init; /*!< phy check init func */ + eth_phy_get_speed_mode_func phy_get_speed_mode; /*!< phy check init func */ + eth_phy_get_duplex_mode_func phy_get_duplex_mode; /*!< phy check init func */ eth_gpio_config_func gpio_config; /*!< gpio config func */ } eth_config_t; @@ -159,6 +178,16 @@ void esp_eth_smi_write(uint32_t reg_num, uint16_t value); */ uint16_t esp_eth_smi_read(uint32_t reg_num); +/** + * @brief Free emac rx buf. + * + * @note buf can not be null,and it is tcpip input buf. + * + * @param[in] buf: start address of recevie packet data. + * + */ +void esp_eth_free_rx_buf(void *buf); + #ifdef __cplusplus } #endif diff --git a/components/lwip/core/pbuf.c b/components/lwip/core/pbuf.c index 29e24ef2b..b95481749 100755 --- a/components/lwip/core/pbuf.c +++ b/components/lwip/core/pbuf.c @@ -80,6 +80,7 @@ #if ESP_LWIP #include "esp_wifi_internal.h" +#include "esp_eth.h" #endif #define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) @@ -351,7 +352,8 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) p->flags = 0; #if ESP_LWIP - p->eb = NULL; + p->user_buf = NULL; + p->user_flag = PBUF_USER_FLAG_OWNER_NULL; #endif LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); @@ -720,9 +722,13 @@ pbuf_free(struct pbuf *p) } else if (type == PBUF_ROM || type == PBUF_REF) { #if ESP_LWIP - if (type == PBUF_REF && p->eb != NULL ) esp_wifi_internal_free_rx_buffer(p->eb); + if (type == PBUF_REF && p->user_flag == PBUF_USER_FLAG_OWNER_WIFI ) { + esp_wifi_internal_free_rx_buffer(p->user_buf); + } + if (type == PBUF_REF && p->user_flag == PBUF_USER_FLAG_OWNER_ETH ) { + esp_eth_free_rx_buf(p->user_buf); + } #endif - memp_free(MEMP_PBUF, p); /* type == PBUF_RAM */ } else { diff --git a/components/lwip/include/lwip/lwip/pbuf.h b/components/lwip/include/lwip/lwip/pbuf.h index 1834c4e04..d84aabaf8 100755 --- a/components/lwip/include/lwip/lwip/pbuf.h +++ b/components/lwip/include/lwip/lwip/pbuf.h @@ -105,6 +105,12 @@ typedef enum { /** indicates this pbuf includes a TCP FIN flag */ #define PBUF_FLAG_TCP_FIN 0x20U +#if ESP_LWIP +#define PBUF_USER_FLAG_OWNER_NULL 0 +#define PBUF_USER_FLAG_OWNER_WIFI 1 +#define PBUF_USER_FLAG_OWNER_ETH 2 +#endif + struct pbuf { /** next pbuf in singly linked pbuf chain */ struct pbuf *next; @@ -138,7 +144,8 @@ struct pbuf { u16_t ref; #if ESP_LWIP - void *eb; + void *user_buf; + u8_t user_flag; #endif }; diff --git a/components/lwip/port/netif/ethernetif.c b/components/lwip/port/netif/ethernetif.c index c6f08ec83..79f21f6b3 100755 --- a/components/lwip/port/netif/ethernetif.c +++ b/components/lwip/port/netif/ethernetif.c @@ -113,7 +113,8 @@ ethernet_low_level_output(struct netif *netif, struct pbuf *p) esp_interface_t eth_if = tcpip_adapter_get_esp_if(netif); if (eth_if != ESP_IF_ETH) { - printf("eth_if=%d netif=%p pbuf=%p len=%d\n", eth_if, netif, p, p->len); + LWIP_DEBUGF(NETIF_DEBUG,("eth_if=%d netif=%p pbuf=%p len=%d\n", eth_if, netif, p, p->len)); + return ERR_IF; } @@ -134,7 +135,6 @@ ethernet_low_level_output(struct netif *netif, struct pbuf *p) } } - //printf("netif=%p pbuf=%p len=%d\n", netif, p, p->len); return esp_eth_tx(q->payload, pbuf_x_len); #else for(q = p; q != NULL; q = q->next) { @@ -160,7 +160,7 @@ ethernetif_input(struct netif *netif, void *buffer, uint16_t len) if(buffer== NULL || netif == NULL) goto _exit; - +#if CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM); if (p == NULL) { //g_rx_alloc_pbuf_fail_cnt++; @@ -168,12 +168,28 @@ ethernetif_input(struct netif *netif, void *buffer, uint16_t len) } memcpy(p->payload, buffer, len); - /* full packet send to tcpip_thread to process */ - if (netif->input(p, netif) != ERR_OK) { - LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); - pbuf_free(p); +/* full packet send to tcpip_thread to process */ +if (netif->input(p, netif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + pbuf_free(p); +} + +#else + p = pbuf_alloc(PBUF_RAW, len, PBUF_REF); + if (p == NULL){ + return; } - + p->payload = buffer; + p->user_flag = PBUF_USER_FLAG_OWNER_ETH; + p->user_buf = buffer; + + /* full packet send to tcpip_thread to process */ +if (netif->input(p, netif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + p->user_flag = PBUF_USER_FLAG_OWNER_NULL; + pbuf_free(p); +} +#endif _exit: ; } diff --git a/components/lwip/port/netif/wlanif.c b/components/lwip/port/netif/wlanif.c index efaa76a73..fea163f8c 100755 --- a/components/lwip/port/netif/wlanif.c +++ b/components/lwip/port/netif/wlanif.c @@ -176,7 +176,8 @@ wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb) return; } p->payload = buffer; - p->eb = eb; + p->user_buf = eb; + p->user_flag = PBUF_USER_FLAG_OWNER_WIFI; #endif /* full packet send to tcpip_thread to process */ diff --git a/examples/14_ethernet/main/tlk110_phy.h b/examples/14_ethernet/main/tlk110_phy.h new file mode 100644 index 000000000..5f2ca644d --- /dev/null +++ b/examples/14_ethernet/main/tlk110_phy.h @@ -0,0 +1,28 @@ +#define BASIC_MODE_STATUS_REG (0x1) +#define AUTO_NEGOTIATION_COMPLETE BIT(5) +#define LINK_STATUS BIT(2) + +#define PHY_IDENTIFIER_REG (0x2) +#define OUI_MSB_21TO6_DEF 0x2000 + +#define SOFTWARE_STAP_CONTROL_REG (0x9) +#define SW_STRAP_CONFIG_DONE BIT(15) +#define AUTO_MDIX_ENABLE BIT(14) +#define AUTO_NEGOTIATION_ENABLE BIT(13) +#define AN_1 BIT(12) +#define AN_0 BIT(11) +#define LED_CFG BIT(10) +#define RMII_ENHANCED_MODE BIT(9) + +#define PHY_STATUS_REG (0x10) +#define AUTO_NEGTIATION_STATUS BIT(4) +#define DUPLEX_STATUS BIT(2) +#define SPEED_STATUS BIT(1) + +#define CABLE_DIAGNOSTIC_CONTROL_REG (0x1e) +#define DIAGNOSTIC_DONE BIT(1) + +#define PHY_RESET_CONTROL_REG (0x1f) +#define SOFTWARE_RESET BIT(15) + + diff --git a/examples/17_ethernet/main/ethernet_main.c b/examples/17_ethernet/main/ethernet_main.c index 836e977f4..7e84a9bad 100644 --- a/examples/17_ethernet/main/ethernet_main.c +++ b/examples/17_ethernet/main/ethernet_main.c @@ -32,30 +32,64 @@ #include "tcpip_adapter.h" #include "nvs_flash.h" #include "driver/gpio.h" +#include "tlk110_phy.h" static const char *TAG = "eth_demo"; +#define DEFAULT_PHY_CONFIG (AUTO_MDIX_ENABLE|AUTO_NEGOTIATION_ENABLE|AN_1|AN_0|LED_CFG) + +void phy_tlk110_check_phy_init(void) +{ + while((esp_eth_smi_read(BASIC_MODE_STATUS_REG) & AUTO_NEGOTIATION_COMPLETE ) != AUTO_NEGOTIATION_COMPLETE) + {}; + while((esp_eth_smi_read(PHY_STATUS_REG) & AUTO_NEGTIATION_STATUS ) != AUTO_NEGTIATION_STATUS) + {}; + while((esp_eth_smi_read(CABLE_DIAGNOSTIC_CONTROL_REG) & DIAGNOSTIC_DONE ) != DIAGNOSTIC_DONE) + {}; +} + +eth_speed_mode_t phy_tlk110_get_speed_mode(void) +{ + if((esp_eth_smi_read(PHY_STATUS_REG) & SPEED_STATUS ) != SPEED_STATUS) { + return ETH_SPEED_MODE_100M; + } else { + return ETH_SPEED_MODE_10M; + } +} + +eth_duplex_mode_t phy_tlk110_get_duplex_mode(void) +{ + if((esp_eth_smi_read(PHY_STATUS_REG) & DUPLEX_STATUS ) == DUPLEX_STATUS) { + return ETH_MDOE_FULLDUPLEX; + } else { + return ETH_MODE_HALFDUPLEX; + } +} + +bool phy_tlk110_check_phy_link_status(void) +{ + return ((esp_eth_smi_read(BASIC_MODE_STATUS_REG) & LINK_STATUS) == LINK_STATUS ); +} + void phy_tlk110_init(void) { - esp_eth_smi_write(0x1f, 0x8000); - ets_delay_us(20000); + esp_eth_smi_write(PHY_RESET_CONTROL_REG, SOFTWARE_RESET); - while (esp_eth_smi_read(0x2) != 0x2000) { + while (esp_eth_smi_read(PHY_IDENTIFIER_REG) != OUI_MSB_21TO6_DEF) { } - esp_eth_smi_write(0x9, 0x7400); - esp_eth_smi_write(0x9, 0xf400); - ets_delay_us(20000); + esp_eth_smi_write(SOFTWARE_STAP_CONTROL_REG, DEFAULT_PHY_CONFIG |SW_STRAP_CONFIG_DONE); + ets_delay_us(300); } void eth_gpio_config_rmii(void) { //txd0 to gpio19 ,can not change - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, 5); - //rx_en to gpio21 ,can not change - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO21_U, 5); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_EMAC_TXD0); + //tx_en to gpio21 ,can not change + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO21_U, FUNC_GPIO21_EMAC_TX_EN); //txd1 to gpio22 , can not change - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO22_U, 5); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO22_U, FUNC_GPIO22_EMAC_TXD1); //rxd0 to gpio25 , can not change gpio_set_direction(25, GPIO_MODE_INPUT); //rxd1 to gpio26 ,can not change @@ -102,8 +136,13 @@ void app_main() config.phy_init = phy_tlk110_init; config.gpio_config = eth_gpio_config_rmii; config.tcpip_input = tcpip_adapter_eth_input; + config.phy_check_init = phy_tlk110_check_phy_init; + config.phy_check_link = phy_tlk110_check_phy_link_status; + config.phy_get_speed_mode = phy_tlk110_get_speed_mode; + config.phy_get_duplex_mode = phy_tlk110_get_duplex_mode; ret = esp_eth_init(&config); + if(ret == ESP_OK) { esp_eth_enable(); xTaskCreate(eth_task, "eth_task", 2048, NULL, (tskIDLE_PRIORITY + 2), NULL);