PDA

View Full Version : Apparent code size problem



eetech
- 25th July 2007, 21:15
I am having a problem that appears to be related to code size. The chip is 16F917, PBP version is 2.46

The total code size is over 4000 words Everything compiles and one version of the code works just fine. However a small change is one subroutine to make it more user friendly seems to break eveything. It appears to fail to initialize properly ( based on fact that the opening splash screen never displays and the instrument will not respond to any of the inputs it should immediately after power up). The code is for a company project and so I can not post it all, but I have posted the two code snippets, the total word count of the program when using each variation and the address range

I encountered this problem once or twice before during this project and both times a change in code size has corrected it. Once was nothing more than adding a line like X = X. This leads me to think it may be some type of boundry issue, but I have to admit I am new enough to PICs and PBP that I am more than a little confused at this time.

Any help or suggestions would be appreciated.

The one that works:
4145 words
0-1037 address range

IF (OhmCheck = FAILED) or _ ' resistor out of tolerance or
(FlagResult <> 0) then ' hardware flag
GOSUB Houston
ENDIF
-------------------------------------------------

Replace it with this one and it does not work:
4281 words
0-10bf address range

IF OhmCheck = FAILED THEN
ErrCnt = ErrCnt + 1
IF ErrCnt = 1 then 'first time gets a pass for a recheck
Device = DISPLAY
GOSUB SetCtrl
LCDOUT $FE,1,"Chk Dckbill conn"
LCDOUT $FE,$C0,"then retry test"
PAUSE 1000
ENDIF
ENDIF
IF (ErrCnt > 1) or (FlagResult <> 0) THEN
GOSUB Houston
ENDIF

Jerson
- 26th July 2007, 04:32
It might have something to do with the gosub Houston routine. Maybe the branch is out of range. You could try to reposition the subroutine Houston and see if it works. I could be totally wrong too... ;)

sayzer
- 26th July 2007, 09:58
...



IF (OhmCheck = FAILED) or _ ' resistor out of tolerance or
(FlagResult <> 0) then ' hardware flag
GOSUB Houston
ENDIF



Try this for the one above:


IF ErrCnt > 1 or FlagResult > 0 THEN GOSUB Houston


-------------------------------------------------

...
Replace it with this one and it does not work:


IF OhmCheck = FAILED THEN
ErrCnt = ErrCnt + 1
IF ErrCnt = 1 then 'first time gets a pass for a recheck
Device = DISPLAY
GOSUB SetCtrl
LCDOUT $FE,1,"Chk Dckbill conn"
LCDOUT $FE,$C0,"then retry test"
PAUSE 1000
ENDIF
ENDIF
IF (ErrCnt > 1) or (FlagResult <> 0) THEN
GOSUB Houston
ENDIF



And try this for the one above:



IF OhmCheck = FAILED or FlagResult > 0 then GOSUB Houston



And try this separately:



IF OhmCheck = FAILED THEN
ErrCnt = ErrCnt + 1

IF ErrCnt = 1 then 'first time gets a pass for a recheck
Device = DISPLAY
GOSUB SetCtrl
LCDOUT $FE,1,"Chk Dckbill conn"
LCDOUT $FE,$C0,"then retry test"
PAUSE 1000
else
gosub Houston
endif

ENDIF


IF FlagResult > 0 THEN GOSUB Houston


Question: Do you set ErrCnt = 0 before the program starts running, or it gets some values from somewhere else?
In your code, it seems that it must be set to zero at initial power up before coming to "IF OhmCheck = FAILED THEN" condition.

Question: FlagResult is a hardware flag. So it can be 1 or 0 only, right? If yes, then why not use IF FlagResult = 1 instead of FlagResult <> 0 ?


Also, as Jerson said, we should see Houston subroutine.

May be there is something in it that makes things messed up.


--------------------------------

sinoteq
- 26th July 2007, 14:17
What you say looks like something I had some time ago. Check the forum for broken code. http://www.picbasic.co.uk/forum/showthread.php?t=5674

The problem is when you add a new variable PBP makes a word variable span 2 banks and that is not allowed. If this happens you get "The Harry Potter Syndrome" black magic and nothing is logical anymore. I fixed this for my 18F4620 pic by adding a dummy variable at the last address in each bank. For example:

bogus_0 VAR BYTE $7F ' force a byte at location 07F
bogus_1 VAR BYTE $0FF ' force a byte at location 0FF
bogus_2 VAR BYTE $1FF ' force a byte at location 1FF
bogus_3 VAR BYTE $2FF ' force a byte at location 2FF
bogus_4 VAR BYTE $3FF ' force a byte at location 3FF
bogus_5 VAR BYTE $4FF ' force a byte at location 4FF
bogus_6 VAR BYTE $5FF ' force a byte at location 5FF
bogus_7 VAR BYTE $6FF ' force a byte at location 6FF
bogus_8 VAR BYTE $7FF ' force a byte at location 7FF

Make sure you get the location right, depending on MCU you should go for different values. Look in the .ASM file for your compiled program and early you will find:

BANK0_START EQU 00080h
BANK0_END EQU 000FFh
BANK1_START EQU 00100h
BANK1_END EQU 001FFh
BANK2_START EQU 00200h
BANK2_END EQU 002FFh
BANK3_START EQU 00300h
BANK3_END EQU 003FFh

Use the END value for you bogus variable and PBP can not make this misstake. Make sure you include BANKA also in the fix.

Hope this will help to remove Harry Potter from your code. And YES MELABS knows about this because they helped me to find it.

Mike

eetech
- 26th July 2007, 15:04
Try this for the one above:


IF ErrCnt > 1 or FlagResult > 0 THEN GOSUB Houston


-------------------------------------------------


And try this for the one above:



IF OhmCheck = FAILED or FlagResult > 0 then GOSUB Houston


And try this separately:



IF OhmCheck = FAILED THEN
ErrCnt = ErrCnt + 1

IF ErrCnt = 1 then 'first time gets a pass for a recheck
Device = DISPLAY
GOSUB SetCtrl
LCDOUT $FE,1,"Chk Dckbill conn"
LCDOUT $FE,$C0,"then retry test"
PAUSE 1000
else
gosub Houston
endif

ENDIF


IF FlagResult > 0 THEN GOSUB Houston


Question: Do you set ErrCnt = 0 before the program starts running, or it gets some values from somewhere else?

In your code, it seems that it must be set to zero at initial power up before coming to "IF OhmCheck = FAILED THEN" condition.

Question: FlagResult is a hardware flag. So it can be 1 or 0 only, right? If yes, then why not use IF FlagResult = 1 instead of FlagResult <> 0 ?

FlagResult is a hardware flag, but it is a set of BIT flags so it can have a result other than 0 or 1.

Also, as Jerson said, we should see Houston subroutine.

May be there is something in it that makes things messed up.


--------------------------------


Both of those examples are fundamentally the same. The difference being your use of the IF without the ENDIF, which some languages (like PBP) allow.
I did try it though.

Yes, ErrCnt is set to 0 before usage.

FlagResult is a hardware flag, but it is a set of BIT flags so it can have a result other than 0 or 1.

The subroutine Houston uses Select Case to decode FlagResult and displays the appropriate error message. It does not return from there but goes into a continous loop because errors that cause Houston to be called are considered critical problems with either the instrument or the site being tested.

I may not have made myself clear in the original post, the problem does not occur because the code in question is run (the program never gets that far). The problem occurs when the first piece of code is replaced by the second.

sinoteq
- 26th July 2007, 15:15
This is what I had, I changed in one place and it died in another. If you check the asm file that you have on the NOT working program it is easy to see. Just look at the end address for each bank and most likely you will see Byte0 of a Word variable there. Byte1 will be in then next bank and this messes up all the RAM area for you even if you don't use that variable in the start of your program.

M

Bruce
- 26th July 2007, 15:31
Without seeing all of your code it's tough for someone to help debug, but it
does sound like a page boundary issue.

If the splash screen never shows on power-up, I'm curious as to where the
routine that handles this is located? Is it near the end of your program?

Are you 100% sure you don't have a GOSUB to a sub-routine somewhere with
a GOTO VS RETURN in the called sub-routine?

eetech
- 27th July 2007, 17:09
There is one thing I did forget to mention (and I aplogize to all of you that have offered help). The mcu initialization is done in assembly. That code block is located immediately after all the variable declarations, etc.
-----------------------------------------------------------------

Mike,
I tried the dummy variable fix, it did not cure the problem. after putting the dummies in I checked the address of every word variable in the asm listing to make sure none crossed a page. Here is the asm listing of the page banks and the dummy declarations.

RAM_START EQU 00020h
RAM_END EQU 001EFh
RAM_BANKS EQU 00004h
BANK0_START EQU 00020h
BANK0_END EQU 0007Fh
BANK1_START EQU 000A0h
BANK1_END EQU 000EFh
BANK2_START EQU 00120h
BANK2_END EQU 0016Fh
BANK3_START EQU 00190h
BANK3_END EQU 001EFh
EEPROM_START EQU 02100h
EEPROM_END EQU 021FFh


'******************************************
' Dummy Variable Declarations *
'******************************************
bogus_0 VAR BYTE $07F
bogus_1 VAR BYTE $0EF
bogus_2 VAR BYTE $16F
bogus_3 VAR BYTE $1EF

----------------------------------------------------------------

Bruce,
The code that displays the splash screen is physically located early in the code and is the first code ran once the initializatin sequences are finished.
I doubled checked my routines, as you suggested, everything ok there.

I know it is hard to help when you can't see the code, and believe me if I could I would upload the entire project and let everyone have a field day with it.


The code blocks out like this:

fuse settings
defines
constant declarations
variable decalrations

GOTO Start

INI:
assembly block (with return) to setup the chip

Setup:
routine (with return) to set initial state of variables, etc

Start:
GOSUB INI
GOSUB Setup

Splash screen is displayed here.

Some initail instrument checks ( proper hookup, etc) are performed here

Switch polling routine here

rest of code body.

Bruce
- 27th July 2007, 19:01
Have you tried replacing your .asm initialization with a BASIC version?

I know you can sometimes save a few bytes by doing some things in .asm,
but if you initialize everything in banks PBP doesn't insert a ton of bank
switching code flipping back & forth between banks. I.E.

' Bank0 first
PORTB = 0
PORTC = 0
T2CON = 0
' Bank1 next
TRISA = 0
TRISB = 0
CMCON1 = 7, etc, etc,

Are you using assembler in other routines?

I would think either something in the INI or Setup routines is causing
the problem since the splash screen routine is supposed to run directly
after Setup.

If one routine is causing the problem, it should be easy to spot.

Start:
GOSUB INI
blink an LED on return to here x times
GOSUB Setup
blink an LED on return to here x times, etc, etc,.

Of course you could always run it through MPSIM too.

eetech
- 30th July 2007, 14:26
Bruce,

I tried the idea of replacing the asm routine with a basic one; pared the program down to just the ini and setup stuff and a display routine. Two versions, one all PBP and the other with the asm block.

Now... I really feel stupid, the all basic one will not run, the other works just fine. So before I can actually try your idea I now have to figure out what I am doing wrong with the ini code in basic. ( and just in case everyone is wondering at this point... yes, I did write the asm block)

I have included both below so that anyone who wants ( after they get up off the floor from laughing) can point out my mistake if they would.

hope I got the code formatting command right so it is easy to read.

Robert

[code]
'************************************************* ***************
' MCU Setup - inline assembly block *
'************************************************* ***************
INIMCU:
asm
bsf STATUS,RP0 ; Select Bank 1

movlw 07h ; turn off comparators
movwf CMCON0

movlw 0xEC ; set A<5,1,0> as digital I/O
movwf ANSEL ; A<3:2> and E<2:0> as analog

movlw 0xFF ; set A<7:0> input; (A<3:2> analog; A<7:4,1:0> digital)
movwf TRISA

movlw 50h ; set A2D Clock 10h:Fosc/8 50h:Fosc/16
movwf ADCON1

movlw 00h ; set PORTB as outputs
movwf TRISB

movlw 0xF8 ; set PORTC C<7:3> as inputs; C<2:0> as outputs
movwf TRISC

movlw 0x00 ; set PORTD as inputs
movwf TRISD

movlw 0Fh ; set PORTE as inputs
movwf TRISE

bcf STATUS,RP0 ; Select Bank 2
bsf STATUS,RP1 ;

clrf LCDCON ; Disable VLCD<3:1>
; inputs on RC<2:0>

bcf STATUS,RP0 ; Select Bank 0
bcf STATUS,RP1
endasm
return



'******************************
' MCU Setup - PBP
'******************************
INIMCU:
CMCON0 = 7
ANSEL = $EC
TRISA = $FF
ADCON1 = $50
TRISB = 0
TRISC = $F8
TRISD = 0
TRISE = $0F
LCDCON = 0
return

[\code]

Jerson
- 30th July 2007, 15:51
Robert

I am wondering if you can do the following. Bruce already suggested this. I am just reminding you of the possibility (to catch a problem) of debugging this technique offers.



GOTO Start

INI:
assembly block (with return) to setup the chip

Setup:
routine (with return) to set initial state of variables, etc

Start:
Led = 1:pause 1000:Led = 0
GOSUB INI
Led = 1:pause 1000:Led = 0
GOSUB Setup
Led = 1:pause 1000:Led = 0

Splash screen is displayed here.

Some initail instrument checks ( proper hookup, etc) are performed here

Switch polling routine here

rest of code body

if you see 3 flashes of the led, you have reached the splash screen code.

Perhaps this will help you find if you are missing a return / stacking too deep. You may have a problem due to the limited caller stack size. Have you looked into this too?

Jerson