Handle several sockets (W5500 TCP stack)

Hi guys,

I got a pcb with an STM32, an ethernet module W5500 and the firmware is using the tcp/ip stack provided by wiznet.

I need to open two sockets, one for the MQTT comms and another one for the MODBUS TCP each of them on a separated task, so I was planning to use a mutex to make the tcp socket thread safe (see img).

Mi question is: Where shall I put the mutex? Since the socket uses a number of different functions (Open, Close, Send, Recv,…) shall I use one unique mutex that limits the use of all the functions to one task? or should I use one mutex for each function?

Also, if the Modbus task has got the control of the peripheral and I receive data for the MQTT, will I loose the data or, as the sockets are different the TCP/IP stack will handle that?

Thanks
Diego B

I’m afraid that your question doesn’t have much to do with FreeRTOS.

But intuitively, I would say yes: multiple sockets can be used because the TCP/IP is responsible for the synchronicity, as long as a socket is owned and used by a single task.

Hi htibosch,

Thanks for your answer.

Maybe I didn’t explain myself very well in my original post but what I’m trying to work out is how to call the socket functions (open, send, recv) from two different tasks without causing any conflicts if both tasks are trying to use the ethernet port at the same time.

I believe I need to use a mutex to prevent one task trying to use the port whilst it’s being used by another task. And I also think that the best place to use that mutex is in the socket functions.

It isn’t about the specific hardware or libraries that I’m using, but about how to integrate them with FreeRTOS, if that makes sense?

Regards,
Diego B

Hi Litan,

we need to distinguish between different issues here. There is no problem using different sockets in different tasks, ie if one task serves socket a and another one serves b, they will never interfere with each other.

You can also serve multiple sockets in the same thread but you may have convoy problems then.

The one interesting scenario is trying to serve the same socket from multiple tasks. That is rarely done, mostly because most protocols are inherently half duplex, meaning you do not gain a whole lot from multiple tasks because they would need to get fully serialized anyways.

If your protocol allows for concurrent access (ie reading and writing from different tasks - it is easy to see that reading from multiple tasks to the same socket must lead to chaos), I believe you are fine with FreeRTOS+TCP - unlike, eg, Lwip which does not support that. But normally it is hard to find a scenario where 1:many works satisfactorily (that exists, but is out of place here).

Hi RAc,

In my case it would be just two task opening one socket each. There isn’t multiple sockets in a task or anything like that. The actual problem is how to make sure that both task don’t try to use the physical layer at the same time.

If I have:

Task_1 → socket_a (ip1, port1)
Task_2 → socket_b (ip2,port2)

And then both tasks try to transmit at the same time, I can see that both tasks have their own socket but are trying to use the same peripheral. That’s going to be a problem isn’t it?

I understand that the FreeRTOS TCP stack is thread safe, but since I’m using a 3rd party library I will need to take care of that myself. I’m just trying to figure out how to.

Regards,
Diego B

You won’t need to worry abut that, it’s already being taken care of by the lower end of the networking software. Otherwise very very few software packets using networking would work at all… :wink:

But in this case the lower end is using an SPI port, I’m not sure that’s going to work without any mutex.

I’ll give it a go and see how it goes.

Thanks for your help.
Diego B

So who wrote the networking software if it’s not FreeRTOS? What does the driver model/SPI driver look like? Without knowing that, there is no chance we can take at guess as to whether there is a problem or not.

On all TCP/IP stacks I’ve ever come across, the back end abstracts away the phyical layer interface and ensures that output is serialized properly, either by queueing frames to be transmitted in a dedicated thread, or by using an “OS local mutex” or other mechanisms. I can’t see how application software would ever want/have to interfere withg that.

Hi RAc,

The TCP/IP is embedded in the ethernet module that I’m using, that’s why I’m not using the FreeRTOS TCP stack. You can read a quick description following this link if you are curious:

https://www.wiznet.io/product-item/w5500/#:~:text=The%20W5500%20chip%20is%20a,100%20Ethernet%20MAC%20and%20PHY.

So they provide a library with some functions that effectively are just writing SPI commands to the module which is in charge of the sockets and networking software as you said.

I just found that their library implements two functions (WIZCHIP_CRITICAL_ENTER and WIZCHIP_CRITICAL_EXIT) to make it OS compatible so that should do the job.

Thanks for your help.
Diego B.

I took a quick look at the library and it seems that you need to register 2 callback functions with the library - ioLibrary_Driver/wizchip_conf.h at master · Wiznet/ioLibrary_Driver · GitHub

The two functions, namely cris_en and cris_ex can be implemented using FreeRTOS mutex.

That was it, thanks very much for looking into it.

By the way, I’ve changed the topic name since this became very specific to the ethernet module that I’m using so it’s easier for other people to land here if they’re having the same problem.

i have similar trouble with RTOS and W5500 ioLibrary but i cant image how to solve that .Can i see ur callback fuctions with mutex
Tks u very much

In the w5500_io.c file when you initialise the callback functions for writing and reading you need to declare the two functions to take and give the mutex.

SemaphoreHandle_t spi2_Semaphore;		/* spi2 Mutex Handle */

int w5500_io_init() {

  //register spi functions
  reg_wizchip_cs_cbfunc(w5500_io_csSel, w5500_io_csDesel);
  reg_wizchip_spi_cbfunc(w5500_io_spiRead8, w5500_io_spiWrite8);
  reg_wizchip_spiburst_cbfunc(w5500_io_spiRead, w5500_io_spiWrite);

  if ( spi2_Semaphore == NULL ){
	spi2_Semaphore = xSemaphoreCreateMutex();
  }
  /* Assumes the semaphore was created successfully and
  can be used. */
  reg_wizchip_cris_cbfunc(w5500_io_enCritical, w5500_io_exCritical);

  if(wizchip_init(NULL, NULL) != 0) return -1;
  return 0;
}

Then all you need to do is declare those two functions to take and give a previously created mutex.

void w5500_io_enCritical(){

	if ( spi2_Semaphore != NULL ){
		xSemaphoreTake( spi2_Semaphore, portMAX_DELAY );
	}
}

void w5500_io_exCritical(){

      if ( spi2_Semaphore != NULL ){
	      xSemaphoreGive( spi2_Semaphore );
      }
}

it still not working.Maybe it got other problem.
Tks u very much