Fred 453 Posted November 8, 2016 Share Posted November 8, 2016 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_PORT P2OUT #define LED_RED_PIN BIT1 #endif #if defined (__MSP430F5529__) #define LED_RED_PORT P1OUT #define LED_RED_PIN BIT0 #endif Usage: LED_RED_PORT |= LED_RED_PIN; 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 Usage: if (something) IRQ_ON; 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. Quote Link to post Share on other sites
Fred 453 Posted November 10, 2016 Share Posted November 10, 2016 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. Quote Link to post Share on other sites
Fred 453 Posted November 10, 2016 Share Posted November 10, 2016 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. http://stackoverflow.com/questions/12630548/c-expand-macro-with-token-pasting 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. Quote Link to post Share on other sites
enl 227 Posted November 10, 2016 Share Posted November 10, 2016 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. Quote Link to post Share on other sites
tonyp12 26 Posted March 2, 2017 Share Posted March 2, 2017 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: BlueLED(set,DIR); BlueLED(clear,OUT); Button1(clear,DIR); // a input Button1(set,OUT); // pull-up resistor Button1(set,REN); Button1(set,IES); // falling edge button1(clear,IFG); Button1(set,IE); Rickta59, Fmilburn and agaelema 3 Quote Link to post Share on other sites
Clavier 34 Posted March 3, 2017 Share Posted March 3, 2017 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, /* ... */ }); } Fmilburn 1 Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.