AVR Xmega - Can I simplify this port / peripheral init code?
I'm unfamiliar with the XMega's, but here's something I've used before. It might look tricky if you haven't used pointers this way.

For this example, let's say that you have three SPI controllers, and they each have three registers associated with them. Let's assume these names and addresses are defined in the XMega's header files:

SPI1_CR1 0x4100
SPI1_CR2 0x4102
SPI1_CR3 0x4104

SPI2_CR1 0x4200
SPI2_CR2 0x4202
SPI2_CR3 0x4204

SPI3_CR1 0x4300
SPI3_CR2 0x4302
SPI3_CR3 0x4304


This example assumes that each SPI register's configuration registers follow a similar address scheme. It's possible that this technique won't work with the XMega.


Create a struct to be used as address pointers:

typedef struct
{
    volatile uint16_t CR1; // assumes 16-bit registers
    volatile uint16_t CR2;
    volatile uint16_t CR3;
} SPI_Regs_t


If the register addresses are not contiguous, you will need to adjust for it in your struct by adding useless struct members:

typedef struct
{
    volatile uint16_t CR1; // assumes 32 bits of space between addresses
    uint16_t USELESS1;
    volatile uint16_t CR2;
    uint16_t USELESS2;
    volatile uint16_t CR3;
} SPI_Regs_t

Define pointers to your SPI register addresses:

#define SPI1 ((SPI_Regs_t *) SPI1_CR1)
#define SPI2 ((SPI_Regs_t *) SPI2_CR1)
#define SPI3 ((SPI_Regs_t *) SPI3_CR1)

Now, you can create functions like so:

void SPIInit(SPI_Regs_t* SPIx)
{
    uint16_t myvar;

    SPIx-&gt;Reg1 = 0xFF;
    uint16_t myvar = SPIx-&gt;Reg2;
}



Of course, you'll probably have to choose different names.  I expect "SPI1" is already used in the XMega headers. :)

So, now, the question is: Is it worth it?