Mike Thielvoldt
Mike Thielvoldt

Reputation: 301

PIC pass SFR address to function in C

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!

Upvotes: 2

Views: 2017

Answers (3)

Felipe Lavratti
Felipe Lavratti

Reputation: 2967

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.

Upvotes: 1

Mike Thielvoldt
Mike Thielvoldt

Reputation: 301

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;
}

Upvotes: 4

janm
janm

Reputation: 18359

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.

Upvotes: 0

Related Questions