views:

124

answers:

3

I am attempting to alter an IAR specific header file for a lpc2138 so it can compile with Visual Studio 2008 (to enable compatible unit testing).

My problem involves converting register definitions to be hardware independent (not at a memory address)

The "IAR-safe macro" is:

#define __IO_REG32_BIT(NAME, ADDRESS, ATTRIBUTE, BIT_STRUCT) \
                    volatile __no_init ATTRIBUTE union       \
                     {                                       \
                       unsigned long NAME;                   \
                       BIT_STRUCT NAME ## _bit;              \
                     } @ ADDRESS
//declaration
//(where __gpio0_bits is a structure that names 
//each of the 32 bits as P0_0, P0_1, etc)
__IO_REG32_BIT(IO0PIN,0xE0028000,__READ_WRITE,__gpio0_bits);
//usage
IO0PIN = 0x0xAA55AA55;
IO0PIN_bit.P0_5 = 0;

This is my comparable "hardware independent" code:

#define __IO_REG32_BIT(NAME, BIT_STRUCT)\
                    volatile union \
                     {                                 \
                       unsigned long NAME;             \
                       BIT_STRUCT NAME##_bit;      \
                     } NAME;
//declaration
__IO_REG32_BIT(IO0PIN,__gpio0_bits);
//usage
IO0PIN.IO0PIN = 0xAA55AA55;
IO0PIN.IO0PIN_bit.P0_5 = 1;

This compiles and works but quite obviously my "hardware independent" usage does not match the "IAR-safe" usage.

How do I alter my macro so I can use IO0PIN the same way I do in IAR? I feel this is a simple anonymous union matter but multiple attempts and variants have proven unsuccessful. Maybe the IAR GNU compiler supports anonymous unions and vs2008 does not.

Thank you.

A: 

The usual way of doing this is with a macro that just casts the desired address to the appropriate type:

#define __IO_REG32_BIT(NAME, BIT_STRUCT) \
    typedef volatile union \
    { \
        unsigned long NAME##_value: \
        BIT_STRUCT NAME##_bit; \
    } NAME##_type

__IO_REG32_BIT(IO0PIN, __gpio0_bits);
#define IO0PIN (*(IO0PIN_type *)0xE0028000)

Now IO0PIN can be used just as you described. However, note that I had to rename the internal field and type name to avoid conflicting with the macro name IO0PIN. You can of course rename things to your liking.

Adam Rosenfield
I tried this code and I had to use:IO0PIN.IO0PIN_value = 0xAA55AA55;IO0PIN.IO0PIN_bit.P0_5 = 1;I want to be able to simply use:IO0PIN = 0xAA55AA55;IO0PIN_bit.P0_5 = 1;It is not important to have IO0PIN point to the address 0xE0028000.I just want a plain old variable to use in high-level unit testing.
Alan_m
If this macro is used on a PC for unit testing it will cause a crash when you try to assign a value to a fixed address (0xE002800)...or am I missing something?
semaj
It compiled just fine but yeah I'm uncertain of the behavior. Again, I have no need to use that address.
Alan_m
@Alan_m: I'm confused about what you're trying to do then. What is wrong with your current hardware-independent code?
Adam Rosenfield
A: 

I know this isn't an answer but I don't have enough reputation to edit the question. I hope this might be helpful for clarification. If you take all of the macros out of the picture, what Alan_m wants to end up with is an anonymous union like the following:

volatile union {
   u32 IO0PIN;
   u16 IO0PIN_bit;
};

That can be referenced like this:

void test( void )
{
   IO0PIN = 0x0xAA55AA55;
   IO0PIN_bit.P0_5 = 0;
}

This works O.K. with the IAR compiler but causes a compiler error on the VC++ compiler

error C2646: global anonymous unions must be declared static

Note that this is from VS2005 so it might be slightly different than VS2008.

I would imagine all of Alan_m's code is already written to IAR standards and would have to be modified to use named unions which he wants to avoid.

semaj
A: 

Ok folks here's what ended up working for me:

#define __IO_REG32_BIT(NAME, BIT_STRUCT)\
    volatile union\
    {\
        unsigned long NAME;\
        BIT_STRUCT NAME##_bit;\
    } NAME##_type;

__IO_REG32_BIT(IO0PIN,__gpio0_bits);        

#define IO0PIN IO0PIN_type.IO0PIN
#define IO0PIN_bit IO0PIN_type.IO0PIN_bit

Now I can use the following in my code for unit testing:

IO0PIN = 0xFFFFFFFF;
IO0PIN_bit.P0_5 = 1;

And the preprocessor will replace it with:

IO0PIN_type.IO0PIN = 0xFFFFFFFF;
IO0PIN_type.IO0PIN_bit.P0_5 = 1;
Alan_m
Thanks to @Adam Rosenfield and @semaj for helping me get to this!
Alan_m