cancel
Showing results for 
Search instead for 
Did you mean: 

Compiler optimized program has errors

Tobe
Senior III

While trying to debug a problem, it seems that another one is giving me a hard time.

One function call is not shown, another has the wrong name ("writeFLASHDoubleWord" should be "waitForBusy").

The breakpoint is also missed.

 

Originally the code worked, but then i moved to the new prototype. I copied the project, and made a few minor changes. Mainly just the pins.

I had some hardfault before, which happend seemingly at "CLEAR_BIT(FLASH->CR, FLASH_CR_PG);" after writing FLASH. But after seeing the above, i doubt this!

37 REPLIES 37

@tjaekel wrote:

With optimization debugging becomes impossible


Not necessarily impossible - but it can certainly make things harder!

 

@Tobe You can read about the GCC optimisation options here: 

https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html 

In particular, note the description of -Og ...

What about an array of structs? Does it need a volatile? The struct itself has no volatile either.

 

 

struct can_frame inputBuffer[INPUT_BUFFER_SIZE] = {0};

 

 

This array takes index which are itself already declared as volatile.

 

I tried Og, but the code runs without issues then...

 

Now i did -O2, with a while(1), to getting in there when debugging. (I had some point where i knew when the error happens).

In the picture, id 1776 is a command, while 1780-1789 are running numbers for the datastream.

From "A" to "G" you see the commands, and 178*´s. the 178* have overwritten the previous commands "B" and "D". The order of the command is right, as you can see at the second place ("003", "005", "a" = 7, "b" = 8, "t" = 9).

After the overflow the index is incremented by 2. "J", "K", "B", "D" should come right after each other, which they dont.

The index is incremented as follows (Those variables are volatile):

 

void moveInputReadIndex(){
	// wait while nothing to read
	if(inputFrameCount < 1){
		print("Error: framecount < 1!");
		return;
	}
	NVIC_DisableIRQ(FDCAN1_IT0_IRQn);
	inputFrameCount--;
	inputReadIndex++;

	if(inputReadIndex >= INPUT_BUFFER_SIZE){
		inputReadIndex = 0;
		inputOverFlow = false;
	}

	if(inputFrameCount > INPUT_BUFFER_SIZE)
		print("ERROR inputFrameCount!");

	NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
}

 

I now have pinpointed the problem beeing when written in to the buffer array. The index is somehow increased by two, but only after the first overflow of the "go around buffer" or how it is called.

 

/*
 * Used by interrupt !!!
 */
int dataFlowControl()
{
	if(inputFrameCount >= INPUT_BUFFER_SIZE)
	{	// Error buffer full
		sendAnswerIfNotSendAlready((struct can_frame*) &flowControlAbort);

		// read messages, so the interrupt is still firing
		TK_FDCAN_GetRx0Message(&hfdcan1, &dummyFrame);
		return -1;
	}
	else if(inputFrameCount > INPUT_BUFFER_SIZE / 2)
	{	// Buffer almost full
		sendAnswerIfNotSendAlready((struct can_frame*) &flowControlBusy);
		//return -1;
	}
	else if(inputFrameCount < INPUT_BUFFER_SIZE / 4)
	{	// Buffer is available
		sendAnswerIfNotSendAlready((struct can_frame*) &flowControlGood);
	}
	return 0;
}


void newMessageIRQ()
{
	unsigned long nowMicros = micros();

	if(dataFlowControl() != 0)
		return;

	// TODO low prio: make another version of this, that filters out ids below x beforehand
	TK_FDCAN_GetRx0Message(&hfdcan1, &inputBuffer[inputWriteIndex]);

	// Bootloader does not use ids below ID_REQUEST and 1764 is from diagnose software (dont use it!)
	if(inputBuffer[inputWriteIndex].id < ID_REQUEST || inputBuffer[inputWriteIndex].id == 1764)
		return;

	// Control data
	if(inputBuffer[inputWriteIndex].id < ID_DATA_START)
	{
		lastControlID   	= (uint32_t) inputBuffer[inputWriteIndex].id;
		lastControlMode 	= (uint32_t) inputBuffer[inputWriteIndex].data[0];
		lastAdditionalData 	= (uint32_t) inputBuffer[inputWriteIndex].data[3];
	}

	lastBusActivityMicros = nowMicros; //TODO: DELETE VARIABLE (is not used)
	inputBuffer[inputWriteIndex].timeMicros= nowMicros;
	inputFrameCount++;
	inputWriteIndex++;
	if(inputWriteIndex >= INPUT_BUFFER_SIZE){
		inputWriteIndex = 0;
		inputOverFlow = true;
	}

}

 

Are you talking about inputWriteIndex? Where else in the program do you use/change it?

JW


@Tobe wrote:

"go around buffer" or how it is called.


Is "circular buffer" aka "ring buffer" the term you're looking for?

 


@Tobe wrote:

but only after the first overflow 


Maybe the overflow is not quite working ... ?

 

As @waclawek.jan said, are we talking about inputWriteIndex?

How is it defined? Where else is it used, and how?

Note that volatile just prevents against accesses being optimised-out - it doesn't do anything to provide atomic access, or guard against race conditions, etc...

 

Its only used in the interrupt "newMessageIRQ()". I just checked.

Yes, thats the term.

How, if the overflow would not work (it does without optimization), does this cause an increment of 2 (inputWriteIndex)?

volatile uint8_t inputWriteIndex = 0;

Its only used in the interrupt ( "newMessageIRQ()")


@Tobe wrote:

How, if the overflow would not work (it does without optimization), does this cause an increment of 2


I was just throwing out a suggestion - maybe the "wrap-around" doesn't quite work, and looks like an extra increment...?

 


@Tobe wrote:

Its only used in the interrupt ( "newMessageIRQ()")


Then why is it not local to newMessageIRQ() ?

 

Its not just one increment. Every x++; seems to add 2.

The value has to persist, so it has to be global.