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 support@ccsinfo.com

Multiple main() functions/Pointer to function/Lost s...Help!

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



Joined: 17 Sep 2003
Posts: 97
Location: Atlanta, GA, USA

View user's profile Send private message

Multiple main() functions/Pointer to function/Lost s...Help!
PostPosted: Thu Jul 06, 2006 7:45 am     Reply with quote

I will spare you from the details of why my program needs this and simply ask for how to do this with CCS. I do REQUIRE this functionality. The job I need this most for is using a PIC18F8722 with 3.249 of PCWH.

Let's say my program looks at a jumper when it boots. This jumper determines the personality of the program. On the PIC, if the input is low it runs one program, and if it is high, it runs another. The programs are not related. The programs must reside in different program memory segments.

The main() can be simple, read the pin, and run one function or the other. But this permanently uses stack space for a call that will never return.

A pointer to a function would solve the problem, but according to their documentation, CCS does not support this standard C feature. They claim they cannot do pointers to functions because there is no way to pass parameters, but they completely overlooked the obvious usefulness of a pointer to a function that does not need parameters. So let us forget CCS' shortcomings and see if there is an alternate approach.

I tried a trick I found on the forum. The code snippet below illustrates it. The point was to go to the main(), call the personality function, and clear the stack:
Code:
#byte STKPTR=0xFFC
#define clear_stack() STKPTR=0

void main(void) {
   Real_Main();
}

void Real_Main(void) {
   clear_stack();
...


It sort of works, but I found that somehow it “corrupts” my ISRs, and cannot be used because of this.

I tried “goto” but that doesn't work either. Since the function is jumped to directly and there is no call to it, the code optimizer doesn't compile the personality programs or any of their subs, or their ISRs. Basically, it only compiles a main() with a few lines in it! I have tried this in many ways and combinations using labels and direct addressing with no success.

Are there any other options have I overlooked? Or perhaps is there a way to make one of these options work? All constructive suggestions will be appreciated!

-Kyle
Ttelmah
Guest







PostPosted: Thu Jul 06, 2006 8:44 am     Reply with quote

CCS, does support pointers to functions. Look at the example 'qsort', for how this is done. However this will still leave you with a call on the stack. At 'heart', what you are describing, is almost the code needed in bootloader type programs. #ORG, will allow you to specify that a program re-uses RAM (with the auto=0 directive), so no memory is wasted, and the 'pop' assembler instruction, or the bodge you have already found, will allow you to pop the return address so this is not lost.
Look at the 'goto_address' command. These allow you to jump to a function elsewhere.
There is no reason for what you post to corrupt the ISR's, unless the system is restarting from a stack overflow, or the routines are returning. Remember that _you_ must ensure this never happens. For the normal 'main', CCS adds a hidden sleep instruction off the end, but with a jump/call to another routine, this protection is lost. Check just how much stack is being used.

Best Wishes
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

Re: Multiple main() functions/Pointer to function/Lost s...H
PostPosted: Thu Jul 06, 2006 8:52 am     Reply with quote

kda406 wrote:
The main() can be simple, read the pin, and run one function or the other. But this permanently uses stack space for a call that will never return.

-Kyle


Within main you can switch for the jumper. Just be sure both functions are declared as inline. There will be no stack space used. A function that is only called once will not use stack space usually. If declared inline a function can not use stack space.

So basicly you don't REQUIRE the functionality you thought you need.

-Neutone
kda406



Joined: 17 Sep 2003
Posts: 97
Location: Atlanta, GA, USA

View user's profile Send private message

PostPosted: Thu Jul 06, 2006 9:16 am     Reply with quote

Thanks for your reply, but it brings up more questions. Firstly, according to CCS, they do NOT support pointers to functions. Here is an excerpt from their most recent manual:
Quote:
How do I make a pointer to a function?
The compiler does not permit pointers to functions so that the compiler can know at compile time the complete call tree.


I am using many #ORG statements. On the auto=0 directive you mentioned, which function gets this parameter? The main() that is never returned to, or one of the personality programs it calls? I have reviewed the CCS documentation on #ORG hundreds of times and am always left wondering what the hell they are talking about in the last paragraph which mentions this directive. Also, there is no example of this directive as far as I have found. Since CCS leaves me in the dark on this, can you explain it to me (and the forum) in more detail?

I mentioned about goto(_address). This didn't work for me because the code optimizer did not compile the personality programs because there were no calls to them. The compiler sees them as unused functions and no code is generated for them.

I have not tried 'pop' yet. Perhaps this will work better than clearing the stack the way I showed earlier.

Many thanks for your help, “Ttelmah”.

-Kyle
kda406



Joined: 17 Sep 2003
Posts: 97
Location: Atlanta, GA, USA

View user's profile Send private message

Re: Multiple main() functions/Pointer to function/Lost s...H
PostPosted: Thu Jul 06, 2006 9:19 am     Reply with quote

Neutone wrote:
...Just be sure both functions are declared as inline. There will be no stack space used. A function that is only called once will not use stack space usually. If declared inline a function can not use stack space.

So basicly you don't REQUIRE the functionality you thought you need....


Thanks Neutone, but as I said, the personality programs must reside in different segments of memory. Is there a way to compile them inline and also in different, discrete segments of memory?

Thanks,
Kyle
Ttelmah
Guest







PostPosted: Thu Jul 06, 2006 9:53 am     Reply with quote

Pop, will be no 'better'. What you are doing, should not fail, unless one of the problems I refer to is occuring. Find out _why_ your code is failing....

Auto, allows two programs to have RAM using the same area. Applies to your two 'main' programs, since these should be able to use the same RAM areas.

The lack of 'pointers to functions', was fixed for specific types of operations a while ago. A lot of the manual is old.

There are two different 'goto' commands. Goto, can only go to a _local_ address. Goto_address, can go _anywhere_. However remember you need to generate the address yourself. If you declare the routine with a #org, then you can just goto_address this location, and arrive at the routine. The optimiser should not remove the routines. For example, the following code:
Code:

   Goto_address(0x2000);

//With the following declaration:

#org 0x2000,0x3000 auto=0 default
#separate
void demo(void) {
   int8 ctr;
   ctr=0;
   printf("Testing");
   for (ctr=0;ctr<10;ctr++);
   while(true);
}

//generates the following assembler:
....................    Goto_address(0x2000);
00194:  GOTO   2000

.................... #org 0x2000,0x3000 auto=0 default
.................... #separate
.................... void demo(void) {
....................    int8 ctr;
....................    ctr=0;
*
0201C:  CLRF   26
....................    printf("Testing");
0201E:  CLRF   27
02020:  MOVF   27,W
02022:  RCALL  2000
02024:  IORLW  00
02026:  BZ    2032
02028:  INCF   27,F
0202A:  MOVWF  28
0202C:  GOTO   0008
02030:  BRA    2020
....................    for (ctr=0;ctr<10;ctr++);
02032:  CLRF   26
02034:  MOVF   26,W
02036:  SUBLW  09
02038:  BNC   203E
0203A:  INCF   26,F
0203C:  BRA    2034
....................    while(true);
0203E:  BRA    203E
.................... }
02040:  RETLW  00

The key here, is that 'ctr', can end up using RAM space that has already been used in 'main'.

Best Wishes
kda406



Joined: 17 Sep 2003
Posts: 97
Location: Atlanta, GA, USA

View user's profile Send private message

PostPosted: Thu Jul 06, 2006 1:50 pm     Reply with quote

First of all, many thanks for your help so far.

I am quite positive my personality functions disappeared when trying goto_address previously. I tried to illustrate this, but with my current, tiny program to illustrate the problem, I cannot get it to occur. However, I can show the optimizer not working correctly when using #ORG statements. Knowing this, perhaps you will believe me when I say the personality programs disappear from the compiled code under certain circumstances. Let's hope it is my mistake because it will be far quicker to fix! Wink

Here is a sample program using some of the points we have discussed:
Code:
#include "18F8722.h"

#use delay(clock=11059200)                     //11.0592 MHz Oscillator
#fuses EC_IO,NOPROTECT,NOIESO,NOBROWNOUT,NOWDT,PUT,NOCPD, NOSTVREN,NODEBUG,NOLVP,NOWRT,NOCPB,NOEBTRB,NOEBTR,CCP2C1, NOWRTD,NOWRTC,NOWRTB,NOFCMEN,NOLPT1OSC,MCLR,NOXINST,MCU, NOWAIT

// This shouldn't end up in the code because nothing calls it.
void Nothing (void) { output_high(PIN_J3); }

#org 0x10000,0x1FFFF auto=0 default
///////// APPLICATION /////////
void main_Palm(void) {
   unsigned int8   i=0;
   while(1) if(i++>250) output_high(PIN_J2); else output_low(PIN_J2);
}

///////// PERSONALITY CHOOSER /////////
#org 0x00024, 0x00FFE default
void main(void) {
   output_high(PIN_J1);                        // Turn on an LED
   goto_address(0x10000);                     // Try it using a discrete address
}

// This also shouldn't end up in the code because nothing calls it.
void Nothing2 (void) { output_high(PIN_J3); }

I think we all agree the code optimizer should not include Nothing and Nothing2 in the compiled output since they are not called. I think it is important to show the whole list file here (sorry for the length):
Code:
00000:  GOTO   002A
.................... #include "18F8722.h"
.................... //////// Standard Header file for the PIC18F8722 device ////////////////
.................... #device PIC18F8722
.................... #list
.................... 
.................... 
.................... #use delay(clock=11059200)                     //11.0592 MHz Oscillator
.................... #fuses EC_IO,NOPROTECT,NOIESO,NOBROWNOUT,NOWDT,PUT,NOCPD, NOSTVREN,NODEBUG,NOLVP,NOWRT,NOCPB,NOEBTRB,NOEBTR,CCP2C1, NOWRTD,NOWRTC,NOWRTB,NOFCMEN,NOLPT1OSC,MCLR,NOXINST,MCU, NOWAIT
.................... 
.................... // This shouldn't end up in the code because nothing calls it.
.................... void Nothing (void) { output_high(PIN_J3); }
.................... 
.................... #org 0x10000,0x1FFFF auto=0 default
.................... ///////// APPLICATION /////////
.................... void main_Palm(void) {
....................    unsigned int8   i=0;
*
10000:  CLRF   06
....................    while(1) if(i++>250) output_high(PIN_J2); else output_low(PIN_J2);
10002:  MOVF   06,W
10004:  INCF   06,F
10006:  SUBLW  FA
10008:  BTFSC  FD8.0
1000A:  GOTO   10016
1000E:  BCF    F9A.2
10010:  BSF    F91.2
10012:  GOTO   1001A
10016:  BCF    F9A.2
10018:  BCF    F91.2
1001A:  GOTO   10002
.................... }
1001E:  RETLW  00
.................... 
.................... ///////// PERSONALITY CHOOSER /////////
.................... #org 0x00024, 0x00FFE default
.................... void main(void) {
*
0002A:  CLRF   FF8
0002C:  BCF    FD0.7
0002E:  CLRF   FEA
00030:  CLRF   FE9
00032:  MOVF   FC1,W
00034:  ANDLW  C0
00036:  IORLW  0F
00038:  MOVWF  FC1
0003A:  MOVLW  07
0003C:  MOVWF  FB4
....................    output_high(PIN_J1);                        // Turn on an LED
0003E:  BCF    F9A.1
00040:  BSF    F91.1
....................    goto_address(0x10000);                     // Try it using a discrete address
00042:  GOTO   10000
.................... }
.................... 
.................... // This also shouldn't end up in the code because nothing calls it.
.................... void Nothing2 (void) { output_high(PIN_J3); }
00024:  BCF    F9A.3
00026:  BSF    F91.3
00028:  RETLW  00
00046:  SLEEP

As you can see, Nothing2() gets compiled in even though nothing calls it! Nothing() is ignored, as it should be. Under certain circumstances, main_Palm() gets ignored and disappears from the code like Nothing() does.

Is the fact that Nothing2() gets compiled in when it is not called indicative of a bug?

Perhaps if we can solve the mystery to Nothing2() we can get to the root of why my personality programs sometimes disappear when I use this approach to the original problem. Remember, I had initially dismissed the use of goto_address for this requirement because the personality programs weren't ending up in the compiled code and I thought it was the optimizer taking them out because they weren't called.

Thanks,
Kyle
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jul 06, 2006 2:09 pm     Reply with quote

As you can see, Nothing2() gets compiled in even though nothing calls it! Nothing() is ignored, as it should be.

Do you realize your sentence above is like a "Who's on First" routine ?
(Abott and Costello comedy routine).
kda406



Joined: 17 Sep 2003
Posts: 97
Location: Atlanta, GA, USA

View user's profile Send private message

PostPosted: Thu Jul 06, 2006 2:16 pm     Reply with quote

PCM programmer wrote:
Do you realize your sentence above is like a "Who's on First" routine ?
(Abott and Costello comedy routine).

That's why I used the parenthesis. I did think it was humorous when I wrote it though. Very Happy
-Kyle
Ttelmah
Guest







PostPosted: Fri Jul 07, 2006 4:05 am     Reply with quote

First, don't fix the address of your 'personality chooser' this low in memory. You are in the area the compiler will expect to use for the interrupt handler. This is probably why it is stopping your interrupts working...
'Nothing2', gets compiled, because your ORG override is still in force. You can make any routine compile, by giving it an ORG, and an ORG with 'default', remains in force, till another ORG is met (or a #ORG default, switches 'back' to normal operation). This is exactly how you can make your routines be compiled, even if not 'called'.
If you add #ORG default, after the 'main', then Nothing2, will not be compiled.

Best Wishes
kda406



Joined: 17 Sep 2003
Posts: 97
Location: Atlanta, GA, USA

View user's profile Send private message

PostPosted: Fri Jul 07, 2006 8:52 am     Reply with quote

Ttelmah,

Adding an #ORG default does allow the optimizer to ignore Nothing2(). I think with the help you have given me here, I can get this running without losing a stack entry permanently.

The goto and ISR problems were two separate issues. Much like a bootloader, I have the ISRs relocated in memory. I removed them to shorten the example. They work flawlessly until I call the personality program and do a 'pop'. I think the goto will be an easier option, so I am not going to spend time further investigating the ISR/pop problem.

Thanks for your help!

-Kyle
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