Program over 2k fails to run- page boundary problem

General discussion on mikroBasic.
Author
Message
Mikemurf
Posts: 11
Joined: 11 Mar 2006 17:22

Program over 2k fails to run- page boundary problem

#1 Post by Mikemurf » 03 Jan 2008 18:13

The attached program fails to display anything on the LCD unless I comment out either line 37, 38, or 39 (angle = angle + 900).

[/code]program Test
' microcontroller P16F877A
Dim Servo As Byte
Dim receive As Byte
Dim T1 As Word absolute $0E
Dim T0 As Byte absolute $01
Dim Test As Word
Dim pos As Word[8]
Dim Output As string[5]
Dim text as char[5]
Dim angle as longint

sub procedure Interrupt
If INTCON.TMR0IF Then
ClearBit(PORTD, Servo)
T0 = -196
Servo = Inc(Servo) And 3
SetBit(PORTD, Servo)
Test = Servo
Test = pos[Servo+0]
Test = pos[Servo+1]
Test = pos[Servo+2]
Test = pos[Servo+3]

T1 = 0 - pos[Servo]
T1CON.TMR1ON = 1
PIR1.TMR1IF = 0
INTCON.TMR0IF = 0
Else
ClearBit(PORTD, Servo)
T1CON.TMR1ON = 0
End If
End sub

sub procedure get_and_display_angle1(dim sign as byte, dim byref angle as word)
if sign = 1 then
angle = angle + 900 '2 lines ok- 3 lines fails to run
angle = angle + 900 '2 lines ok- 3 lines fails to run
angle = angle + 900 '2 lines ok- 3 lines fails to run

end if
WordToStr(angle, Text)
end sub

main:
OPTION_REG = %10000101
INTCON = %11100100
T1CON = %00000000
T2CON = %00000011
TRISB = %00000000
PORTB = %00000000
TRISD = %11110000
PORTD = %00000000

Lcd_config(PORTB, 7, 6, 5, 4, PORTB, 3, 0, 2)
Lcd_Cmd(LCD_CURSOR_OFF)
Lcd_Cmd(LCD_CLEAR)
Lcd_Out(1,1,"mikroElektronika")
Delay_ms(2000)
Lcd_Out(1,1,"A= ")
Lcd_out(2,4,"L= R= ")

For Servo = 0 To 7
pos[Servo] = 7500
Next Servo
Servo = 0
T1 = 0 - pos[Servo]
PIR1.TMR1IF = 0
PIE1.TMR1IE = 1
T1CON.TMR1ON = 1
SetBit(PORTB, Servo)
Usart_Init(9600)

While TRUE
Lcd_Out(2,1,"-")
SetBit(PORTD, 6)
SetBit(PORTD, 7)
if PORTD.6 = 0 then
TMR2 = 0
PIR1.TMR2IF = 0
Lcd_Out(2,1,"<")
while true
if PIR1.TMR2IF then
Lcd_Out(2,2,"?")
delay_ms(1000)
Lcd_Out(2,2," ")
goto getout
else if PORTD.7 = 0 then
get_and_display_angle1(0, angle)
goto getout
end if
end if
wend
end if
if PORTD.7 = 0 then
TMR0 = 0
PIR1.TMR2IF = 0
Lcd_Out(2,1,">")
while true
if PIR1.TMR2IF then
Lcd_Out(2,2,"?")
delay_ms(1000)
Lcd_Out(2,2," ")
goto getout
else if
PORTD.6 = 0 then
get_and_display_angle1(1, angle)
goto getout
end if
end if
wend
end if
getout:
If Usart_Data_Ready = 1 Then
receive = Usart_Read
If receive = "4" Then
pos[0] = pos[0] + 100
If pos[0] > 10500 Then
pos[0] = 10500 End If
Usart_Write_Text("left ")
WordToStr(pos[0], Output)
Usart_Write_Text(Output)
End If
If receive = "6" Then
pos[0] = pos[0] - 100
If pos[0] < 4500 Then
pos[0] = 4500
End If
Usart_Write_Text("right ")
WordToStr(pos[0], Output)
Usart_Write_Text(Output)
End If
If receive = "8" Then
pos[1] = pos[1] + 100
If pos[1] > 10500 Then
pos[1] = 10500
End If
Usart_Write_Text("up ")
WordToStr(pos[1], Output)
Usart_Write_Text(Output)
End If
If receive = "2" Then
pos[1] = pos[1] - 100
If pos[1] < 4500 Then
pos[1] = 4500
End If
Usart_Write_Text("down ")
WordToStr(pos[1], Output)
Usart_Write_Text(Output)
End If
End If
Wend
End.

I assume this is because the program no longer fits in one page of memory. This is confirmed(?) as the .asm file has a new first line as:

$0000 $158A BSF PCLATH, 3

Manual states the following:
"Breaking Through Pages
In applications targeted at PIC16, no single routine should exceed one page (2,000 instructions). If routine does not fit within one page, linker will report an error. When confront with this problem, maybe you should rethink the design of your application – try breaking the particular routine into several chunks, etc."
.

I haved tried to use modules with the same problem.

Have looked at other posting of other people having similiar issues but there has been no information that I can use to help me out here. Can someone tell me why the compiler fails to run > 2k. I know it's probably how the program is written but please explain as a new person to PICs what are the "gotthas" when programs are >2k.

Thanks, Mike

piort
Posts: 1379
Joined: 28 Dec 2005 16:42
Location: Laval,Québec,Canada,Earth... :-)
Contact:

#2 Post by piort » 04 Jan 2008 04:55

hi,

programming is like writting a poem ) Many way to do the same thing but like a poem, you need a minimum of structure... Try to divide you code with procedure and function... Each action is a procedure or function... Put you register adjusment in a init procedure... so after that you code will look like...

Code: Select all


program name

dim xyz   ' var definition

sub procedure interrupt
'interrupt thing
end sub

sub procedure init
'register adjusment
end sub

sub procedure action1
'one action
end sub

sub procedure action2
'another action
end sub

main:
init
while true  ' make that only one time...not 3 time with a goto for exit the loop
action1
action2
wend
end.

If that dosent work, try a P18 ;-)

Mikemurf
Posts: 11
Joined: 11 Mar 2006 17:22

#3 Post by Mikemurf » 04 Jan 2008 12:25

Will take your comments of style into consideration. I am confused however whether a P18 PIC will solve my problem. Compiler says that only 23% of ROM and 27% of RAM are acually used. As you can see the program itself is not very big. Can't believe the P16 is "overloaded" with these statistics. I still think there is a deeper problem here.

Anyone with ideas?

Mikemurf

Sergiods
Posts: 103
Joined: 12 Apr 2007 14:38
Location: Sao Paulo - Brazil

#4 Post by Sergiods » 04 Jan 2008 13:45

Hi Mikemurf,

MB version of what you are using, the compiled code and appeared no mistake, use the version 5.0.0.2

Regards

sergiods

Mikemurf
Posts: 11
Joined: 11 Mar 2006 17:22

#5 Post by Mikemurf » 04 Jan 2008 15:41

sergiods, This was compiled using version 5.0.0.2.

Sergiods
Posts: 103
Joined: 12 Apr 2007 14:38
Location: Sao Paulo - Brazil

#6 Post by Sergiods » 04 Jan 2008 15:51

Hi,

try this code ( your code) changed

Code: Select all

program test
'*******************************************************************************
' microcontroller P16F877A @ 8MHz
'*******************************************************************************
Dim Servo As Byte
Dim receive As Byte
Dim T1 As Word absolute $0E
Dim T0 As Byte absolute $01
Dim Test As Word
Dim pos As Word[8]
Dim Output As string[5]
Dim text as char[5]
Dim angle as longint
'*******************************************************************************
sub procedure Interrupt

    If INTCON.TMR0IF = 1 Then ClearBit(PORTD, Servo)
                              T0 = -196
                              Servo = Inc(Servo) And 3
                              SetBit(PORTD, Servo)
                              Test = Servo
                              Test = pos[Servo+0]
                              Test = pos[Servo+1]
                              Test = pos[Servo+2]
                              Test = pos[Servo+3]
                              T1 = 0 - pos[Servo]
                              T1CON.TMR1ON = 1
                              PIR1.TMR1IF = 0
                              INTCON.TMR0IF = 0
    else
                              ClearBit(PORTD, Servo)
                              T1CON.TMR1ON = 0
    End If
    
End sub
'*******************************************************************************
sub procedure get_and_display_angle1(dim sign as byte, dim byref angle as word)

    if sign = 1 then angle = angle + 900 '2 lines ok- 3 lines fails to run
                     angle = angle + 900 '2 lines ok- 3 lines fails to run
                     angle = angle + 900 '2 lines ok- 3 lines fails to run
    end if
    WordToStr(angle, Text)
    
end sub
'*******************************************************************************
sub procedure out_dir(dim byref vector as string[6])

   Usart_Write_Text(vector)
   WordToStr(pos[0], Output)
   Usart_Write_Text(Output)
   
end sub
'*******************************************************************************
sub procedure lcd_out1()

    Lcd_Out(2,2,"?")
    delay_ms(1000)
    Lcd_Out(2,2," ")
    
end sub
'*******************************************************************************
main:
     OPTION_REG = %10000101
     INTCON = %11100100
     T1CON = %00000000
     T2CON = %00000011
     TRISB = %00000000
     PORTB = %00000000
     TRISD = %11110000
     PORTD = %00000000

     Lcd_config(PORTB, 7, 6, 5, 4, PORTB, 3, 0, 2)
     Lcd_Cmd(LCD_CURSOR_OFF)
     Lcd_Cmd(LCD_CLEAR)
     Lcd_Out(1,1,"mikroElektronika")
     Delay_ms(2000)
     Lcd_Out(1,1,"A= ")
     Lcd_out(2,4,"L= R= ")

     For Servo = 0 To 7
         pos[Servo] = 7500
     Next Servo
     Servo = 0
     T1 = 0 - pos[Servo]
     PIR1.TMR1IF = 0
     PIE1.TMR1IE = 1
     T1CON.TMR1ON = 1
     SetBit(PORTB, Servo)
     Usart_Init(9600)

     While TRUE
           Lcd_Out(2,1,"-")
           SetBit(PORTD, 6)
           SetBit(PORTD, 7)
           if PORTD.6 = 0 then TMR2 = 0
                               PIR1.TMR2IF = 0
                               Lcd_Out(2,1,"<")
                     while true
                          if PIR1.TMR2IF = 1 then lcd_out1()
'                           Lcd_Out(2,2,"?")
'                           delay_ms(1000)
'                           Lcd_Out(2,2," ")
                                                  goto getout
                          else

                           if PORTD.7 = 0 then get_and_display_angle1(0, angle)
                                               goto getout
                           end if
                          end if
                     wend
           end if
           if PORTD.7 = 0 then TMR0 = 0
                               PIR1.TMR2IF = 0
                               Lcd_Out(2,1,">")
                    while true
                        if PIR1.TMR2IF = 1 then lcd_out1()
'                         Lcd_Out(2,2,"?")
'                         Delay_ms(1000)
'                         Lcd_Out(2,2," ")
                                                goto getout
                        else

                         if PORTD.6 = 0 then get_and_display_angle1(1, angle)
                                             goto getout
                         end if
                        end if
                   wend
          end if
getout:
       If Usart_Data_Ready = 1 Then receive = Usart_Read
                           If receive = "4" Then pos[0] = pos[0] + 100
                                            If pos[0] > 10500 Then pos[0] = 10500
                                            End If
                                            out_dir("left ")
'                                                 Usart_Write_Text("left ")
'                                                 WordToStr(pos[0], Output)
'                                                 Usart_Write_Text(Output)
                           end If
                           If receive = "6" Then pos[0] = pos[0] - 100
                                            If pos[0] < 4500 Then pos[0] = 4500
                                            End If
                                            out_dir("right ")
'                                                Usart_Write_Text("right ")
'                                                WordToStr(pos[0], Output)
'                                                Usart_Write_Text(Output)
                           end If
                           If receive = "8" Then pos[1] = pos[1] + 100
                                            If pos[1] > 10500 Then pos[1] = 10500
                                            End If
                                            out_dir("up ")
'                                            Usart_Write_Text("up ")
'                                            WordToStr(pos[1], Output)
'                                            Usart_Write_Text(Output)
                           end If
                           If receive = "2" Then pos[1] = pos[1] - 100
                                            If pos[1] < 4500 Then pos[1] = 4500
                                            End If
                                            out_dir("down ")
'                                            Usart_Write_Text("down ")
'                                            WordToStr(pos[1], Output)
'                                            Usart_Write_Text(Output)
                           End If
      End If
    Wend
End.

Regards

Sergio

Mikemurf
Posts: 11
Joined: 11 Mar 2006 17:22

#7 Post by Mikemurf » 04 Jan 2008 16:50

Thanks Sergio for your time on this. I see were you changed some of the code from:
Usart_Write_Text("down ")
WordToStr(pos[1], Output)
Usart_Write_Text(Output)
to:
out_dir("down ").

The code works with your changes. Thanks for the tip on the "out_dir" function! However, what you did brought the code back under the 2k limit. This code is far from done and will need to add more lines of code. My concern is if I go over the 2k(?) limit again I am predicting I will have compiler issues again.

My question is not what is wrong with my code but rather when a person's code exceeds a certain size why does the complied code ceases to function!

In the original logic just by adding a really meaningless line of code of
"angle = angle + 900", why does my program stop working ???

This seems to be an issue with how the compiler handles ROM pages.

Mikemurf

Sergiods
Posts: 103
Joined: 12 Apr 2007 14:38
Location: Sao Paulo - Brazil

#8 Post by Sergiods » 04 Jan 2008 19:26

hi,

You should be with the MB without registration, so the limit of code of 2k.

Regards

Sergio

Mikemurf
Posts: 11
Joined: 11 Mar 2006 17:22

#9 Post by Mikemurf » 04 Jan 2008 20:02

Yes am registered.

piort
Posts: 1379
Joined: 28 Dec 2005 16:42
Location: Laval,Québec,Canada,Earth... :-)
Contact:

#10 Post by piort » 04 Jan 2008 20:10

hi
Manual states the following:
"Breaking Through Pages
In applications targeted at PIC16, no single routine should exceed one page (2,000 instructions). If routine does not fit within one page, linker will report an error. When confront with this problem, maybe you should rethink the design of your application – try breaking the particular routine into several chunks, etc.".
I am confused however whether a P18 PIC will solve my problem.


Page are P16 limit ...

See how Sergiods make his code... following the same way prevent you to hit the same wall... If you cut your code in small procedure, the compiler can put that in different page without prob...

Happy coding :-)

rmteo
Posts: 1330
Joined: 19 Oct 2006 17:46
Location: Colorado, USA

#11 Post by rmteo » 04 Jan 2008 20:45

Mike, you will not have this issue with the P18s. One of the main reasons I have moved to using PIC24H/J, dsPIC33 and in some cases PIC18FxxJxx. They have far more features (more flash, RAM, peripherals, much higher throughput etc.) and in many cases are more cost-effective than equivalent p16s.

The only reason to use PIC16s are for the lower pin count devices (<20 pins) and lowest possible cost chips (those that are under about $1 each).

Mikemurf
Posts: 11
Joined: 11 Mar 2006 17:22

#12 Post by Mikemurf » 05 Jan 2008 12:21

OK, I guess I am starting to see what you guys are saying. Build a bunch of smaller blocks (subroutines) vs. larger blocks of code. Makes sense if it helps the compiler reshuffle code amoung the different ROM pages.

Guess I am surprised if this is true, why the compiler creates a .hex file anyway leaving the user to find out after lots of troubleshooting that he must have hit this problem. Maybe the compiler is not that robust??

Also surpised that more users have not come across this problem!

Mike

rmteo
Posts: 1330
Joined: 19 Oct 2006 17:46
Location: Colorado, USA

#13 Post by rmteo » 05 Jan 2008 16:52

Mike, as has been mentioned above, this is a hardware issue related to the P16s. The compiler HELP file and manual do point this out.

As to why others have not come across this problem, my guess is that many of them probably do and work around it as suggested, or they move to the P18s, P24s and dsPICs.

Mikemurf
Posts: 11
Joined: 11 Mar 2006 17:22

#14 Post by Mikemurf » 06 Jan 2008 14:52

I have spent time in reorganizing the above code using subroutines where I could. But I still have the same issue when the compiler starts using 2 banks of ROM to store the code. The manual does state that if my code where to exeed 2k instructions in one block the compiler will report an error. Well from the statisics screen showing my procedure sizes, the biggest block I am using is only 469 of ROM space. This is far from the 2k limit per page.

Well doing some investigating, the P16F877A chip I am using has 8K of ROM space This is requires a 13 bit wide program counter to address all this space. However P16 instructions like GOTO and CALL are only 11 bit capable- hence the 2K limitation. To address this the ROM space is divided up into 4 pages of 2K each. So as long as programs are < 2K there are no issues.

However, once a program is over the 2K limit, the PCLATH command is required to set the upper 2 bits of the program counter correctly to address the correct page of ROM space. Problems can occur when a call is made from one ROM page and needs to reference code in another ROM page if the upper 2 bits of the PC are not correctly set first.

The compiler itself automatically adds in the needed PCLATH commands to set the correct PC values as code is running. HOWEVER, what the compiler can not do is guess when an interrupt is going to occur- and from what page it occured. The interrupt code is always at address $4 which resides in page 0 of ROM space.

Well one issue I think I am having is with my interrupt code. For example if code is running in page 1 of ROM space and an interrupt occurs, what happens to the PC after the interupt is done?? From what I gather unless the interrupt code first saves the PC first it gets lost and defaults to page 0 in ROM space upon returning. Thus causing the program to stop running correctly.

Yes as pointed out earlier, if I were to move over to a PIC like the 18F this issue goes away. However I want to understand better what are the issues are when using P16 PICs. Call me sick I guess.

Assume I am stuck with the P16F877A and code that spans 2 pages of ROM space with interrupts. What I am asking for is example interrupt code that will save and restore the PC correctly when it returns. Sure someone has had to do this before!!!!

Mikekurf

Sergiods
Posts: 103
Joined: 12 Apr 2007 14:38
Location: Sao Paulo - Brazil

#15 Post by Sergiods » 06 Jan 2008 16:03

Hi

You can also organize your code with ORG, putting the address on pages higher ..


Regards

Sergio

Post Reply

Return to “mikroBasic General”