// limitations under the License.
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include "rom/ets_sys.h"
static struct emac_config_data emac_config;
-static uint8_t emac_dma_rx_chain_buf[sizeof(struct dma_extended_desc) * DMA_RX_BUF_NUM];
-static uint8_t emac_dma_tx_chain_buf[sizeof(struct dma_extended_desc) * DMA_TX_BUF_NUM];
-static uint8_t emac_dma_rx_buf[DMA_RX_BUF_SIZE * DMA_RX_BUF_NUM];
-static uint8_t emac_dma_tx_buf[DMA_TX_BUF_SIZE * DMA_TX_BUF_NUM];
+static dma_extended_desc_t *emac_dma_rx_chain_buf[DMA_RX_BUF_NUM];
+static dma_extended_desc_t *emac_dma_tx_chain_buf[DMA_TX_BUF_NUM];
+static uint8_t *emac_dma_rx_buf[DMA_RX_BUF_NUM];
+static uint8_t *emac_dma_tx_buf[DMA_TX_BUF_NUM];
-static SemaphoreHandle_t emac_g_sem;
+static SemaphoreHandle_t emac_g_sem = NULL;
static portMUX_TYPE g_emac_mux = portMUX_INITIALIZER_UNLOCKED;
-static xTaskHandle emac_task_hdl;
-static xQueueHandle emac_xqueue;
+static xTaskHandle emac_task_hdl = NULL;
+static xQueueHandle emac_xqueue = NULL;
static uint8_t emac_sig_cnt[EMAC_SIG_MAX] = {0};
static TimerHandle_t emac_timer = NULL;
static SemaphoreHandle_t emac_rx_xMutex = NULL;
esp_err_t esp_eth_set_mac(const uint8_t mac[6])
{
- if((mac[0] & 0x01) == 0) {
- memcpy(&(emac_config.macaddr[0]),mac, 6);
+ if ((mac[0] & 0x01) == 0) {
+ memcpy(&(emac_config.macaddr[0]), mac, 6);
return ESP_OK;
} else {
return ESP_ERR_INVALID_MAC;
}
}
-static void emac_setup_tx_desc(struct dma_extended_desc *tx_desc , uint32_t size)
+static void emac_setup_tx_desc(struct dma_extended_desc *tx_desc, uint32_t size)
{
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;
+ 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;
}
-static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc , uint32_t buf_ptr)
+static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc,
+ uint32_t buf_ptr)
{
if (buf_ptr != 0) {
rx_desc->basic.desc2 = buf_ptr;
}
/*
-* dirty_rx indicates the hardware has been fed with data packets and is the first node software needs to handle;
+* dirty_rx indicates the hardware has been fed with data packets and is the
+* first node software needs to handle;
*
-* cur_rx indicates the completion of software handling and is the last node hardware could use;
+* cur_rx indicates the completion of software handling and is the last node
+* hardware could use;
*
-* cnt_rx is to count the numbers of packets handled by software, passed to protocol stack and not been freed.
+* cnt_rx is to count the numbers of packets handled by software, passed to
+* protocol stack and not been freed.
*
-* (1) Initializing the Linked List. Connect the numerable nodes to a circular linked list, appoint one of the nodes as the head node, mark* the dirty_rx and cur_rx into the node, and mount the node on the hardware base address. Initialize cnt_rx into 0.
+* (1) Initializing the Linked List. Connect the numerable nodes to a circular
+* linked list, appoint one of the nodes as the head node, mark* the dirty_rx
+* and cur_rx into the node, and mount the node on the hardware base address.
+* Initialize cnt_rx into 0.
*
-* (2) When hardware receives packets, nodes of linked lists will be fed with data packets from the base address by turns, marks the node
+* (2) When hardware receives packets, nodes of linked lists will be fed with
+* data packets from the base address by turns, marks the node
* of linked lists as “HARDWARE UNUSABLE” and reports interrupts.
*
-* (3) When the software receives the interrupts, it will handle the linked lists by turns from dirty_rx, send data packets to protocol
+* (3) When the software receives the interrupts, it will handle the linked
+* lists by turns from dirty_rx, send data packets to protocol
* stack. dirty_rx will deviate backwards by turns and cnt_rx will by turns ++.
*
-* (4) After the protocol stack handles all the data and calls the free function, it will deviate backwards by turns from cur_rx, mark the * node of linked lists as “HARDWARE USABLE” and cnt_rx will by turns --.
+* (4) After the protocol stack handles all the data and calls the free function,
+* it will deviate backwards by turns from cur_rx, mark the * node of linked
+* lists as “HARDWARE USABLE” and cnt_rx will by turns --.
*
-* (5) Cycle from Step 2 to Step 4 without break and build up circular linked list handling.
+* (5) Cycle from Step 2 to Step 4 without break and build up circular linked
+* list handling.
*/
static void emac_reset_dma_chain(void)
{
static void emac_init_dma_chain(void)
{
int i;
- uint32_t dma_phy;
- struct dma_extended_desc *p = NULL;
+ dma_extended_desc_t *p = NULL;
//init tx chain
- emac_config.dma_etx = (struct dma_extended_desc *)(&emac_dma_tx_chain_buf[0]);
+ emac_config.dma_etx = emac_dma_tx_chain_buf[0];
emac_config.cnt_tx = 0;
emac_config.cur_tx = 0;
emac_config.dirty_tx = 0;
- dma_phy = (uint32_t)(emac_config.dma_etx);
- p = emac_config.dma_etx;
-
- for (i = 0; i < (DMA_TX_BUF_NUM - 1); i++ ) {
- dma_phy += sizeof(struct dma_extended_desc);
+ p = emac_dma_tx_chain_buf[0];
+ for (i = 0; i < (DMA_TX_BUF_NUM - 1); i++) {
emac_clean_tx_desc(p);
- p->basic.desc3 = dma_phy;
- p->basic.desc2 = (uint32_t)(&emac_dma_tx_buf[0]) + (i * DMA_TX_BUF_SIZE);
- p++;
+ /* point to the buffer */
+ p->basic.desc2 = (uint32_t)(emac_dma_tx_buf[i]);
+ /* point to next descriptor */
+ p->basic.desc3 = (uint32_t)(emac_dma_tx_chain_buf[i + 1]);
+ p = emac_dma_tx_chain_buf[i + 1];
}
- p->basic.desc3 = (uint32_t)(emac_config.dma_etx);
- p->basic.desc2 = (uint32_t)(&emac_dma_tx_buf[0]) + (i * DMA_TX_BUF_SIZE);
-
- //init desc0 desc1
emac_clean_tx_desc(p);
+ /* point to the buffer */
+ p->basic.desc2 = (uint32_t)(emac_dma_tx_buf[i]);
+ /* point to first descriptor */
+ p->basic.desc3 = (uint32_t)(emac_config.dma_etx);
//init rx chain
- emac_config.dma_erx = (struct dma_extended_desc *)(&emac_dma_rx_chain_buf[0]);
+ emac_config.dma_erx = emac_dma_rx_chain_buf[0];
emac_config.cnt_rx = 0;
emac_config.cur_rx = 0;
emac_config.dirty_rx = 0;
- dma_phy = (uint32_t)(emac_config.dma_erx);
- p = emac_config.dma_erx;
-
- for (i = 0; i < (DMA_RX_BUF_NUM - 1); i++ ) {
- dma_phy += sizeof(struct dma_extended_desc);
- emac_clean_rx_desc(p, (uint32_t)(&emac_dma_rx_buf[0]) + (i * DMA_RX_BUF_SIZE));
- p->basic.desc3 = dma_phy;
- p++;
- }
-
- emac_clean_rx_desc(p, (uint32_t)(&emac_dma_rx_buf[0]) + (i * DMA_RX_BUF_SIZE));
+ p = emac_dma_rx_chain_buf[0];
+ for (i = 0; i < (DMA_RX_BUF_NUM - 1); i++) {
+ emac_clean_rx_desc(p, (uint32_t)(emac_dma_rx_buf[i]));
+ /* point to the buffer */
+ p->basic.desc3 = (uint32_t)(emac_dma_rx_chain_buf[i + 1]);
+ /* point to next descriptor */
+ p = emac_dma_rx_chain_buf[i + 1];
+ }
+ /* point to the buffer */
+ emac_clean_rx_desc(p, (uint32_t)(emac_dma_rx_buf[i]));
+ /* point to first descriptor */
p->basic.desc3 = (uint32_t)(emac_config.dma_erx);
}
{
uint32_t phy_num = emac_config.phy_addr;
- while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1 ) {
+ while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
}
REG_WRITE(EMAC_MIIDATA_REG, value);
- REG_WRITE(EMAC_GMIIADDR_REG, 0x3 | ((reg_num & 0x1f) << 6) | ((phy_num & 0x1f) << 11) | ((0x3) << 2));
+ REG_WRITE(EMAC_GMIIADDR_REG, 0x3 | ((reg_num & 0x1f) << 6) |
+ ((phy_num & 0x1f) << 11) | ((0x3) << 2));
- while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1 ) {
+ while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
}
}
uint32_t phy_num = emac_config.phy_addr;
uint16_t value = 0;
- while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1 ) {
+ while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
}
- REG_WRITE(EMAC_GMIIADDR_REG, 0x1 | ((reg_num & 0x1f) << 6) | ((phy_num & 0x1f) << 11) | (0x3 << 2));
- while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1 ) {
+ REG_WRITE(EMAC_GMIIADDR_REG, 0x1 | ((reg_num & 0x1f) << 6) |
+ ((phy_num & 0x1f) << 11) | (0x3 << 2));
+ while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
}
value = (REG_READ(EMAC_MIIDATA_REG) & 0xffff);
return value;
}
-esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, uint16_t value_mask, int timeout_ms)
+esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value,
+ uint16_t value_mask, int timeout_ms)
{
unsigned start = xTaskGetTickCount();
- unsigned timeout_ticks = (timeout_ms + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS;
+ unsigned timeout_ticks = (timeout_ms + portTICK_PERIOD_MS - 1) /
+ portTICK_PERIOD_MS;
uint16_t current_value = 0;
while (timeout_ticks == 0 || (xTaskGetTickCount() - start < timeout_ticks)) {
}
vTaskDelay(1);
}
- ESP_LOGE(TAG, "Timed out waiting for PHY register 0x%x to have value 0x%04x (mask 0x%04x). Current value 0x%04x",
+ ESP_LOGE(TAG, "Timed out waiting for PHY register 0x%x to have value 0x%04x(mask 0x%04x). Current value 0x%04x",
reg_num, value, value_mask, current_value);
return ESP_ERR_TIMEOUT;
}
-
-static void emac_set_user_config_data(eth_config_t *config )
+static void emac_set_user_config_data(eth_config_t *config)
{
emac_config.phy_addr = config->phy_addr;
emac_config.mac_mode = config->mac_mode;
#if DMA_RX_BUF_NUM > 9
emac_config.emac_flow_ctrl_enable = config->flow_ctrl_enable;
#else
- if(config->flow_ctrl_enable == true) {
+ if (config->flow_ctrl_enable == true) {
ESP_LOGE(TAG, "eth flow ctrl init err!!! Please run make menuconfig and make sure DMA_RX_BUF_NUM > 9 .");
}
emac_config.emac_flow_ctrl_enable = false;
#endif
- emac_config.emac_phy_get_partner_pause_enable = config->phy_get_partner_pause_enable;
+ emac_config.emac_phy_get_partner_pause_enable =
+ config->phy_get_partner_pause_enable;
emac_config.emac_phy_power_enable = config->phy_power_enable;
}
ret = ESP_FAIL;
}
- if (emac_config.emac_flow_ctrl_enable == true && emac_config.emac_phy_get_partner_pause_enable == NULL) {
+ if (emac_config.emac_flow_ctrl_enable == true &&
+ emac_config.emac_phy_get_partner_pause_enable == NULL) {
ESP_LOGE(TAG, "phy get partner pause enable func is null");
ret = ESP_FAIL;
}
- if(emac_config.emac_phy_power_enable == NULL) {
+ if (emac_config.emac_phy_power_enable == NULL) {
ESP_LOGE(TAG, "phy power enable func is null");
ret = ESP_FAIL;
}
return;
}
- xSemaphoreTakeRecursive( emac_tx_xMutex, ( TickType_t ) portMAX_DELAY );
+ xSemaphoreTakeRecursive(emac_tx_xMutex, 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]));
+ while ((uint32_t)(emac_dma_tx_chain_buf[emac_config.dirty_tx]) != cur_tx_desc) {
+ emac_clean_tx_desc(emac_dma_tx_chain_buf[emac_config.dirty_tx]);
emac_config.dirty_tx = (emac_config.dirty_tx + 1) % DMA_TX_BUF_NUM;
- emac_config.cnt_tx --;
+ emac_config.cnt_tx--;
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 );
+ xSemaphoreGiveRecursive(emac_tx_xMutex);
}
void esp_eth_free_rx_buf(void *buf)
{
- xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY );
+ xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY);
- emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.cur_rx]), (uint32_t) buf);
+ emac_clean_rx_desc(emac_dma_rx_chain_buf[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) {
}
emac_poll_rx_cmd();
- xSemaphoreGiveRecursive( emac_rx_xMutex );
+ xSemaphoreGiveRecursive(emac_rx_xMutex);
if (emac_config.emac_flow_ctrl_partner_support == true) {
portENTER_CRITICAL(&g_emac_mux);
- if (pause_send == true && emac_config.cnt_rx < FLOW_CONTROL_LOW_WATERMARK) {
+ if (pause_send == true && emac_config.cnt_rx <
+ FLOW_CONTROL_LOW_WATERMARK) {
emac_send_pause_zero_frame_enable();
pause_send = false;
}
{
uint32_t cnt = 0;
uint32_t cur_rx_desc = emac_read_rx_cur_reg();
- struct dma_extended_desc *cur_desc = (struct dma_extended_desc *)cur_rx_desc;
+ struct dma_extended_desc *cur_desc = (dma_extended_desc_t *)cur_rx_desc;
while (cur_desc->basic.desc0 == EMAC_DESC_RX_OWN && cnt < DMA_RX_BUF_NUM) {
cnt++;
}
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)) {
+ while (((uint32_t)(emac_dma_rx_chain_buf[emac_config.dirty_rx]) != cur_rx_desc)) {
//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.emac_tcpip_input((emac_dma_rx_buf[emac_config.dirty_rx]),
+ (((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0) >>
+ EMAC_DESC_FRAME_LENGTH_S) &
+ EMAC_DESC_FRAME_LENGTH),
+ NULL);
+
+ emac_clean_rx_desc(emac_dma_rx_chain_buf[emac_config.dirty_rx],
+ (uint32_t)(emac_dma_rx_buf[emac_config.dirty_rx]));
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
//if open this ,one intr can do many intrs ?
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) {
+ if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
break;
}
- dirty_cnt ++;
+ 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.emac_tcpip_input((emac_dma_rx_buf[emac_config.dirty_rx]),
+ (((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0) >>
+ EMAC_DESC_FRAME_LENGTH_S) &
+ EMAC_DESC_FRAME_LENGTH),
+ NULL);
+
+ emac_clean_rx_desc(emac_dma_rx_chain_buf[emac_config.dirty_rx],
+ (uint32_t)(emac_dma_rx_buf[emac_config.dirty_rx]));
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
}
emac_enable_rx_intr();
return;
}
- xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY );
+ xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY);
while (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
- if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 == EMAC_DESC_RX_OWN) {
+ if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
break;
}
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
//copy data to lwip
- emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
- (((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
-
- }
+ emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]),
+ (((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >>
+ EMAC_DESC_FRAME_LENGTH_S) &
+ EMAC_DESC_FRAME_LENGTH),
+ NULL);
+ }
emac_enable_rx_intr();
emac_enable_rx_unavail_intr();
- xSemaphoreGiveRecursive( emac_rx_xMutex );
+ xSemaphoreGiveRecursive(emac_rx_xMutex);
}
static void emac_process_rx(void)
uint32_t cur_rx_desc = emac_read_rx_cur_reg();
- xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY );
+ xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY);
- if (((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc)) {
+ if (((uint32_t)(emac_dma_rx_chain_buf[emac_config.dirty_rx])) !=
+ 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 ) {
+ while (((uint32_t)(emac_dma_rx_chain_buf[emac_config.dirty_rx]) != cur_rx_desc) &&
+ emac_config.cnt_rx < DMA_RX_BUF_NUM) {
emac_config.cnt_rx++;
- if (emac_config.cnt_rx > DMA_RX_BUF_NUM ) {
+ if (emac_config.cnt_rx > DMA_RX_BUF_NUM) {
ESP_LOGE(TAG, "emac rx buf err!!\n");
}
uint32_t tmp_dirty = emac_config.dirty_rx;
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
-
//copy data to lwip
- emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
- (((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
+ emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]),
+ (((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >>
+ EMAC_DESC_FRAME_LENGTH_S) &
+ EMAC_DESC_FRAME_LENGTH),
+ NULL);
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) {
+ if ((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 &
+ EMAC_DESC_RX_OWN) == 0) {
while (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
- if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 == EMAC_DESC_RX_OWN) {
+ if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
break;
}
ESP_LOGE(TAG, "emac rx buf err!!!\n");
}
uint32_t tmp_dirty = emac_config.dirty_rx;
- emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
+ emac_config.dirty_rx = (emac_config.dirty_rx + 1) %
+ DMA_RX_BUF_NUM;
//copy data to lwip
- emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
- (((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
-
- }
+ emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]),
+ (((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >>
+ EMAC_DESC_FRAME_LENGTH_S) &
+ EMAC_DESC_FRAME_LENGTH),
+ NULL);
+ }
}
}
}
emac_enable_rx_intr();
- xSemaphoreGiveRecursive( emac_rx_xMutex );
+ xSemaphoreGiveRecursive(emac_rx_xMutex);
}
#endif
if (event & EMAC_RECV_INT) {
emac_disable_rx_intr();
if (emac_config.emac_flow_ctrl_partner_support == true) {
- if (emac_get_rxbuf_count_in_intr() < FLOW_CONTROL_HIGH_WATERMARK && pause_send == false ) {
+ if (emac_get_rxbuf_count_in_intr() < FLOW_CONTROL_HIGH_WATERMARK &&
+ pause_send == false) {
pause_send = true;
emac_send_pause_frame_enable();
}
static void emac_set_macaddr_reg(void)
{
REG_SET_FIELD(EMAC_ADDR0HIGH_REG, EMAC_ADDRESS0_HI, (emac_config.macaddr[0] << 8) | (emac_config.macaddr[1]));
- REG_WRITE(EMAC_ADDR0LOW_REG, (emac_config.macaddr[2] << 24) | (emac_config.macaddr[3] << 16) | (emac_config.macaddr[4] << 8) | (emac_config.macaddr[5]));
+ REG_WRITE(EMAC_ADDR0LOW_REG, (emac_config.macaddr[2] << 24) |
+ (emac_config.macaddr[3] << 16) | (emac_config.macaddr[4] << 8) |
+ (emac_config.macaddr[5]));
}
static void emac_check_phy_init(void)
emac_config.emac_flow_ctrl_partner_support = false;
#else
if (emac_config.emac_flow_ctrl_enable == true) {
- if (emac_config.emac_phy_get_partner_pause_enable() == true && emac_config.emac_phy_get_duplex_mode() == ETH_MODE_FULLDUPLEX) {
+ if (emac_config.emac_phy_get_partner_pause_enable() == true &&
+ emac_config.emac_phy_get_duplex_mode() == ETH_MODE_FULLDUPLEX) {
emac_enable_flowctrl();
emac_config.emac_flow_ctrl_partner_support = true;
} else {
if (link_status == true) {
emac_check_phy_init();
- ESP_LOGI(TAG, "eth link_up!!!");
+ ESP_LOGD(TAG, "eth link_up");
emac_enable_dma_tx();
emac_enable_dma_rx();
for (i = 0; i < PHY_LINK_CHECK_NUM; i++) {
evt.event_id = SYSTEM_EVENT_ETH_CONNECTED;
} else {
- ESP_LOGI(TAG, "eth link_down!!!");
+ ESP_LOGD(TAG, "eth link_down");
emac_disable_dma_tx();
emac_disable_dma_rx();
evt.event_id = SYSTEM_EVENT_ETH_DISCONNECTED;
{
esp_err_t ret = ESP_OK;
- if (emac_config.emac_status != EMAC_RUNTIME_START || emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) {
- ESP_LOGI(TAG, "tx netif close");
+ if (emac_config.emac_status != EMAC_RUNTIME_START) {
+ ESP_LOGE(TAG, "tx netif is not ready, emac_status=%d",
+ emac_config.emac_status);
ret = ERR_IF;
return ret;
}
- xSemaphoreTakeRecursive( emac_tx_xMutex, ( TickType_t ) portMAX_DELAY );
+ xSemaphoreTakeRecursive(emac_tx_xMutex, portMAX_DELAY);
if (emac_config.cnt_tx == DMA_TX_BUF_NUM - 1) {
ESP_LOGD(TAG, "tx buf full");
ret = ERR_MEM;
goto _exit;
}
- memcpy((uint8_t *)(emac_config.dma_etx[emac_config.cur_tx].basic.desc2), (uint8_t *)buf, size);
+ memcpy(emac_dma_tx_buf[emac_config.cur_tx], buf, size);
- emac_setup_tx_desc(&(emac_config.dma_etx[emac_config.cur_tx]), size);
+ emac_setup_tx_desc(emac_dma_tx_chain_buf[emac_config.cur_tx], size);
- emac_config.cnt_tx ++;
- emac_config.cur_tx = (emac_config.cur_tx + 1) % DMA_TX_BUF_NUM ;
+ emac_config.cnt_tx++;
+ emac_config.cur_tx = (emac_config.cur_tx + 1) % DMA_TX_BUF_NUM;
emac_poll_tx_cmd();
_exit:
- xSemaphoreGiveRecursive( emac_tx_xMutex );
+ xSemaphoreGiveRecursive(emac_tx_xMutex);
return ret;
}
void emac_process_link_check(void)
{
- if (emac_config.emac_status != EMAC_RUNTIME_START ||
- emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) {
+ if (emac_config.emac_status != EMAC_RUNTIME_START) {
return;
}
- if (emac_config.emac_phy_check_link() == true ) {
- if (emac_config.phy_link_up == false) {
+ if (emac_config.emac_phy_check_link()) {
+ if (!emac_config.phy_link_up) {
emac_process_link_updown(true);
}
} else {
- if (emac_config.phy_link_up == true) {
+ if (emac_config.phy_link_up) {
emac_process_link_updown(false);
}
}
static bool emac_link_check_timer_init(void)
{
- emac_timer = xTimerCreate("emac_timer", (2000 / portTICK_PERIOD_MS),
- pdTRUE, (void *)rand(), emac_link_check_func);
+ emac_timer = xTimerCreate("emac_timer",
+ (CONFIG_EMAC_CHECK_LINK_PERIOD_MS /
+ portTICK_PERIOD_MS),
+ pdTRUE,
+ NULL,
+ emac_link_check_func);
if (emac_timer == NULL) {
return false;
} else {
static void emac_start(void *param)
{
- struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)param;
+ struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)param;
struct emac_open_cmd *cmd = (struct emac_open_cmd *)(post_cmd->cmd);
- ESP_LOGI(TAG , "emac start !!!\n");
+ ESP_LOGD(TAG, "emac start");
cmd->err = EMAC_CMD_OK;
emac_enable_clk(true);
xSemaphoreGive(emac_g_sem);
}
- ESP_LOGI(TAG, "emac start success !!!");
+ ESP_LOGD(TAG, "emac start success");
}
esp_err_t esp_eth_enable(void)
static void emac_stop(void *param)
{
- struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)param;
- ESP_LOGI(TAG, "emac stop");
+ struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)param;
+ ESP_LOGD(TAG, "emac stop");
emac_link_check_timer_stop();
emac_link_check_timer_delete();
xSemaphoreGive(emac_g_sem);
}
- ESP_LOGI(TAG, "emac stop success !!!");
+ ESP_LOGD(TAG, "emac stop success");
}
esp_err_t esp_eth_disable(void)
static esp_err_t emac_ioctl(emac_sig_t sig, emac_par_t par)
{
esp_err_t ret = ESP_OK;
- struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)par;
+ struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)par;
xTaskHandle task_hdl = xTaskGetCurrentTaskHandle();
if (emac_task_hdl != task_hdl) {
emac_event_t e;
for (;;) {
- if (xQueueReceive(emac_xqueue, &e, (portTickType)portMAX_DELAY) == pdTRUE) {
+ if (xQueueReceive(emac_xqueue, &e, portMAX_DELAY) == pdTRUE) {
portENTER_CRITICAL(&g_emac_mux);
emac_sig_cnt[e.sig]--;
portEXIT_CRITICAL(&g_emac_mux);
esp_err_t esp_eth_init(eth_config_t *config)
{
- esp_event_set_default_eth_handlers();
- return esp_eth_init_internal(config);
+ /* dynamically alloc memory for ethernet dma */
+ for (int i = 0; i < DMA_RX_BUF_NUM; i++) {
+ emac_dma_rx_chain_buf[i] = (struct dma_extended_desc *)heap_caps_malloc(sizeof(struct dma_extended_desc), MALLOC_CAP_DMA);
+ emac_dma_rx_buf[i] = (uint8_t *)heap_caps_malloc(DMA_RX_BUF_SIZE, MALLOC_CAP_DMA);
+ }
+ for (int i = 0; i < DMA_TX_BUF_NUM; i++) {
+ emac_dma_tx_chain_buf[i] = (struct dma_extended_desc *)heap_caps_malloc(sizeof(struct dma_extended_desc), MALLOC_CAP_DMA);
+ emac_dma_tx_buf[i] = (uint8_t *)heap_caps_malloc(DMA_TX_BUF_SIZE, MALLOC_CAP_DMA);
+ }
+
+ esp_event_set_default_eth_handlers();
+ return esp_eth_init_internal(config);
}
esp_err_t esp_eth_init_internal(eth_config_t *config)
emac_init_default_data();
- if (config != NULL ) {
+ if (config != NULL) {
emac_set_user_config_data(config);
}
if (emac_config.clock_mode != ETH_CLOCK_GPIO0_IN) {
// 50 MHz = 40MHz * (6 + 4) / (2 * (2 + 2) = 400MHz / 8
rtc_clk_apll_enable(1, 0, 0, 6, 2);
- // the next to values have to be set AFTER "periph_module_enable" is called
REG_SET_FIELD(EMAC_EX_CLKOUT_CONF_REG, EMAC_EX_CLK_OUT_H_DIV_NUM, 0);
REG_SET_FIELD(EMAC_EX_CLKOUT_CONF_REG, EMAC_EX_CLK_OUT_DIV_NUM, 0);
- if (emac_config.clock_mode == ETH_CLOCK_GPIO0_OUT) {
- PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
- REG_WRITE(PIN_CTRL, 6);
- ESP_LOGD(TAG, "EMAC 50MHz clock output on GPIO0");
- } else if (emac_config.clock_mode == ETH_CLOCK_GPIO16_OUT) {
+ if (emac_config.clock_mode == ETH_CLOCK_GPIO16_OUT) {
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT);
ESP_LOGD(TAG, "EMAC 50MHz clock output on GPIO16");
} else if (emac_config.clock_mode == ETH_CLOCK_GPIO17_OUT) {
- PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_EMAC_CLK_OUT_180);
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U,
+ FUNC_GPIO17_EMAC_CLK_OUT_180);
ESP_LOGD(TAG, "EMAC 50MHz inverted clock output on GPIO17");
}
}
emac_enable_clk(true);
- REG_SET_FIELD(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_PHY_INTF_SEL, EMAC_EX_PHY_INTF_RMII);
+ REG_SET_FIELD(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_PHY_INTF_SEL,
+ EMAC_EX_PHY_INTF_RMII);
emac_dma_init();
if (emac_config.clock_mode == ETH_CLOCK_GPIO0_IN) {
// external clock on GPIO0
- REG_SET_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_EXT_OSC_EN);
- REG_CLR_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_INT_OSC_EN);
+ REG_SET_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_EXT_OSC_EN);
+ REG_CLR_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_INT_OSC_EN);
REG_SET_BIT(EMAC_EX_OSCCLK_CONF_REG, EMAC_EX_OSC_CLK_SEL);
ESP_LOGD(TAG, "External clock input 50MHz on GPIO0");
if (emac_config.mac_mode == ETH_MODE_MII) {
}
} else {
// internal clock by APLL
- REG_CLR_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_EXT_OSC_EN);
- REG_SET_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_INT_OSC_EN);
+ REG_CLR_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_EXT_OSC_EN);
+ REG_SET_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_INT_OSC_EN);
REG_CLR_BIT(EMAC_EX_OSCCLK_CONF_REG, EMAC_EX_OSC_CLK_SEL);
}
emac_rx_xMutex = xSemaphoreCreateRecursiveMutex();
emac_tx_xMutex = xSemaphoreCreateRecursiveMutex();
emac_xqueue = xQueueCreate(EMAC_EVT_QNUM, sizeof(emac_event_t));
- xTaskCreate(emac_task, "emacT", 2048, NULL, EMAC_TASK_PRIORITY, &emac_task_hdl);
+ xTaskCreate(emac_task, "emacT", 2048, NULL, EMAC_TASK_PRIORITY,
+ &emac_task_hdl);
emac_enable_clk(false);
esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, emac_process_intr, NULL, NULL);
_exit:
return ret;
}
+
+esp_err_t esp_eth_deinit(void)
+{
+ esp_err_t ret = ESP_FAIL;
+
+ if (!emac_task_hdl) {
+ ret = ESP_ERR_INVALID_STATE;
+ goto _exit;
+ }
+
+ vTaskDelete(emac_task_hdl);
+ emac_task_hdl = NULL;
+
+ vQueueDelete(emac_xqueue);
+ vSemaphoreDelete(emac_tx_xMutex);
+ vSemaphoreDelete(emac_rx_xMutex);
+ vSemaphoreDelete(emac_g_sem);
+ emac_reset_dma_chain();
+ emac_config.emac_phy_power_enable(false);
+ periph_module_disable(PERIPH_EMAC_MODULE);
+ emac_config.emac_status = EMAC_RUNTIME_NOT_INIT;
+
+ /* free memory that dynamically allocted */
+ for (int i = 0; i < DMA_RX_BUF_NUM; i++) {
+ free(emac_dma_rx_chain_buf[i]);
+ free(emac_dma_rx_buf[i]);
+ emac_dma_rx_chain_buf[i] = NULL;
+ emac_dma_rx_buf[i] = NULL;
+ }
+ for (int i = 0; i < DMA_TX_BUF_NUM; i++) {
+ free(emac_dma_tx_chain_buf[i]);
+ free(emac_dma_tx_buf[i]);
+ emac_dma_tx_chain_buf[i] = NULL;
+ emac_dma_tx_buf[i] = NULL;
+ }
+ ret = ESP_OK;
+
+_exit:
+ return ret;
+}
#include "esp_err.h"
#include "esp_event_loop.h"
#include "esp_event.h"
-#include "esp_attr.h"
#include "esp_log.h"
#include "esp_eth.h"
-#include "rom/ets_sys.h"
#include "rom/gpio.h"
-#include "soc/dport_reg.h"
-#include "soc/io_mux_reg.h"
-#include "soc/rtc_cntl_reg.h"
-#include "soc/gpio_reg.h"
-#include "soc/gpio_sig_map.h"
-
#include "tcpip_adapter.h"
-#include "nvs_flash.h"
#include "driver/gpio.h"
-
-#include "soc/emac_ex_reg.h"
#include "driver/periph_ctrl.h"
-
#ifdef CONFIG_PHY_LAN8720
#include "eth_phy/phy_lan8720.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_lan8720_default_ethernet_config
static const char *TAG = "eth_example";
#define PIN_PHY_POWER CONFIG_PHY_POWER_PIN
-#define PIN_SMI_MDC CONFIG_PHY_SMI_MDC_PIN
-#define PIN_SMI_MDIO CONFIG_PHY_SMI_MDIO_PIN
+#define PIN_SMI_MDC CONFIG_PHY_SMI_MDC_PIN
+#define PIN_SMI_MDIO CONFIG_PHY_SMI_MDIO_PIN
#ifdef CONFIG_PHY_USE_POWER_PIN
-/* This replaces the default PHY power on/off function with one that
- also uses a GPIO for power on/off.
-
- If this GPIO is not connected on your device (and PHY is always powered), you can use the default PHY-specific power
- on/off function rather than overriding with this one.
-*/
+/**
+ * @brief re-define power enable func for phy
+ *
+ * @param enable true to enable, false to disable
+ *
+ * @note This function replaces the default PHY power on/off function.
+ * If this GPIO is not connected on your device (and PHY is always powered),
+ * you can use the default PHY-specific power on/off function.
+ */
static void phy_device_power_enable_via_gpio(bool enable)
{
assert(DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable);
if (!enable) {
- /* Do the PHY-specific power_enable(false) function before powering down */
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(false);
}
gpio_pad_select_gpio(PIN_PHY_POWER);
- gpio_set_direction(PIN_PHY_POWER,GPIO_MODE_OUTPUT);
- if(enable == true) {
+ gpio_set_direction(PIN_PHY_POWER, GPIO_MODE_OUTPUT);
+ if (enable == true) {
gpio_set_level(PIN_PHY_POWER, 1);
- ESP_LOGD(TAG, "phy_device_power_enable(TRUE)");
+ ESP_LOGI(TAG, "Power On Ethernet PHY");
} else {
gpio_set_level(PIN_PHY_POWER, 0);
- ESP_LOGD(TAG, "power_enable(FALSE)");
+ ESP_LOGI(TAG, "Power Off Ethernet PHY");
}
- // Allow the power up/down to take effect, min 300us
- vTaskDelay(1);
+ vTaskDelay(1); // Allow the power up/down to take effect, min 300us
if (enable) {
- /* Run the PHY-specific power on operations now the PHY has power */
+ /* call the default PHY-specific power on function */
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(true);
}
}
#endif
+/**
+ * @brief gpio specific init
+ *
+ * @note RMII data pins are fixed in esp32:
+ * TXD0 <=> GPIO19
+ * TXD1 <=> GPIO22
+ * TX_EN <=> GPIO21
+ * RXD0 <=> GPIO25
+ * RXD1 <=> GPIO26
+ * CLK <=> GPIO0
+ *
+ */
static void eth_gpio_config_rmii(void)
{
- // RMII data pins are fixed:
- // TXD0 = GPIO19
- // TXD1 = GPIO22
- // TX_EN = GPIO21
- // RXD0 = GPIO25
- // RXD1 = GPIO26
- // CLK == GPIO0
phy_rmii_configure_data_interface_pins();
- // MDC is GPIO 23, MDIO is GPIO 18
phy_rmii_smi_configure_pins(PIN_SMI_MDC, PIN_SMI_MDIO);
}
-void eth_task(void *pvParameter)
+/**
+ * @brief event handler for ethernet
+ *
+ * @param ctx
+ * @param event
+ * @return esp_err_t
+ */
+static esp_err_t eth_event_handler(void *ctx, system_event_t *event)
{
tcpip_adapter_ip_info_t ip;
- memset(&ip, 0, sizeof(tcpip_adapter_ip_info_t));
- vTaskDelay(2000 / portTICK_PERIOD_MS);
-
- while (1) {
- vTaskDelay(2000 / portTICK_PERIOD_MS);
-
- if (tcpip_adapter_get_ip_info(ESP_IF_ETH, &ip) == 0) {
- ESP_LOGI(TAG, "~~~~~~~~~~~");
- ESP_LOGI(TAG, "ETHIP:"IPSTR, IP2STR(&ip.ip));
- ESP_LOGI(TAG, "ETHPMASK:"IPSTR, IP2STR(&ip.netmask));
- ESP_LOGI(TAG, "ETHPGW:"IPSTR, IP2STR(&ip.gw));
- ESP_LOGI(TAG, "~~~~~~~~~~~");
- }
+ switch (event->event_id) {
+ case SYSTEM_EVENT_ETH_CONNECTED:
+ ESP_LOGI(TAG, "Ethernet Link Up");
+ break;
+ case SYSTEM_EVENT_ETH_DISCONNECTED:
+ ESP_LOGI(TAG, "Ethernet Link Down");
+ break;
+ case SYSTEM_EVENT_ETH_START:
+ ESP_LOGI(TAG, "Ethernet Started");
+ break;
+ case SYSTEM_EVENT_ETH_GOT_IP:
+ memset(&ip, 0, sizeof(tcpip_adapter_ip_info_t));
+ ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(ESP_IF_ETH, &ip));
+ ESP_LOGI(TAG, "Ethernet Got IP Addr");
+ ESP_LOGI(TAG, "~~~~~~~~~~~");
+ ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip.ip));
+ ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip.netmask));
+ ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip.gw));
+ ESP_LOGI(TAG, "~~~~~~~~~~~");
+ break;
+ case SYSTEM_EVENT_ETH_STOP:
+ ESP_LOGI(TAG, "Ethernet Stopped");
+ break;
+ default:
+ break;
}
+ return ESP_OK;
}
void app_main()
{
- esp_err_t ret = ESP_OK;
tcpip_adapter_init();
- esp_event_loop_init(NULL, NULL);
+
+ ESP_ERROR_CHECK(esp_event_loop_init(eth_event_handler, NULL));
eth_config_t config = DEFAULT_ETHERNET_PHY_CONFIG;
- /* Set the PHY address in the example configuration */
config.phy_addr = CONFIG_PHY_ADDRESS;
config.gpio_config = eth_gpio_config_rmii;
config.tcpip_input = tcpip_adapter_eth_input;
config.clock_mode = CONFIG_PHY_CLOCK_MODE;
-
#ifdef CONFIG_PHY_USE_POWER_PIN
- /* Replace the default 'power enable' function with an example-specific
- one that toggles a power GPIO. */
+ /* Replace the default 'power enable' function with an example-specific one
+ that toggles a power GPIO. */
config.phy_power_enable = phy_device_power_enable_via_gpio;
#endif
- ret = esp_eth_init(&config);
-
- if(ret == ESP_OK) {
- esp_eth_enable();
- xTaskCreate(eth_task, "eth_task", 2048, NULL, (tskIDLE_PRIORITY + 2), NULL);
- }
-
+ ESP_ERROR_CHECK(esp_eth_init(&config));
+ ESP_ERROR_CHECK(esp_eth_enable()) ;
}