Quantcast
Channel: MSP430 Technical Forums
Viewing all articles
Browse latest Browse all 2077

const, infomem flash, and volatile keyword

$
0
0

Just thought I'd share a funny debugging session I just went through.  Reminds me of @Rickta59 's post about the compiler "optimizing" things yesterday...

 

So I've never really used the infomem in any of my projects, but, I have a specific need that would be good; Having my WS2811 LED strip water jug "remember" the last RGB color sent to it so it turns back on automatically after its power has been tripped.  Simple enough, I reserve space in Info_B for the R, G, B value and I decided to include a 16-bit "password" that is read to determine if there is valid information there.

 

FYI all my projects use MSPGCC with -Os, so optimization is enabled.

 

Seemed straightforward, I went ahead and declared my variables:

const uint16_t _dmx_password __attribute__((section(".infob"))) = 0x0505;
const uint16_t _dmx_red __attribute__((section(".infob"))) = 0x00FF;
const uint16_t _dmx_green __attribute__((section(".infob"))) = 0x0050;
const uint16_t _dmx_blue __attribute__((section(".infob"))) = 0x0080;

As expected, when mspdebug writes the .elf to firmware, the Info_B segment actually gets initialized with those values correctly.  When writing, I cast those variables to (uint16_t *) to get rid of the const so they're writable.

 

Inside main(), a function is called to load this info from flash, and if it's not valid, just reset the LEDs all to 0x000000:

int dmx512_flash_load(uint8_t startcode)
{
        if (startcode != DMX512_STARTCODE)
                return -1;

        if (_dmx_password != DMX_PASSWORD_VALID)
                return -1;

        dmx512_buffer[0] = (uint8_t) _dmx_red;
        dmx512_buffer[1] = (uint8_t) _dmx_green;
        dmx512_buffer[2] = (uint8_t) _dmx_blue;

        dmx512_update_commit(startcode);

        return 0;
}

DMX_PASSWORD_VALID is defined in my dmx512.h:

/* Flash saving/retrieval of buffer */
int dmx512_flash_load(uint8_t startcode);
void dmx512_flash_commit(uint8_t startcode);
#define DMX_PASSWORD_VALID ((uint16_t) 0xFEF5)

So the initial value is not the same as the intended value.  Next time the user updates the LED, after a short timeout period (during which more updates can happen; so we don't wear out the flash TOO quickly) it commits the new values, including the correct password.

 

In mspdebug, I was seeing that happen correctly.  No errors in flash programming.  I even added some volatile uint16_t counters that incremented upon detecting any KEYV|ACCVIFG in FCTL3 during erase or unlock.

 

But the "if (_dmx_password != DMX_PASSWORD_VALID)" kept failing.

So I changed it around to something like this:

volatile uint16_t temp_pw;

int dmx512_flash_load(uint8_t startcode)
{
        if (startcode != DMX512_STARTCODE)
                return -1;

        temp_pw = _dmx_password;
        if (temp_pw != DMX_PASSWORD_VALID)
                return -1;

        dmx512_buffer[0] = (uint8_t) _dmx_red;
        dmx512_buffer[1] = (uint8_t) _dmx_green;
        dmx512_buffer[2] = (uint8_t) _dmx_blue;

        dmx512_update_commit(startcode);

        return 0;
}

And it was still failing.  What's funny is, while mspdebug showed the contents of 0x1906 (_dmx_password) to be 0xFEF5, temp_pw was showing up as 0x0505 still.

Couldn't figure that out.  Until I started looking at the ASM:

00008d36 <dmx512_flash_load>:

volatile uint16_t temp_pw;
int dmx512_flash_load(uint8_t startcode)
{
        if (startcode != DMX512_STARTCODE)
    8d36:       4f 93           tst.b   r15             
    8d38:       02 24           jz      $+6             ;abs 0x8d3e
                return -1;
    8d3a:       3f 43           mov     #-1,    r15     ;r3 As==11
    8d3c:       30 41           ret                     

        temp_pw = _dmx_password;
    8d3e:       b2 40 05 05     mov     #1285,  &0x1c5e ;#0x0505
    8d42:       5e 1c 
        if (temp_pw != DMX_PASSWORD_VALID)
    8d44:       1e 42 5e 1c     mov     &0x1c5e,r14     
    8d48:       3e 90 f5 fe     cmp     #-267,  r14     ;#0xfef5
    8d4c:       f6 23           jnz     $-18            ;abs 0x8d3a
                return -1;

The darned compiler was optimizing away my flash "const" by including the const value in the instruction.

 

Funny enough, something about it "feels" wrong when I read it but the solution is:

volatile const uint16_t _dmx_password __attribute__((section(".infob"))) = 0x0505;
volatile const uint16_t _dmx_red __attribute__((section(".infob"))) = 0x00FF;
volatile const uint16_t _dmx_green __attribute__((section(".infob"))) = 0x0050;
volatile const uint16_t _dmx_blue __attribute__((section(".infob"))) = 0x0080;

"volatile const" lol...

Does it right:

int dmx512_flash_load(uint8_t startcode)
{
        if (startcode != DMX512_STARTCODE)
    8d36:       4f 93           tst.b   r15             
    8d38:       15 20           jnz     $+44            ;abs 0x8d64
                return -1;

        if (_dmx_password != DMX_PASSWORD_VALID)
    8d3a:       1e 42 06 19     mov     &0x1906,r14     
    8d3e:       3e 90 f5 fe     cmp     #-267,  r14     ;#0xfef5
    8d42:       10 20           jnz     $+34            ;abs 0x8d64
                return -1;

because 0x1906 is the correct Info_B address on the MSP430F5172 for _dmx_password, according to mspdebug.  Now my water jug lamp remembers its color setting across power cycles.

 

Anyway, just sharing this moment of learning... as it only took me an hour to figure out :P

 


Viewing all articles
Browse latest Browse all 2077

Trending Articles