I am a level 4 out of 100 in C programming, so please bear with me, this may be an XY problem. I'm using a PIC18F25 with MPLAB X and the free version of XC8 compiler.
Goal: Sequentially turn on/off 16 LEDs attached to various arbitrarily assigned PORTA/B/C pins.
In my main.h I've defined the following to achieve the LED-Pin mapping:
#define LED_0 LATCbits.LC7 //RC7
#define LED_1 LATCbits.LC5 //RC5
#define LED_2 LATAbits.LA3 //RA3
#define LED_3 LATCbits.LC3 //RC3
#define LED_4 LATBbits.LB7 //RB7
#define LED_5 LATAbits.LA0 //RA0
#define LED_6 LATCbits.LC6 //RC6
#define LED_7 LATCbits.LC4 //RC4
#define LED_8 LATBbits.LB5 //RB5
#define LED_9 LATAbits.LA2 //RA2
#define LED_10 LATBbits.LB6 //RB6
#define LED_11 LATAbits.LA1 //RA1
#define LED_12 LATCbits.LC2 //RC2
#define LED_13 LATCbits.LC1 //RC1
#define LED_14 LATBbits.LB4 //RB4
#define LED_15 LATCbits.LC0 //RC0
So now in main.c I can turn on/off each mapped LED using the LED_x macros easily:
LED_0 = 1;
delay_s(0.25);
LED_0 = 0;
LED_1 = 1;
delay_s(0.25);
LED_1=0;
LED_2=1;
// etc.
// etc.
I don't want to explicitly use LED_0, LED_1, LED_x every single time in my main.c; I want something more elegant that I can loop through and modify in arbitrary fashion. I thought of writing a function which takes a char as a parameter ( with values 0-15 ) and returns a pointer to the appropriate port/pin, by using the 'friendly name' of that port/pin. These friendly names are in the PIC18f25xxx.h header file, and the LATxbits are defined as volatile unsigned chars:
// This is from inside PIC18F25xxx.h:
// Register: LATA
extern volatile unsigned char LATA @ 0xF89;
#ifndef _LIB_BUILD
asm("LATA equ 0F89h");
#endif
// bitfield definitions
typedef union {
struct {
unsigned LATA0 :1;
unsigned LATA1 :1;
unsigned LATA2 :1;
unsigned LATA3 :1;
unsigned :1;
unsigned LATA5 :1;
};
struct {
unsigned LA0 :1;
};
struct {
unsigned :1;
unsigned LA1 :1;
};
struct {
unsigned :2;
unsigned LA2 :1;
};
struct {
unsigned :3;
unsigned LA3 :1;
};
struct {
unsigned :5;
unsigned LA5 :1;
};
} LATAbits_t;
extern volatile LATAbits_t LATAbits @ 0xF89;
So I wrote my function with the same return type:
volatile unsigned char * getLATptr( unsigned char ledIdx ){
switch( ledIdx ){
case 0: return &LATCbits.LC7;
case 1: return &LATCbits.LC5;
case 2: return &LATAbits.LA3;
case 3: return &LATCbits.LC3;
case 4: return &LATBbits.LB7;
case 5: return &LATAbits.LA0;
case 6: return &LATCbits.LC6;
case 7: return &LATCbits.LC4;
case 8: return &LATBbits.LB5;
case 9: return &LATAbits.LA2;
case 10: return &LATBbits.LB6;
case 11: return &LATAbits.LA1;
case 12: return &LATCbits.LC2;
case 13: return &LATCbits.LC1;
case 14: return &LATBbits.LB4;
case 15: return &LATCbits.LC0;
}//switch
return;
}
The point being that I simply give an index value ( 0 -15 ) and this function returns a pointer to the friendly-named register. Then in main.c I attempt to call this function to turn on LED_9:
*(getLATptr(9)) = 1;
I'm getting the compiler error: main.c:81: error: (712) can't generate code for this expression
So: Can anybody enlighten me as to why the compiler cannot generate this code?
Is there something fundamentally wrong with my understanding of C here? Is it an XC8 compiler specific issue?
Or am I approaching the problem from an inherently over-complicated way ( this is my guess! )
Thanks for reading, cheers