ATmega328 UART won't transmit

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

Hi,

 

I've been trying to get the UART on my Arduino to transmit but with no success.  Here is my initialization code:

 

//

// initialize UART

//

UCSR0C &= ~(1<<UMSEL01 | 1<<UMSEL00); // async UART mode

UCSR0C &= ~(1<<UPM01 | 1<<UPM00 | 1<<USBS0 | 1<<UCPOL0); // no parity, 1 stop bit (tx only), clock polarity set to "0" for async mode


UCSR0C |= 1<<UCSZ01 | 1<<UCSZ00; // character size = 8 bits

UCSR0B |= 1<<UCSZ02; //

UCSR0B |= 1<<RXEN0 | 1<<TXEN0; // enable tx, rx pins (overrides normal port pin function)


UCSR0B |= 1<<RXCIE0 | 1<<TXCIE0; // enable rx, tx interrupts

UCSR0A |= 1<<RXC0 | 1<<TXC0; // these bits are also used to enable interrupts on the rx, tx


UBRR0 = BAUD_4800; // set baud rate, 12-bit baud rate register (see Table 20-4, p187 of ATmega328 datasheet)

 

 

 

And here is the UART transmit interrupt routine:

 

ISR(USART_TX_vect)

{

uart_tx_flag = true; // set this flag to indicate that character in tx shift register is done

}

 

 

And here's the code in my main program:

 

else if (uart_tx_flag==true) // if UART tx'd character is done

{

uart_tx_flag=false; // clear semaphore

UDR0 = 0x55; // transmit another byte

}

 

 

I also have a line at the start of my program that loads a byte into the UART transmit buffer to get things kicked off.

 

Thanks for your help!

 

Dan

 

cleaned up the code - Jim

This topic has a solution.
Last Edited: Wed. Sep 20, 2017 - 02:13 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Why all those RWM?  Needlessly complex, hard to debug/understand, and if the registers contain anything other than the post-reset default values, you may not be setting what you think you're setting.

 

Did you realise you were setting 9-bit mode?:

UCSR0C |= 1<<UCSZ01 | 1<<UCSZ00; // character size = 8 bits
UCSR0B |= 1<<UCSZ02; //

Probably not, given the comment.

 

You've also enabled both the receive and send interrupts:

UCSR0B |= 1<<RXCIE0 | 1<<TXCIE0; // enable rx, tx interrupts

... but you've only provided a TX ISR.  If any bytes do come in, the AVR will run the 'catch-all' default ISR and restart your app.  Don't enable the RX interrupt unless you provide an ISR.

 

 

This:

UCSR0A |= 1<<RXC0 | 1<<TXC0; // these bits are also used to enable interrupts on the rx, tx

... is incorrect.  Those are flags, not enable bits.  Writing them as '1' will simply clear any pending interrupt flags.  Not relevant to your situation.

 

What exactly are you trying to accomplish?  The use of the transmit complete interrupt is not common.  Most people poll UDREn (or use the associated interrupt) and feed the USART a new byte as soon as the buffer has room.  The TX has effectively a two-byte buffer (1-byte plus shift register).

 

Anyway, avoid RWM when configuring a peripheral:

UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
UCSR0B = (1<<RXEN0) | (1<<TXEN0);
UBRR0 = BAUD_4800;

... and unless you're actually using the receiver, there's no point in enabling it.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Wed. Sep 20, 2017 - 12:21 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Joey,

 

Yes - I realized I was in 9-bit mode after I posted.  I made all the corrections that you suggested and I am still not seeing any bytes transmitted.

 

Also, I do have an RX interrupt - I'm just not showing it right now because I can't even get the TX to work.

 

I have the clock configured for 8MHz internal RC and divide by 8, so I have a system clock of 1MHz.  I know this is working because I have a timer interrupt setup to run at 50ms and it works perfectly.

 

Is there anything else that I need to do to configure UART clocks, etc. that I may have overlooked?

 

Thanks,
Dan

	//
	//	initialize UART
	//
//	UCSR0C	&=	~(1<<UMSEL01 | 1<<UMSEL00);									// async UART mode
//	UCSR0C	&=	~(1<<UPM01 | 1<<UPM00 | 1<<USBS0 | 1<<UCPOL0);				// no parity, 1 stop bit (tx only), clock polarity set to "0" for async mode
//	UCSR0C	|=	1<<UCSZ01 | 1<<UCSZ00;										// character size = 8 bits

//	UCSR0B	&=	~(1<<UCSZ02);												// 8-bit data
	UCSR0B	|=	1<<RXEN0 | 1<<TXEN0;										// enable tx, rx pins (overrides normal port pin function)
//	UCSR0B	|=	1<<RXCIE0 | 1<<TXCIE0;										// enable rx, tx interrupts
	UCSR0B	|=	1<<RXCIE0 | 1<<UDRIE0;										// enable rx, tx interrupts
	
	UBRR0	=	BAUD_4800;													// set baud rate, 12-bit baud rate register (see Table 20-4, p187 of ATmega328 datasheet)

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//	UART transmitter interrupt
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
ISR(USART_UDRE_vect)
{
	uart_tx_flag = true;					// set this flag to indicate that character in tx shift register is done
}

 

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

I'm just not showing it right now because I can't even get the TX to work.

Then it would seem as though you should start there.  Get TX working.  Forget RX altogether.  One thing at a time, otherwise you're not sure what the source of the problem is.

 

Write a complete, short test program which configures the USART and continuously transmits 'U'.

 

Do you have an oscilloscope?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Hi Joey,

 

That's essentially what I'm doing.  I have a short program that is attempting to transmit.  I am monitoring the TX pin on the Arduino with my o-scope and I get nothing.  I even tried disabling the interrupts so I could poll the transmitter and send a character when the shift register is empty.  That doesn't work either.

 

Thanks,
Dan

		else if( UCSR0A & (1<<UDRE0) )
		{
			UDR0 = 'U';
		}

 

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

By complete and short, I mean:

int main(void) {
    UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
    UCSR0B = (1<<TXEN0);
    UBRR0 = 12;
    while (1) {
        while (!(UCSR0A & (1<<UDRE0)));
        UDR0 = 'U';
    }
}

I don't know what BAUD_4800 is defined as, so I just did the math for 1 MHz, single-speed, 4800 baud.

 

This should give you a 2.4 kHz square wave on TXD.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

I tried that and it worked!  So, I started commenting code out until I found what was causing the problem.  For some reason, timer 2 is keeping the UART TX from running.  I wonder if it has something to do with the Baud Rate generator?

void rc_board_init(void)
{
	//
	// initialize timer 2
	//
	/*
	PRR	|= 1<<PRTIM2 | 1<<PRTIM0 | 1<<PRTIM1;								// turn off timers
	PRR	|= 1<<PRSPI | 1<<PRUSART0 | 1<<PRADC;								// turn off SPI, USART, ADC
	
	PRR  &= ~(1<<PRTIM2);													// enable Timer/Counter 2 module
	OCR2A = 0x30;															// set output compare register (A) for timer/counter 2 (approx 20Hz, 50ms)
	ASSR &=~(1<<AS2);														// select internal clk(io) as clock source for timer/counter 2
	TCCR2B |= (1<<CS22 | 1<<CS21 | 1<<CS20);								// select prescaler to divide by 1024 for timer/counter 2
	TCCR2A |= 1<<WGM21;														// set timer mode to CTC
	TIMSK2 |= 1<<OCIE2A;													// enable interrupt for Compare match A

	TCCR2A |= 1<<COM2A0;													// toggle OC2A on PORTB, bit3 (waveform will appear as 10Hz, 100ms)
	DDRB   |= 1<<DDB3;														// set PORTB, bit3 to output for OC2A
	*/
	//
	//	initialize UART
	//

//	UBRR0	=	BAUD_4800;													// set baud rate, 12-bit baud rate register (see Table 20-4, p187 of ATmega328 datasheet)
//	UCSR0B	|=	1<<TXEN0;													// enable tx, rx pins (overrides normal port pin function)
//	UCSR0B	|=	1<<RXEN0 | 1<<TXEN0;										// enable tx, rx pins (overrides normal port pin function)
//	UCSR0B	|=	1<<RXCIE0 | 1<<UDRIE0;										// enable rx, tx interrupts
	
	UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
	UCSR0B = (1<<TXEN0);
	UBRR0 = 12;
	

	//
	//	initialize ports
	//
	DDRB |= 1<<ARDUINO_LED;													// bit 5 on port B is output (LED on Arduino)
	
	DDRB &= ~(1<<WARM_RST_N | 1<<COLD_RST_N | 1<<PMIC_SYS_RST_N);			// bits 0,1,7 on port B are inputs
	PORTB |= 1<<WARM_RST_N | 1<<COLD_RST_N | 1<<PMIC_SYS_RST_N;				// turn on internal pullups for input pins on port B
	
	DDRC |= 1<<nRESETREQ | 1<<QSPI_RST_N | 1<<PS_SRST_N | 1<<PS_POR_B;		// bits 0,1,2,3 on port C are outputs
	DDRD |= 1<<RC_LED;														// bit 7 on port D is output
	
	//DDRD |= 0x02;															// UART Tx set to output
	
	PORTC = 1<<nRESETREQ | 1<<QSPI_RST_N | 1<<PS_SRST_N | 1<<PS_POR_B;		// set ALL reset lines HIGH
}

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay, I feel really dumb right now.  I just saw what I did.  I was disabling the UART in the timer initialization routine (PRR register)

 

I really appreciate your help.

 

Thanks,

Dan

 

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

Glad you got it sorted.

 

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

dps wrote:
 I was disabling the UART in the timer initialization routine

 

Which is a fine illustration of what Joey said:

joeymorin wrote:
One thing at a time, otherwise you're not sure what the source of the problem is.
 

 

EDIT

 

See also: http://www.avrfreaks.net/comment...

Last Edited: Wed. Sep 20, 2017 - 08:24 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Glad you got it working, but the internal RC makes for a poor serial clock source, as a change in temperature or VCC will cause clock drift and loss of async comms.

When using serial i/o its best to use a xtal clock source.

 

Jim