embeddedavruartusartattiny

UDR register always reads 0xFF


I have an ATTiny that is supposed to receive commands over UART. I have a simple display of eight LEDs that should show the contents of the most recent byte received. I am using an interrupt to read data as it is received. No matter what data I send UDR always reads 0xFF in the interrupt. I know the interrupt is being triggered since the display changes from 0x00 to 0xFF, but it never displays the value I sent over the serial bus.

This is how I enable UART.

UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;

#if USE_2X
UCSRA |= (1U << U2X);
#else
UCSRA &= ~(1U << U2X);
#endif

// Enable receiver and interrupt
UCSRB = (1U << RXEN) | (1U << RXCIE);

// No parity, 8 Data Bits, 1 Stop Bit
UCSRC = (1U << UCSZ1) | (1U << UCSZ0);

This is the code in the interrupt. I have tested display() and it functions correctly on its own thus implying message is always 0xFF.

ISR(USART_RXC_vect) {
    uint8_t message = UDR;
    display(message);
}

I am confident that my computer is sending the correct information, but I have only tested it with a pseudo-terminal to print out the sent bytes. I intend to snoop the hardware connection with an oscilloscope, but I don't believe that is the issue. Is there something that is causing UDR to always read as 0xFF?

Edit: I have snooped the connection with an oscilloscope and have verified that the computer is sending the correct data, at the correct rate. However, the ATTiny is not operating at the correct baud rate. At 2400 baud pulses should be about 400 microseconds long, however the microcontroller is producing pulses over 3 milliseconds long. This explains why it would always read 0xFF, the computer would send nearly the entire byte when the controller thought it was receiving the start bit, when the controller tried to read the remaining data the lines would be undriven, resulting in it reading all ones. I still don't know why this is the case as I believe I am properly setting the baud rate on the controller.

Edit: The issue has been resolved. By default the clock prescaler is set to 8, so the device was only operating at 1MHz, not 8MHz. Setting the clock prescaler to 1 solved the problem.


Solution

  • There can be several problems with uart communication. First check some things:

    1. Is controller configured with the right clock?
      • Internal/External
      • Is F_CPU defined for <util/setbaud.h>?
      • Is BAUD defined for <util/setbaud.h>?
      • Are you using a controller like ATmega16 that has special register access?
      • If you are using an external clock (that should not be devided) is CKDIV8 disabled in FUSES or in special registers at some controllers?
    2. Is:
      • Baudrate,
      • Paritybit,
      • Stopbit setup corret on Transmitter and Receiver

    Debug:

    Example Program

    #define F_CPU 12000000UL
    #define BAUD 9600UL
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/setbaud.h>
    
    ISR(USART_RXC_vect)
    {
        volatile unsigned char message = UDR;
        
        // If it is possible try to write the received data to
        // LEDs (if there are some at your board)
        
        display(message);
    }
    
    int main()
    {
        // To allow changes to clock prescaler it is necessary to set the
        // CCP register (Datasheet page 23)!
        CCP = 0xD8;
    
        // RESET the clock prescaler from /8 to /1 !!!!
        // Or it is necessary to divide F_CPU through the CLK_PRESCALER 
        CLKPSR = 0x00;
    
        UBRRH = UBRRH_VALUE;
        UBRRL = UBRRL_VALUE;
    
        #if USE_2X
            UCSRA |= (1<<U2X);
        #else
            UCSRA &= ~(1<<U2X);
        #endif
    
        // Enable receiver and interrupt
        UCSRB = (1U << RXEN) | (1U << RXCIE);
    
        // No parity, 8 Data Bits, 1 Stop Bit
        
        // Not necessary! Mostly ATmega controller
        // have 8 bit mode initialized at startup
        //UCSRC = (1U << UCSZ1) | (1U << UCSZ0);
        
        // If you are using ATmega8/16 it is necessary to do some
        // special things to write to the UBRRH and UCSRC register!
        // See ATmega16 datasheet at page 162
        
        // Do not forget to enable interrupts globally!
        sei();
        
        while(1);
    }
    

    Please explain what the display() function is doing...