@@ -39,6 +39,14 @@ static const char *TAG = "w5500.mac";
3939#define W5500_SPI_LOCK_TIMEOUT_MS (50)
4040#define W5500_TX_MEM_SIZE (0x4000)
4141#define W5500_RX_MEM_SIZE (0x4000)
42+ #define W5500_ETH_MAC_RX_BUF_SIZE_AUTO (0)
43+
44+ typedef struct {
45+ uint32_t offset ;
46+ uint32_t copy_len ;
47+ uint32_t rx_len ;
48+ uint32_t remain ;
49+ }__attribute__((packed )) emac_w5500_auto_buf_info_t ;
4250
4351typedef struct {
4452 esp_eth_mac_t parent ;
@@ -50,6 +58,7 @@ typedef struct {
5058 int int_gpio_num ;
5159 uint8_t addr [6 ];
5260 bool packets_remain ;
61+ uint8_t * rx_buffer ;
5362} emac_w5500_t ;
5463
5564static inline bool w5500_lock (emac_w5500_t * emac )
@@ -302,59 +311,6 @@ static esp_err_t emac_w5500_stop(esp_eth_mac_t *mac)
302311 return ret ;
303312}
304313
305- IRAM_ATTR static void w5500_isr_handler (void * arg )
306- {
307- emac_w5500_t * emac = (emac_w5500_t * )arg ;
308- BaseType_t high_task_wakeup = pdFALSE ;
309- /* notify w5500 task */
310- vTaskNotifyGiveFromISR (emac -> rx_task_hdl , & high_task_wakeup );
311- if (high_task_wakeup != pdFALSE ) {
312- portYIELD_FROM_ISR ();
313- }
314- }
315-
316- static void emac_w5500_task (void * arg )
317- {
318- emac_w5500_t * emac = (emac_w5500_t * )arg ;
319- uint8_t status = 0 ;
320- uint8_t * buffer = NULL ;
321- uint32_t length = 0 ;
322- while (1 ) {
323- // check if the task receives any notification
324- if (ulTaskNotifyTake (pdTRUE , pdMS_TO_TICKS (1000 )) == 0 && // if no notification ...
325- gpio_get_level (emac -> int_gpio_num ) != 0 ) { // ...and no interrupt asserted
326- continue ; // -> just continue to check again
327- }
328-
329- /* read interrupt status */
330- w5500_read (emac , W5500_REG_SOCK_IR (0 ), & status , sizeof (status ));
331- /* packet received */
332- if (status & W5500_SIR_RECV ) {
333- status = W5500_SIR_RECV ;
334- // clear interrupt status
335- w5500_write (emac , W5500_REG_SOCK_IR (0 ), & status , sizeof (status ));
336- do {
337- length = ETH_MAX_PACKET_SIZE ;
338- buffer = heap_caps_malloc (length , MALLOC_CAP_DMA );
339- if (!buffer ) {
340- ESP_LOGE (TAG , "no mem for receive buffer" );
341- break ;
342- } else if (emac -> parent .receive (& emac -> parent , buffer , & length ) == ESP_OK ) {
343- /* pass the buffer to stack (e.g. TCP/IP layer) */
344- if (length ) {
345- emac -> eth -> stack_input (emac -> eth , buffer , length );
346- } else {
347- free (buffer );
348- }
349- } else {
350- free (buffer );
351- }
352- } while (emac -> packets_remain );
353- }
354- }
355- vTaskDelete (NULL );
356- }
357-
358314static esp_err_t emac_w5500_set_mediator (esp_eth_mac_t * mac , esp_eth_mediator_t * eth )
359315{
360316 esp_err_t ret = ESP_OK ;
@@ -520,6 +476,8 @@ static esp_err_t emac_w5500_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t
520476 emac_w5500_t * emac = __containerof (mac , emac_w5500_t , parent );
521477 uint16_t offset = 0 ;
522478
479+ ESP_GOTO_ON_FALSE (length <= ETH_MAX_PACKET_SIZE , ESP_ERR_INVALID_ARG , err ,
480+ TAG , "frame size is too big (actual %u, maximum %u)" , length , ETH_MAX_PACKET_SIZE );
523481 // check if there're free memory to store this packet
524482 uint16_t free_size = 0 ;
525483 ESP_GOTO_ON_ERROR (w5500_get_tx_free_size (emac , & free_size ), err , TAG , "get free size failed" );
@@ -553,12 +511,103 @@ static esp_err_t emac_w5500_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t
553511 return ret ;
554512}
555513
514+ static esp_err_t emac_w5500_alloc_recv_buf (emac_w5500_t * emac , uint8_t * * buf , uint32_t * length )
515+ {
516+ esp_err_t ret = ESP_OK ;
517+ uint16_t offset = 0 ;
518+ uint16_t rx_len = 0 ;
519+ uint32_t copy_len = 0 ;
520+ uint16_t remain_bytes = 0 ;
521+ * buf = NULL ;
522+
523+ w5500_get_rx_received_size (emac , & remain_bytes );
524+ if (remain_bytes ) {
525+ // get current read pointer
526+ ESP_GOTO_ON_ERROR (w5500_read (emac , W5500_REG_SOCK_RX_RD (0 ), & offset , sizeof (offset )), err , TAG , "read RX RD failed" );
527+ offset = __builtin_bswap16 (offset );
528+ // read head
529+ ESP_GOTO_ON_ERROR (w5500_read_buffer (emac , & rx_len , sizeof (rx_len ), offset ), err , TAG , "read frame header failed" );
530+ rx_len = __builtin_bswap16 (rx_len ) - 2 ; // data size includes 2 bytes of header
531+ // frames larger than expected will be truncated
532+ copy_len = rx_len > * length ? * length : rx_len ;
533+ // runt frames are not forwarded by W5500 (tested on target), but check the length anyway since it could be corrupted at SPI bus
534+ ESP_GOTO_ON_FALSE (copy_len >= ETH_MIN_PACKET_SIZE - ETH_CRC_LEN , ESP_ERR_INVALID_SIZE , err , TAG , "invalid frame length %u" , copy_len );
535+ * buf = malloc (copy_len );
536+ if (* buf != NULL ) {
537+ emac_w5500_auto_buf_info_t * buff_info = (emac_w5500_auto_buf_info_t * )* buf ;
538+ buff_info -> offset = offset ;
539+ buff_info -> copy_len = copy_len ;
540+ buff_info -> rx_len = rx_len ;
541+ buff_info -> remain = remain_bytes ;
542+ } else {
543+ ret = ESP_ERR_NO_MEM ;
544+ goto err ;
545+ }
546+ }
547+ err :
548+ * length = rx_len ;
549+ return ret ;
550+ }
551+
556552static esp_err_t emac_w5500_receive (esp_eth_mac_t * mac , uint8_t * buf , uint32_t * length )
557553{
558554 esp_err_t ret = ESP_OK ;
559555 emac_w5500_t * emac = __containerof (mac , emac_w5500_t , parent );
560556 uint16_t offset = 0 ;
561557 uint16_t rx_len = 0 ;
558+ uint16_t copy_len = 0 ;
559+ uint16_t remain_bytes = 0 ;
560+ emac -> packets_remain = false;
561+
562+ if (* length != W5500_ETH_MAC_RX_BUF_SIZE_AUTO ) {
563+ w5500_get_rx_received_size (emac , & remain_bytes );
564+ if (remain_bytes ) {
565+ // get current read pointer
566+ ESP_GOTO_ON_ERROR (w5500_read (emac , W5500_REG_SOCK_RX_RD (0 ), & offset , sizeof (offset )), err , TAG , "read RX RD failed" );
567+ offset = __builtin_bswap16 (offset );
568+ // read head first
569+ ESP_GOTO_ON_ERROR (w5500_read_buffer (emac , & rx_len , sizeof (rx_len ), offset ), err , TAG , "read frame header failed" );
570+ rx_len = __builtin_bswap16 (rx_len ) - 2 ; // data size includes 2 bytes of header
571+ // frames larger than expected will be truncated
572+ copy_len = rx_len > * length ? * length : rx_len ;
573+ } else {
574+ // silently return when no frame is waiting
575+ goto err ;
576+ }
577+ } else {
578+ emac_w5500_auto_buf_info_t * buff_info = (emac_w5500_auto_buf_info_t * )buf ;
579+ offset = buff_info -> offset ;
580+ copy_len = buff_info -> copy_len ;
581+ rx_len = buff_info -> rx_len ;
582+ remain_bytes = buff_info -> remain ;
583+ }
584+ // 2 bytes of header
585+ offset += 2 ;
586+ // read the payload
587+ ESP_GOTO_ON_ERROR (w5500_read_buffer (emac , emac -> rx_buffer , copy_len , offset ), err , TAG , "read payload failed, len=%d, offset=%d" , rx_len , offset );
588+ memcpy (buf , emac -> rx_buffer , copy_len );
589+ offset += rx_len ;
590+ // update read pointer
591+ offset = __builtin_bswap16 (offset );
592+ ESP_GOTO_ON_ERROR (w5500_write (emac , W5500_REG_SOCK_RX_RD (0 ), & offset , sizeof (offset )), err , TAG , "write RX RD failed" );
593+ /* issue RECV command */
594+ ESP_GOTO_ON_ERROR (w5500_send_command (emac , W5500_SCR_RECV , 100 ), err , TAG , "issue RECV command failed" );
595+ // check if there're more data need to process
596+ remain_bytes -= rx_len + 2 ;
597+ emac -> packets_remain = remain_bytes > 0 ;
598+
599+ * length = copy_len ;
600+ return ret ;
601+ err :
602+ * length = 0 ;
603+ return ret ;
604+ }
605+
606+ static esp_err_t emac_w5500_flush_recv_frame (emac_w5500_t * emac )
607+ {
608+ esp_err_t ret = ESP_OK ;
609+ uint16_t offset = 0 ;
610+ uint16_t rx_len = 0 ;
562611 uint16_t remain_bytes = 0 ;
563612 emac -> packets_remain = false;
564613
@@ -569,26 +618,90 @@ static esp_err_t emac_w5500_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *
569618 offset = __builtin_bswap16 (offset );
570619 // read head first
571620 ESP_GOTO_ON_ERROR (w5500_read_buffer (emac , & rx_len , sizeof (rx_len ), offset ), err , TAG , "read frame header failed" );
572- rx_len = __builtin_bswap16 (rx_len ) - 2 ; // data size includes 2 bytes of header
573- offset += 2 ;
574- // read the payload
575- ESP_GOTO_ON_ERROR (w5500_read_buffer (emac , buf , rx_len , offset ), err , TAG , "read payload failed, len=%d, offset=%d" , rx_len , offset );
576- offset += rx_len ;
577621 // update read pointer
622+ rx_len = __builtin_bswap16 (rx_len );
623+ offset += rx_len ;
578624 offset = __builtin_bswap16 (offset );
579625 ESP_GOTO_ON_ERROR (w5500_write (emac , W5500_REG_SOCK_RX_RD (0 ), & offset , sizeof (offset )), err , TAG , "write RX RD failed" );
580626 /* issue RECV command */
581627 ESP_GOTO_ON_ERROR (w5500_send_command (emac , W5500_SCR_RECV , 100 ), err , TAG , "issue RECV command failed" );
582628 // check if there're more data need to process
583- remain_bytes -= rx_len + 2 ;
629+ remain_bytes -= rx_len ;
584630 emac -> packets_remain = remain_bytes > 0 ;
585631 }
586-
587- * length = rx_len ;
588632err :
589633 return ret ;
590634}
591635
636+ IRAM_ATTR static void w5500_isr_handler (void * arg )
637+ {
638+ emac_w5500_t * emac = (emac_w5500_t * )arg ;
639+ BaseType_t high_task_wakeup = pdFALSE ;
640+ /* notify w5500 task */
641+ vTaskNotifyGiveFromISR (emac -> rx_task_hdl , & high_task_wakeup );
642+ if (high_task_wakeup != pdFALSE ) {
643+ portYIELD_FROM_ISR ();
644+ }
645+ }
646+
647+ static void emac_w5500_task (void * arg )
648+ {
649+ emac_w5500_t * emac = (emac_w5500_t * )arg ;
650+ uint8_t status = 0 ;
651+ uint8_t * buffer = NULL ;
652+ uint32_t frame_len = 0 ;
653+ uint32_t buf_len = 0 ;
654+ esp_err_t ret ;
655+ while (1 ) {
656+ /* check if the task receives any notification */
657+ if (ulTaskNotifyTake (pdTRUE , pdMS_TO_TICKS (1000 )) == 0 && // if no notification ...
658+ gpio_get_level (emac -> int_gpio_num ) != 0 ) { // ...and no interrupt asserted
659+ continue ; // -> just continue to check again
660+ }
661+ /* read interrupt status */
662+ w5500_read (emac , W5500_REG_SOCK_IR (0 ), & status , sizeof (status ));
663+ /* packet received */
664+ if (status & W5500_SIR_RECV ) {
665+ status = W5500_SIR_RECV ;
666+ /* clear interrupt status */
667+ w5500_write (emac , W5500_REG_SOCK_IR (0 ), & status , sizeof (status ));
668+ do {
669+ /* define max expected frame len */
670+ frame_len = ETH_MAX_PACKET_SIZE ;
671+ if ((ret = emac_w5500_alloc_recv_buf (emac , & buffer , & frame_len )) == ESP_OK ) {
672+ if (buffer != NULL ) {
673+ /* we have memory to receive the frame of maximal size previously defined */
674+ buf_len = W5500_ETH_MAC_RX_BUF_SIZE_AUTO ;
675+ if (emac -> parent .receive (& emac -> parent , buffer , & buf_len ) == ESP_OK ) {
676+ if (buf_len == 0 ) {
677+ free (buffer );
678+ } else if (frame_len > buf_len ) {
679+ ESP_LOGE (TAG , "received frame was truncated" );
680+ free (buffer );
681+ } else {
682+ ESP_LOGD (TAG , "receive len=%u" , buf_len );
683+ /* pass the buffer to stack (e.g. TCP/IP layer) */
684+ emac -> eth -> stack_input (emac -> eth , buffer , buf_len );
685+ }
686+ } else {
687+ ESP_LOGE (TAG , "frame read from module failed" );
688+ free (buffer );
689+ }
690+ } else if (frame_len ) {
691+ ESP_LOGE (TAG , "invalid combination of frame_len(%u) and buffer pointer(%p)" , frame_len , buffer );
692+ }
693+ } else if (ret == ESP_ERR_NO_MEM ) {
694+ ESP_LOGE (TAG , "no mem for receive buffer" );
695+ emac_w5500_flush_recv_frame (emac );
696+ } else {
697+ ESP_LOGE (TAG , "unexpected error 0x%x" , ret );
698+ }
699+ } while (emac -> packets_remain );
700+ }
701+ }
702+ vTaskDelete (NULL );
703+ }
704+
592705static esp_err_t emac_w5500_init (esp_eth_mac_t * mac )
593706{
594707 esp_err_t ret = ESP_OK ;
@@ -631,6 +744,7 @@ static esp_err_t emac_w5500_del(esp_eth_mac_t *mac)
631744 emac_w5500_t * emac = __containerof (mac , emac_w5500_t , parent );
632745 vTaskDelete (emac -> rx_task_hdl );
633746 vSemaphoreDelete (emac -> spi_lock );
747+ heap_caps_free (emac -> rx_buffer );
634748 free (emac );
635749 return ESP_OK ;
636750}
@@ -677,6 +791,10 @@ esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, con
677791 BaseType_t xReturned = xTaskCreatePinnedToCore (emac_w5500_task , "w5500_tsk" , mac_config -> rx_task_stack_size , emac ,
678792 mac_config -> rx_task_prio , & emac -> rx_task_hdl , core_num );
679793 ESP_GOTO_ON_FALSE (xReturned == pdPASS , NULL , err , TAG , "create w5500 task failed" );
794+
795+ emac -> rx_buffer = heap_caps_malloc (ETH_MAX_PACKET_SIZE , MALLOC_CAP_DMA );
796+ ESP_GOTO_ON_FALSE (emac -> rx_buffer , NULL , err , TAG , "RX buffer allocation failed" );
797+
680798 return & (emac -> parent );
681799
682800err :
@@ -687,6 +805,7 @@ esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, con
687805 if (emac -> spi_lock ) {
688806 vSemaphoreDelete (emac -> spi_lock );
689807 }
808+ heap_caps_free (emac -> rx_buffer );
690809 free (emac );
691810 }
692811 return ret ;
0 commit comments