Search code examples
cpointersbit-fieldsmicrochip

[ansi c]Pass bitifield as reference


In microchip C30 compiler i can set pin i/o value using LAT register in this way:

LATBbits.LATB10=1;

LATBbits is defined as:

typedef struct tagLATBBITS {
  unsigned LATB0:1;
  unsigned LATB1:1;
  unsigned LATB2:1;
  unsigned LATB3:1;
  unsigned LATB4:1;
  unsigned LATB5:1;
  unsigned LATB6:1;
  unsigned LATB7:1;
  unsigned LATB8:1;
  unsigned LATB9:1;
  unsigned LATB10:1;
  unsigned LATB11:1;
  unsigned LATB12:1;
  unsigned LATB13:1;
  unsigned LATB14:1;
  unsigned LATB15:1;
} LATBBITS;
extern volatile LATBBITS LATBbits __attribute__((__sfr__));

My target is to write a function that can set i/o value using LAT register as an argument, in pseudocode:

void setPin(unsigned int* latReg, unsigned int value){
  (*latReg)=value;
}

setPin(&LATBbits.LATB10, 1);

Unfortunately this code won't compile because "cannot take address of bit-field 'LATB10'".

I need it because i want to realize a simil-class library that can handle a port expander. Each port expander can have different pins, so i need to configure it and i think to do something like this:

typedef struct sPortExpander{
  unsigned int* CS;
  unsigned int* SPBUFF;
  ecc...
} PortExpander

void PortExpander_setOutput(PortExpander p, unsigned char value){
  (*p.CS)=0;
  // Send SPI data
  (*p.CS=1);
}

In this way i can manage multiple port expander.

So, there is a way to do what i try to do?

Thanks.


Solution

  • Declare the struct as __attribute__((packed)), then use:

    void function setPin(struct LATBBITS *reg, unsigned int fieldno, unsigned int value){
        if (value)
            *(uint16_t *)reg |= (1 << fieldno);
        else
            *(uint16_t *)reg &= ~(1 << fieldno);
    }