1. This forum section is a read-only archive which contains old newsgroup posts. If you wish to post a query, please do so in one of our main forum sections (here). This way you will get a faster, better response from the members on Motherboard Point.

port I/O abstraction macros

Discussion in 'Embedded' started by Tom Torfs, Jun 2, 2006.

  1. Tom Torfs

    Tom Torfs Guest

    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
    }
    }
    */
     
    Tom Torfs, Jun 2, 2006
    #1
    1. Advertisements

  2. Tom Torfs

    John Temples Guest

    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 Temples, Jun 2, 2006
    #2
    1. Advertisements

  3. Tom Torfs

    Tom Torfs Guest

    John,

    John Temples schreef:
    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, Jun 2, 2006
    #3
  4. Tom Torfs

    DAC Guest

    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, Jun 3, 2006
    #4
  5. Tom Torfs

    Tom Torfs Guest

    DAC,
    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
     
    Tom Torfs, Jun 4, 2006
    #5
  6. 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, Jun 5, 2006
    #6
  7. Tom Torfs

    Tom Lucas Guest

    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, Jun 5, 2006
    #7
  8. Tom Torfs

    CBFalconer Guest

    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, Jun 5, 2006
    #8
  9. Tom Torfs

    Tom Lucas Guest

    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, Jun 6, 2006
    #9
  10. 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.
    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-
     
    Le Chaud Lapin, Jun 6, 2006
    #10
  11. Tom Torfs

    CBFalconer Guest

    Well, the primary function of a university is to teach how to
    learn. The details of what to learn are somewhat secondary. The
    emphasis in a technical school is somewhat more concentrated on
    subject matter. So the key thing in an interview is how fast does
    the interviewee catch on, rather than the detailed knowledge.

    --
    "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, Jun 6, 2006
    #11
  12. How do you elegantly divide a _signed_ integer by 32 using shifts in
    systems that are using 2's complement representation ?

    Paul
     
    Paul Keinanen, Jun 6, 2006
    #12
  13. You use arithmetic shifts where the MSB is duplicated rather than
    using a logical shift.

    In C and C++ the >> operator has implementation-defined results on a
    signed integer, so it isn't going to be very elegant if it is written
    to be portable. So I guess you could use Java which uses >> for
    arithmetic and >>> for logical.


    Best regards,
    Spehro Pefhany
     
    Spehro Pefhany, Jun 6, 2006
    #13
  14. Not sure if this is elegant or correct (no time to check), but I would
    just shift if the value is non-negative and shift-plus-or-in-1's if it
    is negative:


    Also I guess I failed to mention - in the exam that I gave the
    interviewee, I told him up front that the value to be divided was
    unsigned, and that he could ignore any round-off errors.
    You braved Java. I'm impressed. :)

    -Le Chaud Lapin-
     
    Le Chaud Lapin, Jun 6, 2006
    #14
  15. Any decent compiler (for any language) should do that for a signed
    data type.
    That does not solve the problem.

    What do you get even with MSB duplication in 2's complement notation,
    when you shift -3 one position to the right ? I got -2.

    Now we have to discuss, what INT(-3/2) should be. At least I learned
    in primary school that this should be -1, not -2.

    Paul
     
    Paul Keinanen, Jun 6, 2006
    #15
  16. I certainly agree.

    That's why I interview people on multiple axes to give them an
    opportunity to show their value. I look for

    1. intelligence
    2. knowledge
    3. passion

    If a person seems to be lacking in knowledge, I attempt to check
    intelligence/passion by asking questions that the person should know.
    For example, one recent candidate had studied geophysics for
    undergraduate (not electrical engineering or computer science), and was
    having trouble with his knowledge domain on Windows. So I asked him
    questions about geophysics (based on what little I knew). Because he
    did not answer these questions very well, I had to conclude that he was
    just looking for a job to have a salary.

    I also started making generic exams to be used during interviews in our
    (multi-billion $US) company (yes, strange, i know). The idea is to
    create a separation between the interviewer and the interviewee. Some
    candidates have cling - they cling to you like a charged sock - when
    you try to get them to answer a question. With paper exams, some
    degree of objectivity can be maintained.

    Incidentally, this person who did not know how to divide by 32 using >>
    scored the lowest on the C++ exam of all candidates I interviewed.
    During a heated post-interview discussion with HR, the HR rep implied
    that the introduction of paper exams is less objective than what we
    were doing before - ad hoc, hand-waiving qualifications with no notes
    whatsover, just personal opinions.

    -Le Chaud Lapin-
     
    Le Chaud Lapin, Jun 6, 2006
    #16
  17. But it's *not* guaranteed.

    ISO/IEC 9899:1999 (E) 3.4.1
    1 implementation-defined behavior
    unspecified behavior where each implementation documents how the
    choice is made
    2 EXAMPLE An example of implementation-defined behavior is the
    propagation of the high-order bit
    when a signed integer is shifted right.

    In this case, both answers have an |error| = 0.5

    If you take INT(-7/4) you get -1 using the division operator, and -2
    using two arithmetic shifts. The former has an |error| of 0.75 vs 0.25
    for the >> operator. In enjineering school I learned that smaller
    errors are better. ;-)



    Best regards,
    Spehro Pefhany
     
    Spehro Pefhany, Jun 7, 2006
    #17
  18. Tom Torfs

    Tom Lucas Guest

    I did a compiler design module as part of my course but the lecturer was a
    bit horny for lexical analysis and the entire course was spent on English
    linguistics. Of course, I'd heard this before hand and the only reason I
    took the course is because the same exam questions are asked year after year
    ;-)

    I see little point in graduating knowing how to write a compiler or design
    an FM radio unless you are directly going into Sony's Radio Compiler
    division. Knowing what a compiler does and the sort of tricks current
    optimisers play will be more useful in the real world than knowing how to
    parse an arithmetic expression. Similarly knowing about RF, demodulation and
    amplifiers is more useful to the real world than an rudimentary FM radio
    kit.

    I think it is more important for someone to leave university understanding
    why it is important to optimise integer division rather than just have a
    tool box of techniques - they will learn those on the job. Of course, if the
    chap then fails to understand how the shifting works once he's been shown it
    then he has probably not grasped the most important skill from university -
    learning how to learn.
     
    Tom Lucas, Jun 7, 2006
    #18
  19. There seems to be a bit of a contradiction here. You seem to be saying
    that shallow practice is not good (FM kit), but you also seem to be
    saying that basic theory (being able to parse arithmetic expressions)
    is not good either.

    A person cannot design an FM radio without understanding many aspects
    of electronic theory. In the case I was speaking of, the electronics
    course gives a bag of components, and a lot of theory. You're expected
    to make everything, including the amplifiers, filters, phase-lock loop
    (from a pre-packaged VCO), etc. Anyone who had not been paying
    attention to the theory would simply not be able to make the radio.
    The same course (or the next one) introduces Kalman filtering. It's
    not a connect-the-dots type project.

    For the compiler, I think it is very important to be able to parse
    arithmetic expressions. Knowledge of automata theory can be
    invaluable. For my current job, I recently had to make a small
    compiler for a stack machine. Here's the tokenizer for lexical
    analysis:

    bool next_token (Token &token)
    {
    // Advance past any white space that might be present:
    while (isspace(operator[](index)))
    ++index;

    // If we encounter the end of the string after consuming white
    space, there are no more tokens to read.
    if (operator[](index) == 0)
    return false;

    switch (operator[](index))
    {
    case '(' :
    token.type = Token::TYPE_LEFT_PARENTHESIS;
    token.offset = index++;
    token.length = 1;
    break;

    case ')' :
    token.type = Token::TYPE_RIGHT_PARENTHESIS;
    token.offset = index++;
    token.length = 1;
    break;

    case '!' :
    token.type = Token::TYPE_OPERATOR_NOT;
    token.offset = index++;
    token.length = 1;
    break;

    And simple piece of compiler:

    case Token::TYPE_PREDICATE :
    if (typename
    Infectable::predicate_functions.locate(operator ()(token.offset,
    token.length)))
    instructions.suffix (Instruction(typename
    Object::predicate_functions.RHE()));
    else
    instructions.suffix(Instruction(0)); // DEFECT: Need to
    figure out semantics of not finding the predicate.
    break;

    I have no clue about optimization, but what I needed to know to make
    this compiler can be found in the first few chapters of any compiler
    book. Self-reliance is achieved by focusing on a small bit and
    learning that well, than reading the whole book casually and not
    remembering anything. I started dong this long ago after a
    converstation I had with a professor just before my graduation. I
    asked, "There is so much to learn in the world...is it better to hurry
    up and grab what you can and depend on other people for deep insight or
    is it bet..." he finished my sentenced quickly and said, "It's better
    for you to know." I asked, "But does one person have time in his life
    to...?" he says, "Yes." I asked, "Are you sure?" he said, "Yes."

    -Le Chaud Lapin-
     
    Le Chaud Lapin, Jun 7, 2006
    #19
  20. Tom Torfs

    CBFalconer Guest

    You don't have to go to school to learn those things. But it
    helps, as does the ability to read. On c.l.c we see many newbies
    totally confused about how to handle interactive input, when all
    they need is to build some sort of primitive lexer. I have even
    had relatively experienced people argue over the need for one char
    lookahead.

    --
    "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, Jun 7, 2006
    #20
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.