[Solved] Function Argument Changing by Serial.println()?

Hey everyone. Got a really weird problem. Here’s my code:

Serial.println(flashOffset, HEX);
SparkFlash_writeB(buffer, bufferSize, flashOffset)
Serial.println(flashOffset, HEX);

and here’s my function

bool SparkFlash_writeB(const uint8_t* buffer, int numByteToWrite, int extFlashOffset)
{
#ifdef VERBOSE
        char buff[50];
        // sprintf(buff,"SFWB1: Flash Offset: %d", extFlashOffset);
        // Serial.println(buff);
        sprintf(buff,"Writing %d bytes from %p to Ext Flash @ %x", numByteToWrite, buffer, 0x80000 + extFlashOffset);
        Serial.println(buff); 
#endif
    int temp = 0;
    int bytesWritten = 0;
    for (int i=0;i<numByteToWrite;i++)
    {
        // Grab the current value of the image at positions i and i + 1 (two bytes))
        temp = (buffer[i] << 8) + buffer[i+1];
        // Write those values to flash
        if(SparkFlash_write(extFlashOffset + i, temp) == 2)
        {
            bytesWritten += 2;
        }
        else
        {
            sprintf(buff,"Failed to write bytes @ %x", 0x80000 + i + extFlashOffset);
            Serial.println(buff);
        }
        i++;
    }
#ifdef VERBOSE
    sprintf(buff,"SFWB2: Flash Offset: %d", extFlashOffset);
    Serial.println(buff);
    sprintf(buff,"Bytes Written: %d/%d'\n", bytesWritten, numByteToWrite);
    Serial.println(buff);
    Serial.println("Write Complete");
#endif
if(bytesWritten == numByteToWrite)
    return true;
else
    return false;
}

I’m writing around 6k bytes to external flash memory. flashOffset is passed as 0 but somehow becomes 0x3030 after this function is finished. If I keep

sprintf(buff,"SFWB2: Flash Offset: %d", extFlashOffset);
Serial.println(buff);

in my code flashOffset “stays” at 0 but when I comment it out it becomes 0x3303.

Ie, without the sprintf line I get the following out of the code above:

0
3030

With the sprintf line I get the following

0
0

What the hell is going on? Any ideas?

That IS odd - but just for curiosity - could you try to declare flashOffset as volatile?
If the problem disappears, I might have a suspicion.

1 Like

Do you suggest I change it in the function definition or in the “global” code.

Ie,

bool SparkFlash_writeB(const uint8_t* buffer, int numByteToWrite, volatile int extFlashOffset)

or

volatile int flashOffset = 0;
Serial.println(flashOffset, HEX);
SparkFlash_writeB(buffer, bufferSize, flashOffset)
Serial.println(flashOffset, HEX);

?

Went with the first one (adding volatile to the function defintion) and it appears to work. I’d love to hear your suspicion @ScruffR

Thanks for the help!

@harrisonhjones, perhaps your local char buff[50] declaration is not large enough and the sprintf overflows it.

1 Like

I guess it might. Any idea why volatile fixes it?

I would actually have thought of the global flashOffset and not the local extFlashOffset, but the reason might still be the same after all.

While PauI’s suspicion might be the more generally applicable one, I wouldn’t dismiss the idea of a compiler/optimizer issue.
Since the optimizer might see flashOffset as not mutating, it might have used a µP register to store the value across the whole set of instructions, overlooking the possible change of register inside the fn.
And volatile prevents this faulty optimization.

I might be wrong, but it sounds cool, doesn’t it :smile: :wink:


Furthermore, I wouldn’t see why ‘volatile’ would fix an overrun buffer or how sprintf() would repair the original value of flashOffset after a buffer overrun.
But then 0 is not the best value to confirm that the value was actually “repaired” - maybe you could try some other values to confirm it actually is the same value before and after.

1 Like

@ScruffR, I like your explanation, right or wrong! :stuck_out_tongue:

1 Like

I might be wrong, but maybe the variable is put elsewhere in memory map when declared volatile. Then the code overflows into some other variable, making bug magically “disappear”. Oh I spent days catching a bug exactly like this in my early C programming days :smile:

1 Like

AFAIK volatile does not actually cause any relocation of a variable but rather instructs the optimizer to keep its fingers off the variable and any instruction involving it, furthermore it even demands that the compiler ensures that every read to this variable retrieves the value from its original memory location.


e.g. http://crasseux.com/books/ctutorial/volatile.html
The volatile keyword serves as a warning to the compiler that it should not optimize the code containing the variable (that is, compile it so that it will run in the most efficient way possible) by storing the value of the variable and referring to it repeatedly, but should reread the value of the variable every time. (Volatile variables are also flagged by the compiler as not to be stored in read-only memory.)

1 Like

Yes, I understand volatile keyword. But when compiler chooses addresses for each variable, volatile variables might end up elsewhere in memory map that “normal” ones. Reordering declarations might have the same effect.
It is wild guess of course, but reminded me my frustration hunting a bug which appeared when I added a declaration of a global variable and disappeared when I removed it. Variables got reordered somehow and an overflow (I found out few days later) began most likely to corrupt more important variable than before.
I am by no means compiler expert, but this was my observation. It was old DOC Borland C++ compiler, not sure if it could apply for the one Spark uses. But I guess it could.

That’s a nice explanation @ScruffR, but I’d be surprised if it’s a compiler bug - there’s a well understood protocol about which registers are preserved/clobbered across function calls. (But having said that, optimization bugs are relatively common!)

I guess the way to know for sure is to increase the size of the sprintf buffer to 256 bytes, remove volatile and see if the problem disappears.

3 Likes

I will do that later today or tomorrow and see what happens! Thanks for all the help everyone

Just out of curiosity, did you find out what the reason was?

1 Like