Memory Leak when using (12Bit )BITFIELD with an M0???

Haai All

When using bitfields with union and struct with 12 bits there seems to be an issue. The problem only occurs with the M0 board. The following code works fine on a Uno.

#define define_Serial_Debug_Port Serial

typedef union {
    struct {
        // Byte 0 - 1
        unsigned int  Var12bit1 : 12;
        
        // Byte 1 - 2
        unsigned int  Var12bit2 : 12;
        
        // Byte 3 - 4
        unsigned int  Var12bit3 : 12;
        
        // Byte 4 - 5
        unsigned int  Var12bit4 : 12;
        
        // Byte 6
        unsigned int  MsgCounter : 4;
        unsigned intnibble_dummy : 4;
        
        // Byte 7
        unsigned int  ChckSum : 8;
    };
    uint8_t Array[8];
} struct_Var8bytes;

struct_Var8bytes variable_Var8Bytes;

void function_ShowMem ( void )
{
    variable_Var8Bytes.ChckSum =
        variable_Var8Bytes.Array[0] +
        variable_Var8Bytes.Array[1] +
        variable_Var8Bytes.Array[2] +
        variable_Var8Bytes.Array[3] +
        variable_Var8Bytes.Array[4] +
        variable_Var8Bytes.Array[5] +
        variable_Var8Bytes.Array[6]
        ;
        
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[0], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[1], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[2], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[3], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[4], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[5], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[6], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[7], HEX );
    
    define_Serial_Debug_Port.print ( " ---- " );
    
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Var12bit1, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Var12bit2, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Var12bit3, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Var12bit4, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.MsgCounter, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.ChckSum, HEX );
    
    define_Serial_Debug_Port.print ( " - EOM" );
    
    define_Serial_Debug_Port.println ( );
}

void setup()
{
    Serial.begin ( 115200 );
    
    define_Serial_Debug_Port.println ( "Start run" );
}

void loop()
{
    define_Serial_Debug_Port.println ( );
    
    variable_Var8Bytes.Var12bit1 = 0x1;
    variable_Var8Bytes.Var12bit2 = 0x2;
    variable_Var8Bytes.Var12bit3 = 0x3;
    variable_Var8Bytes.Var12bit4 = 0x4;
    
    function_ShowMem();
    
    variable_Var8Bytes.Var12bit1 = 0x0ff;
    variable_Var8Bytes.Var12bit2 = 0x1ff;
    variable_Var8Bytes.Var12bit3 = 0x2ff;
    variable_Var8Bytes.Var12bit4 = 0x3ff;
    
    function_ShowMem();
    
    variable_Var8Bytes.MsgCounter++;
    
    delay ( 500 );
}

The screen output shows this.

Terminal Output M0:

Start run

1,20,0,0,3,40,0,0 ---- 1,2,3,4,0,64 - EOM
FF,F0,1F,0,FF,F2,3F,0 ---- FF,1FF,2FF,3FF,0,3E - EOM

1,20,0,0,3,40,0,1 ---- 1,2,3,4,1,64 - EOM
FF,F0,1F,0,FF,F2,3F,1 ---- FF,1FF,2FF,3FF,1,3E - EOM

...

Byte number #3 contains an extra 0x00!!

Running the same code on an Arduino Uno Shows the correct order, and no extra 0x00 byte.

Terminal Output Uno:

Start run

1,20,0,3,40,0,0,64 ---- 1,2,3,4,0,64 - EOM
FF,F0,1F,FF,F2,3F,0,3E ---- FF,1FF,2FF,3FF,0,3E - EOM

1,20,0,3,40,0,1,65 ---- 1,2,3,4,1,65 - EOM
FF,F0,1F,FF,F2,3F,1,3F ---- FF,1FF,2FF,3FF,1,3F - EOM

...

Changing the order of the struct/union shows its correctly??!!!

Code:

#define define_Serial_Debug_Port Serial

typedef union {
    struct {
    
        // Byte 0
        unsigned int  MsgCounter : 4;
        unsigned intnibble_dummy : 4;
        
        // Byte 1 - 2
        unsigned int  Var12bit1 : 12;
        
        // Byte 2 - 3
        unsigned int  Var12bit2 : 12;
        
        // Byte 4 - 5
        unsigned int  Var12bit3 : 12;
        
        // Byte 5 - 6
        unsigned int  Var12bit4 : 12;
        
        // Byte 7
        unsigned int  ChckSum : 8;
    };
    uint8_t Array[8];
} struct_Var8bytes;

struct_Var8bytes variable_Var8Bytes;

void function_ShowMem ( void )
{
    variable_Var8Bytes.ChckSum =
        variable_Var8Bytes.Array[0] +
        variable_Var8Bytes.Array[1] +
        variable_Var8Bytes.Array[2] +
        variable_Var8Bytes.Array[3] +
        variable_Var8Bytes.Array[4] +
        variable_Var8Bytes.Array[5] +
        variable_Var8Bytes.Array[6]
        ;
        
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[0], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[1], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[2], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[3], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[4], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[5], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[6], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[7], HEX );
    
    define_Serial_Debug_Port.print ( " ---- " );
    
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Var12bit1, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Var12bit2, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Var12bit3, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Var12bit4, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.MsgCounter, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.ChckSum, HEX );
    
    define_Serial_Debug_Port.print ( " - EOM" );
    
    define_Serial_Debug_Port.println ( );
}

void setup()
{
    Serial.begin ( 115200 );
    
    define_Serial_Debug_Port.println ( "Start run" );
}

void loop()
{
    define_Serial_Debug_Port.println ( );
    
    variable_Var8Bytes.Var12bit1 = 0x1;
    variable_Var8Bytes.Var12bit2 = 0x2;
    variable_Var8Bytes.Var12bit3 = 0x3;
    variable_Var8Bytes.Var12bit4 = 0x4;
    
    function_ShowMem();
    
    variable_Var8Bytes.Var12bit1 = 0x0ff;
    variable_Var8Bytes.Var12bit2 = 0x1ff;
    variable_Var8Bytes.Var12bit3 = 0x2ff;
    variable_Var8Bytes.Var12bit4 = 0x3ff;
    
    function_ShowMem();
    
    variable_Var8Bytes.MsgCounter++;
    
    delay ( 500 );
}

Terminal Output M0:

Start run

0,1,20,0,3,40,0,64 ---- 1,2,3,4,0,64 - EOM
0,FF,F0,1F,FF,F2,3F,3E ---- FF,1FF,2FF,3FF,0,3E - EOM

1,1,20,0,3,40,0,65 ---- 1,2,3,4,1,65 - EOM
1,FF,F0,1F,FF,F2,3F,3F ---- FF,1FF,2FF,3FF,1,3F - EOM
Start run
...

Terminal Output Uno:

Start run

0,1,20,0,3,40,0,64 ---- 1,2,3,4,0,64 - EOM
0,FF,F0,1F,FF,F2,3F,3E ---- FF,1FF,2FF,3FF,0,3E - EOM

1,1,20,0,3,40,0,65 ---- 1,2,3,4,1,65 - EOM
1,FF,F0,1F,FF,F2,3F,3F ---- FF,1FF,2FF,3FF,1,3F - EOM
...

Am I doing something wrong or like there is something wrong with the compiler for the M0 when using BITFIELDS > 8.
It would be nice to have an solution for this.

Thanks for reading.

Try to use #pragma pack(1).

Whandall:
Try to use #pragma pack(1).

Awesome, this works. Hopefully for all combination cases. I will test. Glad to see its not a core bug! Thank you very much!

It's just standard behaviour. Alignement is a thing on most if not all not 8-bit architectures.

Whandall:
It's just standard behaviour. Alignement is a thing on most if not all not 8-bit architectures.

Used in Midi Structs and CAN Bus before, never noticed before. Maybe i have to revisit those projects :slight_smile: Thanks again

Just for the For other (noobs) like me...
It will crash the Arduino hard when not using this only with the specified variables.

I guess something like...

#define define_Serial_Debug_Port Serial

#pragma pack(1)
typedef union {
    struct {
        // Byte 0 - 1
        unsigned int  Var12bit1 : 12;
       
        // Byte 1 - 2
        unsigned int  Var12bit2 : 12;
       
        // Byte 3 - 4
        unsigned int  Var12bit3 : 12;
       
        // Byte 4 - 5
        unsigned int  Var12bit4 : 12;
       
        // Byte 6
        unsigned int  MsgCounter : 4;
        unsigned intnibble_dummy : 4;
       
        // Byte 7
        unsigned int  ChckSum : 8;
    };
    uint8_t Array[8];
} struct_Var8bytes;

struct_Var8bytes variable_Var8Bytes;
#pragma pack()

void function_ShowMem ( void )
{
    variable_Var8Bytes.ChckSum =
        variable_Var8Bytes.Array[0] +
        variable_Var8Bytes.Array[1] +
        variable_Var8Bytes.Array[2] +
        variable_Var8Bytes.Array[3] +
        variable_Var8Bytes.Array[4] +
        variable_Var8Bytes.Array[5] +
        variable_Var8Bytes.Array[6]
        ;
       
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[0], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[1], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[2], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[3], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[4], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[5], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[6], HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Array[7], HEX );
   
    define_Serial_Debug_Port.print ( " ---- " );
   
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Var12bit1, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Var12bit2, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Var12bit3, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.Var12bit4, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.MsgCounter, HEX );
    define_Serial_Debug_Port.print ( "," );
    define_Serial_Debug_Port.print ( variable_Var8Bytes.ChckSum, HEX );
   
    define_Serial_Debug_Port.print ( " - EOM" );
   
    define_Serial_Debug_Port.println ( );
}

void setup()
{
    Serial.begin ( 115200 );
   
    define_Serial_Debug_Port.println ( "Start run" );
}

void loop()
{
    define_Serial_Debug_Port.println ( );
   
    variable_Var8Bytes.Var12bit1 = 0x1;
    variable_Var8Bytes.Var12bit2 = 0x2;
    variable_Var8Bytes.Var12bit3 = 0x3;
    variable_Var8Bytes.Var12bit4 = 0x4;
   
    function_ShowMem();
   
    variable_Var8Bytes.Var12bit1 = 0x0ff;
    variable_Var8Bytes.Var12bit2 = 0x1ff;
    variable_Var8Bytes.Var12bit3 = 0x2ff;
    variable_Var8Bytes.Var12bit4 = 0x3ff;
   
    function_ShowMem();
   
    variable_Var8Bytes.MsgCounter++;
   
    delay ( 500 );
}