2
\$\begingroup\$

I have an AVR (ATMega644) connected to a Raspberry PI via serial connection. The AVR is powered with 5V and the AVR=>RPI Tx line is using a 1k8/3k3 voltage divider to get a 3v3 level.

If the 10ms wait (XXX in the code) is not present (according to the data sheet I do not have to wait at all) I receive this nonsense (python repr() of the received data):

 '\x00\xaa\x8a\x8a\xea\n'
 '\xe9\xf5%\xc5E\xd5\xa4\xfcBYE WORLD\r\n'

When the 10ms delay is there I receive this:

'\x00HELLO WORLD\r\n'
'BYE WORLD\r\n'

This is pretty much fine. I'd like to know why there's a \0 before the very first actual data byte ('H') though. I never send one for sure!

However, my main question is why the delay between initializing and sending data is necessary.

Notes: My F_CPU value is correct and so are the fuses. I also tried using a lower baudrate (4800) and a different chip.

This is the code I'm using:

#include <avr/interrupt.h>
#include <util/delay.h>
#include <util/setbaud.h>


inline void uart_putc(char c)
{
    loop_until_bit_is_set(UCSR0A, UDRE0);
    UDR0 = c;
}


inline void uart_puts(const char *s)
{
    while (*s) {
        uart_putc(*s++);
    }
}


int main()
{
    // we don't need/use any interrupts
    cli();

    // -DF_CPU=18432000L -DBAUD=19200 used when compiling
    UBRR0H = UBRRH_VALUE;
    UBRR0L = UBRRL_VALUE;
    // 8 data bits
    UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01);
    // enable transmitter
    UCSR0B |= (1 << TXEN0);

    _delay_ms(10);  // XXX
    uart_puts("HELLO WORLD\r\n");
    _delay_ms(250);
    uart_puts("BYE WORLD\r\n");

    // do nothing
    while (1)
        ;

    return 0;
}
\$\endgroup\$
5
  • \$\begingroup\$ Sounds like the output pins are in an unstable state before enabling the UART. Try setting them to a known good state, e.g. output high, before enabling. \$\endgroup\$ Commented Nov 29, 2013 at 23:58
  • \$\begingroup\$ I tried output+low and input+pullup - no difference. Using 330/180ohm resistors as someone suggested on IRC also didn't change anything. \$\endgroup\$ Commented Nov 30, 2013 at 0:39
  • \$\begingroup\$ Update, it only happens when the receiving end is my Pi. With a simple USB2Serial interface I don't need the delay - even if I keep the resistors to get down to 3v3. \$\endgroup\$ Commented Nov 30, 2013 at 4:07
  • \$\begingroup\$ Flush RPi's input buffer before you start. It is always a good idea to have some form of a handshake before you start to send data. I personally prefer the use of predefined data frames. \$\endgroup\$
    – jippie
    Commented Nov 30, 2013 at 9:15
  • \$\begingroup\$ You may be able to improve synchronization speed by using (more) stop bits. \$\endgroup\$
    – jippie
    Commented Nov 30, 2013 at 9:17

2 Answers 2

2
\$\begingroup\$

Basically what you do in

// enable transmitter
UCSR0B |= (1 << TXEN0);

_delay_ms(10);  // XXX

is inserting 10ms of stop bits (1). This helps your receiver to synchronize with the data stream (which conveniently starts with a start bit 0). Until then the AVR pin is high impedance and filling your input buffer with garbage to which your receiver is trying to synchronize.

Every time the receiver reads 10 bits that fit the frame (start-bit 0, 8 data bits, stop-bit 1) the data bits are pushed in the input buffer. Only when the frame doesn't match, bits get discarded until it does find a matching 10 bit string.

This also explains the importance for using start and stop bits in asynchronous transmission. This also explains why using 1.5 or 2 stop bits improves speed of synchronization; the probability of received data accidentally fitting the frame for a single byte decreased.

\$\endgroup\$
1
\$\begingroup\$

I am not aware of your specific hardware or of how your software handles exceptions, but if your circuit is transitioning from an undefined to a defined state you need to give the system time to deal with the states which arrive at 'the boundary' as signals appear to be valid as they settle down, but are not. Using a USB2serial interface probably ensures that the converter output is always defaulted to a legal state whenever illegal input is received so there is no "wakeup time" - see below. .

Longer: If your serial line is active,idle and operating as defined it will be in a defined state - high for a system with positive logic and low for a system with negative logic. Systems which connect with TTL (nominally 0/+5V) or system voltage levels (0/3 or 0/3.3 or 0/5 or whatever) usually are positive logic. RS232 inverts this logic and an idle state is usually low. If connecting at TTL levels the level is what the level is - send 3V3 and you see 3V3 etc. If you the sender to changes to high impedance when disabled the receiver has to 'decide' what it should do wit the input. It is usual to pull the input up to +V with a resistor or equivalent which is large enough (ie low enough load) that it has zero effect on normal operation. Under disabled conditions it sets the input to "idle". If you use USB to RS@32 or USB to logic level serial interfaces they usually look after such niceties. If you connect directly then YOU must decide what happens during disabled state and if you do not do so then Murphy will.

If your software is semi-Murphy proof and you receive a long low signal (illegal) the software may reject it. Less MP (Murphy Proof) software may instead gibber.

If you transition from illegal to legal input (after say a data send enablement) the levels as the circuit stabilises may appear as signal.

If your circuit has time constants involving capacitors that charge to a proper DC level during operation they may be at ground when you first receive data. As they charge to the correct value a 1 or 0 may tend to be interpreted incorrectly. Usually the bias will be one way or the other so eg 1's may become 0's but 0's are OK. But if there are runs of all 1 or all 0, during system stabilisation these may be more affected by the charging capacitors or whatever.

In your case the hex
AA 8A 8A EA
= 1010 1010, 1000 1010, 1000 1010, 1110 1010 are probably meant to be "ELLO"
= $45 $4C $4C $4F
= 0100 0101, 0100 1100, 0100 1100, 0100 1111 It's not clear that one is caused by incorrect decoding of the other BUT it probably is.

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