Semaphore between ISR and thread (Thread Waiting for the semaphore forever)

holim wrote on Thursday, June 15, 2017:


I’m working on a custom board with STM32F407 MCU.
The code was generated by CubeMX of ST Micro.
And it has FreeRTOS v8.2.3.

The issue resides in Ethernet side.
From a PC, I ping the custom board.
Ethernet communication is ok after reset.
But the traffic is blocked after some time (minutes or hours).
Only power reset resolves the situation.

From my investigation, I’ve found this issue is related with semaphore.
ISR (Interrupt Service Routine) releases the semaphore.
And ethernet thread obtains the semaphore to handle the frames.

When the problem happens, ISR continuously tries to release the semaphore,
but fails 'cause the semaphore is already full.
But the thread doesn’t receive the semaphore but seems to be suspended forever.
The thread stops LED blinking, which is fine until it blocks.

I tried replacing the semaphore in thread with osDelay(1). (1 ms Sleep).
Then the communication was OK for half a day.
But it shows a performance degradation of ethernet.

Please, refer to the following codes which is unchanged after being taken from CubeMX.

I also tested the counting semaphore with max count 10.
(Original code has binary semaphore.)

Count 10 is consumed very quickly.
And thread waits for the semaphore forever.

FreeRTOS v9.0 was also tried, but no change.

Any idea or suggestion will be greatly appreciated.

Thank you so much.

static void low_level_init(struct netif netif)

create a binary semaphore used for informing ethernetif of frame reception */
s_xSemaphore = osSemaphoreCreate(osSemaphore(SEM) , 1 );

/* create the task that handles the ETH_MAC */
osThreadDef(EthIf, ethernetif_input, osPriorityRealtime, 0, INTERFACE_THREAD_STACK_SIZE);
eth_input_handle = osThreadCreate (osThread(EthIf), netif);


void ethernetif_input( void const * argument )


struct pbuf *p;
struct netif *netif = (struct netif *) argument;

for( ;; )
if (osSemaphoreWait( s_xSemaphore, TIME_WAITING_FOR_INPUT)==osOK)
p = low_level_input( netif );
if (p != NULL)
if (netif->input( p, netif) != ERR_OK )
} while(p!=NULL);

rtel wrote on Thursday, June 15, 2017:

There are several things here which are out of our control. First you
are using the ST OS abstraction layer, rather than the native API, plus
(by the looks of it) lwIP which is not our code, the project was created
by the Cube tool, not us, etc. It is hard then to know if there are any
implementation issues within that whole stack of software.

The first thing you need to do is see what the task that ‘takes’ the
semaphore is actually doing rather than doing what it should be. You
might be able to make use of the trace tool, or just use the debugger,
to work that out.

From experience of all the other support requests I would say the most
common cause (by far) of similar problems is an incorrect priority
assignment. Keep with FreeRTOS V9 (as it has more asserts defined) and
ensure configASSERT() is defined. Does the assert ever
fail? Also, see the note about ensuring no subpriority bits are defined

If the interrupt priority settings are coming from the Cube software I
would expect them to be right though.

heinbali01 wrote on Thursday, June 15, 2017:

in addition to Richard remarks:

I also tested the counting semaphore with max count 10.
(Original code has binary semaphore.)

I think I would leave it to a binary semaphore. When the semaphore is set, it means that 1 or more packet segments have been received.

As you indicate, the problem is “caused” by the Ethernet task that hangs after a while.

Does that port check the Link Status ( LS ) of the PHY? As soon as the LS goes down, the device can not deliver its packets and it may block quite a while. Test: what happens if you unplug the device for a minute or so?

I don’t know how much time you already have invested in this lwIP project? You might want to have a look at FreeRTOS’s own TCP/IP stack here It has a good driver for both the STM32F4 and STM32F7.


holim wrote on Monday, June 19, 2017:

First of all, thank you for the answer.

OK. I agree that there are many softwares incorporated in my current application.
And it’s another reason to make it hard for me to debug this issue.
I also posted this issue on ST Micro, but it’s not solved yet.

Anyhow, according to your comment,
I did some more jobs on configASSERT and subpriority mechanism.
I added the following in my application and checked there’s no assertion error.

  1. define configASSERT( x ) if ((x) == 0) {term_printf(TPID_UART, “Assertion Failed, %s %d\r\n”, FILE, LINE );}
  2. NVIC_SetPriorityGrouping(NVIC_PriorityGroup_4);

If there’s anything more to check, please let me know.
It would help me a lot to resolve this issue.

holim wrote on Tuesday, June 20, 2017:

Thank you very much for your reply.

Ok. I will keep the semaphore as a binary one.

Current firmware doesn’t check the Link Status of PHY.
I tested the unplugging of LAN cable for a few minutes
and plugging the cable again to the port.
“Ping” was not replied while being unplugged
and replied some seconds after the cable is connected.
So, it seems to be working well for this case.

And according to your proposal,
I have ported FreeRTOS-Plus-TCP package (RTOS v9 with TCP) after removing LWIP package.
But it is quite strange that the same symptom is happening again.

When the issue happens, RBUS (Receive Buffer Unavailable Status) register is set,
which causes the MCU’s DMA not to handle any incoming frames since there’s no buffer.
At this moment, the frame handling task “prvEMACHandlerTask” should copy the frame
and release the buffer by changing the owner bit.
But the “prvEMACHandlerTask” does not seem to free the buffer successfully
so that MCU’s DMA waits forever for the buffer to be released for itself.

In my opnion, this seems to be a synchronization issue between DMA and a thread.

Anyhow, just to step forward, I changed some codes in “HAL_ETH_RxCpltCallback” as follows.

void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef *heth )
    BaseType_t xHigherPriorityTaskWoken = 0;
    ulISREvents |= EMAC_IF_RX_EVENT;
	if( xEMACTaskHandle != NULL )
		//vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
		//portYIELD_FROM_ISR( xHigherPriorityTaskWoken );

I just blocked the context switching from ISR for the task “prvEMACHandlerTask”.
This test code worked for 12 hours until now without problem.
But the ping is very slow since the task has a very low priority.
Please, note that from the tracing of previous firmware,
the task was suspended forever after executing the context swtiching.

portYIELD_WITHIN_API(); Line 1526 of Queue.C of FreeRTOS V8.2.3

				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
				prvUnlockQueue( pxQueue );
				if( xTaskResumeAll() == pdFALSE )
					portYIELD_WITHIN_API();  // !!!! Line 1526

                //queue.c -> Line 1526

I’m pinging from 5 consoles with the following command.
ping -t -l 1400
A bit large packet test actually.
But the problem also happens with one console of simple ping command (ping x.x.x.x).
It just take more time to reproduce the issue.

Well, this is just a ping test and should be working fine.
I also wonder if I am the only one who has this kind of issue.

Anyhow, please give me some more idea on this.

Thank you again.