NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Support Forum » Interrupts and serial communications

June 09, 2010
by gnkarn
gnkarn's Avatar

I need to communicate at fast speed between computer and my kit, Im using the usart library so I developed a simple Rx function on the RX interrupt routine instead of using the one in the library.

This in order to make it more efficient as the uc is doing other thinks at "the same time". I have other interrupt routine that takes care of updating a display with data on a buffer, and im updating that buffer with the information received on the serial port ( stored on the Ring buffer 128bytes).

I´m using a serial Ring buffer to manage the received data, in order to provide the time for taking data out of the ring buffer and and writing it to the "display" buffer.

The problem is , that it works well at low "frame rates" if i send from computer to the uc at a baudrate of 115200 , only 2 frames per second ( 32 bytes per frame), it works fine, just going to 3 errors begins.

each frame begins with a a header sequence, so it automatically syncs if something bad happens, but im sure i having something wrong because i should be able to achieve 30 Fps with no problems.

my question is : how should i configure the interrupts in order for each one not interfering with the other ( my guess is that this is what may be going on).

Any advice is appreciated,

here is some code in case it helps

interrupt routine

// ************************************************************
//                  USART receive interrupt - PUT
// ************************************************************

ISR(USART_RX_vect)
/*{
  //ultima_tecla holds the last key received
  ultima_tecla =UDR0;
  //send received data back
  // no need to wait for empty send buffer
  UDR0=ultima_tecla;
}**/

{
  unsigned char data;
  unsigned char tmphead;

  /* Read the received data */
  data = UDR0; 
  //UDR0 = data;//Sends data back ( ECHO debugging)                
  /* Calculate buffer index *///hace el rollover en caso de sobrepasar el buffer
  tmphead = ( USART_RxHead + 1 ) & USART_RX_BUFFER_MASK;//lo transforma asi en circular.
  USART_RxHead = tmphead;      /* Store new index */

  if ( tmphead == USART_RxTail )
  {
    USART_RxBuf_Status = OVERFLOW;/* ERROR! Receive buffer overflow */
    return;// ver si retorno o si hago algo mas
  }

  USART_RxBuf[tmphead] = data; /* Store received data in buffer */
  USART_RxBuf_Status = NORMAL ;// Fifo receive buffer ok

Function to take data out of the ring buffer :

/******************************************************************************

Name: USART0_Receive(void)
Description: GET - Verifica el Ringbuffer, actualiza punteros y retorna un valor
Input:      none
Output:     ultimo dato en cola sin leer
Misc:                   #
******************************************************************************/

/* Read and write functions */
unsigned char USART0_Receive( void )
{
  unsigned char tmptail;

  if ( (USART_RxHead == USART_RxTail) )  /* Wait for incomming data */
    {USART_RxBuf_Status = VACIO; // esta vacio
  return (0)    ;
  }
  tmptail = ( USART_RxTail + 1 ) & USART_RX_BUFFER_MASK;/* Calculate buffer index */

  USART_RxTail = tmptail;                /* Store new index */

  return USART_RxBuf[tmptail];           /* Return data */
}
/******************************************************************************

The header detection code and display buffer update code not included here.

June 10, 2010
by mrobbins
(NerdKits Staff)

mrobbins's Avatar

Hi gnkarn,

Using a ring buffer and interrupts is a good way to be able to handle more data throughput.

In the fastest possible extreme, a new byte may arrive 11,520 times per second (115200 baud rate / 10 bits per byte because of start and stop bits). That's 87 microseconds between bytes. Is it possible that your other interrupt (the one updating your display) might take longer than that? If so, you might be losing bytes.

However, you seem to indicate that you are able to receive entire frames of 32-bytes perfectly fine, but your problems arise when you try to receive multiple frames in quick succession. After receiving a complete frame, is there anything you do with that information that blocks interrupts from firing?

In our LED Array Kit we use two separate display buffers -- one being actively loaded form the serial port data, and the other being read to the display. This prevents possible weirdness from happening when updating a field that's being used by another part of the program.

As with all interrupt programming, have you made use of "volatile" to mark variables that are modified by an interrupt handler?

Is the USART0_Receive function being called from within an interrupt handler? If not, then you have to account for the possibility that the various buffer state variables might change even as you're doing the reading. For example, a new byte could arrive between your tmptail=... line and the next USART_RxTail line, in which case that byte might be lost forever!

Hope this points you in the right direction!

Mike

June 11, 2010
by gnkarn
gnkarn's Avatar

Thank you Mike, I will verify whats going on, you make me note a very good point, as im updating the head pointer ( a PUT function) on the Rx interrupt routine, and the Tail pointer on the RX function ( a GET function) that is outside the interrupt routine and as the ring buffer is only 128 bytes long the put interrupt routine could make the Head to go Beyond the Tail , and the Rx function will no be able to notice the overflow. Related to the Volatile qualifier, as i have optimization off, i thought it wouldn´t have any effect , am I right?

Will check and think on how to fix, thanks a lot for your excellent support as usual.

Gustavo

June 12, 2010
by mrobbins
(NerdKits Staff)

mrobbins's Avatar

Hi Gustavo,

I'm not 100% sure, but my understanding is that the "volatile" qualifier is still important even without gcc optimizations, because referencing the variable from SRAM is so fundamentally different than just working with it in registers. If unsure, I'd tend to add the volatile keyword to more places -- this will only cause a performance hit, where as missing one could cause totally incorrect logic.

Mike

Post a Reply

Please log in to post a reply.

Did you know that a square wave sounds different than a sine wave? Learn more...