Different behaviour caused by breakpoints?

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

Hello there.

This may sound quite vague but I think it's better to ask a generic question before providing all the related code.

I use an ATMega48 to get a number of single ADC conversions from 2 channels without changing the ADMUX during conversions. Specifically, I first get 250 results from ADC0, then I disable the ADC, change the channel in ADMUX, re-enable and get another 250 single conversion results from ADC2. The ADEN remains set during each set of 250 conversions.

An if statement in each while loop (one for each channel) updates the maximum value found on each channel. The maximum values are stored in a volatile uint16_t array (i.e. Results[0]...[1]). The first conversion results are discarded as they should.

At the end, a series of if statements compare the maximum values of the two channels and show the respective messages on an LCD.

When I debug the code with JTAGICE mk2 and set a breakpoint before changing ADMUX to switch to ADC2, everything works fine and I finally get the right output on the LCD.

However, when the code runs free of breakpoints, the output is wrong and it seems(*) like the maximum value on ADC2 is equal to the one on ADC0.
(*) for the time being I have only tried to tie the inputs to either AVCC or GND.

I guess this is a timing-related issue but since ADC conversion is paused when a breakpoint is reached then I think it should exhibit the same behaviour regardless of the existence of breakpoints. Interrupts are disabled. I also tried applying a long delay in place of the breakpoint but I got the same erroneous result.

How can this be attributed to the presence or not of breakpoints? Any ideas?

Regards.

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

Are timer's involved? - they may continue to run when stopped at a breakpoint. There's a toggle in Studio to switch this behaviour.

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

Thanks for the quick response Clawson!

No timers, no interrupts. Internal 8MHz, CKDIV8 off, prescaler /64.

The problem is that I can't locate the problem as when breakpoints are there, the values in the ADC data reg are correct. This is definetely not the case when it runs without breakpoints.

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

I don't have any experience relating to avr. However, I did ran into a compiler on a different chip (non-avr) where breakpoints impacted execution. in that particular case, each access to memory will trigger a memory verification optionally. the code / breakpoints would work correctly if the memory verification is turned off. the code would work correctly if the memory verification OR breakpoints is turned on. With both memory verification AND breakpoints turned on, the code doesn't work.

while it is a highly unique situation (because of the memory verification mechanism), I think it is possible that breakpoints alter execution.

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

To test if it is just timing put a delay in where you have the breakpoint and see what happens....

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

Haven't played with debugwire before, but it seems that when you insert breakpoints using debugwire, a break instruction is inserted in the program memory. Maybe that's were things get messed up when using avr-gcc due to optimizations. Try to view the output using mixed view when setting breakpoints and find the location of the break command. Is it were it was expected to be? Alternatively you can manually insert a breakpoint by simply using the break instruction (in asm, of course).

I believe it's time you provided the source code, though...

So, now I know how ICs work:
they work with smoke.
Cause every time you let the smoke come out of an IC, it stops working.
I can prove it, too...

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

Show us the code (particularly how you are changing the channels).

Regards,
Steve A.

The Board helps those that help themselves.

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

Time for guessing is over - can you post a small example of your code that demonstrates the problem? I would like the ADC function along with whatever initializes the ADC and whatever calls the ADC function. You don't need to post the LCD code.

Thanks!

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

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

First of all, thanks for the replies.

Just to keep it simple, I removed any unnecessary chunks of code and tried again but I still experience the same problem.

So here we are:
ATMega48. ADC0 to AVCC, ADC2 to GND.

#include 
#include 
#include 
#include "lcd_driver.h"

#define VoutLim			100		

const uint8_t *msg_ptr;   //Messages are defined elsewhere
volatile uint16_t FindMax (uint8_t, uint8_t);
volatile uint16_t Vin1Max=0, Vin2Max=0;

int main (void)
{

	DDRD=0xFF;
	DDRB=0xFF;
	DDRC=0x00;

	initialization_4bit();  //LCD initialization

   	DIDR0=	0b00111111;					//Disable digital input buffer on ADC5:0
	ADCSRB=	0b00000000;					//No use
	ADMUX|=	(1<<REFS0);					//Reference: AVCC

	Vin1Max=FindMax(0,250);				//Find max value on ADC0 for 250samples

* If breakpoint is put in here, everything works fine. This is a 0x03FF reading on ADC0, a 0x0000 on ADC2 and the proper output on the LCD.
If no breakpoint exists, then the finally reading on ADC2 is 0x3FF as well so is the Vin2max.

	Vin2Max=FindMax(2,250);				//Find max value on ADC2 for 250samples



		if ((Vin1Max>VoutLim)&&(Vin2Max>VoutLim))
		{
			sendcom_4bit(1);   //Clear LCD
			msg_ptr=msg13;
			lcd_msg(msg_ptr,0,2);			//Show message
		}
		
		else if ((Vin1Max>VoutLim)&&(Vin1Max>Vin2Max))
		{
			sendcom_4bit(1);
			msg_ptr=msg07;
			lcd_msg(msg_ptr,0,2);			//Show message
		}
		
		else if ((Vin2Max>VoutLim)&&(Vin2Max>Vin1Max))
		{
			sendcom_4bit(1);
			msg_ptr=msg08;
			lcd_msg(msg_ptr,0,2);			//Show message
		}
				
		else
		{
			sendcom_4bit(1);
			msg_ptr=msg09;
			lcd_msg(msg_ptr,0,5);			//Show message
		}


	msg_ptr=msg11;						
	lcd_msg(msg_ptr,1,4);					//Show end message

while(1)
{

_delay_ms(10);

}

return 0;
}
		



volatile uint16_t FindMax (uint8_t ch, uint8_t iter)
{
	volatile uint8_t icounter=0;
	volatile uint16_t result=0,Vmax=0;	
	

	ADMUX=(ADMUX&0b11111000)|ch;		//Set channel 
		
			
	ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1);	//activate ADC - clk/64
	
	
	while (icounter4)				//reject first 4 samples
			{ 
			    result=ADCH*256+ADCL;	//get result
			
				if (Vmax

The configuration:

Quote:
AVR Studio 4.18.716
GUI Version 4, 18, 0, 685
JTAGICE mkII 1, 0, 1, 155
ATmega48 234

Operating System
Major 6
Minor 1
PlatformID 2
Build 7600

Plugins:

AvrPluginAvrAsmObject 1, 0, 0, 48
AvrPluginavrgccplugin 1, 0, 0, 11
Stk500Dll 1, 0, 1, 15

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

Use a small delay to allow for some settling time when you change ADMUX. 10us will probably be ok.

You could also consider discarding the first conversion.
The other point is one that koschi made:

             result=ADCW;           //will always work
             result=ADCH*256+ADCL;  //is VERY suspect

If you want to use suspicious constructs, by all means. AFIK, the compiler is free to read ADCH or ADCL in any order that it likes. It is your job to ensure a non-ambiguous instruction. You can do this with separate statements. Or possibly by using parentheses, but I am unsure how reliable that would be.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
result=ADCH*256+ADCL;  //is VERY suspect 

it is only "very suspect" if continuous adc is in process. if you are doing just one-off conversion, that piece of code is perfectly fine.

check the datasheet.

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

Busted! :D
At last!

Thank you David and millwood!

It is this line indeed:

result=ADCH*256+ADCL;  //is VERY suspect 

Not only suspect but vicious!

But how this breakpoint gives me what I need? I should cast a glance at the disassembler and let you know.

Thanks again guys, very helpful!

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

Quote:

if you are doing just one-off conversion, that piece of code is perfectly fine.

No it isn't - the likelihood (though there's no guarantee and that's part of the problem) is that ADCH will be read before ADCL. They must be read in the other order - perhaps you missed this fact in the datatsheet you're so keen of telling others to read?

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

Steve "Koshchi" already pointed out the ADC reading error in the other thread yesterday.

The OP @#$%^ed himself by starting 2 threads on the same topic and ignoring the answers.

JW

Topic locked