EmbeddedRelated.com
Forums

port I/O abstraction macros

Started by Tom Torfs June 2, 2006
Everyone,

Earlier I posted some macros that allow you to easily define binary
constants in C (see http://cprog.tomsweb.net/binconst.txt). Playing
similar tricks with the preprocessor, I now created some macros that
allow you to make easy abstraction of port I/O's. It's written for the
MSP430 but the concept can be applied to other embedded architectures.

 You simply define your signal location like:
	 #define LED P1,0
 and then use them like:
	 SETDIR(LED);
	 CLR(LED);
	 TOGGLE(LED);

The obvious advantage, besides readability, is that in the next
hardware design or layout iteration - when most of the signals have
shifted to different pins on different ports - all you need to change
is one simple and readable #define in a central location.

Header file (or http://cprog.tomsweb.net/portio.txt):

/* Port I/O abstraction macros - by Tom Torfs, 2006
 * MSP430 implementation
 * Donated to the public domain. No warranties whatsoever.
 *
 * These macros allow you to make easy abstraction of I/O port & pin
numbers.
 * You simply define your signal location like:
 *	 #define LED P1,0
 * and then use them like:
 *	 SETDIR(LED);
 *	 CLR(LED);
 *	 TOGGLE(LED);
 *	...
 *
 * The obvious advantage, besides readability, is that in the next
 * hardware design or layout iteration - when most of the signals have
 * shifted to different pins on different ports - all you need to
change
 * is one simple and readable #define in a central location
 *
 * In addition, nothing stops you from porting this header to other
 * microcontroller families. The specifics such as direction and
interrupt
 * registers may be different but the basic concepts hold.
 *
 * Overview of user macros:
 * - Reading from port registers: (these are meant to be used in
expressions)
 *   x = IN(signal), OUTBUF(signal), DIR(signal), SEL(signal),
IE(signal), IES(signal), IFG(signal)
 * - Writing to port registers: (these are meant to be used as
statements)
 *   output bit manipulation: SET(signal); CLR(signal); TOGGLE(signal);
 *   direction bit manipulation: SETDIR(signal); CLRDIR(signal);
 *   special function bit manipulation: SETSEL(signal); CLRSEL(signal);
 *   interrupt bits manipulation: SETIE(signal); CLRIE(signal);
SETIES(signal); CLRIES(signal);
 *   interrupt flag manipulation: SETIFG(signal); CLRIFG(signal);
 *   copy 1 or 0 into output bit: CPYBIT(signal,bitvalue)
 * - Getting the port name (string) or bit number (integer literal)
corresponding to a signal:
 *   const char s[] = PORTNAME(name);
 *   x = BITNUM(name);
 * - Interrupt vector for port corresponding to a signal: (requires
compiler-specific mapping)
 *   INTVECTOR(name)
 */

/********** HELPER MACROS **********/

#define POUT_(Pn) Pn##OUT
#define PIN_(Pn)  Pn##IN
#define PDIR_(Pn) Pn##DIR
#define PSEL_(Pn) Pn##SEL
#define PIE_(Pn)  Pn##IE
#define PIES_(Pn) Pn##IES
#define PIFG_(Pn) Pn##IFG

#define IN_(p,b)  (PIN_(p)&(1<<b))
#define OUTBUF_(p,b) (POUT_(p)&(1<<b))
#define DIR_(p,b) (PDIR_(p)&(1<<b))
#define SEL_(p,b) (PSEL_(p)&(1<<b))
#define IE_(p,b)  (PIE_(p)&(1<<b))
#define IES_(p,b) (PIES_(p)&(1<<b))
#define IFG_(p,b) (PIFG_(p)&(1<<b))

#define SET_(p,b) POUT_(p)|=(1<<(b))
#define CLR_(p,b) POUT_(p)&=~(1<<(b))
#define TOGGLE_(p,b) POUT_(p)^=(1<<(b))
#define SETDIR_(p,b) PDIR_(p)|=(1<<(b))
#define SETSEL_(p,b) PSEL_(p)|=(1<<(b))
#define SETIE_(p,b)  PIE_(p)|=(1<<(b))
#define SETIES_(p,b) PIES_(p)|=(1<<(b))
#define SETIFG_(p,b) PIFG_(p)|=(1<<(b))
#define CLRDIR_(p,b) PDIR_(p)&=~(1<<(b))
#define CLRSEL_(p,b) PSEL_(p)&=~(1<<(b))
#define CLRIE_(p,b)  PIE_(p)&=~(1<<(b))
#define CLRIES_(p,b) PIES_(p)&=~(1<<(b))
#define CLRIFG_(p,b) PIFG_(p)&=~(1<<(b))

#define PORTNAME_(p,b) #p
#define BITNUM_(p,b) b

#define INTVECTOR_(p,b) INTVECTOR_##p

/********** USER MACROS **********/

/* for reading from port registers
   note: these return 0 or nonzero, not 0 or 1
         if necessary, use as: x = IN(signal) ? 1 : 0;
		 not necessary for normal use in if() etc. */
#define IN(name)  IN_(name)
#define OUTBUF(name) OUTBUF_(name)
#define DIR(name) DIR_(name)
#define SEL(name) SEL_(name)
#define IE(name)  IE_(name)
#define IES(name) IES_(name)
#define IFG(name) IFG_(name)

/* for writing to port registers */
#define SET(name) SET_(name)
#define CLR(name) CLR_(name)
#define TOGGLE(name) TOGGLE_(name)
#define SETDIR(name) SETDIR_(name)
#define SETSEL(name) SETSEL_(name)
#define SETIE(name)  SETIE_(name)
#define SETIES(name) SETIES_(name)
#define SETIFG(name) SETIFG_(name)
#define CLRDIR(name) CLRDIR_(name)
#define CLRSEL(name) CLRSEL_(name)
#define CLRIE(name)  CLRIE_(name)
#define CLRIES(name) CLRIES_(name)
#define CLRIFG(name) CLRIFG_(name)

#define CPYBIT(name,bit) ((bit) ? (SET_(name)) : (CLR_(name)))

/* if you want to know the port (string) or the bit number (integer
literal) */
#define PORTNAME(name) PORTNAME_(name)
#define BITNUM(name)   BITNUM_(name)

/* interrupt vector for port */
#define INTVECTOR(name) INTVECTOR_(name)

/* mapping to compiler-specific interrupt vector names/numbers
   (this is for mspgcc, adapt for your compiler) */
#define INTVECTOR_P1 PORT1_VECTOR
#define INTVECTOR_P2 PORT2_VECTOR

/* USAGE EXAMPLE:

   - define your port I/O's as follows: (note you MUST use a #define,
not an enum)
	#define LED P1,0
	#define INPUTSIGNAL P2,1
	#define ANALOGSIGNAL P6,3
	#define INTSIGNAL P2,2
	#define SIGBIT0 P3,7
	#define SIGBIT1 P3,6
	#define SIGBIT2 P3,5
	#define UNUSED1 P1,5
	#define UNUSED2 P1,6
	#define UNUSED3 P1,7

   - examples of usage:
	SETDIR(LED); CLR(LED); TOGGLE(LED);
	CLRDIR(INPUTSIGNAL); x = IN(INPUTSIGNAL);
	SETSEL(ANALOGSIGNAL);
	SETIE(INTSIGNAL); CLRIE(INTSIGNAL);
	CPYBIT(SIGBIT0,x&1); CPYBIT(SIGBIT1,x&2); CPYBIT(SIGBIT2,x&4);
	SETDIR(UNUSED1); SETDIR(UNUSED2); SETDIR(UNUSED3); // set to output to
save power
	printf("The LED is on port %s, bit %d.\n", PORTNAME(LED),
BITNUM(LED));
    ADC12MCTL0 = SREF_0 | BITNUM(ANALOGSIGNAL);

   - example interrupt routine (compiler-specific syntax)
	interrupt(INTVECTOR(INTSIGNAL)) int_func(void)
	{
		if (IFG(INTSIGNAL))
		{
			// do something...
			CLRIFG(INTSIGNAL);	// clear interrupt flag
		}
	}
*/

On 2006-06-02, Tom Torfs <tomtorfs@gmail.com> wrote:
> I now created some macros that > allow you to make easy abstraction of port I/O's. > > You simply define your signal location like: > #define LED P1,0 > and then use them like: > SETDIR(LED); > CLR(LED); > TOGGLE(LED);
> The obvious advantage, besides readability
I prefer to go a step further, because these types of macros require you to embed the hardware's logic state throughout your code. I use macros like: #define LED_ON(led) LED_ ## led = 1 #define LED_OFF(led) LED_ ## led = 0 #define LED_GREEN some_port_pin_name LED_ON(GREEN); which I find more readable (neither I nor the person reading my code needs to remember whether a logic high or a logic low turns on an LED), and more maintainable (when the hardware changes and the LEDs become active low, I just have to make a change in a header). This doesn't work when some LEDs are active high and others are active low, but in that case I'll use something like: #define LED_GREEN some_port_pin_name #define LED_GREEN_ON LED_GREEN = 1 #define LED_GREEN_OFF LED_GREEN = 0 which still keeps the logic state of the hardware in one place. -- John W. Temples, III
John,

John Temples schreef:

> I prefer to go a step further, because these types of macros require > you to embed the hardware's logic state throughout your code. I use > macros like: > > #define LED_ON(led) LED_ ## led = 1 > #define LED_OFF(led) LED_ ## led = 0 > > #define LED_GREEN some_port_pin_name > > LED_ON(GREEN);
I do that too, using my macros that would become then: #define LED_ON(led) CLR(led) #define LED_OFF(led) SET(led) However, often you need more complicated operations than just setting or clearing the bit - manipulating corresponding interrupt flags, direction registers, associated interrupt vectors etc. For these operations, the macros I posted automatically map the correct port registers for the signal (e.g. for P2.3 on MSP430 this would pick out bit 3 of P2OUT, P2IN, P2DIR, P2SEL, P2IE, P2IES and P2IFG, respectively). greetings, Tom
"Tom Torfs" <tomtorfs@gmail.com> wrote in message 
news:1149274847.733281.46970@u72g2000cwu.googlegroups.com...
> Everyone, > > Earlier I posted some macros that allow you to easily define binary > constants in C (see http://cprog.tomsweb.net/binconst.txt). Playing > similar tricks with the preprocessor, I now created some macros that > allow you to make easy abstraction of port I/O's. It's written for the > MSP430 but the concept can be applied to other embedded architectures. > > You simply define your signal location like: > #define LED P1,0 > and then use them like: > SETDIR(LED); > CLR(LED); > TOGGLE(LED);
We take on alot of intern students and student projects etc. and I have always found their ability to do bitwise manipulation in C to be completely hopeless. What are universities teaching them these days? Its the year 2006 and they still come out knowing how to program an 8051 in assembly but not knowing what c &= ~(1<<4); does.
DAC,

> We take on alot of intern students and student projects etc. and I have > always found their ability to do bitwise manipulation in C to be completely > hopeless. What are universities teaching them these days? Its the year 2006 > and they still come out knowing how to program an 8051 in assembly but not > knowing what c &= ~(1<<4); does.
But then again you have to admit this method is a bit clunky compared to the bit set / bit clear instructions the underlying architecture usually provides. Also, all you can say from that statement is that it clears bit 4 of a certain variable or register. Some more abstraction can go a long way to making a program more readable. But the main goal for me is not even readability, but being able to easily swap port pins around (for layout or other reasons), without having to wade through the program and adjust all I/O statements. greetings, Tom
DAC wrote:

> We take on alot of intern students and student projects etc. and I > have always found their ability to do bitwise manipulation in C to be > completely hopeless. What are universities teaching them these days? > Its the year 2006 and they still come out knowing how to program an > 8051 in assembly but not knowing what c &= ~(1<<4); does.
Forget interns, we've interviewed "experienced" engineers that have trouble writing pseudo-code to shift an 8-bit value out a 1-bit port. Then there are those that have trouble explaining the procedure to represent a number in binary. One insisted that the number had to be "converted to hex" first! -- Mark McDougall, Engineer Virtual Logic Pty Ltd, <http://www.vl.com.au> 21-25 King St, Rockdale, 2216 Ph: +612-9599-3255 Fax: +612-9599-3266
"DAC" <Mister@Enigma.net> wrote in message 
news:448155af$0$29269$afc38c87@news.optusnet.com.au...
> > "Tom Torfs" <tomtorfs@gmail.com> wrote in message > news:1149274847.733281.46970@u72g2000cwu.googlegroups.com... >> Everyone, >> >> Earlier I posted some macros that allow you to easily define binary >> constants in C (see http://cprog.tomsweb.net/binconst.txt). Playing >> similar tricks with the preprocessor, I now created some macros that >> allow you to make easy abstraction of port I/O's. It's written for the >> MSP430 but the concept can be applied to other embedded architectures. >> >> You simply define your signal location like: >> #define LED P1,0 >> and then use them like: >> SETDIR(LED); >> CLR(LED); >> TOGGLE(LED); > > We take on alot of intern students and student projects etc. and I have > always found their ability to do bitwise manipulation in C to be > completely hopeless. What are universities teaching them these days? Its > the year 2006 and they still come out knowing how to program an 8051 in > assembly but not knowing what c &= ~(1<<4); does.
I must say that I graduated in 2001 from a Computer Systems course and at no point was bitwise manipulation even mentioned unless you took a module rather unhelpfully named as "industrial control" which scared people off with talk of dull ladder diagrams but was actually assembly language programming of PICs. Good course in fact but under-subscribed because no-one was sure what it actually was. My degree was a hybrid so I mixed with the Computer Scientists and the Electronic Engineers but neither of them would have even seen an embedded system without going on the industrial control module. The closest the EE guys got was an ancient 6800 programmed in hex via a 16 key keypad but it was only for one lab class and you just followed the crib sheet without having to understand what you were doing.
Tom Lucas wrote:
>
... snip ...
> > I must say that I graduated in 2001 from a Computer Systems course > and at no point was bitwise manipulation even mentioned unless you > took a module rather unhelpfully named as "industrial control" > which scared people off with talk of dull ladder diagrams but was > actually assembly language programming of PICs. Good course in fact > but under-subscribed because no-one was sure what it actually was.
Please tell us where you took this course, so we are at least warned that their graduates are uneducated. Bit manipulation is tied into binary numbers, and is not in the least hard to understand. Ladder diagrams are something else. -- "Our enemies are innovative and resourceful, and so are we. They never stop thinking about new ways to harm our country and our people, and neither do we." -- G. W. Bush. "The people can always be brought to the bidding of the leaders. All you have to do is tell them they are being attacked and denounce the pacifists for lack of patriotism and exposing the country to danger. It works the same way in any country." --Hermann Goering.
"CBFalconer" <cbfalconer@yahoo.com> wrote in message 
news:4484521F.AAC53E12@yahoo.com...
> Tom Lucas wrote: >> > ... snip ... >> >> I must say that I graduated in 2001 from a Computer Systems course >> and at no point was bitwise manipulation even mentioned unless you >> took a module rather unhelpfully named as "industrial control" >> which scared people off with talk of dull ladder diagrams but was >> actually assembly language programming of PICs. Good course in fact >> but under-subscribed because no-one was sure what it actually was. > > Please tell us where you took this course, so we are at least > warned that their graduates are uneducated. Bit manipulation is > tied into binary numbers, and is not in the least hard to > understand. Ladder diagrams are something else. >
This was Cardiff University and their standard of education is actually very good. Binary arithmetic was certainly covered and so all the students would certainly have understood bit manipulation from that side but my point was that it was rarely, if ever, linked to embedded programming. I'm sure the class could tell you what "c &= ~(1<<4);" does once the C notation had been explained (I believe it's all Java now) but they wouldn't know why you would want to do it. To be honest, there's lots of bread and butter embedded stuff that was never mentioned on the course but then it was an academic course and concentrated on the thoery that you would never otherwise learn. The other skills are learnt by doing, once you have graduated and are being trained in the workplace and with a good grasp of theory you would quickly pick up the bitwise manipulation - it would be a much harder the other way round. I'm sure that most people agree that you don't start learning how to be an Engineer until you start working but I would also add that in that environment you often have to learn just enough to solve a problem and don't have time to go into the theoretical depths. That's what universities are for. You can go to a college if you want to do something more vocational.
Tom Lucas wrote:
> I must say that I graduated in 2001 from a Computer Systems course and at no > point was bitwise manipulation even mentioned unless you took a module > rather unhelpfully named as "industrial control" which scared people off > with talk of dull ladder diagrams but was actually assembly language > programming of PICs. Good course in fact but under-subscribed because no-one > was sure what it actually was.
I just had a protracted argument about hiring someone who claimed to have device driver writing experience, but did not know how to divide and integer by 32 using bit shifting. The other members of the team did not think this was something that a Senior Software Engineer should know.
> My degree was a hybrid so I mixed with the Computer Scientists and the > Electronic Engineers but neither of them would have even seen an embedded > system without going on the industrial control module. The closest the EE > guys got was an ancient 6800 programmed in hex via a 16 key keypad but it > was only for one lab class and you just followed the crib sheet without > having to understand what you were doing.
I know of at least 3 technical universities that will not let you get a B.S.E.E. without knowing how to write a compiler, and will not let you get a B.S.C.S without knowing how to design an FM radio. The idea is to quash any possibility that you might subsequently misrepresent your university as an idiot who cannot divide a number by 32 using bit-shifting. -Le Chaud Lapin-