PIC18, XC8 and returning pointers to registers ?  - Page 1
Forum section: electronics / general

author: smoothVTer
author_rank: Regular Contributor
timestamp: November 02, 2016, 08:04:19 pm
content: 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:Code:#define LED_0LATCbits.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 //RC0So now in main.c I can turn on/off each mapped LED using the LED_x macros easily:Code: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:Code:// This is from inside PIC18F25xxx.h:// Register: LATAextern volatile unsigned char LATA @ 0xF89;#ifndef _LIB_BUILDasm("LATA equ 0F89h");#endif// bitfield definitionstypedef 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:Code: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;}//switchreturn;}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:Code:*(getLATptr(9)) = 1;I'm getting the compiler error: main.c:81: error: (712) can't generate code for this expressionSo: 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

author: edavid
author_rank: Super Contributor
timestamp: November 02, 2016, 08:14:27 pm
content: Bitfields don't have addresses, so you can't use the address operator on them.