# Register map using C for a MAX30001 analog front end

I am trying to follow the best practices in register mapping. I have a MAX30001 analog front end for ECG applications (Datasheet) and in page 38, there is a table that contains user command and register map: 32 words, each with 24 bits of information. Should I use structures or macros ?

Using structures with bit fields:

typedef struct {

volatile uint8_t Bit0 : 1;
volatile uint8_t Bit1 : 1;
volatile uint8_t Bit2 : 1;
volatile uint8_t Bit3 : 1;
// ...
// and so on
// ...
volatile uint8_t Bit23 : 1;
} foo;


Using macros:

#define STATUS (*(volatile uint32_t*)0x01))

• Could you explain how would you use structures or macros? For each, add an example (and external references, if any), perhaps. I probably understand what you mean [I think]. But it would be better if you explain yourself. – Nick Alexeev Nov 26 '17 at 20:55
• let's say you want to set BINT (statusReg:bit3) ... how would the code look for each of the mapping methods? ... which would be easier to read? – jsotola Nov 26 '17 at 21:42
• Alright. post edited. – Pryda Nov 26 '17 at 22:35

In the general case, where you have memory mapped registers, you should always avoid bitfield structs. This is because those are very poorly specified by the C standard. Fundamental things that you may assume are specified, are not. This includes bit order, byte order, padding & alignment.

In addition, uint8_t among other types, is not even an allowed type in bitfields! You can only use int types, though if int counts as signed or unsigned is not specified either...

To sum it up, bitfields are horribly unreliable and you are left at the mercy of the compiler implementation (if any) when you use them.

What you should do instead, is to always use address and bit mask macros, together with the bit-wise operators. Those are 100% well-defined and portable.

The MAX30001 uses an SPI interface. It's not a memory-mapped device, so neither structures nor macros are usable here.

About all you can usefully do is define a bunch of macros to represent the register numbers and individual bits within them, e.g:

#define MAX30001_NO_OP           0x00
#define MAX30001_STATUS          0x01
#define MAX30001_STATUS_EINT     0x800000
#define MAX30001_STATUS_EOVF     0x400000
#define MAX30001_STATUS_FSTINT   0x200000
// etc


Even for memory-mapped devices, it's generally best to avoid bitfields (like Bit0:1). C compilers often handle them poorly, and make few guarantees about how bitfields will be packed into a structure. Use macros to represent individual bits within a single register.