2

I am attempting to pass a reference to an I/O pin as an function argument on a PIC24F MCU using C. For PICs, the device header file provides access to the i/o buffer registers via:

LATAbits.LATA2 = 0;    // sets the pin (RA2 in this case) low.
if (PORTAbits.RA3) {   // reads the state of the pin. (RA3)

I want to do something like this:

int main() {
    Configure();                        // Sets up peripherals, etc. 
    WaitForHigh(PORTAbits.RA3);         // waits for pin RA3 to go hi. 
    ...

    return 0;
}

void WaitForHigh( ?datatype? pin_reference ) { 

    while( !pin_reference );            // Stays here until the pin goes hi.
}

So what datatype am I trying to pass here? And what's actually going on when I poll that pin? Below, I copy a relevant portion from the PIC24F device header that I'm using in case it helps.

#define PORTA PORTA
extern volatile unsigned int  PORTA __attribute__((__sfr__));
typedef struct tagPORTABITS {
  unsigned RA0:1;
  unsigned RA1:1;
  unsigned RA2:1;
  unsigned RA3:1;
  unsigned RA4:1;
  unsigned RA5:1;
} PORTABITS;
extern volatile PORTABITS PORTAbits __attribute__((__sfr__));

Thank you in advance!

Mike Thielvoldt
  • 181
  • 1
  • 11

3 Answers3

4

As an alternative to using a macro, a function can accept both the PORT register address (or latch register address, eg. LATA in the case of a pin configured for output) and the mask of the bit in the register that is needed. For example:

#include<p24FV32KA301.h>   // defines both PORTA and _PORTA_RA3_MASK 

void WaitForHigh( volatile unsigned int * port, pin_mask ) { 

    while( !(*port & pin_mask) );           // Stays here until the pin goes hi.
}


int main() 
{
    ...
    WaitForHigh( &PORTA, _PORTA_RA3_MASK );         // waits for pin RA3 to go hi. 
    ...

    return 0;
}
Mike Thielvoldt
  • 181
  • 1
  • 11
  • 1
    You should strictly have a prototype for `WaitForHigh` or define it *before* main. One problem with macros is lack of data type checking, but by omitting the prototype, you are not checking in any case. You might also declare it `_inline` too if supported by your compiler (they invariably do); in which case it will probably be as efficient as the macro. Check the generated code if it is critical (or even just of interest). – Clifford Oct 12 '14 at 09:56
  • 1
    Agreed, @Clifford. Editing for completeness. – Mike Thielvoldt Oct 12 '14 at 10:44
1

Please, note that the PORT bit values are obtained through a bit field, so, answering your question, you can't. Bit fields doesn't have address, so you cannot pass it as a pointer to a function.

Instead, you could use a Macro:

#define WaitForHigh(p) do{while(!(p));}while(0)

It is true that macros has it's draw backs on code readability, yet, given that proper care is taken, there are situations where they're the best solution. It is arguable if macro is the best solution in this Q&A, yet it is important to mention.


Thanks to the commenters for the suggestions to improve the macro safeness.

Felipe Lavratti
  • 2,887
  • 16
  • 34
  • 1
    I see. This seems like a simple, good solution for the problem I posed, but evaluating [Macros-vs-functions](http://stackoverflow.com/questions/9104568/macro-vs-function-in-c) more generally, it appears that there are disadvantages to using macros for some tasks. – Mike Thielvoldt Oct 12 '14 at 09:16
  • 2
    I would suggest `#define WaitForHigh(p) do{while(!(p));}while(0)` to both enforce expected evaluation of `p` and to guard against accidental inclusion of code in the loop if a `;` were omitted. Two *more* reasons macros need special care, and are perhaps best avoided. – Clifford Oct 12 '14 at 10:11
0

You can combine preprocessor processing with a function to get what you wan along with compile time checking of the symbols. For example:

#define PORT_FUNC(f, p, b) f(p, b)
#define WaitForHigh(p, b) PORT_FUNC(WaitForHighImp, &p, _ ##p## _ ##b## _MASK)

void WaitForHighImp(volatile unsigned* p, unsigned char mask)
{
    while (!(*p & m))
        ;
}

int main()
{
    WaitForHigh(PORTA, RA3);
}

The advantage of this approach is that you online say "PORTA" once and "RA3" once at the time of the call, you make sure the bit name is present in the port and that the bit is present.

janm
  • 17,976
  • 1
  • 43
  • 61