I am trying to get a union together to map out some bit fields in a register map. The code I have is the following:
typedef union __attribute__((packed)) {
struct {
uint8_t MODE:3;
uint8_t VSHCT:3;
uint8_t VBUSCT:3;
uint8_t AVG:3;
uint8_t RSVD:3;
uint8_t RST:1;
};
struct {
uint8_t lsbyte:8;
uint8_t msbyte:8;
};
uint16_t w;
} CON_MAP_t;
I am initializing the fields with:
CON_MAP_t map = {
.RST = 0,
.RSVD = 4,
.AVG = 0,
.VBUSCT = 4,
.VSHCT = 4,
.MODE = 7
}
So far this is all fine, no compiler issues or warnings.
I expect the binary/hex representation to be 01000001_00100111 / 0x4127.
However, in the debugger I end up with a value for 'w' of: 00000100_00100111 The least significant byte is correct, but the msb(yte) is not.
I am not sure if I'm missing something fundamental here and I've just been staring at it too long, but any insight would be highly appreciated!
I am using: MPLABX v6.05 Latest XC32 Compiler
Device is a PIC32MX130F064D debugging with a PICKIT4.
When it comes to using compilers that supports some additional features over standard C compilers, like XC32 Compiler, it always is better to refer to its guides and manuals for special cases like this one.
The XC32 does fully support bit fields in structures and also guarantee the order as the first defined bit as to be the Least Significant bit. Here is how it described in section 8.6.2 Bit Fields in Structures of XC32 C Compiler User's Guide:
MPLAB XC32 C/C++ Compiler fully supports bit fields in structures. Bit fields are always allocated within 8-bit storage units, even though it is usual to use the type
unsigned int
in the definition. Storage units are aligned on a 32-bit boundary, although this can be changed using thepacked
attribute.
The first bit defined will be the Least Significant bit of the word in which it will be stored. When a bit field is declared, it is allocated within the current 8-bit unit if it will fit; otherwise, a new byte is allocated within the structure. Bit fields can never cross the boundary between 8-bit allocation units.
For example, the declaration:
struct {
unsigned lo : 1;
unsigned dummy : 6;
unsigned hi : 1;
} foo;
will produce a structure occupying 1 byte.
So according to the guide description you should see the same order as per your bit definition.
Also note that packed
attribute is meant to use only if you want to alter the 32-bit boundary. But it is not necessary since yours is only 16-bits.
Here is a demo showing the expected result following with the code:
Demo code shown in the screenshot:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef union {
struct {
unsigned MODE:3;
unsigned VSHCT:3;
unsigned VBUSCT:3;
unsigned AVG:3;
unsigned RSVD:3;
unsigned RST:1;
};
struct {
uint8_t lsbyte:8;
uint8_t msbyte:8;
};
uint16_t w;
} CON_MAP_t;
int main(int argc, char** argv) {
CON_MAP_t map = {
.RST = 0,
.RSVD = 4,
.AVG = 0,
.VBUSCT = 4,
.VSHCT = 4,
.MODE = 7
};
if(map.lsbyte == 0x27 && map.msbyte == 0x41)
return (EXIT_SUCCESS);
else
return (EXIT_FAILURE);
}