2

I have been developing software drivers for the hw peripherals implemented in the field programmable gate array on this platform. I have been using C++ programming language and arm-none-eabi-gcc compiler.

One of the peripherals has following register map

Register            Offset in bytes in          Bits description
                respect to the base address     
========================================================================================
REGISTER_0              0x00                         0-15
                                                    16-31
----------------------------------------------------------------------------------------
REGISTER_1              0x04                         0-15
----------------------------------------------------------------------------------------
REGISTER_2              0x08                         0-15
----------------------------------------------------------------------------------------
REGISTER_3              0x0C                         0-15
                                                    16-31
----------------------------------------------------------------------------------------
CONTROL_REG             0x10                         0: enable
                                                     1: reset
                                                     2: mask_00 
                                                     3: mask_01
                                                     4: mask_02
                                                     5: mask_03
                                                     6: mask_04
                                                     7: mask_05 
                                                     8: mask_06
                                                     9: mask_07                              
----------------------------------------------------------------------------------------
REGISTER_5              0x14                         0-15
                                                    16-31
----------------------------------------------------------------------------------------
REGISTER_6              0x18                         0-15
                                                    16
----------------------------------------------------------------------------------------
REGISTER_7              0x1C                         0-15
                                                    16
----------------------------------------------------------------------------------------
REGISTER_8              0x20                         0-31
----------------------------------------------------------------------------------------

For the register CONTROL_REG it would be convenient for me to have a possibility to work with individual mask bits along with all the mask bits at once. So I have decided to use union in bit field

int main(int argc, char** argv) {

    struct ControlReg
    {
        uint32_t enable_bit: 1;
        uint32_t reset_bit:  1;
        union
        {
            struct
            {
                uint32_t bit_0: 1;
                uint32_t bit_1: 1;
                uint32_t bit_2: 1;
                uint32_t bit_3: 1;
                uint32_t bit_4: 1;
                uint32_t bit_5: 1;
                uint32_t bit_6: 1;
                uint32_t bit_7: 1;
            }bits;
            uint8_t byte;
       }mask;
   };

   ControlReg control_reg;
   control_reg.mask.byte = 0xAA;
    
   cout << "Mask bit 0: " << control_reg.mask.bits.bit_0 << endl;
   cout << "Mask bit 1: " << control_reg.mask.bits.bit_1 << endl;        
   cout << "Mask bit 2: " << control_reg.mask.bits.bit_2 << endl;
   cout << "Mask bit 3: " << control_reg.mask.bits.bit_3 << endl;        
   cout << "Mask bit 4: " << control_reg.mask.bits.bit_4 << endl;
   cout << "Mask bit 5: " << control_reg.mask.bits.bit_5 << endl;        
   cout << "Mask bit 6: " << control_reg.mask.bits.bit_6 << endl;
   cout << "Mask bit 7: " << control_reg.mask.bits.bit_7 << endl;
}

I have tested that and it works. Nevertheless I have doubts whether this construction is correct. Can anybody tell me whether the approach I have chosen is correct solution for my problem? Thanks in advance.

L3sek
  • 211
  • 3
  • 8
  • Does the register really have a single bit, another single bit and then something of 8bit size? That is what the shown code seems to describe and I doubt it. The fact that you tested it successfully in your environment means that I would trust using it in that environment as much as I trust testing it (i.e. probably enough). But for readability purposes (i.e. targeting humans instead of your compiler, linker) I would change the representation. If you want and if you provide enough details on the register I could propose an alternative in an answer. – Yunnosch Nov 24 '20 at 09:11
  • 1
    Your MCU vendor and/or compiler vendor will normally provide a header with register and bitfield access defined. I strongly recommend that you use such a header specific to your toolchain because bitfield ordering and packing is implementation defined, and because there is no real benefit in defining your own and introducing your own errors over using code that has been validated and used by many more developers. – Clifford Nov 24 '20 at 09:27
  • The above may work in that it produces the output you expect, but your code does not actually assign `control_reg` to any physical register - how do you know that it overlays the register precisely - it is implementation dependent how the compiler packs and aligns bit-fields. It is an X-Y problem in any case. Tell us what the MCU is, and a different more appropriate solution might be proposed. – Clifford Nov 24 '20 at 09:31
  • @Clifford thank you for your reaction. I have been developing drivers for peripherals implemented in field programmable gate array. So I have no supporting header files. I am going to use the placement new construction for assigning the control_reg to physical register. – L3sek Nov 24 '20 at 09:32
  • Then you need to consult your compiler's documentation on how it aligns bitfields. You may be able to control it through `#pragma` or `__attribute__` modifiers. Being reticent about your platform and toolchain is not helping you in this, because the only possible answer without that knowledge is "_it depends_". – Clifford Nov 24 '20 at 09:46
  • Documentation notwithstanding, you might inspect the structure in your debugger to verify its memory layout, because your `cout` inspection proves little. Even without a debugger (by far the simplest method of verification), you might for example compare `&control_reg` with `&control_reg.mask.byte` to test the `byte` is in the correct location relative to the address of the register. You should in any case in this question also describe the register, otherwise how will we know whether the code is a valid map to it even with knowledge of the platform and toolchain? – Clifford Nov 24 '20 at 09:49
  • ... too late, it got closed. Edit it or try again, it is a fair question with insufficient information. – Clifford Nov 24 '20 at 09:50
  • The very point of closing questions (instead of deleting them) is to give the OP a chance to edit and provide more details. So it isn't "too late". – Lundin Nov 24 '20 at 09:52
  • @Lundin : My "too late" comment was precipitated by the fact that by the time I'd posted the preceding comment on how to improve the question, the question was already closed. In that sense it was I that was too late with the advice. But clearly it is not literally "too late". Personally I'd have given more time for the OP to respond to the comments, by improving the question before voting to close, accounting for the possibility of different time-zones for example. – Clifford Nov 24 '20 at 19:19
  • @Clifford I have just attempted to add the missing information into my question. – L3sek Nov 24 '20 at 19:32
  • This is an XY problem, when hopefully the question reopens I can write a detailed answer, but the idea is that you're using C++ and the last thing you need is bitfields. Those were a necessity in C, perhaps, for convenience, but not in C++. Use accessor methods to modify the state of bitfields - they'll be inlined, and make your life relatively easy. You may even forgo using a structure declaration at all, and just use accessors to access individual fields, using pointer arithmetic with a `char *` base address - which can be constexpr probably. – Kuba hasn't forgotten Monica Nov 24 '20 at 19:41
  • 1
    I cannot see how that union could work. The byte member cannot align with bits 2 to 9 of a larger type. – Clifford Nov 24 '20 at 20:59
  • Also please keep in mind that bitfields are not portable code and are compiler/MCU dependent. Like someone else suggested, consider referencing the microcontroller documentation as these SFR (special function registers) are already defined in a header somewhere. – cowboydan Nov 25 '20 at 12:18

0 Answers0