1
\$\begingroup\$

​Hi,

​I'm having a problem with the USART_RX_vect interrupt of the ATMega 328p. The receiving works fine and I'm able to evaluate the sent bits (so it's not due to the baudrate) but everytime I send a bit, the ISR gets executed 4 times.​

So a ISR like this:

ISR(USART_RX_vect) {
    uart_transmit('t');
    uart_flush();
}

Will transmit {'t', 't', 't', 't'}

I have no clue why this is happening, and I hope you can help me.


My main is a empty loop (of course I execute uart_setup). My ISR is like above. I'm using avr-gcc on linux.

This is my UART Setup:

void uart_setup() {                                                                                                                                                                                                 
      UBRR0H = (BAUDRATE >> 8);                                                                                                                                                                                       
      UBRR0L = BAUDRATE;                                                                                                                                                                                              

      // Set 8-Bit mode                                                                                                                                                                                               
      setBit(UCSR0C, UCSZ01);                                                                                                                                                                                         
       setBit(UCSR0C, UCSZ00);                                                                                                                                                                                         

      setBit(UCSR0B, RXEN0); // Receiver enable                                                                                                                                                                       
      setBit(UCSR0B, TXEN0); // Transmitter enable                                                                                                                                                                    

      setBit(UCSR0B, RXCIE0); // Enable RX Interrupt                                                                                                                                                                  
      sei(); // Enable global interrupts                                                                                                                                                                              
  }       

void uart_transmit(unsigned char data)                                                                 
{                                                                                                      
    while (!( UCSR0A & (1<<UDRE0))); // wait while register is free                     
    UDR0 = data; // load data in the register                        
}         

void uart_flush( void ) {                                                                              
          unsigned char dummy;                                                                           
          while ( UCSR0A & (1<<RXC0) ) dummy = UDR0;                                                     
  }                                                                                                                                                                                                                                                                                                                                                   
\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

It appears that the design of your code is such that when a byte is received in the UART, you wish to dispose of that byte and respond by transmitting a "t".

The UART shares a common receive/transmit buffer register. Since your UART receive routine is interrupt driven, you should immediately read the received character before putting the response in the buffer otherwise you will retrigger the receive interrupt when you exit.

There is also no reason to have the 'while' code in the uart_flush routine since you know there is a character in the buffer based on the fact that an interrupt brought you to this point. Just read the buffer register.

Here is a simplified version of a corrected ISR without the functions:

ISR(USART_RX_vect) {
     unsigned char dummy;
     dummy = UDR0;                     // dump the rcvr buffer
     while (!( UCSR0A & (1<<UDRE0)));  // wait until the register is free                     
     UDR0 = data;                      // load xmt data in the register
}
\$\endgroup\$
0
\$\begingroup\$

The function uart_flush() serves no purpose from what I can see, unless you are using it to wait for all bytes to be received? I think your problem is that you are doing things in a backwards order, you are getting the Rx interrupt and then writing to the UART data register then reading from it without any guarantee that the transmission has completed. I think you need to swap the order you call transmit and flush in your ISR.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.