View previous topic :: View next topic |
Author |
Message |
turpin62
Joined: 19 Mar 2008 Posts: 11 Location: UK
|
Subroutine returns to wrong point - any ideas |
Posted: Wed Mar 19, 2008 1:20 pm |
|
|
Hi,
I am writing a data transmision code for a PIC12F509 using PCWH compiler version 4.030. Thought this morning that this was a 20 minute job - ever the optimist!
The programme has a call once routine that reads a unique serial number into a variable to give the chip an ID.
The call jumps into the routine OK and executes OK but then jumps back to the wrong point in the programme skipping about 3 lines. Analysing the ASM programme memory it would seem that the routine ends with a GOTO that points to 6 assembler instructions beyond the call.
Anyone with any ideas as to what is going on? Better still anyone know how to fix it?
I can cure the problem by calling the routine twice, the compiler then ends the routine on a RETLW and for whatever reason has pushed the right PC value onto the stack and so jumps back OK. However, when I do this the problem moves to the next call once routine which now jumps back to the wrong point. I can't call all the routines twice! |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 19, 2008 1:27 pm |
|
|
This PIC only has a 2-deep stack.
1. Are you using the #separate directive ?
If so, look at the top of the .LST file. How many stack levels
does it report ?
2. Are you using #asm code to jump around in the program,
instead of using C code ?
3. Is it possible that you accidently erased the MOVLW instruction
at the end of ROM that contains the OSCCAL value ? |
|
![](templates/subSilver/images/spacer.gif) |
turpin62
Joined: 19 Mar 2008 Posts: 11 Location: UK
|
|
Posted: Wed Mar 19, 2008 1:49 pm |
|
|
1) Not using #SEPARATE but .lst file reports
Stack: 2 worst case (1 in main + 1 for interrupts)
2) There is an ASM jump to pick up the ID. However, this code works on the same chip in another application so I don't think it is a problem. Also, if I double up on the calls to this routine the problem moves to the next single call routine which has no ASM.
3) No
Thanks for your help |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 19, 2008 1:52 pm |
|
|
If you can cut the program down to a small size and still have it
show the problem, then post it and I'll look at it. |
|
![](templates/subSilver/images/spacer.gif) |
RLScott
Joined: 10 Jul 2007 Posts: 465
|
|
Posted: Wed Mar 19, 2008 2:34 pm |
|
|
Normally, when a single call is made to a routine, the compiler optimizes away the call by inserting the code for the called routine in-line. So this has nothing to do with stacks. I am just surprised that in your case the called routine gets its own location and needs a goto to get into it and a goto to get out of it. Are you using any special directives at all that have to do with code location? Are you using any #ASM directives? As PCM Programmer said, try to get a minimal example that fails and post the code.
Robert Scott
Real-Time Specialties |
|
![](templates/subSilver/images/spacer.gif) |
Matro Guest
|
|
Posted: Thu Mar 20, 2008 2:32 am |
|
|
Hi Robert,
Just 2 things. Here the code seems not to use "goto" to enter the function but "call" and returns with "retlw".
And it seems that the compiler doesn't optimize this kind of things because I'd got the same problem with a once called function.
The jump was made by a "goto" if I let the compiler choose the location of the function, but as soon as I choose the location with a #ORG directive the jump was made by a "call".
Regards,
Matro |
|
![](templates/subSilver/images/spacer.gif) |
turpin62
Joined: 19 Mar 2008 Posts: 11 Location: UK
|
|
Posted: Thu Mar 20, 2008 5:15 am |
|
|
Cutting down the code actually makes the problem go away which probably gives a clue as to the nature of the problem
The ID location is set up by #define to reserve some space
#org 0x00ef, 0x00ff
int32 const serial=0xaabbccdd;
The ID is read by a short ASM routine
void getid(){
delay_us(2);
#asm
CALL 0xF1
MOVWF (&val2)
CALL 0xF2
MOVWF (&val3)
CALL 0xF3
MOVWF (&val4)
#endasm
delay_us(2);
return;
}
The #ORG statement is required to ensure that both the constant and the read routine are in the same segment of memory. So I compile the code, see where the routine ends up and move the constant into that segment. This I thought would be easier than managing the high PC bits in STATUS. I suspect this has turned out to be a Garmin Sat-nav style short-cut and now I am stuck in the river.
The call and returns all work fine in the ASM segment. If I force the call out to getid to use CALL and RETLW rather than GOTO the problem is resolved. This seems to imply that it is a compiler error rather than a stack issue. The problem also only seems to occur when the call to getid crosses a memory page boundary and STATUS <6:5> is changed, hence the problem goes away when I cut down the programme.
I am going to package up the whole ID routine into a high programme memory routine so that everything is in one segment to try and resolve the problem.
Thanks for all your helpul comments |
|
![](templates/subSilver/images/spacer.gif) |
RLScott
Joined: 10 Jul 2007 Posts: 465
|
|
Posted: Thu Mar 20, 2008 5:20 am |
|
|
So where is your problem? If the compiler uses a "call" and a "retlw", then everything is OK. If you use the #ORG statement on a function called only once, then the compiler also uses a "call" and "retlw", so again everything is OK. If you don't use an #ORG statement, then the compiler uses a "goto" to get into and out of the function. That seems OK too, when I try it. So what condition is making your code use a returning "goto" that is targetted to the wrong place? Are you sure it is wrong?
Robert Scott
Real-Time Specialties |
|
![](templates/subSilver/images/spacer.gif) |
turpin62
Joined: 19 Mar 2008 Posts: 11 Location: UK
|
|
Posted: Thu Mar 20, 2008 9:39 am |
|
|
The problem only occurs when the call to getid() is on a different memory page to the function code and the ID space. In my case the call is on the page above 0x200 and the function and ID space is between 0x050 and 0x0ff.
This is the disassembled call to getid()
228 902 CALL 0x2
This jumps to a goto and memory page switch thus
202 4A3 BCF 0x3, 0x5
203 A53 GOTO 0x53
It jumps to location 53 on page 1
This is the location of getid - clearly the required vector is 50 which should point to 51 not 54 (therby giving the short 2us delay)
Worse still the programme jumps to empty memory at the end of getid() and then runs up half a page of empty memory before running over the page boundary where the first thing it hits is the call to getid() -That's just bad luck. The GOTO 5B should be 58 to point to the RETLW which should pop the original PC and take us back to page 2 at instruction 229.
Basically all of the GOTO statements miss their intended target by 3 in this example.
04E FFF XORLW 0xff
04F FFF XORLW 0xff
050 A54 GOTO 0x54
051 9F1 CALL 0xf1
052 02D MOVWF 0xd
053 9F2 CALL 0xf2
054 02E MOVWF 0xe
055 9F3 CALL 0xf3
056 02F MOVWF 0xf
057 A5B GOTO 0x5b
058 800 RETLW 0
059 FFF XORLW 0xff
05A FFF XORLW 0xff
05B FFF XORLW 0xff
05C FFF XORLW 0xff
05D FFF XORLW 0xff
05E FFF XORLW 0xff
As for a solution I have now juggled the call/function/ID space all onto the same page. But I would be interested to know what has gone wrong in my original.
Looks like a compiler yip to me. |
|
![](templates/subSilver/images/spacer.gif) |
Ken Johnson
Joined: 23 Mar 2006 Posts: 197 Location: Lewisburg, WV
|
|
Posted: Thu Mar 20, 2008 11:43 am |
|
|
Just noticed your compiler version - 4.030.
Can you try this on the latest version - 4.069?
Ken |
|
![](templates/subSilver/images/spacer.gif) |
turpin62
Joined: 19 Mar 2008 Posts: 11 Location: UK
|
|
Posted: Thu Mar 20, 2008 11:53 am |
|
|
Hi Ken,
I had the same thought this morning and so upgraded to 4.069.
The compilation above is from 4.069. |
|
![](templates/subSilver/images/spacer.gif) |
turpin62
Joined: 19 Mar 2008 Posts: 11 Location: UK
|
|
Posted: Sun Mar 23, 2008 12:30 pm |
|
|
Finally had a bit of time to sort out a short code that shows the problem - below.
Used #ORG to force the getid function to call across the memory page boundary.
As included here the sleep command never executes as the program jumps into the middle of getid and then runs off into empty memory.
Change the delay at the end of getid to a larger value (50us) and the programme still jumps into the middle of getid but does at least terminate correctly so that the sleep now executes.
Beats me!
Code: | #include <12F509.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC //Internal RC Osc
#FUSES PROTECT //Code protected from reading
#FUSES NOMCLR //Master Clear pin used for I/O
#use delay(clock=4000000)
#define GP0 PIN_B0
#define GP1 PIN_B1
#define GP2 PIN_B2
#define GP3 PIN_B3
#define GP4 PIN_B4
#define GP5 PIN_B5
#org 0x00f0, 0x00ff
int32 const serial=0xaabbccdd;
int8 val2, val3, val4;
int32 serial2;
void setoption();
#org 0x0050, 0x00ea
void getid(){
#asm
CALL 0xF1
MOVWF (&val2)
CALL 0xF2
MOVWF (&val3)
CALL 0xF3
MOVWF (&val4)
#endasm
delay_us(2);//This ASM function reads the chipID into val2..val4. The function must be in the same page as the data
return;
}
#org 0x0200, 0x0300
void main()
{
setoption();//set timer 0 clock 1Mhz giving approx 4uS to each clock increment set weak pull ups off
set_tris_b(0x01);// sets GPIO to 00000001 GP0 input. GP4 is the data output, GP2 is the LED power
getid();
sleep();
return;
}
void setoption(){
delay_us(5);
#ASM
MOVLW 0b01000001
OPTION
#ENDASM//set up wake up on pin change and wpu off psa assigned T0 1:4
return;
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
|