67. Control Register Using Nested Bitfields

You are given a control register represented using nested struct bitfields. The register is 8-bit wide and divided into the following layout:

BitsFieldDescription
0enable1 = ON, 0 = OFF
1mode0 = Normal, 1 = Sleep
2–3priority2-bit value (0–3)
4–7reservedReserved (must be 0)


Your task is to:

  • Simulate this register using nested struct and bitfields
  • Implement a function that takes a pointer to the register and validates:
    • enable must be 1
    • priority must be less than or equal to 2
    • reserved must be all 0s

Return 1 if valid, else return 0.

 

Example-1

Input: 0x05 → 00000101
Output: 1

(enable=1, mode=0, priority=1, reserved=0)


Example-2

Input: 0x0F → 00001111
Output: 0

(priority=3, reserved=0)


Example-3

Input: 0x95 → 10010101
Output: 0

(reserved ≠ 0)


 

 

Need Help? Refer to the Quick Guide below

A union is a special data structure where all members share the same memory location.

It allows we to store data in one form and access it in another, without conversions.

union Example {
    uint32_t num;
    uint8_t bytes[4];
};

In this example, num and bytes occupy the same 4 bytes of memory.

Why Use Unions in Firmware?

Unions are widely used in embedded firmware to:

Use CaseExample
Access individual bytes of a registerTransmitting 32-bit values as 4 bytes
Overlay structured fields on raw buffersParse sensor or protocol frames
Serialize/deserialize data to/from byte streamsUART, SPI, I2C communication
Interpret float as 4 raw bytesSending float over network or UART

 

Key Concept: Memory Reinterpretation

we can write to one member of the union and read from another:

union Data {
    float f;
    uint8_t bytes[4];
};

union Data d;
d.f = 3.14;

// Now d.bytes contains raw byte representation of float

Important: No memory is copied. This is just a reinterpretation of the same bytes.

 

Common Union Patterns in Firmware

1. Extract Bytes from a 32-bit Value

union {
    uint32_t value;
    uint8_t bytes[4];
} reg;

reg.value = 0x12345678;
// reg.bytes[0] = 0x78 (LSB), reg.bytes[3] = 0x12 (MSB)

Useful in:

  • Sending 32-bit data over 8-bit UART
  • Writing data into memory-mapped buffers

2. Modify Specific Bytes

reg.bytes[0] = 0xAB;  // Modify LSB
reg.bytes[3] = 0xCD;  // Modify MSB

Updates the overall reg.value automatically.

3. Overlay Struct on Union (Packet Layout)

union Packet {
    struct {
        uint8_t header;
        uint8_t length;
        uint8_t payload[2];
        uint8_t checksum;
    };
    uint8_t raw[5];
};

we can fill fields via struct and transmit raw[ ], or receive raw[ ] and access fields via struct.

4. Decode Bitfields from ADC or Status Register

typedef union {
    uint16_t raw;
    struct {
        uint16_t data : 12;
        uint16_t gain : 2;
        uint16_t ready : 1;
        uint16_t error : 1;
    } bits;
} ADC_Result;

ADC_Result res;
res.raw = 0x8D4E;

We can access res.bits.gain or res.bits.data directly, like register view.

5. Transmit Float as Bytes

union {
    float f;
    uint8_t b[4];
} tx;

tx.f = 2.718;
// Now send tx.b[0..3] over UART

 

Struct vs Union — Key Difference

  • Struct: All members occupy separate memory — total size is the sum of all members (plus padding).
  • Union: All members share the same memory — total size is equal to the size of the largest member.

Example:

struct S {
    uint32_t a;   // 4 bytes
    uint8_t  b;   // 1 byte
}; // Likely size = 8 (due to padding)

union U {
    uint32_t a;   // 4 bytes
    uint8_t  b;   // shares with a
}; // Size = 4

Union Firmware Relevance

Where It HelpsHow
Low-level communicationConvert structured data to raw byte stream
Compact control register designAccess fields and bytes efficiently
Protocol simulationInterpret packets by field
Debugging / AnalysisByte-level inspection of float/int
Buffer-safe conversionNo memcpy needed

 

Common Pitfalls

MistakeFix
❌ Assuming order of bytes is same across systems (endianness)Use endian-aware handling
❌ Accessing wrong member after overwriteAlways ensure which member was last written
❌ Using union across different compilersCompiler-specific behavior in padding/bit order (document  format)
✅ Use unions for reinterpretation, not logic computation 
✅ Always check sizeof(union) if using in communication