Usart

Hi guys, been trying to learn about USART, got two dev boards here, one with a mega128 in smd format, the other with 1284 in 40 PIN Dip format. I have got usart working on the smd dev board perfectly and I am trying to port it to the dip version. I have changed the registers to the new boards, and it compiles and programs fine however nothing comes through on my terminal. The serial port on the dev board was already there, I have wired pins 10 and 12 of the MAX232 to 15 and 14 respectively for RX and TX.
Im posting my uart.c sorry its quite long:


/*------------------------------------------------*/
/* UART functions                                 */
#include <avr/io.h>
#include <avr/interrupt.h>
#include "uart.h"

#define	SYSCLK		8000000
#define	BAUD		9600


typedef struct _fifo {
	uint8_t	idx_w;
	uint8_t	idx_r;
	uint8_t	count;
	uint8_t buff[64];
} FIFO;


static volatile
FIFO txfifo, rxfifo;

// Initialize UART
void uart_init()
{
	rxfifo.idx_r = 0;
	rxfifo.idx_w = 0;
	rxfifo.count = 0;
	txfifo.idx_r = 0;
	txfifo.idx_w = 0;
	txfifo.count = 0;

	UBRR0L = SYSCLK/BAUD/16-1;
	UCSR0B = _BV(RXEN0)|_BV(RXCIE0)|_BV(TXEN0);
}

// Get a received character
uint8_t uart_test ()
{
	return rxfifo.count;
}
//uart_get
uint8_t uart_get ()
{
	uint8_t d, i;


	i = rxfifo.idx_r;
	while(rxfifo.count == 0);
	d = rxfifo.buff[i++];
	cli();
	rxfifo.count--;
	sei();
	if(i >= sizeof(rxfifo.buff))
		i = 0;
	rxfifo.idx_r = i;

	return d;
}
// Put a character to transmit
void uart_put (uint8_t d)
{
	uint8_t i;


	i = txfifo.idx_w;
	while(txfifo.count >= sizeof(txfifo.buff));
	txfifo.buff[i++] = d;
	cli();
	txfifo.count++;
	UCSR0B = _BV(RXEN0)|_BV(RXCIE0)|_BV(TXEN0)|_BV(UDRIE0);
	sei();
	if(i >= sizeof(txfifo.buff))
		i = 0;
	txfifo.idx_w = i;
}
// UART RXC interrupt
SIGNAL(SIG_UART0_RECV)
{
	uint8_t d, n, i;


	d = UDR0;
	n = rxfifo.count;
	if(n < sizeof(rxfifo.buff)) {
		rxfifo.count = ++n;
		i = rxfifo.idx_w;
		rxfifo.buff[i++] = d;
		if(i >= sizeof(rxfifo.buff))
			i = 0;
		rxfifo.idx_w = i;
	}
}
// UART UDRE interrupt
SIGNAL(SIG_UART0_DATA)
{
	uint8_t n, i;


	n = txfifo.count;
	if(n) {
		txfifo.count = --n;
		i = txfifo.idx_r;
		UDR0 = txfifo.buff[i++];
		if(i >= sizeof(txfifo.buff))
			i = 0;
		txfifo.idx_r = i;
	}
	if(n == 0)
		UCSR0B = _BV(RXEN0)|_BV(RXCIE0)|_BV(TXEN0);
}

I use uart_put to send to the terminal but I dont get anything - my baud rates are the same…
P.S
I have done loopback tests between:
pins 2 and 3 of serial cable - successful.
pins 7 and 13 of MAX232 - succesful.
pins 14 and 15 of powered avr - successful.
so it must be a code problem???

Your code is complicated and I didn’t read most of it. I think you should write a new test program which is much simpler. It should not use any interrupts or buffers. It should just wait until a byte is available on the UART, then read it, toggle and LED, and send it out again.

What do you mean when you say you did a loopback test on pins 14 and 15 of the AVR? Did you do this test with the MAX-232 connected to the AVR or disconnected?

One of our friends had a lot of trouble using the UART on the DIP version of the ATmega1284, but the SMD version worked for him. His problem was that sudden transitions of any kind on the RX line would cause parts of his RAM to become corrupted. I forget what the solution was but I can find out if your other avenues of troubleshooting don’t work.

–David

hi David, so I took your advice and came up with a much much simpler usart code. posted for anyone interested.
uart.c:


/*------------------------------------------------*/ 
/* UART functions                                 */ 

#include <avr/io.h> 
#define USART_BAUDRATE 9600 
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) 


void USART_Transmit( unsigned char txData ) 
{ 
   /* Wait for empty transmit buffer */ 
   while ( !( UCSR0A & (1<<UDRE0)) ); 
   /* Put data into buffer, sends the data */ 
   UDR0 = txData; 
} 


/* Initialize UART */ 

void uart_init() 
{ 
   UCSR0B |= (1 << RXEN0) | (1 << TXEN0);   // Turn on the transmission and reception circuitry 
   //UCSR0C |= (1 << UMSEL01) | (1 << UCSZ00) | (1 << UCSZ01); // Use 8-bit character sizes 

   UBRR0H = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register 
   UBRR0L = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register 
} 


/* Get a received character */ 
uint8_t uart_get () 
{ 
   unsigned char d; 
   while ((UCSR0A & (1 << RXC0)) == 0) {}; // Do nothing until data have been recieved and is ready to be read from UDR 
   d=UDR0; 
   return d; 
} 

/* Transmit a character */ 
void uart_put(uint8_t d) 
{ 
    
   USART_Transmit( d ); 
} 

/* Transmit a string */ 
void uart_puts(const char *s) 
{ 
   while (*s) 
      USART_Transmit( *s++ ); 
} 

uart.h:

void uart_init(void);         /* Initialize UART */ 
uint8_t uart_get (void);      /* Get a byte from UART Rx */ 
uint8_t uart_test(void);      /* Check number of data in UART Rx FIFO */ 
void uart_put(unsigned char);   /* Transmit a byte*/ 
void uart_puts(const char *s);   /* Transmit a string of bytes*/ 

it works perfectly on this chip. I also have added


static FILE mystdout = FDEV_SETUP_STREAM(uart_put, NULL, _FDEV_SETUP_WRITE);

which makes printing to the terminal a dream.
Over the loopback test, yes I did it with max232 attached to make sure that a signal was passing through it successfully, obviously the board needed to be powered for that test.
hope the above is giving something back to this forum.
Alex

Thanks for sharing your code with us! I’m glad you were able to get things working by simplifying it. If you get the interrupt version working, feel free to share it with us.

Here’s one tip for the ring buffers: you don’t actually need to keep track of a “count” variable, you can compute it whenever you need it by doing something like (writeIndex - readIndex) % sizeof(buffer). You can see how much free space is available in the buffer by doing (readIndex - writeIndex - 1) % sizeof(buffer). Then you don’t have to disable and enable interrupts constantly. You could see this working in practice by looking at the source code of the Wixel UART library:

github.com/pololu/wixel-sdk/blo … ore/uart.c

You could also look at the source code of OrangutanSerial in the Pololu AVR C/C++ Library, but it is kind of complicated to read because it supports chips that have either 1 or 2 UARTs.

–David

Thanks.
BTW I came across the strangest error message today:

and then:

Isnt that a crazy error?
The function aparently causing the problem is:


void function(double *p, double *x, int m, int n, void *adata){
double *Actual_Output = (double *)adata;
double Fitted_Curve;
double bit1, bit2;
int i;
		  
  for (i = 0; i<n; i++)
  {

	bit1 = sinh(p[2])*exp(p[0]*(i+1)*2*M_PI);
	bit2 = (1/(p[0]*p[1]));
	Fitted_Curve = bit2*(p[2]-arcsinh(bit1));
    
	x[i] = Actual_Output[i+3]-Fitted_Curve;
	
    }

}

but it looks absolutely fine to me!

That sounds like a crazy error!

I tried to reproduce it here using C:\WinAVR-20100110 but was unable to. The program I made compiled successully. If you gave more details about your compilation process and provided a complete program I might be able to reproduce it. Also, where is arcsinh declared? It doesn’t seem to be in math.h.

–David

Ahh I made arcsinh because it isnt in math.h! Was actually quite proud of it, and Im considering editing math.h to include it.
I fixed that error, strange one though - it was caused by the fact that avrstudio reverted back to the avr toolchain which annoyed me in slightly…
Its one thing after another with these avr’s… Now it doesnt recognize my avrmega1284 because it only has 1284p in its lists. That means I cant program fuses, and i cant program (and verfiy) the chip. Apparently I have to go and add my own chip into WinAVR.