Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

#define vs. enums for addressing peripherals

I have to program peripheral registers in an ARM9-based microcontroller.

For instance, for the USART, I store the relevant memory addresses in an enum:

enum USART
{
    US_BASE = (int) 0xFFFC4000,
    US_BRGR = US_BASE + 0x16,
    //...
};

Then, I use pointers in a function to initialize the registers:

void init_usart (void)
{
    vuint* pBRGR = (vuint*) US_BRGR;
    *pBRGR = 0x030C;
    //...
}

But my teacher says I'd better use #defines, such as:

#define US_BASE (0xFFFC4000)
#define US_BRGR (US_BASE + 0x16)
#define pBRGR   ((vuint*) US_BRGR)

void init_usart (void)
{
    *pBRGR = 0x030C;
}

Like so, he says, you don't have the overhead of allocating pointers in the stack.

Personally, I don't like #defines much, nor other preprocessor directives. So the question is, in this particular case, are #defines really worth using instead of enums and stack-allocated pointers?


Related question: Want to configure a particular peripheral register in ARM9 based chip

like image 783
parras Avatar asked Oct 19 '10 17:10

parras


3 Answers

The approach I've always preferred is to first define a struct reflecting the peripherals register layout

typedef volatile unsigned int reg32; // or other appropriate 32-bit integer type
typedef struct USART
{
    reg32 pad1;
    reg32 pad2;
    reg32 pad3;
    reg32 pad4;
    reg32 brgr;
    // any other registers
} USART;

USART *p_usart0 = (USART * const) 0xFFFC4000;

Then in code I can just use

p_usart0->brgr = 0x030C;

This approach is much cleaner when you have multiple instances of the same sort of peripheral:

USART *p_usart1 = (USART * const) 0xFFFC5000;
USART *p_usart2 = (USART * const) 0xFFFC6000;

User sbass provided a link to an excellent column by Dan Saks that gives much more detail on this technique, and points out its advantages over other approaches.

If you're lucky enough to be using C++, then you can add methods for all the common operations on the peripheral and nicely encapsulate the devices peculiarities.

like image 73
Stephen C. Steel Avatar answered Nov 04 '22 05:11

Stephen C. Steel


I am afraid that enum are a dead end for such a task. The standard defines enum constants to be of type int, so in general they are not compatible with pointers.

One day on an architecture with 32bit int and 64bit pointers you might have a constant that doesn't fit into an int. It is not well defined what will happen.

On the other hand the argument that enum would allocate something on the stack is not valid. They are compile time constants and have nothing to do with the function stack or no more than any constants that you specify through macros.

like image 5
Jens Gustedt Avatar answered Nov 04 '22 05:11

Jens Gustedt


Dan Saks has written a number of columns on this for Embedded Systems Programming. Here's one of his latest ones. He discusses C, C++, enums, defines, structs, classes, etc. and why you might one over another. Definitely worth reading and always good advice.

like image 3
sbass Avatar answered Nov 04 '22 06:11

sbass