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/TMS320F28379D: Compiler-opt corrupts the data written inside a union (Bitfield)

Part Number: TMS320F28379D

Tool/software: TI C/C++ Compiler


I want to write the Registers of an external IC. Therefore the data has to be send on one Pin in a strictly defined order.

To keep things readable I wrote an union for that task.

If I run the method Reg_Comm.setupt_Bitstream() the resulting Bitstreams are different depending on the compiler-opt-lvl I chose.

While using opt-lvl 0 The Bitfiled is filled with the data as expected.
But when I change the opt-lvl to 2 the data inside the Bitfiled is different at many places.

(the Data differes after the call of the private method set_Register_Data() )
I allready tried the followeing things.
- Make the union voaltile
- Make the Bitstream-Array voaltile
- delete the fuctiion set_Register_Data() and write it directly into setup_Bitstream()

None of these steps helped.

Detailed Compiler-settings:
Working:
-v28 -ml -mt --cla_support=cla1 --float_support=fpu32 --tmu_support=tmu0 --vcu_support=vcu2 -Ooff --opt_for_speed=4
Data-Corruption:
-v28 -ml -mt --cla_support=cla1 --float_support=fpu32 --tmu_support=tmu0 --vcu_support=vcu2 -O2 --opt_for_speed=4


Here is the Code:

//HEADER START HERE

#define HIGHEST_REGISTER_NUMBER   0x0C 

typedef union{
    struct {
        uint32_t P          : 1;    
        uint32_t DATA_CRC   : 4;
        uint32_t DATA       : 8;
        uint32_t DATA_S     : 1;    
        uint32_t W          : 1;    
        uint32_t R          : 1;    
        uint32_t ADR_CRC    : 4;
        uint32_t ADR        : 7;
        uint32_t ID         : 3;    
        uint32_t CTS        : 1;    
        uint32_t ADR_S      : 1;    
    }Fct_Grp;

    struct{
        uint32_t P_Bit0         : 1;
        uint32_t DATA_CRC_Bit0  : 1;
        uint32_t DATA_CRC_Bit1  : 1;
        uint32_t DATA_CRC_Bit2  : 1;
        uint32_t DATA_CRC_Bit3  : 1;
        uint32_t DATA_Bit0      : 1;
        uint32_t DATA_Bit1      : 1;
        uint32_t DATA_Bit2      : 1;
        uint32_t DATA_Bit3      : 1;
        uint32_t DATA_Bit4      : 1;
        uint32_t DATA_Bit5      : 1;
        uint32_t DATA_Bit6      : 1;
        uint32_t DATA_Bit7      : 1;
        uint32_t DATA_S_Bit0    : 1;    
        uint32_t W_Bit0         : 1;    
        uint32_t R_Bit0         : 1;    
        uint32_t ADR_CRC_Bit0   : 1;
        uint32_t ADR_CRC_Bit1   : 1;
        uint32_t ADR_CRC_Bit2   : 1;
        uint32_t ADR_CRC_Bit3   : 1;
        uint32_t ADR_Bit0       : 1;
        uint32_t ADR_Bit1       : 1;
        uint32_t ADR_Bit2       : 1;
        uint32_t ADR_Bit3       : 1;
        uint32_t ADR_Bit4       : 1;
        uint32_t ADR_Bit5       : 1;
        uint32_t ADR_Bit6       : 1;
        uint32_t ID_Bit0        : 1;    
        uint32_t ID_Bit1        : 1;    
        uint32_t ID_Bit2        : 1;    
        uint32_t CTS_Bit0       : 1;    
        uint32_t ADR_S_Bit0     : 1;    
    }Bits;

    uint32_t Hex;

}Register_Bitstream;
    
class Reg_Comm{
public:
    void setup_Bitstream();
    
    Register_Bitstream Bitstream[HIGHEST_REGISTER_NUMBER + 1];
private:
    void set_Register_Adr();
    void set_Register_Data();    
};

//HEADER ENDS HERE

//CPP START HERE

#define ENCDS           0
#define M2S             0x00
#define SELRES          0x03
#define HYS             0x00
#define SELSSI          1
#define CRC6            0
#define NZB             0
#define RPL             0
#define AERR            0
#define FERR            0
#define FCTR            0x0004
#define GRAY            0
#define TMODE           0x00
#define TIMO            0
#define TMA             0
#define TOA             0
#define RATIO           0x00
#define GAIN            0x06
#define SINOFFS         0x00
#define COSOFFS         0x00
#define REFOFFS         0
#define PHASE           0x00

void Reg_Comm::setup_Bitstream(){
    set_Register_Adr();
    set_Register_Data();

    for(int i = HIGHEST_REGISTER_NUMBER; i >= 0x00; i--){
        Bitstream[i].Fct_Grp.ADR_S  = 1;
        Bitstream[i].Fct_Grp.CTS   = 1;

        Bitstream[i].Fct_Grp.ID      = 0b000;

        /*Bitstream[i].Fct_Grp.ADR_CRC = calculate_CRC(   (uint16_t) Bitstream[i].Fct_Grp.ADR
                                                    + ( ((uint16_t) Bitstream[i].Fct_Grp.ID) << 7)
                                                    + ( ((uint16_t) Bitstream[i].Fct_Grp.CTS)    << 10)
                                                    , 11);
		*/

        Bitstream[i].Fct_Grp.R      = 0;
        Bitstream[i].Fct_Grp.W      = 1;
        Bitstream[i].Fct_Grp.DATA_S = 1;

        /*Bitstream[i].Fct_Grp.DATA_CRC = calculate_CRC(Bitstream[i].Fct_Grp.DATA
                                                     , 8);
		*/
        Bitstream[i].Fct_Grp.P = 0;
    }
}

void Reg_Comm::set_Register_Adr(){
    for(uint16_t i = 0; i <= HIGHEST_REGISTER_NUMBER; i++){
        Bitstream[i].Fct_Grp.ADR = i;
    }
}

void Reg_Comm::set_Register_Data(){
    // the data can be changed just by updating the #define

    // Register 0x00
    Bitstream[0x00].Bits.DATA_Bit7  = ENCDS;

    Bitstream[0x00].Bits.DATA_Bit5 = (M2S & 0x01) ? 1:0;
    Bitstream[0x00].Bits.DATA_Bit6= (M2S & 0x02) ? 1:0;

    Bitstream[0x00].Bits.DATA_Bit0 = (SELRES & 0x01) ? 1:0;
    Bitstream[0x00].Bits.DATA_Bit1 = (SELRES & 0x02) ? 1:0;
    Bitstream[0x00].Bits.DATA_Bit2 = (SELRES & 0x04) ? 1:0;
    Bitstream[0x00].Bits.DATA_Bit3 = (SELRES & 0x08) ? 1:0;
    Bitstream[0x00].Bits.DATA_Bit4 = (SELRES & 0x10) ? 1:0;

    // Register 0x01
    Bitstream[0x01].Bits.DATA_Bit5 = (HYS & 0x01) ? 1:0;
    Bitstream[0x01].Bits.DATA_Bit6 = (HYS & 0x02) ? 1:0;
    Bitstream[0x01].Bits.DATA_Bit7 = (HYS & 0x04) ? 1:0;

    // Register 0x02
    Bitstream[0x02].Bits.DATA_Bit6 = SELSSI;

    // Register 0x03
    Bitstream[0x03].Bits.DATA_Bit7 = CRC6;
    Bitstream[0x03].Bits.DATA_Bit6 = RPL;

    Bitstream[0x03].Bits.DATA_Bit1 = AERR;
    Bitstream[0x03].Bits.DATA_Bit0 = FERR;

    // Register 0x04
    Bitstream[0x04].Fct_Grp.DATA  |= (uint16_t) (FCTR & 0x00FF) << 7;

    // Register 0x05
    Bitstream[0x05].Bits.DATA_Bit7   = GRAY;

    Bitstream[0x05].Bits.DATA_Bit0 = (FCTR & 0x0100) ? 1:0;
    Bitstream[0x05].Bits.DATA_Bit1 = (FCTR & 0x0200) ? 1:0;
    Bitstream[0x05].Bits.DATA_Bit2 = (FCTR & 0x0400) ? 1:0;
    Bitstream[0x05].Bits.DATA_Bit3 = (FCTR & 0x0800) ? 1:0;
    Bitstream[0x05].Bits.DATA_Bit4 = (FCTR & 0x1000) ? 1:0;
    Bitstream[0x05].Bits.DATA_Bit5 = (FCTR & 0x2000) ? 1:0;
    Bitstream[0x05].Bits.DATA_Bit6 = (FCTR & 0x4000) ? 1:0;

    // Register 0x06
    Bitstream[0x06].Bits.DATA_Bit5 = TIMO;

    Bitstream[0x06].Bits.DATA_Bit1 = (TMODE & 0x01) ? 1:0;
    Bitstream[0x06].Bits.DATA_Bit2 = (TMODE & 0x02) ? 1:0;
    Bitstream[0x06].Bits.DATA_Bit3 = (TMODE & 0x04) ? 1:0;

    Bitstream[0x06].Bits.DATA_Bit0 = TMA;

    // Register 0x07
    Bitstream[0x07].Bits.DATA_Bit3    = TOA;

    // Register 0x08
    Bitstream[0x08].Bits.DATA_Bit4   = (GAIN & 0x01) ? 1:0;
    Bitstream[0x08].Bits.DATA_Bit5   = (GAIN & 0x02) ? 1:0;
    Bitstream[0x08].Bits.DATA_Bit6   = (GAIN & 0x04) ? 1:0;
    Bitstream[0x08].Bits.DATA_Bit7   = (GAIN & 0x08) ? 1:0;

    Bitstream[0x08].Bits.DATA_Bit0  = (RATIO & 0x01) ? 1:0;
    Bitstream[0x08].Bits.DATA_Bit1  = (RATIO & 0x02) ? 1:0;
    Bitstream[0x08].Bits.DATA_Bit2  = (RATIO & 0x04) ? 1:0;
    Bitstream[0x08].Bits.DATA_Bit3  = (RATIO & 0x08) ? 1:0;

    // Register 0x09
    Bitstream[0x09].Fct_Grp.DATA |= SINOFFS << 7;

    // Register 0x0A
    Bitstream[0x0A].Fct_Grp.DATA |= COSOFFS << 7;

    // Register 0x0B
    Bitstream[0x0B].Bits.DATA_Bit2  = (PHASE & 0x01) ? 1:0;
    Bitstream[0x0B].Bits.DATA_Bit3  = (PHASE & 0x02) ? 1:0;
    Bitstream[0x0B].Bits.DATA_Bit4  = (PHASE & 0x04) ? 1:0;
    Bitstream[0x0B].Bits.DATA_Bit5  = (PHASE & 0x08) ? 1:0;
    Bitstream[0x0B].Bits.DATA_Bit6  = (PHASE & 0x10) ? 1:0;
    Bitstream[0x0B].Bits.DATA_Bit7  = (PHASE & 0x20) ? 1:0;

    Bitstream[0x0B].Bits.DATA_Bit1 = REFOFFS;

    Bitstream[0x0B].Bits.DATA_Bit0  = (RATIO & 0x10) ? 1:0;
}

//CPP ENDS HERE

  • What compiler (not CCS) version do you use?

    Thanks and regards,

    -George

  • TI v16.9.6.LTS
  • I added volatile to the Bitstream array ...

        volatile Register_Bitstream Bitstream[HIGHEST_REGISTER_NUMBER + 1];
    

    I built with --opt_level=2 (same as -O2).  I inspected the assembly code generated by the compiler.  I compared it to the assembly generated by building with no optimization and no use of volatile.  I inspected the memory accesses in the function Reg_Comm::set_Register_Data.  Ignore the stack accesses.  Look at the memory accesses for Bitstream.  I didn't look at every single one.  But I looked at enough to be confident the same memory accesses are occurring in the same order.

    Based on that analysis, I conclude that adding that volatile should solve your problem.  If it doesn't, then show how the memory access order to Bitstream is different between the builds.

    Thanks and regards,

    -George

  • Hello George,

    I allready tried to add volatile to the Array delcaration but for me this didn't work.

    Looking at the generated assembly Code I also notice many differences in the order.

    The private Method set_Register_Data starts with the following code:

    -opt 2:

    338         Bitstream[0x05].Bits.DATA_Bit7   = GRAY;
    0086a3:   8EA4        MOVL         XAR0, @XAR4
    335         Bitstream[0x04].Fct_Grp.DATA  |= (uint16_t) (FCTR & 0x00FF) << 7;
    0086a4:   8BA4        MOVL         XAR1, @XAR4
    340         Bitstream[0x05].Bits.DATA_Bit0 = (FCTR & 0x0100) ? 1:0;
    0086a5:   C5A4        MOVL         XAR7, @XAR4
    0086a6:   A2BD        MOVL         *SP++, XAR3
    341         Bitstream[0x05].Bits.DATA_Bit1 = (FCTR & 0x0200) ? 1:0;
    0086a7:   86A4        MOVL         XAR2, @XAR4
    302         Bitstream[0x00].Bits.DATA_Bit7  = ENCDS;
    0086a8:   18C4EFFF    AND          *+XAR4[0], #0xefff
    342         Bitstream[0x05].Bits.DATA_Bit2 = (FCTR & 0x0400) ? 1:0;

    -opt off

    000227:   18C4EFFF    AND          *+XAR4[0], #0xefff
    304         Bitstream[0x00].Bits.DATA_Bit5 = (M2S & 0x01) ? 1:0;
    000229:   8A42        MOVL         XAR4, *-SP[2]
    00022a:   18C4FBFF    AND          *+XAR4[0], #0xfbff
    305         Bitstream[0x00].Bits.DATA_Bit6= (M2S & 0x02) ? 1:0;
    00022c:   8A42        MOVL         XAR4, *-SP[2]
    00022d:   18C4F7FF    AND          *+XAR4[0], #0xf7ff
    307         Bitstream[0x00].Bits.DATA_Bit0 = (SELRES & 0x01) ? 1:0;
    00022f:   8A42        MOVL         XAR4, *-SP[2]
    000230:   1AC40020    OR           *+XAR4[0], #0x0020
    308         Bitstream[0x00].Bits.DATA_Bit1 = (SELRES & 0x02) ? 1:0;
    000232:   8A42        MOVL         XAR4, *-SP[2]
    000233:   1AC40040    OR           *+XAR4[0], #0x0040
    309         Bitstream[0x00].Bits.DATA_Bit2 = (SELRES & 0x04) ? 1:0;
    000235:   8A42        MOVL         XAR4, *-SP[2]
    000236:   18C4FF7F    AND          *+XAR4[0], #0xff7f
    310         Bitstream[0x00].Bits.DATA_Bit3 = (SELRES & 0x08) ? 1:0;
    000238:   8A42        MOVL         XAR4, *-SP[2]
    000239:   18C4FEFF    AND          *+XAR4[0], #0xfeff

    at -opt off everything is called in the exact way it was coded which is correct.

    The added volatile keyword as I understood should force the compiler to stick to the same calling order, but this isn't the case.

    However in that Codesegment I don't care about the calling order it's not important.

    What the big Problem ist, is that some totally different data inside the Bitfield gets corrupted when the compileroptimisation is activated.

    Just for example:
    -opt 02 generates the following problem with the data inside Bitstream[7].Fct_Grp.ADR

    Here everything is fine:


    But when running the next line of assembler Code something goes wrong:


    the Data inside Bitstream[7].Fct_Grp.ADR changed from 7 to 0 which clearly isn't the purpose of that line of Code.
    More Erros with the ADR inside Bitsreams are accuring and with these errors the external IC is setup wrong and won't work.

    I have few to no experience with assambler on your devices and I can't fiure out what is going wrong.

  • Marcel Kummer said:
    The added volatile keyword as I understood should force the compiler to stick to the same calling order, but this isn't the case.

    The volatile memory accesses occur in the same order as the C source.  Instructions that do not perform a volatile memory access, including other memory accesses, can occur in any order.  So, when you are considering whether the compiler did it correctly, you have to isolate the analysis strictly to the volatile memory accesses, and ignore all the other instructions.  When I do that, I see the same order whether optimization is used or not.

    Marcel Kummer said:
    What the big Problem ist, is that some totally different data inside the Bitfield gets corrupted when the compileroptimisation is activated.

    Part of what confuses you, I suspect, is the reordering of the instructions.  Look at the source line numbers in your screen shot.  385, 383, 378, and so on.  No where close to original source order.  The instruction or instructions which follow a C statement is not the full implementation of that statement, but only part of it.  That's why you see line 383 show up twice.  I realize this is confusing.  But it is part of what you have to live with when you step through optimized code.  

    I cannot explain what happens between those screen shots.  Which instruction gets executed?  Keep in mind that, due to pipelining, it could be an earlier instruction that your screen shot does not show.  I don't know enough details about C2000 to say.  If you want to get into this even deeper, then we need to involve some C2000 device experts.

    Thanks and regards,

    -George

  • Thanks for the detailed answer, that helped me understanding what is going on.

    I misunderstood the influence of volatile to the compileroptimization and excepected some other behaviour.
    That's why I thopught the data got corrupted.