stm32-community / stm32-enc28j60

An ENC28J60 (cheap ethernet module) library for STM32 projects
62 stars 26 forks source link

Speed of communication too slow #12

Open gdavid2 opened 6 months ago

gdavid2 commented 6 months ago

Hi !

I was trying to use this library to communicate in TCP from a STM32F103C8 MCU (the bluepill board) to my computer, but I am facing a communication speed issue.

My LAN is a switch, some PCs and the MCU, all connected by cables ofc. I am using the ENC28J60 as my Ethernet shield and I was trying to ping the board with my computer. See the file attached. image (the first while(1) was for testings, and the second is the real loop. In this second loop the only thing done was to call the function packetloop_icmp_tcp().)

My PC is able to send pings and receive pongs from the board, but with 500 ms delay on average. Also my PC is able to ping other PCs with 1 ms delay on average.

I tried to monitor the time that elapses through the function packetloop...() with HAL_GetTick(), it was about 150 ms. I also tried to vary the SPI rate from 281kb/s to 18Mb/s to see if it has an effect on the ping delay but I couldn't see any difference. I'm currently working to use DMA.

I think it's normal that the communication cannot be as quick as between PCs because of the clock frequency of the MCU is only 72 MHz compared to GHz's PC clock frequency, but is this the performance I can expect or can I hope for better ? And if I can hope for better how can I improve my results ?

Thank you for reading :)

xaionaro commented 6 months ago

Hey.

My PC is able to send pings and receive pongs from the board, but with 500 ms delay on average. Also my PC is able to ping other PCs with 1 ms delay on average.

Yeah, the driver is by design very slow. I initially needed it to send temperature and other low-bandwidth sensor data. And I never thought it'd become so popular, so I was completely fine with low speed back then :( For example, it manually toggles the CS pin to read or/and write every couple of bytes. And the CS latency is by default 2ms: https://github.com/stm32-libs/stm32-enc28j60/blob/51e00328bda610f7e58a1935b68ac132e99d9977/inc/enc28j60.h#L33

You can partially mitigate the problem by setting ETHERNET_CS_DELAY around 1000 (and try to play with this value to see where is the optimal trade off between performance and stability).

But if only somebody could invest time into making it to use hardware SPI instead of this software unoptimized SPI, it could drastically improve the performance (and stability on high speeds).

gdavid2 commented 6 months ago

Hi,

Thank you for your answer !

I'm looking towards using interrupts or DMA to see if will improve anything. I hope I'll find some results 🤞

I'll keep you updated

DtNeo commented 5 months ago

Hello,

Experience of the week : DMA : No success for a standard configuration on my STM32F407ZGT6 - board : FK407M2-ZGT6 I think this is the library that is not suitable for DMA. I'm not expert enough for changing this here. I hope be better in the next few months because I have 5 module of ENC28J60 to optimize in my projects :smile:

PING : # define ETHERNET_CS_DELAY 1000 I have an average of 12ms with the ping, but it's recent, I don't know if this will break or be unstable.

# define ETHERNET_CS_DELAY 2 I had 500ms of ping

# define ETHERNET_CS_DELAY 1 I had 400ms of ping

# define ETHERNET_CS_DELAY 0 I had 150ms of ping

I will work on WOL and TCP.

Have fun

EDIT : I forgot to mention the "interrupt" functionality. It seems not to be working as I expected. I receive interrupts from the ENC28J60 pin, but only when this line of code is executed: ES_packetloop_icmp_tcp(packet, ES_enc28j60PacketReceive(NET_BUF_SIZE, packet));

This implies that I must check if a packet is available for analysis, and it seems there is always a packet in the network, which triggers the interrupt. Perhaps we need to implement a filter to determine the relevance of the packet before initiating a meaningful interrupt.

I still need to consider this further.

gdavid2 commented 5 months ago

Hey!

But if only somebody could invest time into making it to use hardware SPI instead of this software unoptimized SPI, it could drastically improve the performance (and stability on high speeds).

I did this : image image image

With 500kB/s baud rate I have 6us between two spi frames and the cs\ is up for 2us. Maybe there is better but i found this handy.

image image Also, I use a pin of the uC on an EXTI line that calls this callback.

I obtained a ping in 5ms.

I've also implemented interrupts and dma handling, but performances aren't here :/ (same perfs as blocking mode) I'm going to forget about interrupts because code will become hard to read and to understand. 5ms is enough for me.

xaionaro commented 5 months ago

O, wow! This would be a drastic improvement. Would you publish a PR?

gdavid2 commented 5 months ago

Hey!

I would like to :-) So i tried to test it in a new project to verify before PR if it works and I faced an issue : if you call the socket in the main it won't work. I can't figure out why.

In an EXTI callback it works fine for me and I think it's better to do so. I could take some time to do a tutorial on how to use the enc28j60 with its interrupt pin and how to manage the callback and .ioc in a readme if u're also ok with that ?

DtNeo commented 4 months ago

Hello,

Here are my updates from last week! And thank you @gdavid2 for your work, it's help me a lot !

Average ping is 4.57 ms with NSS Output Signal, no interrupt, no DMA, SPI prescaler at 2 (although this seems unstable); ChatGPT informed me that the ENC28J60 module could achieve between 1 and 2 ms; And I haven't tested the stability or handled a large amount of data yet.

I am working on a v3 branch, which will take some time but should assist new users:

I still need to work on DMA, WOL, interrupts, the web server... For example, I would like to read logs in HTML, but I am not sure if it's possible, how to do it, or if an SD card is needed to store logs. Actualy I have log via UDP on a distance server.

Regarding the NSS Output Signal, there's not much to change in the current code. CS needs to be changed on the SPI to be the NSS Output signal. In the enc28j60.h file, just use the code for NSS and not for CS.

#ifdef CS_Only
#if ETHERNET_CS_DELAY >= 10
#define ETHERNET_CS_DELAY_PROC {volatile uint32_t i=ETHERNET_CS_DELAY; while(i--);}
#else
#define ETHERNET_CS_DELAY_PROC Delay(ETHERNET_CS_DELAY)
#endif

#define disableChip  ETHERNET_CS_GPIO->BSRR = ETHERNET_CS_PIN;\
    ETHERNET_LED_GPIO->BSRR = ETHERNET_LED_PIN << 16;\
    ETHERNET_CS_DELAY_PROC;
#define enableChip   ETHERNET_CS_GPIO->BSRR = ETHERNET_CS_PIN<<16;\
    ETHERNET_LED_GPIO->BSRR = ETHERNET_LED_PIN;\
    ETHERNET_CS_DELAY_PROC;
#endif

#ifdef NSS_OutputSignal
#define disableChip __HAL_SPI_DISABLE(hspi);
#define enableChip __HAL_SPI_ENABLE(hspi);
#endif

I used #ifdef CS_Only and #ifdef NSS_OutputSignal in the new v3 code to help people choose between CS and NSS.

The code of this project has a lot of features, and must of time, I just need to uncoment or complete it. For example, the way the code automatically handles return (UDP_DATA_P); in thepacketloop_icmp_tcp function.

Have fun !

gdavid2 commented 4 months ago

Hi !

Nice to see we're a lot working with this driver :D

I see you defined enableChip with __HAL_SPI_ENABLE() function. It is not necessary because it is done in the HAL implementation like HAL_SPI_TransmitReceive(). So the uC is enabling the SPI peripheral two times in a row with the code you shown. I personally defined enableChip as 0 and it works well.

I've been working on a TCP server socket recently, work in progess ;-)

See u soon !

DtNeo commented 4 months ago

Hello,

I will test without it to see. Thank you.

Regarding TCP, have you had any success? I've been stuck for days. It seems that the checksum is wrong, but I need more time and tests to understand it.

I am working on a v3 with a lot of changes, probably too many.

gdavid2 commented 4 months ago

The TCP server socket I wrote is able to respond to ARP and ICMP, and is also able to accept one TCP client to connect, but it is still really unstable and lacks lots of features like disconnection and connection refreshing.

I will need to put some effort into this 😢

DtNeo commented 4 months ago

I give up on TCP/HTTP. I just spent my whole week working on an HTTP request with TCP, but it seems my client doesn't accept the ACK-SYN from the STM32. I'm putting v3 on standby. I have a lot to do, and I hope to find some time to organize all of these functions better.

xaionaro commented 4 months ago

@DtNeo you could push it anyway. We can keep it as experimental here. May be (though unlikely) somebody else will find time to complete it :)

xaionaro commented 4 months ago

@gdavid2 you could also push what you already have (let's make one more branch).

DtNeo commented 4 months ago

Hello, just a few general pieces of information. I'm not used to doing PRs, but I will do my first one here in this project

I need more weeks because I want to do it right. I want to explain my new organization too, as I deleted some files and added more. The ip_arp_udp_tcp.c file is too big and mixes a lot of things. So, it will be split into specific files: net.c, udp.c, tcp.c, dns.c, websrv.c, and packet.c.

The packet.c file will handle the general treatment of web packets because this function "packetloop_icmp_tcp" is very tricky.

I created : defines.c, NTP, RTC, LogManager, and packet files for this new v3, it's a lot to handle.

Currently, we define the type of code we want, such as "TCP_Client" or "WWW_client"... I would like to "disable" code and be able to delete some files. For example, if we want only the UDP part, we should be able to delete files like TCP, websrv, and RTC... So, there's still a lot to do, and we will release a v3 beta for extensive testing. I want to test this code on STM32F407, STM32F411, and STM32H7237.

Probably all summer so don't worry, I will come back with more code !

DtNeo commented 4 months ago

Hello, just for info : this product : AliExpress WeAct Studio seller

MCU STM32F446RET HSE 180Mhz (Crystal Clock at 8Mhz) PRESCALER at 2 NSS output on pin A4 ping at 1.70ms

DtNeo commented 1 month ago

Hello,

I finally sent the PR! Sorry for the delay. 😅

Regarding this issue, I think we can close it. The ping is no longer an issue. It initially depended on NSS and then on the MCU's MHz.

New issues might arise with this v3 branch, so stay tuned!

Have fun!