0
votes

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.

1
Enable the TX pin and connect to your terminal RX and then send a letter periodically and see if it makes it to the terminal. This will test lots of things, including if the baud is set to what you expect, if the voltage levels match, if the clock speed on the ATINY is right, etc. - bigjosh
Maybe show us body of display function :-) - dunajski
what is micro you use ? ther is a lote of Atinys (Atiny25,atiny 416 , ....) which one you use ?? ... and provide display function body .... try to resent the recived data to computer again and see if it will be the same one - Ibram Reda
I am using an ATTiny102. After snooping the connection with an oscilloscope I can see that there is an issue with the baud rate being used by the ATTiny. At 2400 baud it is producing pulses nearly 3 milliseconds long, when they should be about 400 microseconds. - elliptic_hyperboloid
display() just lights up 8 LEDs to show the value of the byte it is passed. It have tested it with hard coded values and it works without issue. i.e. display(0b01101101) - elliptic_hyperboloid

1 Answers

1
votes

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:

  • If you are using a PC for communication, create a loopback at the UART adapter and check with a terminal (TeraTerm, Putty, ...) if the messages you send are received correctly.
  • You also can enable the TX controller and check if loopback is working on your uC.
  • If it is possible try to write the received data to some leds to check if some date is received
  • Is GND betweend receiver and transmitter connected?
  • Are the voltage levels between transmitter and receiver the same?
  • Do transmitter and receiver have its own source? (Then do not connect VCC!)
  • Check if the clock on the controller is correct (switch on an led with _delay_ms() function every second)

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...