16 Devices using USB-to-Serial Adapter

When you’re opening the serial connection in Hyperterminal, and you get to the window where you configure the com port settings for COM9, what kind of “Flow Control” is selected? My guess is that “Hardware” is selected by default. If you select “None” your loopback test should work.

With hardware flow control, each device in a serial pair uses some of the extra serial pins (DTR, DSR, RTS, CTS) to check if the other device is ready to receive data. This isn’t always necessary, as many modern devices can receive bytes any time, as fast as the serial protocol will send them, but it is still sometimes useful.

To do a complete loopback test with hardware flow control turned on, you would also need to connect the adapter’s RTS (request to send) pin to its CTS (clear to send) pin. This way whenever hyperterminal wants to send data, it will “request to send” by changing the state of the RTS pin, which will change the state of the CTS pin, signaling that it is “clear to send” the data bytes.

Did that take care of it?

-Adam

P.S. Hyperterminal is nice in that it’s available on any Windows computer, but it can be a little cumbersome to use. My favorite serial terminal is Bray terminal, which puts all of the settings up front in the main window. If you’re interested, you can get it here (it’s free of course).

Thanks Adam…setting h/w control to ‘none’ worked…loop back test worked out…i’ll keep u informed of what happens next.
I have checked the Bray terminal…it is really impressive.
I appreciate your knowledge & help !

Now here is the latest what I did…Let me go point wise…

  1. I used the AVR atmega16 microcontroller with an external 8 MHz crystal.
  2. I used a “Pololu USB to Serial adaptor” to get a serial port on my laptop.
  3. Checked the serial port by “loop back test”…it worked fine…i.e. connected serial ports’ Tx to its Rx & opened Hyperterminal …what I typed is what returned to the terminal…so the serial port on my laptop was fine.
  4. My atmega16 development board has a max232 ic connection done & a female serial port provided.
  5. Then I burnt the following code on the the atmega16.
#include <iom16v.h>
#include <macros.h>

void main(void)
{
 CLI(); //disable interrupts
 UCSRB = 0b00000000;
 UCSRA = 0b00100000;
 UCSRC = 0b10000110;
 UBRR = 51;
 UCSRB = 0b00011000;
 SEI();//enable interrupts
 while(1)
 {
  while(!UDRE);
  UDR='a';
 }
}

6. Connected the Tx of the atmega16 development board to Rx of Pololu USB to Serial adaptor fitted to my laptop. And also connected both the grounds.
7. Made a connection thru Hyperterminal at 9600 bauds / Hardware Control : None / Parity : None / Databits : 8 / Stop Bits : 1.
8. I was expecting “aaaaaaaaaaaaaa…” on the Hyperterminal screen…but nothing happened.
9. Referring to Table no. 70 on page 170 of Atmega16’s datasheet I also tried with UBRR = 0 (i.e. at 0.5 M bauds) so that error = 0, but that too did not work.

Please advise !!

When you say you connected to the TX of the development board, do you mean you had a direct connection to the TX pin of the atmega16, or is this like an output of the max232 level shifter? You want to connect the RX of your USB to Serial adapter directly to the TX pin of the AVR, and the voltages produced by the max232 could actually damage the adapter, so it might be time for another loopback test.

Aside from that it looks like your register descriptions are a little more complex than they need to be. I don’t have an ATMega16 to test this out on, but I think you could have something as simple as this as your main function:

UCSRB=0b00001000;//TX enable
UCSRC=0b00000110;//Asynchronous no pairity, one stop bit, 8 data bits
UBRR=51;//9600 bps at 8MHz

while(1){
	while(!(UCSRA&(1<<UDRE)));//wait for transmission to complete
	UDR='a';
}

Your code uses the statement “while(!UDRE);” to pause until transmission of a byte is complete. Unless that macros library you import includes some neat functions I’m not aware of, to your compiler, UDRE is just a placeholder constant, in this case defined as the number 5, as in the fifth byte of the UCSRA register. Essentially you’re saying “while(!5);”, or “while(0);”. This is always false, so your code then immediately loads an ‘a’ into the transmit register, which is definitely not going to be done transmitting the previous ‘a’, although I’m not sure what the effect of this would be. In any case, to check if the transmitter is done transmitting you need to check the UDRE bit in the UCSRA register, as in the code snippet above.

The last thing I can think of to check is if your ATMega16 is actually using the 8MHz crystal, or one of its own internal oscillators which could be operating at 1MHz, 2MHz, 4MHz, or 8MHz. Can you check the fuse settings to see what clock source you’re using?

So, any luck after all that? By the way, you don’t need to worry about the 0.2% baud rate error you’ll get trying to talk at 9600bps using an 8MHz clock. Being off by less than one percent isn’t going to cause any problems.

-Adam

Thanks Adam…it worked…Earlier I was connecting it after max232 of atmega development, hence it was not working…I am happy my Pololu adaptor did not get fried !!

I connected Rx of Pololu adaptor to Tx pin of Atmega16 & Tx of Pololu adaptor to Rx pin of Atmega16…then corrected the UDRE code…then it was a smooth sail…all Rx & Tx functions worked as desired…

Here is my code…first 9 commented lines describe the code…

//ATMega16 at 8MHz
//USART 
//Using Pololu USB-To-Serial Adaptor
//PD0 = Rx (wired to Pololu's Tx)
//PD1 = Tx (wired to Pololu's Rx)
//Works with Hyperterminal
//Type 'a'...returns 'abcd'
//Type 'b'...returns 'bcde'
//and so on.

#include <iom16v.h>
#include <macros.h>

int flag = 0;
char data;

void uartTx(char c);

void main(void)
{
 int i,j;
 
 UCSRB = 0b00000000;
 UCSRA = 0b00100000;
 UCSRC = 0b10000110;
 UBRR = 51;
 UCSRB = 0b11011000;

 while(1)
 {
  while(UCSRA&(1<<RXC))
  {
   data=UDR;
   uartTx(data);
   uartTx(data+1);
   uartTx(data+2);
   uartTx(data+3);
  }
 }
}

void uartTx(char c)
{
 while(!(UCSRA&(1<<UDRE)));
 UDR = c;
}

- Siddhartha

The Pololu adaptor’s Tx & Rx pins operate at TTL levels so the cannot be connected to RS232’s Rx & Tx pins respectively. What how to get RS232 level voltages from Pololu adaptor ? Kindly advise.

The whole point of our adapter is to get TTL levels. If you want RS-232, you should just get a standard USB-to-serial adapter at a consumer electronics store. If you really want to make your own converter, you can use a MAX232-style chip (many companies, including Maxim, TI and sipex/exar make them), which can both generate the voltages needed from 3.3/5V and act as a level converter.

- Jan

I am trying to establish serial communication between ATmega1281 and laptop using usb to serial adapter. I am trying to echo the character typed from Bray’s terminal. Please could someone help me out with the following code. I don’t know where I am going wrong.

#include <avr/io.h>
//BAUD 9600
//FOSC 1000000 //ATmega1281 internal osc CLKDIV8 active 8MHz/8 = 1MHz



/* Prototypes */
void InitUART( unsigned char baudrate );
unsigned char ReceiveByte( void );
void TransmitByte( unsigned char data );

/* Main - a simple test program*/
int main( void )
{
	
	InitUART( 6 ); /* Set the baudrate to 9600 bps using a 1MHz internal osc */

	for(;;) 	    /* Forever */
	{
		TransmitByte( ReceiveByte() ); /* Echo the received character */
	}
return 0;
}

/* Initialize UART */
void InitUART( unsigned char baudrate )
{
	UBRR0 = baudrate;
	UCSR0B = ( (1<<RXEN0) | (1<<TXEN0) );  /* Enable UART receiver and transmitter */
	UCSR0C = ( (1<<USBS0) | (1<<UCSZ01) | (1<<UCSZ00)); //Set Frame format: 8 data, 2 stop bits
}

/* Read and write functions */
unsigned char ReceiveByte( void )
{
	while ( !(UCSR0A & (1<<RXC0)) ) 	/* Wait for incomming data */
		;
	return UDR0;	//Return data
}

void TransmitByte( unsigned char data )
{
	while ( !(UCSR0A & (1<<UDRE0)) )
		; 			                /* Wait for empty transmit buffer */
	UDR0 = data; 			        /* Start transmittion */
}

I am trying to establish serial communication between ATmega1281 and laptop using usb to serial adapter. I am trying to echo the character typed from Bray’s terminal. Please could someone help me out with the following code. I don’t know where I am going wrong.


#include <avr/io.h>
//BAUD 9600
//FOSC 1000000 //ATmega1281 internal osc CLKDIV8 active 8MHz/8 = 1MHz



/* Prototypes */
void InitUART( unsigned char baudrate );
unsigned char ReceiveByte( void );
void TransmitByte( unsigned char data );

/* Main - a simple test program*/
int main( void )
{
	
	InitUART( 6 ); /* Set the baudrate to 9600 bps using a 1MHz internal osc */

	for(;;) 	    /* Forever */
	{
		TransmitByte( ReceiveByte() ); /* Echo the received character */
	}
return 0;
}

/* Initialize UART */
void InitUART( unsigned char baudrate )
{
	UBRR0 = baudrate;
	UCSR0B = ( (1<<RXEN0) | (1<<TXEN0) );  /* Enable UART receiver and transmitter */
	UCSR0C = ( (1<<USBS0) | (1<<UCSZ01) | (1<<UCSZ00)); //Set Frame format: 8 data, 2 stop bits
}

/* Read and write functions */
unsigned char ReceiveByte( void )
{
	while ( !(UCSR0A & (1<<RXC0)) ) 	/* Wait for incomming data */
		;
	return UDR0;	//Return data
}

void TransmitByte( unsigned char data )
{
	while ( !(UCSR0A & (1<<UDRE0)) )
		; 			                /* Wait for empty transmit buffer */
	UDR0 = data; 			        /* Start transmittion */
}

Hi Shona,

There are lots of potential problems (code, wiring, adapter drivers, terminal configuratoin, etc…), but I see one big one immediately.

Your code indicates that the ATMega1281 is running at 1MHz (using the internal 8MHz oscillator divided by 8). If you look at table 22-9 (on page 228 of the ATMega1281 datasheet), you are using the best possible UBRR scaling value to try to generate 9600 bps, but with such a low clock frequency the actual baud rate generated by the AVR will be off by -7%! I’ve seen CP2102-based USB to Seral adapters handle as much as a 2% baud rate deviation, but 7% is WAY out there!

So, two things to try immediately to fix this:

  1. Set UART0 to double speed (set the U2X0 bit in UCSR0A) and set UBRR0=12.
  2. Switch the chip over to running at 8MHz (clearing the divide-clock-internally-by-8 fuse) and set UBRR=51.

Either of these options will give you 9600 bps with an error of +0.2%, which is much more reasonable.

Good luck!

-Adam

Thanks Adam! I tried both the options but i keep getting an error. When I tried to run the following program at 8Mhz(external clock on board) and set the UBRR =51, I get “aX” at the Bray’s terminal whereas it should display ‘a’. I really don’t understand if it is a register configuration problem.

#include <avr\io.h>
#include<util/delay.h>
#define xtal 8000000L
#define baud 9600

int main(void)
{
   // Calculate UBRR correctly using large temp variables
      uint32_t temp;
	   
	   //	  UCSR0A = (1<<U2X0);
			 
      temp = xtal/16/baud-1;
	       UBRR0H = (temp >> 8);
      UBRR0L = (temp & 0xFF);

   // Initialize UCSRB
      UCSR0B= (1 <<RXEN0 | 1 << TXEN0 );
   
   // Initialize UCSRC cprrect;y
      UCSR0C = ( (0<<UMSEL01) | (0<<UMSEL00) | (1<<USBS0) | (1<<UCSZ01)|(1<<UCSZ00) );

	 
   
    // Loop until UDR register is empty
	while(1)
	{
         while((UCSR0A & (1 <<UDRE0)) == 0)
      		;
      // Transmit letter a

        
		 UDR0 = 'a';
		 _delay_ms(250);
	

  	};
   return 0;
} 

You’re using util/delay.h wrong. First of all, you need to define the F_CPU macro before including it so that it will know how fast your clock is, and thus know how the correspondence between instruction cycles and real time. Secondly, _delay_ms has a maximum allowed argument which depends on F_CPU, so if you’re at 8MHZ then _delay_ms(250) will not work. You should look at delay.h on your computer, and also there is some online documentation for delay.h. You would be better off calling _delay_ms(1) 250 times in a for-loop.

-David Grayson

Thanks a lot everyone!! The problem was very stupid. I was not programming the fuse settings.