Usart0 for atmega128

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

Hello all,
I am reasonably new to microprocessor programing (atmega128) and I was wondering if anyone could give me some pointers as to why the only function which actually does anything in the following test code I compiled together from various odds ends is the UART_RX_interrupt which prints out a random character to my hyper terminal connection on my PC. I know for a fact i have set the baud rate correctly (8-n-1, no flow control)and it all compiles correctly on ICCAVR latest version. All the other functions putchars and etc seem to do nothing and i have no real idea why. I know my main is a bit messy but at the moment i just use it for testing and i can fix that easily. Antways any simple pointers are much appreciated, thanks folks.


#include 
#include 
#include 

// macros
#define bit_get(p,m) ((p) & (m)) 
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m) ((p) ^= (m))
#define bit_write(c,p,m) (c ? bit_set(p,m) : bit_clear(p,m))


/* UART Buffer Defines */
#define UART_RX_BUFFER_SIZE 128 /* 1,2,4,8,16,32,64,128 or 256 bytes */
#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1 )
#define UART_TX_BUFFER_SIZE 128 /* 1,2,4,8,16,32,64,128 or 256 bytes */
#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1 )

#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )
#error RX buffer size is not a power of 2
#endif


#pragma interrupt_handler UART_RX_interrupt:10 UART_TX_interrupt:11

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

void delay_ms(int n)
{
//delay subroutine, in milliseconds

	int x;
	while(n--){
	  x=2443;		//factor for 8mhz crystal
	  while(x--);
	}
}
 
int putchar(char c)
    {
	
	//int _textmode;
    if (_textmode && c == '\n')
        putchar('\r');
    /* Wait for empty transmit buffer */
    while ( !(UCSR0A & (1<<UDRE0)) ){
                          
    /* Putting data into buffer , sends the data */
    UDR0 = c;  
	}
    return c;
  }

int getchar(void)
    {
		while ((UCSR0A & 0x80) == 0);
        
    return UDR0;
    }

	
/* Static Variables */
static unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE];
static volatile unsigned char UART_RxHead;
static volatile unsigned char UART_RxTail;
static unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
static volatile unsigned char UART_TxHead;
static volatile unsigned char UART_TxTail;

/* initialize UART */
void InitUART( unsigned char baudrate )
	{
	unsigned char x;
	UBRR0H = 0x00;
	UBRR0L = baudrate; /* set the baud rate */
	/* enable UART receiver and transmitter, and
	receive interrupt */
	UCSR0A = ( (1<<RXCIE0) | (1<<RXEN0) | (1<<TXEN0) );
	x = 0; /* flush receive buffer */
	UART_RxTail = x;
	UART_RxHead = x;
	UART_TxTail = x;
	UART_TxHead = x;
}

void UsartInit(unsigned char baudrate){
/* Set baud rate */
UBRR0H = (unsigned char)(baudrate>>8);
UBRR0L = (unsigned char)baudrate;
/* Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 2stop bit */
UCSR0C = (1<<USBS0);
}

/* interrupt handlers */
void UART_RX_interrupt( void )
{
	unsigned char data;
	unsigned char tmphead;
	data = UDR0; /* read the received data */
	/* calculate buffer index */
	tmphead = ( UART_RxHead + 1 ) & UART_RX_BUFFER_MASK;
	UART_RxHead = tmphead; /* store new index */
	if ( tmphead == UART_RxTail )
		{
		/* ERROR! Receive buffer overflow */
		}
	UART_RxBuf[tmphead] = data; /* store received data in buffer */
}

void UART_TX_interrupt( void )
{
	unsigned char tmptail;

	/* check if all data is transmitted */
	if ( UART_TxHead != UART_TxTail )
		{
		/* calculate buffer index */
		tmptail = ( UART_TxTail + 1 ) & UART_TX_BUFFER_MASK;
		UART_TxTail = tmptail; /* store new index */
		UDR0 = UART_TxBuf[tmptail]; /* start transmition */
		}
	else
		{
		UCSR0A &= ~(1<<UDRIE0); /* disable UDRE interrupt */
	}
}

/* Read and write functions */
unsigned char ReceiveByte( void )
	{
	unsigned char tmptail;

	while ( UART_RxHead == UART_RxTail ) /* wait for incomming data */
		;
	tmptail = ( UART_RxTail + 1 ) & UART_RX_BUFFER_MASK;/* calculate buffer index */
	UART_RxTail = tmptail; /* store new index */
	return UART_RxBuf[tmptail]; /* return data */
}

void TransmitByte( unsigned char data )
	{
	unsigned char tmphead;
	/* calculate buffer index */
	tmphead = ( UART_TxHead + 1 ) & UART_TX_BUFFER_MASK; 
		/* wait for free space in buffer */

	while ( tmphead == UART_TxTail )
		;
	UART_TxBuf[tmphead] = data; /* store data in buffer */
	UART_TxHead = tmphead; /* store new index */
	UCSR0A |= (1<<UDRIE0); /* enable UDRE interrupt */
}

void USART_Flush( void )
{
unsigned char dummy;
while ( UCSR0A & (1<<RXC0) ) dummy = UDR0;
}

unsigned char DataInReceiveBuffer( void )
{
	return ( UART_RxHead != UART_RxTail ); 
		/* return 0 (FALSE) if the receive buffer is empty */
}


/* main test program*/

void main(void)
{
unsigned char  text;
unsigned char* test;
unsigned char  Rxok;
unsigned char* data;
int stationID;
int Rx;
int length;
int timeout;
int i;

	UsartInit(0x1F); 
	//UBRR0L =  0x5F;  /* 0xBF; //for 9600 bps // 0x07 for 115.2k bps */
	UBRR0H = 0x00;
	_SEI(); /* enable interrupts => enable UART interrupts */
	UART_TX_interrupt();
	UART_RX_interrupt();
	i = 0;
	timeout = 0;
	length = 16;
	//printf("f");
	test = "x";
	
	Rx = 0x1B;
	stationID = 0x01;
	Rxok = Rx;
	//printf(test);
	text = stationID;
	//TransmitByte('x');
	data = "this is a data !";
	//text = ReceiveByte();
	
	while (1) /* forever */
	{
	//printf("go!");
	
	//putchar(text);
	//putchar('c');
	//putchar('\n');
		//printf(data);
		//UART_TX_interrupt();
		printf("o");
		putchar('!');
		TransmitByte(Rx);
		TransmitByte('!');
		UDR0 = '!';
		UDR0 = ' ';
		TransmitByte(ReceiveByte());
		//USART_Flush();
		UART_TX_interrupt();
		//TransmitByte(0x61);
		//TransmitByte( ReceiveByte() ); /* echo the received character */
		
		/* test loop for comms */
		//UART_RX_interrupt();
		if(ReceiveByte() == 'O'){
		USART_Flush();
		UART_RX_interrupt();
		    if(ReceiveByte() == 'K'){
			USART_Flush();
		        //if(ReceiveByte() == 'T'){
				UART_TX_interrupt();
				TransmitByte(text);
				USART_Flush();
				timeout = 0;
				//if(ReceiveByte() != 'O' ){  //only O not OK at the moment
				    while(timeout < 10000){
					UART_TX_interrupt();
				    TransmitByte(Rxok);   //watch for transmit timeouts here
				    timeout = timeout + 1;
					//printf("this is a data !");
					
					    while(i < length){
						UART_TX_interrupt();
						TransmitByte(data[i]);
						USART_Flush();
						i = i+ 1;
					    }
		            }
				//}
				
		        //}
		    }
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well all your comments about setting the baud rate differ a lot. Please tell us what crystal is it that you have connected to the AVR (is it 8 MHz maybe?) and what baud rate you do want, because I can't really figure it out.

And are you sure you have set the fuses to use the external crystal, if not, then the AVR gets its clock from an internal oscillator which, basically without any calibration tricks, is not accurate enough for serial port communications.

- Jani

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

Looks like you are calling the interrupt handlers as if they were normal functions, that will not work. I suggest you start with something simpler (no interrupts) and verify that you can send and receive.
/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
/* Set frame format: 8data, 2stop bit */ 
UCSR0C = (1<<USBS0); 

This does not give you 8data, 2 stop bits, try

UCSR0C |= (1<<USBS0); 

/Lars

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

I seem to remember reading somewhere that 99.9% of UART problems are timing related?

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

Quote:
I seem to remember reading somewhere that 99.9% of UART problems are timing related?

The code is such a mess that I'm not sure that it would matter much in this case.

      printf("o"); 
      putchar('!'); 
      TransmitByte(Rx); 
      TransmitByte('!'); 
      UDR0 = '!'; 
      UDR0 = ' '; 
      TransmitByte(ReceiveByte()); 
      UART_TX_interrupt(); 

I don't understand what you are trying to do with this code. You are using 5 different methods to send bytes here.

Quote:
I know for a fact i have set the baud rate correctly (8-n-1, no flow control)

And we know from the code that it is not even close to being correct. In the code you are trying to set to 2 stop bits, not 1, and in the process you are setting it to 5 data bits.

   //UBRR0L =  0x5F;  /* 0xBF; //for 9600 bps // 0x07 for 115.2k bps */ 

This is the only thing we have to go by to determine what your cpu frequency is. If 0x5f is for 9600 and 0x07 is for 115.2k, then your cpu frequency would be 14.7456MHz. If you think that 0xBF gives you 9600, then your cpu frequency would have to be 29.5MHz (clearly wrong since no AVR can handle that frequency). For the actual value that you are using, 0x1f, you don't say what baud rate you expect. If the cpu frequency is really 14.7456MHz, then the baud rate would be 28.8k.

Regards,
Steve A.

The Board helps those that help themselves.

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

Yeah sorry about those dodgy coments 14.7456Mhz is my oscilator setting. As i said main at the moment is simply a mishmash of testing and things which means the comments are misleading. The compatibility fuse setting seems a good idea i had forgotten about and that (8-n-1) suggestion. Will implement and see how it goes.

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

start simple-

#include 

void tx_byte(uint8_t b){
    while(!(UCSR0A&(1<<UDRE0)));
    UDR0=b;
}

uint8_t rx_byte(void){
    while(!(UCSR0A&(1<<RXC0)));
    return UDR0;
}

int main(void){
    //14.7456mhz 28.8kbaud, 8-n-1
    //turn terminal echo off
    UBRR0L=31;
    UCSR0A=((1<<RXEN0)|(1<<TXEN0)); //enable tx/rx

    //echo rx->tx
    //type in terminal
    //will echo back to terminal
    while(1){
        tx_byte(rx_byte());
    }

    return 0;
}

then build on that.

If you can get the avr to echo back what you typed, you got the rx and tx working correctly.

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

I'd start even simpler:

#include  

void tx_byte(uint8_t b){ 
    while(!(UCSR0A&(1<<UDRE0))); 
    UDR0=b; 
} 

int main(void){ 
    //14.7456mhz 28.8kbaud, 8-n-1 
    //turn terminal echo off 
    UBRR0L=31; 
    UCSR0A=(1<<TXEN0); //enable tx
    //echo rx->tx 
    //type in terminal 
    //will echo back to terminal 
    while(1){ 
        tx_byte('U'); 
    } 

    return 0; 
}

Then just look at the TXD line on a scope or a frequency counter. At 28,800 baud the bits should be 34.7us wide. If they are not then the AVR is not fused to use the crystal. Once they are seen to be 34.7us wide then connecting up to Hyperterminal will show the "UUUUU..." being output. Take it from there.

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

After ensuring the baud was set correctly and fixing the interrupt vectors to 19 and 21 tor RX and TX completed and disregarding interupts and using simple code such as was suggested. I have found with an osciliscope that there are no characters at all being transmited at all at any rate. How do i set the m103 fuse to not be in compatibility mode is it;

PORTC = 0x00;
DDRC = 0x00;

??

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

Quote:
How do i set the m103 fuse to not be in compatibility mode is it;
You need a programmer and change the fuses (ie uncheck the m103 fuse)

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Ah of course, the programmer heh heh. Yeah m103 compatibility mode fuse is no longer a problem but my program won't transmit a single thing still for some wierd reason (and yes i am plugged in to usart0 not usart1 :)).

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

Its easy to write a putchar that DOES NOT use the tx interrupt. Unfortunately, the suggestions were posted assuming you used the GCC compiler. I see you are in fact using the excellent iccavr compiler, which I can assure you works fine on a mega128 at 14.7456. Want me to send you a compilable example for this configuration?

Imagecraft compiler user

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

Yes please, i think a compilable example would be of great help to me. I have spent quite some time now getting these functions to work exactly how I would like them to without complete success.

Rentenreppa@hotmail.com is an email you can send to if you wish. Or personal message.

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

Here's a program for my olimex mt128 that uses both serial ports, reads the a/d, uses the lcd, and reads the button keypad

Attachment(s): 

Imagecraft compiler user

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

Ah an excellent program, on my device i can now get USART port 1 up and running for transmit and recieve which is what i require. Usart0 however cannot work for me and i have no idea why and i am begining to think its maybe some kind of hardware problem. Anyways thankyou everybody for the help its been a good learning experience for me. :)