atmega16m1 full duplex uart

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have problem with the atmega16m1 using the UART in full duplex mode. It seems that sending a byte fails (silently) when the UART is in the process of receiving a byte.

Has anyone gotten the UART to work reliably in full duplex mode?

Thanks,
Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As far as I know, the receiver and transmitter ONLY share a baud rate clock and control registers. There are separate shift registers for receive and transmit, as well as independent control logic.

How do you know that it is not working?

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a test program echoing each received character with a sequence count, printed in 4 character hex. If I hit the keyboard really fast both handed every now and then the sequence count is only printed with 3 characters.

After some failures I connected an additional UART's RX pin to the atmeag16m1's TX pin and it prints exactly the same as the regular terminal. So it's not my modem, the 16m1 actually doesn't transmit the character.

This only happens when I send characters really fast, not during regular typing (I'm a slow typer).

Any insights?

Markus

PS: If it helps I can post the code.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've simplified it to the following program (taking out hex printing and includes).

#include 
#include 

static void uart_init() {
  LINCR = _BV( LSWRES);             // terminate whatever is going on
  while ( LINSIR & _BV( LBUSY)) ;   // wait until LIN/UART unit is ready, p.207/8
#if 19200 == BAUD
  LINBRR = 12;                      // set baud rate 19200, p.208
#elif 115200 == BAUD
  LINBTR = _BV( LDISR) + 14;        // Figure 20-8, p.209
  LINBRR = 4;
#else
#  error "BAUD not defined or wrong (19200/115200)."
#endif
  while ( LINSIR & _BV( LBUSY)) ;     // wait until LIN/UART unit is ready, p.207/8
  LINCR  = _BV( LENA) | _BV( LCMD2);  // enable UART in "byte transfer" mode, p.202/203
  LINCR |= _BV( LCMD1) | _BV( LCMD0); // enable UART in "full duplex" mode, p.216/217
  PORTD |= _BV( PD4);                 // pullup for RXD
}

static bool uart_havech() {
  return LINSIR & _BV( LRXOK);
}

static uint8_t uart_getch() {
  return LINDAT;
}

static void uart_putch( uint8_t c) {
  while ( LINSIR & _BV( LBUSY)) ; // p.207/208
  LINDAT = c;
}

int main() {

  uart_init();

  uint16_t cnt = 0x1200;
  for (;;) {
    if ( uart_havech()) {
      uint8_t c = uart_getch();
      uart_putch( '0');
      uart_putch( '1');
      uart_putch( '2');
      uart_putch( 'a' + (++cnt & 0x0F));
      uart_putch( ':');
      uart_putch( ' ');
      uart_putch( c);
      uart_putch( '\r');
      uart_putch( '\n');
    }
  }
  return 0;
}

A snippet from the output on randomly hitting the keyboard with all fingers:

02H: j
012I: f
02J: ;
012K: l
012L: k
02M: d
012N: s
02O: j
012P: f
012A: l
02B: k
012C: j
02D: d
012E: s

Any help would be appreciated.

Thanks,
Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You cant send 4 chars back for every char that comes in if the send and receive is at the same rate. How about send a known string like 0123456789 and you can check if its correct and send back a + or a -

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Maybe I misunderstand your suggestion, but reception on the m1 works fine, it's sending a character from the m1 while it receives one seems to be a problem.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
      uint8_t c = uart_getch();
      uart_putch( '0');
      uart_putch( '1');
      uart_putch( '2');
      uart_putch( 'a' + (++cnt & 0x0F));
      uart_putch( ':');
      uart_putch( ' ');
      uart_putch( c);
      uart_putch( '\r');
      uart_putch( '\n');

This way you are receiving only every 10th byte.
(If rx bytes comes without gaps)

Receive 1 byte
Send 9 bytes
Receive 1 byte (but meanwhile another 9 bytes came )
Send 9 bytes
...

To catch all bytes I would receive incoming bytes in RX interrupt and save in an array.
Or am I wrong?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Visovian wrote:
To catch all bytes I would receive incoming bytes in RX interrupt and save in an array.
Or am I wrong?
His problem is not losing received bytes (he will losing some, but that is a don't care in this test), the problem are the lost sent bytes.

      uart_putch( '0');
      uart_putch( '1');
      uart_putch( '2');
      ...
02H: j
012I: f
02J: ;
012K: l
012L: k
02M: d
012N: s
02O: j
012P: f
012A: l
02B: k
012C: j
02D: d
012E: s 

The '1' is missing sometimes.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MegaTorr wrote:
it's sending a character from the m1 while it receives one seems to be a problem.
I don't think so. Because then the missing bytes would be random, but it is ever the '1' that is missing sometimes.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No. I have not read your data sheet.

You appear to be missing the '1' every now and then.
I am surprised to see you receiving 'A', 'B', ... when you are doing uart_putch('a'), 'a'+1, ...

So I think you have parity errors and framing errors.
If you have selected '1 stop bits' for your AVR, and your Terminal is expecting a less civilised '2 stop bit'.

People are often obsessed with selecting '2 stop bits'. This works fine with humans typing, but when you send a string with uart_puts() or have multiple uart_putchar() calls, there are no gaps between bytes.

Oh, are you using 9600 baud or 115200 baud?

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi David,

all UARTs are configured for 8N1 @ 115200 baud. Originally I was running 19200 baud. When I discovered the problem, I thought maybe a different baud rate would help - didn't make a difference.

The 'a' vs. 'A' thingy is a copy and paste error - good catch. I switched to 'a' because it turned out easier to read for me.

With the original code, where the uart_ functions are in a different module the error is not as predictable as in this example. I am missing either the '1' or the '2'.

I ran a test, stopping sending bytes if there is something in the receive buffer. Turns out when I miss a character 2 characters later there is a character available (uart_havech() returns true). So instead of

012K: l

I get

02K

and then the output stops.

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Figured it out:

static void uart_putch( uint8_t c) {
  //while ( LINSIR & _BV( LBUSY)) ;     // ready to send a character?, p.207/208
  while ( !( LINSIR & _BV( LTXOK))) ;   // was previous character sent?, p.205
  LINDAT = c;
}

Turns out LBUSY has not very much to do with being able to send a character, unlike the data sheet suggests.

The big difference is that LTXOK is only asserted once a character is sent. Meaning I have to send a character first without testing for LTXOK, since it cannot be asserted otherwise. A bit annoying ... :roll:

Have fun,
Markus