Jump to content

Basic MSP430 GPIO Macros

Recommended Posts

Interesting stuff. I was thinking about this only yesterday, primarily because I have a project that I switch between a F5529LP dev board and a F5510 final PCB. That means it's helpful to be able to switch pins and ports with some sections like this


#if defined (__MSP430F5510__)
#define LED_RED_PIN 	BIT1

#if defined (__MSP430F5529__)
#define LED_RED_PIN BIT0

This simple stuff is all fine, but gets messy when using interrupts and needing to define multiple PxDIR, PxIN, PxOUT, PxSELn, PxIE, etc.


Then I started doing this sort of thing, but it started to feel a bit wrong

#define IRQ_ON P2IE |= IRQ_PIN

  if (something)
I might just use the parameterized macros with ## such as GPIO_SEL(x) so I only have to define the port once. I knew I'd seen something similar once, but couldn't remember where or when. Thanks for reminding me.
Link to post
Share on other sites

Anyone know what I'm doing wrong here?

#define LED_PORT    1
#define PxOUT(port) P##port##OUT

PxOUT(LED_PORT) ^= 0x01;
I get a compilation error - identifier "PLED_PORTOUT" is undefined.


I can see that the value that I pass to the parameterized macro is taken literally rather than being itself defined as 1. How do I tell the preprocessor to make the substitution?


My code looks similar to that above. I've tried changing the ordering, whitespace, throwing in brackets. I can't seem to get it to work.

Link to post
Share on other sites

Ah - Just after I posted I managed to find an answer myself although it's not elegant. It seems that to expand again you need another level of redirection.



This works because of the first rather pointless looking line:

#define PxOUT(port)   PxOUT_(port)
#define PxOUT_(port)  P##port##OUT
#define LED_PORT      1

PxOUT ( LED_PORT ) ^= 0x01;
If anyone knows a slightly neater solution then let me know, but this will do.
Link to post
Share on other sites


Welcome to the preprocessor. I don't know of any more elegant solution as parameters are literal, though there may be one. The second level forces the parameter to be seen as a token itself and be substituted. The initial version did not let the token be seen on its own.


I learned the power, and limitations, or macro expansion with asmh on MVS, writing a 12 liner to expand to the twelve days of xmas for a class. The C/C++ preprocessor is more capable, but is still not doing full featured regeps.



If anyone knows a slightly neater solution then let me know, but this will do.

Link to post
Share on other sites
  • 3 months later...

As all gio registers start with port and then OUT, IN, IE etc, example: P1OUT, with some macro word scrambling you can do this:

#define read &           // words for common gpio interaction
#define clear &= ~
#define set |=
#define toggle ^=

#define Button1(y,x)    (P1 ##x y BIT0)       // PORT and PIN (ignore the ##x y)
#define BlueLED(y,x)    (P2 ##x y BIT5) 

To use them:

Button1(clear,DIR);                       // a input
Button1(set,OUT);                         // pull-up resistor
Button1(set,IES);                         // falling edge
Link to post
Share on other sites

This is how I do my GPIO initialization. It doesn't handle any later GPIO accesses, but it's a nice table, and smaller and faster than configuring the bits one by one.

/* use 0 or 1 to set the output level */
#define OUTPUT        0x00    /* default */
#define INPUT         0x02
#define PULL_DOWN     0x04
#define PULL_UP       0x05
#define REDUCED_DRIVE 0x00    /* default */
#define FULL_DRIVE    0x08
#define GPIO          0x00    /* default */
#define PERIPHERAL    0x10

struct digital_io_init_f5529 {
    u8 P1[8];
    u8 P2[8];
    u8 P3[8];
    u8 P4[8];
    u8 P5[8];
    u8 P6[8];
    u8 P7[8];
    u8 P8[3];
    u8 PJ[4];

static void init_port(const u8 *init, unsigned int count, uint16_t int base_address)
    uint16_t out = 0, dir = 0, ren = 0, ds = 0, sel = 0;
    uint16_t bit;

    for (bit = 1; count > 0; init++, bit <<= 1, count--) {
        if (*init & 1)          out |= bit;
        if (!(*init & INPUT))   dir |= bit;
        if (*init & PULL_DOWN)  ren |= bit;
        if (*init & FULL_DRIVE) ds  |= bit;
        if (*init & PERIPHERAL) sel |= bit;
    HWREG16(base_address + OFS_PAOUT) = out;
    HWREG16(base_address + OFS_PADIR) = dir;
    HWREG16(base_address + OFS_PAREN) = ren;
    HWREG16(base_address + OFS_PADS ) = ds;
    HWREG16(base_address + OFS_PASEL) = sel;

static void init_ports(const struct digital_io_init_f5529 *init)
    init_port(init->P1, 8 + 8, PA_BASE);
    init_port(init->P3, 8 + 8, PB_BASE);
    init_port(init->P5, 8 + 8, PC_BASE);
    init_port(init->P7, 8 + 3, PD_BASE);
    init_port(init->PJ, 4,     PJ_BASE);

void init()
    init_ports(&(const struct digital_io_init_f5529){
           .P4[4] = PERIPHERAL | OUTPUT,
           .P4[5] = PERIPHERAL | INPUT,
           .P7[0] = GPIO | INPUT | PULL_UP,
           .P7[1] = GPIO | OUTPUT | FULL_DRIVE,
           /* ... */
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...