CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

function within a struct

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Aug 07, 2007 2:21 pm     Reply with quote

I'm not sure how to reference a function pointer as a structure element.
I mean, when you call the function. It kept giving me an "Expect ;" error.
So, I just moved the function pointer from the structure element into
a temp variable (declared as a function pointer), and had it call the
"Hello" function. Then it compiled, and it worked. It displays this:
Quote:
Hello World


There may be a way to do it. I just don't have any more time to spend
on it. Here's the working test program. This was tested with vs. 4.049.
Code:

#include <18F452.h>
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000) 
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

void Hello(void)
{
printf("Hello World\n\r");
}


typedef void (*_fptr)(void);


struct
{
 int8   Set1;         
 int8   call;             
 _fptr func_ptr;     
}Call_struct;

   
//====================================
void main()
{
_fptr temp;

Call_struct.func_ptr = Hello;
temp = Call_struct.func_ptr;

(*temp)();

while(1);     
}       
Storic



Joined: 03 Dec 2005
Posts: 182
Location: Australia SA

View user's profile Send private message Send e-mail

PostPosted: Tue Aug 07, 2007 6:10 pm     Reply with quote

Thankyou,
I have slightly modified your code to expand on the function call
Code:
#include <18f67J10.h>
#device *=16
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES H4_SW                    //High speed osc with SW enabled 4x PLL
#FUSES NODEBUG                  //No Debug mode for ICD
//#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode enabled
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NOPROTECT                //Code not protected from reading
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES IESO                     //Internal External Switch Over mode enabled
#FUSES PRIMARY                  //Primary clock is system clock when scs=00
#FUSES RESERVED                 //Used to set the reserved FUSE bits

#use delay(clock=20000000)

#use rs232(baud=38400, xmit=PIN_C6, rcv=PIN_C7,enable = PIN_C1, ERRORS)

void Hello(void)
{
printf("Hello World\n\r");
}

void Thankyou(void)
{
printf("thankyou for your help\n\r");
}

void Goodby(void)
{
printf("coding on \n\n\r");
}

typedef void (*_ptr)(void);


typedef struct
{
 int8   Set1;         
 int8   call;             
 void   *func_ptr;
}Call_struct;

Call_struct key[3];
//====================================
void main()
{
int i,j =0;
_ptr temp[3];

key[0].func_ptr = Hello;
key[1].func_ptr = Thankyou;
key[2].func_ptr = Goodby;

for (i=0;i<=2;++i) {temp[i] = key[i].func_ptr;}

(*temp[0])();
delay_ms(1000);
(*temp[1])();
delay_ms(2000);
(*temp[2])();
while(1);     



Thanks Smile Shocked
_________________
What has been learnt if you make the same mistake? Wink
Pret



Joined: 18 Jul 2006
Posts: 92
Location: Iasi, Romania

View user's profile Send private message

PostPosted: Wed Aug 08, 2007 12:33 am     Reply with quote

Anyway.... function pointers is not supported by CCS due the PIC lack of stack. Sice all local variables are stored as global, compiler must know the entire calling tree before. A function pointer breaks this roule.

In the above example, compile makes an workaround. Internally he's saving tags to functions instead pointers. When a call occurs, internally he substitute with switch (tag) and calls the right function. You can find this in CCS help.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Aug 08, 2007 1:22 am     Reply with quote

Actually, the compiler does create a pointer to the function, as you can
see in the .LST file code below. This is generated from the program
that I posted earlier in this thread.
Unfortunately, there's a bug in it. It's not storing the MSB of the 'Hello()'
function address. The program works if the function is in the first 256
bytes of program memory, but it fails if it's located higher in program
memory.
Code:

... void Hello(void) 
... { 
.... printf("Hello World\n\r"); 
0030:  CLRF   0C
0032:  MOVF   0C,W
0034:  RCALL  0004
0036:  INCF   0C,F
0038:  MOVWF  00
003A:  MOVF   00,W
003C:  BTFSS  F9E.4
003E:  BRA    003C
0040:  MOVWF  FAD
0042:  MOVLW  0D
0044:  SUBWF  0C,W
0046:  BNZ   0032
.... } 
0048:  RETLW  00
.... 

... Call_struct.func_ptr = Hello; 
0068:  MOVLW  00      // *** BUG -- MSB of address is not saved.
006A:  MOVLW  30
006C:  MOVWF  08
... temp = Call_struct.func_ptr; 
006E:  CLRF   0B
0070:  MOVFF  08,0A
.... 
.... (*temp)(); 
0074:  CLRF   FEA
0076:  MOVLW  0A
0078:  MOVWF  FE9
007A:  RCALL  0022
.................... 


So, I came up with a fix for that. I declared the function pointer
in the structure as an 'int16'. Then in main(), when I assign the
the function pointer to 'temp', I cast it to an _fptr. In fact, that
last part doesn't seem to be needed.
Here's a revised program with the changes given above.
Code:
#include <18F452.h>
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000) 
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#org 0x1000,0x1030
void Hello(void)
{
printf("Hello World\n\r");
}


typedef void (*_fptr)(void);


struct
{
 int8   Set1;         
 int8   call;             
 int16  func_ptr;     
}Call_struct;

   
//====================================
void main()
{
_fptr temp;

Call_struct.func_ptr = Hello;
temp = (_fptr)Call_struct.func_ptr;

(*temp)();

while(1);     
}       



Here's part of the .LST file for the revised program. You'll note that
the 'Hello()' function is at 0x1000, because it's now org'ed there.
If you look at the line where the address of 'Hello' is loaded into the
structure element, you'll see that it's getting the full 16-bit address now.
It works when I run it in MPLAB simulator. I tested this with vs. 4.046.
Code:
.... printf("Hello World\n\r"); 
*
1000:  CLRF   0C
1002:  MOVF   0C,W
1004:  CALL   0008
1008:  INCF   0C,F
100A:  MOVWF  00
100C:  MOVF   00,W
100E:  BTFSS  F9E.4
1010:  BRA    100E
1012:  MOVWF  FAD
1014:  MOVLW  0D
1016:  SUBWF  0C,W
1018:  BNZ   1002
.................... } 
101A:  RETLW  00


.................... Call_struct.func_ptr = Hello; 
0052:  MOVLW  10
0054:  MOVWF  03
0056:  MOVLW  00
0058:  MOVWF  08
005A:  MOVFF  03,09
.................... temp = (_fptr)Call_struct.func_ptr; 
005E:  MOVFF  09,0B
0062:  MOVFF  08,0A
.................... 
.................... (*temp)(); 
0066:  CLRF   FEA
0068:  MOVLW  0A
006A:  MOVWF  FE9
006C:  RCALL  0026
.................... 
Pret



Joined: 18 Jul 2006
Posts: 92
Location: Iasi, Romania

View user's profile Send private message

PostPosted: Wed Aug 08, 2007 2:58 am     Reply with quote

Interesting...but:
Quote:
The compiler does not permit pointers to functions so that the compiler can know at compile time the complete call tree. This is used to allocate memory for full RAM re-use. Functions that could not be in execution at the same time will use the same RAM locations. In addition since there is no data stack in the PICĀ®, function parameters are passed in a special way that requires knowledge at compile time of what function is being called. Calling a function via a pointer will prevent knowing both of these things at compile time. Users sometimes will want function pointers to create a state machine. The following is an example of how to do this without pointers:

enum tasks {taskA, taskB, taskC};

run_task(tasks task_to_run) {
switch(task_to_run) {
case taskA : taskA_main(); break;
case taskB : taskB_main(); break;
case taskC : taskC_main(); break;
}
}


Anyway, i tried some time ago to make a generic timer that take a pointer to a function to execute it recurrently. This was not working. Then after i found the reason from help. Maybe for simple and predictable calls works...
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group