Socket Recv Interrupt on Atmel SAMW25

mutty00 wrote on Sunday, August 21, 2016:

Hi,

I’m expecting a little issue using FreeRTOS on my project that uses TCP socket on a SAMW25 system.

Here follows a simplified stub of code I’m using. The first part is the callback function that handle received message interrupt, the second part is the task that manage the received message.

static void socket_cb(SOCKET sock, uint8_t u8Msg, void *pvMsg)
{
	switch (u8Msg) 
	{
	/* Message receive */
	case SOCKET_MSG_RECV:
	{
		tstrSocketRecvMsg *pstrRecv = (tstrSocketRecvMsg *)pvMsg;
		if (sock==tcp_client_socket) 
		{
		 if (pstrRecv && pstrRecv->s16BufferSize > 0) 
		 {
		  BaseType_t xHigherPriorityTaskWoken=pdFALSE;
              port_pin_set_output_level(LED_RED_KEY,false);    xTaskNotifyFromISR(xSerialTaskH,pstrRecv>s16BufferSize,eSetValueWithoutOverwrite,&xHigherPriorityTaskWoken ); 
		 } 
		 else 
		 {
		  close(tcp_server_socket);
		  tcp_server_socket = -1;
		 }
		}
	
	}
	break;

	default: break;
	}
}
static void Task(void *params)
{

 for (;;)	
 {	
  
  //Do Something
   
  portDISABLE_INTERRUPTS(); /// I added this to fix the issue.....
  recv(tcp_client_socket, TCPBuffer, sizeof(TCPBuffer), 0);
  xTaskNotifyWait( 0x00, ULONG_MAX, &ulSize, portMAX_DELAY ); 
  
  //endless repeat for incoming all messages
  
  }
 }

The problem I have is that if I’ve many pending messages on Wifi, as soon as recv function is called, interrupt is generated. If interrupt if executed BEFORE xTaskNotifyWait is completed, the xTaskNotifyFromISR called form ISR is not effective and task is never waked up. The only solution I’ve fond at the moment is to DISABLE INTERRUPT before calling recv and xTaskNotifyWait ( that atomatically re-enable them.

I’d like to know if there are other solution for this.

Thank you.

rtel wrote on Sunday, August 21, 2016:

Its is very hard to say as I don’t know which TCP/IP stack you are using, where the code comes from, how the driver is implemented, etc…but if I were to guess that socket_cb() is called from an interrupt then I would also guess that functions such as close() probably cannot be called from interrupts.

mutty00 wrote on Sunday, August 21, 2016:

Hi,

probably I’ve not explained very well my problem.
The question is not related to the specific TCP stack, is a more generic problem that I expected also in the past with FreeRTOS.

I try to provide you another example of more or less the same problem that I had on another project on AVR32 + FreeRTOS. In this case I have to read a 512 bytes sector from an SD card via SPI and DMA mode.Very simple operation, ho drivers of additional firmware library involved in this case.

Here follows the other example:

void vReadBlock(void *RamPointer)
{ 
  xMMCPDCAHandle = xTaskGetCurrentTaskHandle();
  
  AVR32_PDCA.channel[8].mar = (unsigned int)RamPointer;
  AVR32_PDCA.channel[8].TCR.tcv = 512;
  AVR32_PDCA.channel[8].CR.ten = 1; 
  
  AVR32_PDCA.channel[9].mar = (unsigned int)ucMMCBufferTX;
  AVR32_PDCA.channel[9].TCR.tcv = 512;
  __disable_interrupt();  ///<- !!!!!!!!! HERE I DISABLE INTERRUPT 
  AVR32_PDCA.channel[8].IER.trc = 1;
  AVR32_PDCA.channel[9].CR.ten = 1; 
  
  vTaskSuspend(NULL);
  
}

////////////////////////////////////////////////////////////////////////////////

#pragma optimize = no_inline
static portBASE_TYPE vSPI1RxCompletedISR( void )
{ 
  AVR32_PDCA.channel[8].IDR.trc = 1;
  AVR32_SPI1.CR.lastxfer = 1;
  portENTER_CRITICAL();
  xTaskResumeFromISR(xMMCPDCAHandle); 
  portEXIT_CRITICAL();
  AVR32_PDCA.channel[8].SR; //Dummy Read
  return pdFALSE;
}////////////////////////////////////////////////////////////////////////////////

The first function vReadBlock set and trigger the SPI DMA for SD Card reading ( pay attention only at the last 4 lines ): once DMA is triggered task suspend ifself waiting for operation completed.

The second function is the DMA interrupt that wakes vReadBlock when reading is completed.
( focus only in the xTaskResume function, other code is for DMA handling of AVR32)

Let’s look at vReadBlock: suppose that data block to read is only few bytes and SPI data rate very high, and suppose that system have to process many other interrupt request from other prefipherals. Suppose also that I skip __disable_interrupt()

  //__disable_interrupt();  
  AVR32_PDCA.channel[8].IER.trc = 1;
  AVR32_PDCA.channel[9].CR.ten = 1; 
  
  vTaskSuspend(NULL);

As soon as AVR32_PDCA.channel[9].CR.ten is executed DMA start tranfer. Suppose that now you have to serve some other interrupts that takes some times to be executed. ( suppose up to 10 ms )
Meantime DMA transfer is for sure completed and vSPI1RxCompletedISR is called and executed.
xTaskResumeFromISR(xMMCPDCAHandle) inside ISR is also executed.
Afted this execution of vReadBlock restarts and vTaskSuspend is executed, locking the task forever. ( because xTaskResume was already hit from DMA ISR )

This is avoided if i temporarly disable any int ( just for the time to execute 3rd and part of 4th code row :

  __disable_interrupt();  
  AVR32_PDCA.channel[8].IER.trc = 1;
  AVR32_PDCA.channel[9].CR.ten = 1; 
  
  vTaskSuspend(NULL);

I hope now is more clear.

There is some other way to do that ??

davedoors wrote on Sunday, August 21, 2016:

Dont use task suspends to trigger a task, see http://www.freertos.org/taskresumefromisr.html

mutty00 wrote on Monday, August 22, 2016:

Ok Dave. Seems to be fine.

Thanks.