AVR32 UART to Ethernet Performance

mrprotokoll wrote on Thursday, October 11, 2012:

Hi,

i have an EVK1100 from Atmel and have tried to build a serial to ethernet bridge, starting from the ASF sample project (lwip + FreeRTOS Example from the Atmel Studio 6). I have made some changes to support up to 4 serial interfaces (running at 921.600 baud) which lead to 4 separate TCP/IP ports.

Everything is running quite well if there is only less traffic. After that i have connected some measurement systems to the serial ports (each systems has a sample rate of 4 kHz. and each data packet consist of 16 Bytes resulting in a data throughput of 64 kBytes / second). But the AVR seems to be overloaded by those measurement systems. So i have made some test but the best result i can get where 2 channels running without data loss. If i connect more channels, there will be a massive data loss on the serial side.

Can Someone give me some hints, what i could change to improve the performance.

rtel wrote on Thursday, October 11, 2012:

Well, I don’t know your code, or how you have implemented your serial drivers, so I can only give generic hints.  The most efficient way of implementing the drivers will be to use a DMA.  That way the Rx can be left running all the time with little CPU overhead, and the Tx can be zero copy (again with little overhead) and the CPU can get on and do other processing while both the Rx and Tx are in process.

Don’t try doing anything slow, like using message queues to pass characters into and out of the UART interrupts.

Regards.

mrprotokoll wrote on Thursday, October 11, 2012:

I have used the original serial drivers, which had come with the project ( http://support.atmel.no/knowledgebase/avr32studiohelp/AT32UC3B_Software_Framework/SERVICES/FREERTOS/Demo/AVR32_UC3/DOC/html/serial_8c-source.html ). And as far as i can see, they are using queues from FreeRTOS.

I think i have to write my own serial driver, but i can’t use DMA, because the measurement systems can be configured at run time, so there is not allways a fixed data packet legth.

mrprotokoll wrote on Thursday, October 11, 2012:

Sorry, was the wrong link. I can’t find the correct one.

Only the init sequence seems to be different, so i will post he correct one here. I have made some extension to the code to handle those 4 serial interfaces.

/*!
 * \brief Init the serial port.
 * \param UsartId The identifier of the Usart to init.
 * \param ulWantedBaud The required baudrate.
 * \param uxRxQueueLength The length of the Rx buffer (if 0, rx is not supported).
 * \param uxTxQueueLength The length of the Tx buffer (if 0, tx is not supported).
 * \return xComPortHandle Handler on the COM port.
 */
xComPortHandle xUsartInit( eCOMPort UsartId, unsigned portLONG ulWantedBaud,
                           unsigned portBASE_TYPE uxRxQueueLength,
                           unsigned portBASE_TYPE uxTxQueueLength)
{
  xComPortHandle    xReturn;
  xUsartPrivateData *pxUsart;
  int               UsartRxEnMask = ((uxRxQueueLength==0) ? 0 : AVR32_USART_CR_RXEN_MASK);
  int               UsartTxEnMask = ((uxTxQueueLength==0) ? 0 : AVR32_USART_CR_TXEN_MASK);
  int               iTempoStatus;
  // USART options.
  usart_options_t USART_OPTIONS =
  {
    .baudrate     = 57600,
    .charlength   = 8,
    .paritytype   = USART_NO_PARITY,
    .stopbits     = USART_1_STOPBIT,
    .channelmode  = USART_NORMAL_CHMODE
  };
  USART_OPTIONS.baudrate = ulWantedBaud;
//  xReturn = pxUsart = (UsartId == serCOM1 ? &xUsart0 : &xUsart1);
	if (UsartId == serCOM1)
	{
		pxUsart = &xUsart0;
		xReturn = pxUsart;
	}
	if (UsartId == serCOM2)
	{
		pxUsart = &xUsart1;
		xReturn = pxUsart;
	}
	if (UsartId == serCOM3)
	{
		pxUsart = &xUsart2;
		xReturn = pxUsart;
	}
	if (UsartId == serCOM4)
	{
		pxUsart = &xUsart3;
		xReturn = pxUsart;
	}
	
  /* Create the rx and tx queues. */
  iTempoStatus =  iprvSerialCreateQueues( uxRxQueueLength, &(pxUsart->xRxedChars),
                          uxTxQueueLength, &(pxUsart->xCharsForTx) );
  /* Configure USART. */
  if( ( iTempoStatus != pdFAIL ) &&
      ( ulWantedBaud != ( unsigned portLONG ) 0 ) )
  {
    portENTER_CRITICAL();
    {
      /**
       ** Configure USART.
       **/
      /* Enable USART RXD & TXD pins. */
      if(UsartId == serCOM1)
      {
        if(uxRxQueueLength)
		{
          gpio_enable_module_pin(AVR32_USART0_RXD_0_1_PIN, AVR32_USART0_RXD_0_1_FUNCTION);
//			gpio_enable_module_pin(AVR32_USART0_RXD_0_0_PIN, AVR32_USART0_RXD_0_0_FUNCTION);
		}
        if(uxTxQueueLength)
		{
          gpio_enable_module_pin(AVR32_USART0_TXD_0_1_PIN, AVR32_USART0_TXD_0_1_FUNCTION);
//			gpio_enable_module_pin(AVR32_USART0_TXD_0_0_PIN, AVR32_USART0_TXD_0_0_FUNCTION);
		}
      }
      if(UsartId == serCOM2)
      {
        if(uxRxQueueLength)
		{
          gpio_enable_module_pin(AVR32_USART1_RXD_0_1_PIN, AVR32_USART1_RXD_0_1_FUNCTION);
//          gpio_enable_module_pin(AVR32_USART1_RXD_0_0_PIN, AVR32_USART1_RXD_0_0_FUNCTION);
		}		  
        if(uxTxQueueLength)
		{
          gpio_enable_module_pin(AVR32_USART1_TXD_0_1_PIN, AVR32_USART1_TXD_0_1_FUNCTION);
//          gpio_enable_module_pin(AVR32_USART1_TXD_0_0_PIN, AVR32_USART1_TXD_0_0_FUNCTION);
		}		  
      }
      if(UsartId == serCOM3)
      {
	      if(uxRxQueueLength)
	      gpio_enable_module_pin(AVR32_USART2_RXD_0_1_PIN, AVR32_USART2_RXD_0_1_FUNCTION);
	      if(uxTxQueueLength)
	      gpio_enable_module_pin(AVR32_USART2_TXD_0_1_PIN, AVR32_USART2_TXD_0_1_FUNCTION);
      }
      if(UsartId == serCOM4)
      {
	      if(uxRxQueueLength)
	      gpio_enable_module_pin(AVR32_USART3_RXD_0_1_PIN, AVR32_USART3_RXD_0_1_FUNCTION);
	      if(uxTxQueueLength)
	      gpio_enable_module_pin(AVR32_USART3_TXD_0_1_PIN, AVR32_USART3_TXD_0_1_FUNCTION);
      }
      // Initialize USART in RS232 mode.
      usart_init_rs232(pxUsart->usart, &USART_OPTIONS, CP_PBA_SPEED);
      /* We're not fully done yet: disable receiver and transmitter. */
      pxUsart->usart->cr |= AVR32_USART_CR_RXDIS_MASK | AVR32_USART_CR_TXDIS_MASK;
      // Register the USART interrupt handler to the interrupt controller and
      // enable the USART interrupt.
      if(UsartId == serCOM1)
      	INTC_register_interrupt((__int_handler)&vUSART0_ISR, AVR32_USART0_IRQ, AVR32_INTC_INT2);
      if(UsartId == serCOM2)
      	INTC_register_interrupt((__int_handler)&vUSART1_ISR, AVR32_USART1_IRQ, AVR32_INTC_INT3);
      if(UsartId == serCOM3)
		INTC_register_interrupt((__int_handler)&vUSART2_ISR, AVR32_USART2_IRQ, AVR32_INTC_INT1);
      if(UsartId == serCOM4)
		INTC_register_interrupt((__int_handler)&vUSART3_ISR, AVR32_USART3_IRQ, AVR32_INTC_INT1);
      /* Enable USART interrupt sources (but not Tx for now)... */
      if(uxRxQueueLength)
        pxUsart->usart->ier = AVR32_USART_IER_RXRDY_MASK;
      /* Enable receiver and transmitter... */
      pxUsart->usart->cr |= UsartTxEnMask | UsartRxEnMask;
    }
    portEXIT_CRITICAL();
  }
  else
  {
    xReturn = serINVALID_COMPORT_HANDLER;
  }
  return xReturn;
}