This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Compiler/MSP430FR5969: uint16_t pointer to uint8_t value

Part Number: MSP430FR5969

Tool/software: TI C/C++ Compiler

I have a structure set up like this:

struct foo{

uint8_t low;

uint8_t high;

} foo;

And when I do this:

void foo(){

uint16_t volatile *bar;

bar = (uint16_t volatile *) &foo.low

}

the pointer bar does not get the address of the foo.low byte. Instead  it's something completely different. In this specific compile version the address of the foo.low is 0x0000B2E6 but the pointer bar points to 0x000003C2 which is just plain wrong. 

The debugger expressions thinks it should work brilliantly i.e. *(uint16_t volatile *) &foo.low resolves to a 16-bit value with foo.high being top byte. 

  • It appears you are showing a cut down form of the problem code, and not the real thing.  For the actual function which contains the equivalent of this line ...

    Olli Mannisto said:
    bar = (uint16_t volatile *) &foo.low

    ... please submit a test case as described in the article How to Submit a Compiler Test Case.

    Thanks and regards,

    -George

  • Ok, you got a pm. In the actual code the action happens is here:

    void PWM_Decode_Init(){
        //Calculate the DAC value for our 100% current
        USHORT * volatile current;
        UCHAR volatile low_current;
        current = (USHORT *) &myconfig_rw.current_l;
        low_current = myconfig_rw.low_current;
        PWM_status.current_constant=Calculate_Current_Constant(*current, false);

    The interesting bit is that *current contains the expected value (0x0140) combining current_l and current_h. However the Calculate_Current_Constant function receives 0xFFFF instead. 

    See also in stackexchange: 

    stackoverflow.com/.../c-word-pointer-to-a-byte-structure-member

  • For what it's worth, if I store the address as ULONG, pass that to the Calculate_Current_Constant and cast it as a USHORT pointer inside the function, it works fine.
  • Olli Mannisto said:
    Ok, you got a pm.

    Thank you.  Now I have the source code.  But I don't know which version of the compiler you use, or the build options.  Please show the build options exactly as the compiler sees them.

    Thanks and regards,

    -George

  • That would be TI 17.9.0.STS for debug and 16.9.2.LTS [16.9.4.LTS] for release. I should probably make both use the same version. 

    Compiler flags:

    -vmspx --code_model=large --data_model=restricted --near_data=globals -O0 --opt_for_speed=3 --use_hw_mpy=F5 --include_path="C:/ti/ccsv7/ccs_base/msp430/include" --include_path="C:/ti/ccsv7/ccs_base/msp430/include" --include_path="C:/git/LedDriver/LED_Driver_Firmware/driverlib/MSP430FR5xx_6xx" --include_path="C:/ti/ccsv7/tools/compiler/ti-cgt-msp430_17.9.0.STS/include" --advice:hw_config="all" --define=__DEBUG__ --define=__MSP430FR5969__ --define=_MPU_ENABLE -g --printf_support=minimal --diag_warning=225 --diag_wrap=off --display_error_number --silicon_errata=CPU21 --silicon_errata=CPU22 --silicon_errata=CPU40

    Linker flags:

    -vmspx --code_model=large --data_model=restricted --near_data=globals -O0 --opt_for_speed=3 --use_hw_mpy=F5 --advice:hw_config="all" --define=__DEBUG__ --define=__MSP430FR5969__ --define=_MPU_ENABLE -g --printf_support=minimal --diag_warning=225 --diag_wrap=off --display_error_number --silicon_errata=CPU21 --silicon_errata=CPU22 --silicon_errata=CPU40 -z -m"LED_Driver_Firmware.map" --heap_size=400 --stack_size=400 --cinit_hold_wdt=on -i"C:/ti/ccsv7/ccs_base/msp430/include" -i"C:/ti/ccsv7/ccs_base/msp430/include" -i"C:/ti/ccsv7/tools/compiler/ti-cgt-msp430_17.9.0.STS/lib" -i"C:/ti/ccsv7/tools/compiler/ti-cgt-msp430_17.9.0.STS/include" -i"C:/ti/ccsv7/ccs_base/msp430/lib/5xx_6xx_FRxx" -i"C:/ti/ccsv7/ccs_base/msp430/lib/FR59xx" --priority --reread_libs --define=_MPU_ENABLE --diag_wrap=off --display_error_number --warn_sections --xml_link_info="LED_Driver_Firmware_linkInfo.xml" --use_hw_mpy=F5 --rom_model

  • I built the C code down to assembly and inspected it.  I cannot find any problems with the instructions.  But I did find a problem with the Dwarf information.  I filed CODEGEN-3987 in the SDOWP system to have this investigated.  You are welcome to follow it with the SDOWP link below in my signature.

    Keep in mind I cannot run the code.  But as far as I can tell, it should run correctly.  The debugger is showing you incorrect values because of the Dwarf problem.  Does this match what you experience?

    Thanks and regards,

    -George

  • The debugger started showing correct values once I cast the pointer as USHORT * volatile current . But if I dereference it as an argument to a function, a wrong value gets passed to the function. And yes this did break the code so it's real all right.

    I could try to cut down the code for you but in my experience this tends to make the error disappear as well.. The problem is in the init routines so no external hardware is needed at that point.
  • I believe I have this figured out.
    The uint8_t myconfig_rw.current_l is located (right now) in memory address 0x004563, which is not word-aligned. The
    current = (USHORT *) &myconfig_rw.current_l; line generates this:
    MOVX.A #0x04563,0x0000a(SP)

    When I deference this to a word variable, these lines are generated
    MOVA 0x000a(SP),R15
    MOV.W @R15,0x000e(SP)

    0x000e receives 0xFFFF instead of whatever is in address 0x04563 as that's not a valid word aligned address.

    Now *debugger* does not have issues with showing word values from odd addresses and will happily display expected value (0x140) in the pointer address.
  • Olli Mannisto said:
    The uint8_t myconfig_rw.current_l is located (right now) in memory address 0x004563, which is not word-aligned.

    I'm sorry I didn't think of that.  I considered the possibility of misalignment.  But when I saw that the structure member current_l is at an even offset (2), I dismissed that idea.  I overlooked the fact that this entire structure only contains bytes, and so it could start on an odd byte address.  

    You can force the structure to be aligned with the DATA_ALIGN pragma.  Or, if you prefer, you can do the same thing with the GCC "aligned" variable attribute.  These are documented in the MSP430 compiler manual.

    Note that this code ...

    Olli Mannisto said:
    current = (USHORT *) &myconfig_rw.current_l;

    ... causes a violation of the strict aliasing rule.  A web search on that term yields lots of background information on it.  The actual violation occurs whenever you dereference the pointer current.  The compiler presumes you never violate this rule.  That said, some users do violate it anyway, though very carefully.  Using the DATA_ALIGN pragma on the all byte structure would be an example of that.  

    Thanks and regards,

    -George

  • This has some implications on the external access to the registry. It appears that I need to deconstruct word writes/reads to byte accesses whenever the SPI master is accessing a word. 

    ..And, yes, attempt to do similar thing with the byte/word reads.