No Transmission on SAMV71

rkyrk wrote on Wednesday, February 28, 2018:

Almost a duplicate of Tom Walsh post on the transmission issue with SAME70.
For my project we are using a Atmel SAMV71 Xplain Ultra and FreeRTOS + TCP.
As a base we chose the board specific examples provided by Atmel studio and upgraded the FreeRTOS version to 10 (8x as default i think).

We can see incoming messages being sent over the link in the embedded debugger and that we try to respond or send packages of our own (DHCP etc), but we cannot pick up any outgoing messages with wireshark or from the router logs.
Hence we get no IP address to the board and are somewhat stuck in our project.

Same issue arises from other examples like LWIP – we can see no errors from the debbuger, it states that its DHCP but times out and sets static ip – none are shown in wireshark or picked up by router logs.

As students with little debbuging experience we are unsure where to even look for the faults – concerning as well as the examples states that they are plug-and-play(lack for better woring) and good starting plattforms for projects.

Software
FreeRTOS
FreeRTOS PLus TCP
network driver recommended on avrfreaks forum: (We have tested with the default also)
https://github.com/jtbr/FreeRTOS-TCP_SAMV71_NetIntf/blob/master/NetworkInterface.c

“Log” from the embedded debugger

-- Freertos Example --

-- SAMV71-XLTRA

-- ATSAMV71Q21B
-- Compiled: Feb 23 2018 11:00:19 --

Network buffer initialized.
Determine the first anonymous TCP port number to get assigned.
prvIPTask started
GMACInit started...
xGMACWaitLS: 1 (PHY 1) periph freq 150 Mhz
Network buffers: 60 lowest 60
Polling RX-Event...
pxGetNetworkBufferWithDescriptor.
Network buffers: 59 lowest 59
prvInitialiseDHCP: start after 250 ticks
pxGetNetworkBufferWithDescriptor.
vDHCPProcess: discover
gmac_start_transmission called.
Packet is sent to the network.
pxGetNetworkBufferWithDescriptor.
vDHCPProcess: discover
vDHCPProcess: timeout 10000 ticks
gmac_start_transmission called.
Packet is sent to the network.
pxGetNetworkBufferWithDescriptor.
vDHCPProcess: discover
vDHCPProcess: timeout 20000 ticks
gmac_start_transmission called.
Packet is sent to the network.
pxGetNetworkBufferWithDescriptor.
vDHCPProcess: discover
vDHCPProcess: timeout 40000 ticks
gmac_start_transmission called.
Packet is sent to the network.
pxGetNetworkBufferWithDescriptor.
vDHCPProcess: discover
vDHCPProcess: timeout 80000 ticks
gmac_start_transmission called.
Packet is sent tNetwork buffers: 58 lowest 58
o the network.
Network buffers: 59 lowest 58
vDHCPProcess: giving up 160000 > 120000 ticks
Network UP.
Machine info:
 IP Address = 192.168.0.9 
 MAC Address = FC C2 3D 12 1B 82 
pxGetNetworkBufferWithDescriptor.
Generating ARP request.
gmac_start_transmission called.
Packet is sent to the network.
pxGetNetworkBufferWithDescriptor.
Generating ARP request.
gmac_start_transmission called.
Packet is sent to the network.
pxGetNetworkBufferWithDescriptor.
Generating ARP request.
Returning GMAC_TX_BUSY
Unsuccessful packet send
pxGetNetworkBufferWithDescriptor.
Generating ARP request.
Returning GMAC_TX_BUSY
Unsuccessful packet send

Any hits/help is very welcome
Thanks for your time
Regards,

Robert & Karl

rkyrk wrote on Wednesday, February 28, 2018:

[reserving this spot if i need to upload any code or other relevant information]

heinbali01 wrote on Wednesday, February 28, 2018:

Hi Robert, Karl, what we found earlier is that the GMAC of a SAME70 has 3 priority queues. Even if you only use one priority queue, the others must be set-up to point to a valid DMA descriptor.

For SAME70, we added the following:

#if( SAME70 != 0 )
	COMPILER_ALIGNED(8)
	static gmac_tx_descriptor_t gs_tx_desc_null;
#endif

and later on:

	#if( SAME70 != 0 )
	{
		gmac_set_tx_priority_queue(p_hw, (uint32_t)&gs_tx_desc_null, GMAC_QUE_1);
		gmac_set_tx_priority_queue(p_hw, (uint32_t)&gs_tx_desc_null, GMAC_QUE_2);
	}

The SAM V7 has more than 3 priority queues, and they probably must all be set to point to an empty descriptor.

DHCP and testing: I would recommend to switch off DHCP and supply a fixed IP-address. The stack will send so-called gratuitous ARP packets every 20 seconds:

    #define arpGRATUITOUS_ARP_PERIOD    ( pdMS_TO_TICKS( 20000 ) )

ARP packets should arrive on every node ( laptop ) on a LAN and can be seen in Wireshark.
You can easily filter ARP packets with the word “arp”.

How about memory caching? Remember that DMA has direct access to the memories, it works beyond the caching system. So just before starting a transmission, the memories invoved should be flushed.
Or, an easier solution while testing: switch off all memory caching for all RAM(s).

Please keep us up-to-date about your progress, I’m very curious. Thanks!

rkyrk wrote on Monday, March 05, 2018:

Thanks for the reply Hein!
With the suggested changes we can set a static IP and the traffic is visiable on wireshark.
However the router does not recognize the device, as it would with lets say a Raspberri or other computer(I.e showns as a “connected device” in the router admin panel).
But when we can ping the device with normal respons and all traffic looks good.
DHCP still does not work – we get a offer of an IP from the router but something happens with the package that we are uncertain of – but we think it has somerthing to do with the FreeRTOS_recfrom function, it always return 0 or -11.

A big step in the right direction anyways :slight_smile:
Thanks again!

/*-----------------------------------------------------------*/

/*
 * FreeRTOS_recvfrom: receive data from a bound socket
 * In this library, the function can only be used with connectionsless sockets
 * (UDP)
 */
int32_t FreeRTOS_recvfrom( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength )
{
BaseType_t lPacketCount = 0;
NetworkBufferDescriptor_t *pxNetworkBuffer;
FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
TickType_t xRemainingTime = ( TickType_t ) 0; /* Obsolete assignment, but some compilers output a warning if its not done. */
BaseType_t xTimed = pdFALSE;
TimeOut_t xTimeOut;
int32_t lReturn;
EventBits_t xEventBits = ( EventBits_t ) 0;

	if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_UDP, pdTRUE ) == pdFALSE )
	{
		return -pdFREERTOS_ERRNO_EINVAL;
	}

	lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );

	/* The function prototype is designed to maintain the expected Berkeley
	sockets standard, but this implementation does not use all the parameters. */
	( void ) pxSourceAddressLength;

	while( lPacketCount == 0 )
	{
		if( xTimed == pdFALSE )
		{
			/* Check to see if the socket is non blocking on the first
			iteration.  */
			xRemainingTime = pxSocket->xReceiveBlockTime;

			if( xRemainingTime == ( TickType_t ) 0 )
			{
				#if( ipconfigSUPPORT_SIGNALS != 0 )
				{
					/* Just check for the interrupt flag. */
					xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_INTR,
						pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK );
				}
				#endif /* ipconfigSUPPORT_SIGNALS */
				break;
			}

			if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 )
			{
				break;
			}

			/* To ensure this part only executes once. */
			xTimed = pdTRUE;

			/* Fetch the current time. */
			vTaskSetTimeOutState( &xTimeOut );
		}

		/* Wait for arrival of data.  While waiting, the IP-task may set the
		'eSOCKET_RECEIVE' bit in 'xEventGroup', if it receives data for this
		socket, thus unblocking this API call. */
		xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_RECEIVE | eSOCKET_INTR,
			pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );

		#if( ipconfigSUPPORT_SIGNALS != 0 )
		{
			if( ( xEventBits & eSOCKET_INTR ) != 0 )
			{
				if( ( xEventBits & eSOCKET_RECEIVE ) != 0 )
				{
					/* Shouldn't have cleared the eSOCKET_RECEIVE flag. */
					xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_RECEIVE );
				}
				break;
			}
		}
		#else
		{
			( void ) xEventBits;
		}
		#endif /* ipconfigSUPPORT_SIGNALS */

		lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );

		if( lPacketCount != 0 )
		{
			break;
		}

		/* Has the timeout been reached ? */
		if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) )
		{
			break;
		}
	} /* while( lPacketCount == 0 ) */

	if( lPacketCount != 0 )
	{
		taskENTER_CRITICAL();
		{
			/* The owner of the list item is the network buffer. */
			pxNetworkBuffer = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) );

			if( ( xFlags & FREERTOS_MSG_PEEK ) == 0 )
			{
				/* Remove the network buffer from the list of buffers waiting to
				be processed by the socket. */
				uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
			}
		}
		taskEXIT_CRITICAL();

		/* The returned value is the data length, which may have been capped to
		the receive buffer size. */
		lReturn = ( int32_t ) pxNetworkBuffer->xDataLength;

		if( pxSourceAddress != NULL )
		{
			pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
			pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
		}

		if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 )
		{
			/* The zero copy flag is not set.  Truncate the length if it won't
			fit in the provided buffer. */
			if( lReturn > ( int32_t ) xBufferLength )
			{
				iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - lReturn ) );
				lReturn = ( int32_t )xBufferLength;
			}

			/* Copy the received data into the provided buffer, then release the
			network buffer. */
			memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ), ( size_t )lReturn );

			if( ( xFlags & FREERTOS_MSG_PEEK ) == 0 )
			{
				vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
			}
		}
		else
		{
			/* The zero copy flag was set.  pvBuffer is not a buffer into which
			the received data can be copied, but a pointer that must be set to
			point to the buffer in which the received data has already been
			placed. */
			*( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ) );
		}

	}
#if( ipconfigSUPPORT_SIGNALS != 0 )
	else if( ( xEventBits & eSOCKET_INTR ) != 0 )
	{
		lReturn = -pdFREERTOS_ERRNO_EINTR;
		iptraceRECVFROM_INTERRUPTED();
	}
#endif /* ipconfigSUPPORT_SIGNALS */
	else
	{
		lReturn = -pdFREERTOS_ERRNO_EWOULDBLOCK;
		iptraceRECVFROM_TIMEOUT();
	}

	return lReturn;
}

rkyrk wrote on Monday, March 05, 2018:

Update:
Setting FreeRTOS_ZERO_COPY to 0 made DHCP work and we are visiable in the router admin panel as a connected device. looks good!

We do how ever not respond to future ARP request (router asking who has xxx ip – our ip address).

Looking into this now.

heinbali01 wrote on Monday, March 05, 2018:

We do how ever not respond to future ARP request
(router asking who has xxx ip – our ip address).

Isn’t that the so-called gratuitous ARP-request that your are seeing? It comes from your device every 20 seconds. That ARP request is actually a question like: “does any device happen to have the same IP-address as I have?”

Can you ping you device now? Ping also uses one ARP request to find the MAC-address of your device