1
\$\begingroup\$

I'm testing my first ever PCB design, which is based on an ATMega328, and I've come across some undesirable behavior with the UART:

When I have the UART connected to my computer through a FTDI USB cable, it works perfectly, yet if I detach the cable from the PCB, I can send input on the PCB's Rx line just by touching both Rx and ground with one fingertip at the same time.

I've actually had an issue with fingers causing bad inputs before, and the answer to that was that I had floating voltages.

Of course, the Rx/Tx lines, when they are not connected to anything, would be floating too, which I think is causing the same issue here.

I really need this to be reliable -- in particular, I would like there to be no input on the UART when there isn't really anything sending input.

Two questions, then:

  1. What could be causing this?

  2. What should I do to fix it? Pull-up on the Rx line?

Further information: this is how I was testing.

#include <avr/io.h>

#define USART_BAUDRATE 9600
#define F_CPU 16000000UL
#define UBRR_VALUE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

#define pin (PC3)

void initUART(void)
{
    // Set baud rate
    UBRR0H = (uint8_t)(UBRR_VALUE >> 8);
    UBRR0L = (uint8_t)UBRR_VALUE;
    // Set frame format to 8 data bits, no parity, 1 stop bit
    UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);
    //enable transmission and reception
    UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
}
void sendUARTByte(uint8_t data)
{
    // Wait for byte to be transmitted
    while (!(UCSR0A & (1<<UDRE0))) { }
    // Transmit data
    UDR0 = data;
}
uint8_t receiveUARTByte()
{
    // Wait for byte to be received
    while (!(UCSR0A & (1<<RXC0))) { }
    // Receive data
    return UDR0;
}
int main(void)
{
    uint8_t input = '!';

    DDRC = _BV(pin);
    PORTC = 0;

    initUART();
    while(1)
    {
        PORTC |= _BV(pin);
        sendUARTByte(input);
        input = receiveUARTByte();

        PORTC &= ~_BV(pin);
        sendUARTByte(input);
        input = receiveUARTByte();
    }
}

Essentially all it's doing is toggling PC3 (= pin) whenever there's any input on the UART, and just mirroring the input back to the output.

It works just fine when connected to my computer, but then if I detach the Rx line and move the ground line to another pad (so that I can easily touch the Rx and ground pins at the same time), I still get the pin toggling at a high frequency, but I don't get any output back to the computer (even though the Tx and ground lines are still connected).

Here's the relevant part of the schematic as well: PCB Schematic

The UART is in the center left.

\$\endgroup\$
2
\$\begingroup\$

It's pretty common to activate the internal pullup at least, and perhaps provide a stronger external one. Floating inputs don't just cause false signals; an input near the logic level crossover voltage can cause a chip to consume excessive current, since both the upper and lower FET's can be partially turned on, causing a conductance path from the supply to ground.

For example, on an ATmega you can set the primary serial receive pin's internal pullup like this.

/* Idea copied from arduino bootloader - Enable internal pull-up 
resistor on pin D0 (RX), in order to supress line noise */
  DDRD &= ~_BV(PIND0);
  PORTD |= _BV(PIND0);
\$\endgroup\$
  • \$\begingroup\$ If you know how to, could you provide code that sets the internal pull-up? I'm looking through the datasheet and I'm not quite sure how to do it. (Will it be ok if I somehow set the Rx pin as an input in the code manually, in addition to just telling the UART module to take care of it?) \$\endgroup\$ – Jashaszun Jun 19 '17 at 4:20
  • \$\begingroup\$ If you find the Arduino core UART code I believe that does it; if I recall correctly, on an AVR to set the pullup on an input you write the output data register for that bit to a 1, in addition to setting it as an input in the data direction register. \$\endgroup\$ – Chris Stratton Jun 19 '17 at 4:22
  • \$\begingroup\$ Oh wait, I just missed one piece of data -- Rx is the PD0 pin! Yeah, I should just be able to set PORTD = 1 and DDRD = 0 (for bit 0, of course). \$\endgroup\$ – Jashaszun Jun 19 '17 at 4:22
  • \$\begingroup\$ Awesome, it works!! I actually figured out those two lines of code just a second before you edited your post, but I'm glad I could double-check it against that. Thanks! \$\endgroup\$ – Jashaszun Jun 19 '17 at 4:27
0
\$\begingroup\$

I faced same problem when I custom designed my ATmega64 PCB.

It was working fine when TX/RX connected to computer through FTDI USB Cable and if I disconnect FTDI from computer or from ATmega64 Board then Controller Output Pins were toggling without any input.

  1. Solution: I had LM317 on board set at 3.7 V. I connected TX/RX with it and problem was solved.

  2. Solution: I designed a second PCB with stronger ground and 3.7 V plane and TX/RX didn't show any problem then. So, you can improve GND and VCC plane in PCB Designing.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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