cstructmicrocontrollerbit-fieldscodewarrior

How to create bitfield out of existing variables in C


I am working on a Motorola HCS08 µCU in CodeWarrior V10.6, I am trying to create an extern bitfield which has bits from existing registers. The way the bitfields are created in the µCU header is like

typedef unsigned char byte;
typedef union {
  byte Byte;
  struct {
    byte PTAD0       :1;
    byte PTAD1       :1;                                     
    byte PTAD2       :1;                                     
    byte PTAD3       :1;                                     
    byte PTAD4       :1;                                     
    byte PTAD5       :1;                                     
    byte PTAD6       :1;                                     
    byte PTAD7       :1;                                     
  } Bits;
} PTADSTR;
extern volatile PTADSTR _PTAD @0x00000000;
#define PTAD                            _PTAD.Byte
#define PTAD_PTAD0                      _PTAD.Bits.PTAD0
#define PTAD_PTAD1                      _PTAD.Bits.PTAD1
#define PTAD_PTAD2                      _PTAD.Bits.PTAD2
#define PTAD_PTAD3                      _PTAD.Bits.PTAD3
#define PTAD_PTAD4                      _PTAD.Bits.PTAD4
#define PTAD_PTAD5                      _PTAD.Bits.PTAD5
#define PTAD_PTAD6                      _PTAD.Bits.PTAD6
#define PTAD_PTAD7                      _PTAD.Bits.PTAD7

Which will let the register value be changed either by PTAD = 0x01, or PTAD_PTAD0 = 1, for example. This definition is basically the same for PTAD, PTBD, PTCD, ... PTGD, the only thing changing is the address.

My attemp to create a custom bitfield out of the previous existing variables is

typedef union {
  byte Byte;
  struct {
    byte *DB0;
    byte *DB1;
    byte *DB2;
    byte *DB3;
    byte *DB4;
    byte *DB5;
    byte *DB6;
    byte *DB7;
  } Bits;
} LCDDSTR;

I would create and initialize the bitfield as LCDDSTR lcd = {{&PTGD_PTGD6, &PTBD_PTBD5, ...}}, because by some reason, the initialization like LCDSTR lcd = {*.Bits.DB0 = &PTGD_PTGD6, *.Bits.DB1 = &PTBD_PTBD5, ...} (treating it as a struct, please correct me again) advice in How to initialize a struct in accordance with C programming language standards does not work with this compiler (it does work on an online compiler).

However, as you may see I am sort of grouping the bits, and (if it would work) I would be able to change the values of the actual register by doing *lcd.Bits.DB0 = 1, or something like that, but if I do lcd.Byte = 0x00, I would be changing the last (I think) byte of the memory address contained in lcd.Bits.DB0, you know, because the struct doesn't actually contains the data, but the pointers instead.

How would I go on achieving a struct that is able to contain and modify bits from several registers? (I guess the problem here is that in memory the bits are not one next to the other, which I guess would make it easier). Is it even possible? I hope it is.


Solution

  • How would I go on achieving a struct that is able to contain and modify bits from several registers? (I guess the problem here is that in memory the bits are not one next to the other..

    I don't think you can do it with a struct. That is because bitfields by definition have to occupy the same or contiguous addresses.

    However macros may be useful here

    #define DB0  PTGD_PTGD6
    #define DB1  PTBD_PTBD5
    ....
    

    And to clear the bits to all 0's or set to all 1's you can use a multiline macro

    #define SET_DB(x) do { \
        PTGD_PTGD6 = x;    \
        PTBD_PTBD5 = x;    \
        ......             \
    } while(0)