ATmega328 code compiles, uploads, does not execute?

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

Hi

 

I'm new to AVRFreaks - Hello! 

 

I'm having a strange problem, where my code compiles without errors in AS6.2, uploads to the ATmega328P (and verifies), but doesn't seem to execute!

- I'm using latest version of AS6.2

- Using a USBTiny programmer, so uploading using AVRDude (using this process http://www.crash-bang.com/using-...)

- Code compiles without errors

- Code uploads successfully

- Code doesn't execute

- Have tried a clean build, compiling as Debug or Release (in case that triggers something)

 

The code was working, until I spent a little time tidying up comments to make it more readable.

 

Can anyone think of any conceivable reason why the code wouldn't work? 

 

I recall this happening in another project, but then I could track it down to an arbitrary #define statement - I removed it and the code ran again; replaced it and the code stopped...

 

I'm sure I'm missing something really simple. I've attached the code incase anyone else is as confused as I am!

 

Thanks

Andrew

Attachment(s): 

This topic has a solution.
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well I had a look but there's more than 50KB of .c code there and I odn't plan to wade through it all. As it is split into modules like ADC and I2C can I assume you have tested each in turn and know that they all work as expected independently? If so the fault must surely lie in the 20KB of source that binds them all together.

 

Now you said "doesn't execute" and " the code wouldn't work". I'm afraid that tells nothing about what you expect the code to do and what actually happened. I find it extremely unlikely that it does not execute AT ALL. The fact is that if you apply power to an AVR it starts fetching and executing opcodes and about the only thing you can do to stop that is SLEEP. So I imagine it is executing. It's just not executing what you intended. 

 

What do you have in the way of debug? Do you have a debugWire debugger so you can observe the code in action? If not I see UART routines there - so if you pepper every line of execution with "at line 17 - about to call ...()" where does it stop?

The code was working, until I spent a little time tidying up comments to make it more readable.

Probably time to explore a revision control system. 

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

AndyTallack wrote:
I'm having a strange problem, where my code compiles without errors in AS6.2, uploads to the ATmega328P (and verifies), but doesn't seem to execute!

No, that is not strange at all!

 

It is very easy to create a 'C' program that is completely syntactically valid (ie, produces no compiler errors) but does nothing - or crashes.

 

In exactly the same way that it's easy to make up an English sentence where all the words are correctly spelled, but it's complete nonsense!

 

The code was working, until I spent a little time tidying up comments to make it more readable.

So you obviously broke something in that process!

 

Go back to the code before you "tidied" it, and do a diff with the "tidied" code - that should show where you went wrong.

 

As Cliff says, a revision control system really helps with this kind of thing

 

Can anyone think of any conceivable reason why the code wouldn't work? 

Yes - see above!

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

 

clawson wrote:
Now you said "doesn't execute" and " the code wouldn't work". I'm afraid that tells nothing about what you expect the code to do and what actually happened.

Indeed.

 

See: http://www.catb.org/esr/faqs/sma...

 

The fact is that if you apply power to an AVR it starts fetching and executing opcodes and about the only thing you can do to stop that is SLEEP. So I imagine it is executing. It's just not executing what you intended. 

Indeed again!

 

The ATmega328P has a debugWIRE On-chip Debug System - use it!

 

This will allow you to trace your program execution, and see what's actually happening within the chip.

 

https://www.avrfreaks.net/comment...

 

One of the first things to do when starting with a new chip should always be to learn to use its debugger:

 

https://www.avrfreaks.net/comment...

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fair comment on not giving enough detail - suitably slapped on the wrists ;) Apologies.

Line 2 of the code in the main() routine outputs a welcome message to the UART - this is not sent over UART in this code. I have tested the UART module in a new project so I know that my module works, my USB-Serial converter works and my USB port works.

What confuses me then is that it doesn't seem to be the execution path of the code, or an infinite loop or anything else - execution does not progress to line 2, which it does in another standalone project and I can't see any possible reason why it wouldn't.

Is it likely that some undetected issue at another point in the program could possibly cause this?

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

As I said, you've almost certainly broken something in your "tidying up".

 

Have you done the diff?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well if it's the first 2 UART calls that "go wrong" it should be easy to isolate.

 

I see a lot of needless messing about with UCSR0C in UART_init(). I assume the ultimate goal is 8N1? That (0x06) is the power on default. So there seems little point in actually going anywhere near USCR0C at all.

 

If you are going to can I just point out that of the 8 bits you only write known values to 7? However I guess you don't need to write the 0 bit UCPOL0 as I think one can assume it'll be 0 anyway (and it's only for synchronous). To be honest I would just have written it as:

UCSR0C =  (1<<UCSZ00) | (1<<UCSZ01) ;

Using '=' rather than '|=' the implication of that is the that other 6 bits ARE 0. If you really feel the need to document that fact then perhaps:

UCSR0C =  (0 << UMSEL01) | (0 << UMSEL00) | (0 << UPM01) | (0 << UPM00) | (0 << USBS0) | (1 << UCSZ00) | (1 << UCSZ01) | (0 << UCPOL0) ;

Though personally I think that loses the 1's in a sea of 0's.

 

The UART_writeString() and the UART_writeChar() on which it's based look like standard fodder.

 

As such I don't think you have introduced a typo into this code and personally I think that the breakdown of comms. is just coincidental with your editing. More likely a fuse has changed or a wire is loose.

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

clawson wrote:
I don't think you have introduced a typo into this code and personally I think that the breakdown of comms. is just coincidental with your editing. More likely a fuse has changed or a wire is loose.

Quite possibly.

 

The way to check would be to load the old, "un-tidied" code and see if it still works...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The way to check would be to load the old, "un-tidied" code and see if it still works...

A luxury that may only be available to those with RCS wink

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

Thanks all - appreciate the input.  Have taken the comments and suggestions and worked through them. I don't have any kind of versioning in place, so that's a good place to start.  Any suggestions other than Github?

 

@clawson I agree that I'm not being very elegant with the UART calls - my thinking was that if this was a standalone library I wouldn't want to rely on any power-on values as conceivably someone may want to change the protocol config part-way through the code.  As you picked up, the aim is to try to document it for those not familiar with the UART for an article I'm working on (some may say if I can't get this right I shouldnt be writing articles!)

 

So I found an Atmel ICE and that didn't help - basically I found that the rest of the program was executing but all calls to the UART library failing.

 

As I don't have versioning, I wasn't able to roll-back or do a diff, so I basically cleared out code, bottom to top, routine by routine, from the main "Beyond Arduino 6 - 1 Temp Log.c" file, testing along the way.

 

The offending line of code was the UART_writeString in the snippet below, right up before my main while(1) loop:

	if ((timeYear == 1) && (timeMonth ==1) && (timeDay == 1) && (timeMin == 0))
	{
		bTimeSet = 0;	//Time not set
		UART_writeString("Time not yet set - no logging will occur.\r\n");
	}
	else
	{
		bTimeSet = 1;	//Time is set
	}

 

So I figured that maybe there was some kind of memory issue with me pushing too many strings around in my code - but having just cleared out all my other routines I'd canned most of them so it couldn't be that.

 

Then...

I tried changing the text in the string, and it still failed.

I tried moving the function call out of the If block - still failed

I eventually pasted back all my original code, deleted the offending line and worked around by putting the call somewhere else in the program flow and voila - it worked again.

 

The problem is solved, but I must admit I'm still scratching my head like mad!

 

Thanks again for the input - hope that I can give back to the forum in some way.

 

Cheers

Andrew

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

AndyTallack wrote:
Any suggestions other than Github?

What do you have against Git?

 

(actually, isn't Github a hosting service?)

 

SVN is another popular one.

 

A crude way is just to take copies of your complete project folder tree - you can just drag-and-drop in File Manager, or use XCOPY at the command line...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't have any kind of versioning in place, so that's a good place to start.  Any suggestions other than Github?

rcs, the granddaddy of versioning software, is sufficient for single-user projects and local disks.

I've used git, mercurial, and svn on web-based OSSW, and I have a hard time telling how they do better on simple things.

 

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

Sounds like time for a separate thread for discussing revision control systems.

 

Here: https://www.avrfreaks.net/forum/b...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So I figured that maybe there was some kind of memory issue 

What did the avr-size report during the build say? What was the combined size of .data and .bss?

 

On the whole you don't want much more than about 70..75% usage in Data because the stack/autos will tend to eat about 20%+

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

clawson wrote:

So I figured that maybe there was some kind of memory issue 

What did the avr-size report during the build say? What was the combined size of .data and .bss?

 

 

Once I'd deleted most of the code, and still experienced the failure, I was running at a size of:

 

.data 0x330              816
.text 0x1156           4,438
.bss 0xe                 14
.comment 0x30                 48
.note.gnu.avr.deviceinfo 0x40                 64
.debug_aranges 0x1a8              424
.debug_info 0x2766        10,086
.debug_abbrev 0x957           2,391
.debug_line 0x8ee           2,286
.debug_frame 0x4d0           1,232
.debug_str 0x6ba           1,722
.debug_loc 0x17d6           6,102
.debug_ranges 0x148              328
Total 0x74ff        29,951

 

Which doesn't seem overly demanding...

 

 

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

Agree - the ony significant figures (for RAM) there are 816+14 = 830. A mere drop in the 2,048 byte ocean (unless you go wild with recursion and automatics!)

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

Which still leaves me scratching my head... maybe I just need to move on with life and put it into the category of the inexplicable.

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

So I found an Atmel ICE and that didn't help - basically I found that the rest of the program was executing but all calls to the UART library failing.

Reviewing this thread I find that a VERY curious comment indeed. How can you not find the source of the problem if you have an Atmel-ICE and can look inside the AVR to see what's going on?

 

I guess the one way that debugged code differs from realtime is the speed of operation and possible interactions between two threads of execution. I can't remember the code now - was it using interrupts?

 

Equally I would step builds both with/without the errant UART string in place and see how execution differs.

 

On the whole (until I believe the investigation is exhaustive) I wouldn't just let something like this go. It could be a portent of something much bigger that might be going to affect your code or, perhaps more worrying, some pernicious issue that you don't notice at first but that comes out and bites when you are least expecting it.

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

Perhaps I'm not looking in the right place.

 

My very first call of the main() is to a routine that configures the UART:

void UART_Init(uint16_t baudRate)

{
	uint16_t my_UBRR;

	//Calculate the value of the UBRR register, to set the Baud Rate
	my_UBRR = (F_CPU/16UL/baudRate) - 1;

	//Set the Baud rate
	UBRR0H = (unsigned char)(my_UBRR >> 8);		//Set the High register
	UBRR0L = (unsigned char)my_UBRR;			//Set the Low register

	//Stop Bit: 1 - ensure bit is unset (incase it was set before)
	UCSR0C &= ~(1<<USBS0);

	//Data Bits: 8
	UCSR0C |= ( (1<<UCSZ00) | (1<<UCSZ01) );

	//Parity: None - ensure bits unset (incase they were set before)
	UCSR0C &= ~( (1<<UPM00) | (1<<UPM01) );

	//Mode: Ensure Asynchronous Mode (clear bits incase they were set before)
	UCSR0C &= ~( (1<<UMSEL00) | (1<<UMSEL01) );
	
	//Enable the Transmitter and Receiver
	UCSR0B |= (1<<TXEN0) | (1<<RXEN0);

}

As pointed out previously - this code is a little lengthy and not very elegant, but is this way for a reason.

I step through this with the ICE successfully.

 

 

My second function call is to write a string to the UART using UART_writeString:

void UART_writeString(const char dataString[])
{
	uint16_t i = 0;
	
	//Loop through the string, writing character by character
	while(dataString[i])
	{
		UART_writeChar(dataString[i]);	//write each character in turn
		i++;
	}
}

void UART_writeChar(unsigned char data)
{
	
	//Wait until transmit buffer empty
	while ( !(UCSR0A & (1<<UDRE0) ) );
	
	//write char
	UDR0 = data;
	
}

I am able to step through this successfully with the ICE - however nothing appears on the UART.

 

 

If I remove the offending line (which is later in the main(), but before the while(1) loop), then the characters appear on the UART.

 

These function calls are literally the very first calls of the program - no conditional branching, no interrupts are enabled.  It seems that having the offending line in the code causes the UART to fail completely - no further comms seems to occur (although to be fair I haven't yet had time to breakpoint my UART Receive interrupt and check whether the UART receive is working).

 

I guess I struggle to understand how a statement later in the code is able to affect an earlier one.  Is this something worth logging to Atmel perhaps, so that they can point out where I've completely missed the boat (somehow)!

 

I agree with you about the risk of a big bite when I least expect it - I just can't wrap my head around the seeming lack of logic to it.

 

Last Edited: Thu. Jun 25, 2015 - 02:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I read thru the templogger.c with the main and it looks real nice. How about try this: add a line like jnk=UDR0; right before you set TXRIE. I could type yet another sentence on why I think this might help, but its faster to just add the line, recompile, reburn, and run.

 

Imagecraft compiler user

Last Edited: Thu. Jun 25, 2015 - 04:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am able to step through this successfully with the ICE - however nothing appears on the UART.

So put a breakpoint on the "UDR0 = data" line - what is being loaded into UDR0 each time - do they look like 'T', 'e', 'm'.. and the remaining characters of "Temperature Logger Startup" ?

 

If you just RXEN a UART and set a sensible UBRR then when using a debugger you can even skip all the UDRE stuff - your steps will be slower than UDRE takes to set so you can almost literally just do successive UDR0= statements and you should simply see the characters coming out the other end.

 

If a seemingly unrelated string elsewhere in the build defeats this I would say 'T', 'e'... can't be the values being written to the UDR0 register.

 

If they aren't, what are? And if you look at the mixed C/Asm view and step the opcodes where are the LD's getting their data - does the address in X or Z (whichever it happens to use) match the location of the .data in the .lss ?

Last Edited: Thu. Jun 25, 2015 - 03:57 PM