ATmega328P Timer0 and UART confliction

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

Hello forum,

I bought two arduino pro mini boards based on ATmega328P.

I wrote a program in Atmel Studio and I used avrdude and an ISP programmer (usbasp) to flash the hex.

 

My intention was to connect that tiny board with an RFM95 (LoRa module).

I didn't want to make a PCB from scratch. I found those boards very cheap and I decided to use them to make some LoRa nodes.

 

The problem is that UART seems lose its synchronization when timer0 is enabled.

Same thing happens when I use timer1 instead of timer0.

 

when the function SystemTimerInit() is executed, UART stopped working for some reason and I read gibberish on my terminal.

when timer0 (or timer1) is disabled it works fine.

 

Fuses are: (E:FD, H:D9, L:E2)

Chip runs at 8MHz with internal RC.

Board is powered through the ISP programmer at 3.3V I also used it with other power supply but it didn't work

UART BaudRate is 38400. The error according to datasheet is about 0.2%

 

This is the code for timer0

void SystemTimerInit( void )
{
	cpuTimeSinceLastBoot = ( uint64_t )0;
	TCCR0B = ( 1 << CS01 ) | ( 1 << CS00 );
	TIMSK0 = ( 1 << TOIE0 ); //Enable Timer0 Overflow Interrupt
	TCNT0 = 131;
}

ISR( TIMER0_OVF_vect )
{
	cpuTimeSinceLastBoot++;
	TCNT0 = 131;
}

 

this is the code for UART

void UartInit(void)
{
	UCSR0B |= (1 << RXEN0) | (1 << TXEN0);   // Use 8-bit character sizes - URSEL bit set to select the UCRSC register
	UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01);   // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
	UBRR0H = (uint8_t)(BAUD_PRESCALE >> 8);   // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
	UBRR0L = (uint8_t)BAUD_PRESCALE;
}

uint8_t UartSendByte(uint8_t data)
{
	/* Wait for empty transmit buffer */
	while (!(UCSR0A & (1<<UDRE0)));
	/* Put data into buffer, sends the data */
	UDR0 = (data & 0xFF);
	return 1;
}

void PrintLine(char *data_ptr)
{
	while(*data_ptr)
	{
		UartSendByte(*(data_ptr++));
	}
	return;
}

 

and this is the main function

int main(void)
{
	UartInit();
	sei();
	SystemTimerInit();

	for (;;) // Loop forever
	{
		PrintLine("Test firmware\r\n");
	}
}

 

Attachment(s): 

Last Edited: Fri. Sep 28, 2018 - 04:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

giorgos3924 wrote:
This is the code for timer0
giorgos3924 wrote:
ISR( TIMER1_OVF_vect )

 

To go further, show a complete small test program that demonstrates your symptoms.

https://www.avrfreaks.net/commen...

theusch wrote:

I should make the checklist some kind of sticky...

https://www.avrfreaks.net/commen... and many others

Please post a complete test program.  Tell your AVR model and clock speed.  Tell your language, brand of toolchain and version.  Tell compile options, and build results.  Are there any warnings?Show your schematic and describe what is connected.

 

What do you expect to happen?  What >>is<< happening?  How are you testing?

 

 

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Fri. Sep 28, 2018 - 04:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you, this was my mistake while I did tests.

 

This above is my complete program. Sorry if I forget anything.

 

Still nothing though.

 

I'm expecting to see "Test firmware" on my terminal but I see gibberish instead.

UART Baud rate works perfectly if timer0 is stopped.

 

 

My problem seems to be in timer0 overflow interrupt.

If I don't enable TOIE0 flag problem disappears.

I can read timer value though accessing TCNT0.

 

//Global array.
char DebugBuffer[100];

 

for (;;) // Loop forever
	{
		PrintLine("Test firmware\r\n");
		sprintf(DebugBuffer,"TCNT0: %d\r\n",TCNT0);
		PrintLine(DebugBuffer);
	}

 

EDIT

When I put timer code in main.c file everything works fine.

why does that happen?

Last Edited: Fri. Sep 28, 2018 - 05:23 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

giorgos3924 wrote:
I bought two arduino pro mini boards based on ATmega328P.

giorgos3924 wrote:
Fuses are: (E:FD, H:D9, L:E2) Chip runs at 8MHz with internal RC.

giorgos3924 wrote:
The problem is that UART seems lose its synchronization

 

A pro-mini has a resonator (16MHz most likely) why use internal R/C?

The USART needs an accurate and stable clock source, the internal R/C is neither, why not use the external resonator, it's there, it works!

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

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

ki0bk wrote:

giorgos3924 wrote:
I bought two arduino pro mini boards based on ATmega328P.

giorgos3924 wrote:
Fuses are: (E:FD, H:D9, L:E2) Chip runs at 8MHz with internal RC.

giorgos3924 wrote:
The problem is that UART seems lose its synchronization

 

A pro-mini has a resonator (16MHz most likely) why use internal R/C?

The USART needs an accurate and stable clock source, the internal R/C is neither, why not use the external resonator, it's there, it works!

 

Jim

 

Because I want it to operate at 3.3V not at 5V.

 

I also don't mind if I lose some bytes. it's not very important.

The main issue is that it isn't working at all!

 

As I added in my edit above, I put my code in main.c file and works fine now, but I don't understand why.

Last Edited: Fri. Sep 28, 2018 - 05:29 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can still use the 16MHz external resonator, just set the cpu clock divider to /2 to run at 8MHz early in your init.

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

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

giorgos3924 wrote:

 

uint8_t UartSendByte(uint8_t data)
{
	/* Wait for empty transmit buffer */
	while (!(UCSR0A & (1<<UDRE0)));
	/* Put data into buffer, sends the data */
	UDR0 = (data & 0xFF);
	return 1;
}

void PrintLine(char *data_ptr)
{
	while(*data_ptr)
	{
		UartSendByte(*(data_ptr++));
	}
	return;
}

 

A comment unrelated to your original question... if a function does

not return a meaningful value, it should not return anything at all.

 

UartSendByte should be declared void since, as written, it doesn't

provide anything other than a 1 when finished.  You even ignore

the returned value in PrintLine, understandably.

 

--Mike

 

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

avr-mike wrote:

A comment unrelated to your original question... if a function does

not return a meaningful value, it should not return anything at all.

 

UartSendByte should be declared void since, as written, it doesn't

provide anything other than a 1 when finished.  You even ignore

the returned value in PrintLine, understandably.

 

--Mike

 

 

Thank you Mike, your comment is very helpful! You are right about return values!

 

I solved my problem, though.

I have separate folder for my timer that includes two files, timer.c and timer.h

I just added one line and it works perfectly now.

#include <avr/interrupt.h>

I also had my interrupt handler into timer.c file

 

ISR( TIMER0_OVF_vect )
{
	cpuTimeSinceLastBoot++;
	TCNT0 = 131;
}

 

it seems like it is mandatory to include interrupt.h Although there was no error to inform me.

Last Edited: Fri. Sep 28, 2018 - 05:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:

You can still use the 16MHz external resonator, just set the cpu clock divider to /2 to run at 8MHz early in your init.

 

Jim

 

Can I? Sorry, I wasn't aware about that!

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

giorgos3924 wrote:
I have separate folder for my timer that includes two files, timer.c and timer.h I just added one line and it works perfectly now.
giorgos3924 wrote:
This above is my complete program.

So, although I asked for the complete program, and you claimed the complete program was posted, it really >>was not<<.  [there is a reason for that request, as you see now, along with the other items on my "checklist"]

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

theusch wrote:

giorgos3924 wrote:
I have separate folder for my timer that includes two files, timer.c and timer.h I just added one line and it works perfectly now.
giorgos3924 wrote:
This above is my complete program.

So, although I asked for the complete program, and you claimed the complete program was posted, it really >>was not<<.  [there is a reason for that request, as you see now, along with the other items on my "checklist"]

 

Yes, you're right! I misunderstood, my bad!

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

giorgos3924 wrote:
Yes, you're right! I misunderstood, my bad!

giorgos3924 wrote:
Although there was no error to inform me.

Again, post the complete test example.  All of the files, along with the build sequence.  The compiler needs to know what ISR means from somewhere...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

You may want to declare

cpuTimeSinceLastBoot

as volatile if you plan to use this in main(), as variables shared between main() and ISR() should be volatile.

 

 

Jim

 

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

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

Also, you probably really want to use 'CTC' mode for your timer instead of

manually setting TCNT0 in the overflow interrupt.  This save CPU cycles and

also guarantees that the timing won't get messed up by a higher-priority

interrupt delaying the change to TCNT0.  Think what would happen if TCNT0

had a value of 1 instead of 0 when you reset it to 131.

 

--Mike

 

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

Your baud rate calculation is wrong.  It should be:   UBRR = (8000000/(16*38400) ) - 1   according to table 24.1  in section 24.4.1 of the Mega328P data sheet.

 

Whenever you get gibberish on a UART output, then the most likely cause is that the baud rate is not correct.

Last Edited: Fri. Sep 28, 2018 - 07:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simonetta wrote:
Whenever you get gibberish on a UART output, then the most likely cause is that the baud rate is not correct.

It is hard to disagree with that, but remember that OP reported it worked fine until the timer (and associated interrupt enable) was added.  So the clock and baud rate setting were "close enough" at least for sanity check.

 

Why do you say BAUD_PRESCALE is incorrect?

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.