Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Problem with tables going over the 0x100 boundary

Status
Not open for further replies.

nclark

New Member
ok I've been stuck for 2 days, tried everything I could find on the net and read the “Implementing a Table Read" (AN556) Application note about 25 times and I just can't figure it out!

I'm reading tables that contain text menus that will be displayed on a LCD screen. Everything was going great and all until I started to add interrupt code just before the tables and everything shifted in memory to go over the 0x100 border, now everything before the border works great with my display code but nothing after it works.

Here is a snipet of my original code...
Code:
DisplayBatID    call    LCD_Clr
                clrf    count                   ;set counter register to zero
DisplayBatID_1  movf    count, w                ;put counter value in W
                call    BatIDL1            	;get a character from the text table
                xorlw   0x00                    ;is it a zero?
                btfsc   STATUS, Z
                goto    DisplayBatID_2
                call    LCD_Char
                incf    count, f
                goto    DisplayBatID_1
DisplayBatID_2  call    LCD_Line2
                clrf    count                   ;set counter register to zero
DisplayBatID_3  movf    count, w                ;put counter value in W
                call    BatIDL2			;get a character from the text table
                xorlw   0x00                    ;is it a zero?
                btfsc   STATUS, Z
                goto    DisplayBatID_4
                call    LCD_Char
                incf    count, f
                goto    DisplayBatID_3
DisplayBatID_4  bcf     flags,  change
                retlw   0x00
Nigel should recognise this code :) (BTW thanks for the great tutorials!)

Then after my problems started to appear, I tried to implement the code in the application note from Microchip but nothing good has worked and I'm pretty much stumped right now. So I'm hoping someone else might have stumbled on this problem and could give me a push in the right direction. I'm pretty much confused about the HIGH and LOW directives or whatever they call them as seen in the application note.

BTW I'm using a PIC16F873 MCU

Thanks!
 
You didn't post the most relevant code, the one which makes the actual table read!

I assume that PCLATH is at it default power-up value of 0. In this case, all instructions using the "ADDWF PC,F" or "MOVWF PC,F" instructions will end up in the first 256 locations in memory. Since you are putting the interrupt service routines in those locations, you are running out of space there.

The quick fix is to relocate the table outside this range, preferably at the start of a 256 byte boundary. You then simply initialize PCLATH to point to that location. Attached is sample code to illustrate:

Code:
;
    call   GET_TABLE_VALUE
;
;   additional code follows here
;
    goto   elsewhere
GET_TABLE_VALUE:
    movwf  temp             ; temporarily save WREG
;
    movlw  HIGH TABLE_START
    movwf  PCLATH
;
    movf   temp,W
    movwf  PC,F
;
;----------------------------------------------------
    ORG    (HIGH $ + 1)*100h ; start on the next page

TABLE_START:
    retlw  0
    retlw  1
;   .
;   .
;   .
;   .
    retlw  d'254'
    retlw  d'255'
;----------------------------------------------------
 
motion said:
You didn't post the most relevant code, the one which makes the actual table read!

I assume that PCLATH is at it default power-up value of 0. In this case, all instructions using the "ADDWF PC,F" or "MOVWF PC,F" instructions will end up in the first 256 locations in memory. Since you are putting the interrupt service routines in those locations, you are running out of space there.

The quick fix is to relocate the table outside this range, preferably at the start of a 256 byte boundary. You then simply initialize PCLATH to point to that location. Attached is sample code to illustrate:

Exactly, for a PIC with reasonable size memory I would tend to put the tables in the very highest page, setting PCLATH accordingly - if the tables are more than 256 bytes I would then use the next page below as well. In this way, with the tables working down from the top of memory, a page at a time, and the program working upwards from the bottom of memory, it avoids any clashes - until they get large enough to meet! - but this means a seriously large program!.
 
:idea:

They way I impliment long lookup tables is to load PCLATH as well in the look up BEFORE the jump.........


LOOKUP_LONG
MOVF LU_HIGH,W ;MOVE LOOKUP HIGH TO W
MOVWF PCLATH ;STORE IN PC LATCH HIGH

MOVF LU_LOW,W ;MOVE LOOKUP LOW TO W
ADDWF PCL,F ;ADD TO PROGRAM COUNTER LOW

RETLW XX
RETLW XX ;ETC

This is very similar to you earlier code, but you were loading a fixed literal into pc latch high.

Your calling code (to the look up) will have to keep track of pc latch high, if you know the starting value then on increasing "LU_LOW" if carry is set then increase "LU_HIGH"


code to call lookup....

INCF LU_LOW,F ;INCREASE LOOK UP LOW

BTFSC STATUS,C ;IS CARRY SET?
INCF LU_HIGH,F ;YES, INCREASE LOOK UP HIGH VALUE

Hope this helps!
 
Thanks guys for the replies, but I finally figured it out. Here is the code I finally came up with (that I forgot to post in my original question), pretty much what I already had going and was wondering why it would not work!

Code:
DisplayBatID    call    LCD_Clr
                clrf    offset                  ;set offset register to zero
                movlw   d'1'                    ;set count register to the first
                movwf   count                   ;|character in the table
DisplayBatID_1    
                movf    count, w                ;put count value in offset
                movwf   offset                  ;|

                movlw   LOW BatIDL1             ;get low address of the table
                addwf   offset, f               ;add the low address of the offset value
                movlw   HIGH BatIDL1            ;get high adress of the table
                btfsc   STATUS, C               ;check if carry bit is set from the add operation
                addlw   1                       ;if carry set add 1 to w
                movwf   PCLATH                  ;place the high address in PCLATH
                movf    offset, w               ;place low address in w
                
                call    BatIDL1                 ;get a character from the text table
                xorlw   0x00                    ;is it a zero?
                btfsc   STATUS, Z               ;check if zero bit is set from the above compare
                goto    DisplayBatID_2          ;if zero set get out of here
                call    LCD_Char                ;zero not set, display character
                incf    count, f                ;increment count register
                goto    DisplayBatID_1          ;start again and get next character in table

DisplayBatID_2  call    LCD_Line2
                clrf    offset                  ;set offset register to zero
                movlw   d'1'                    ;set count register to the first
                movwf   count                   ;|character in the table
DisplayBatID_3    
                movf    count, w                ;put count value in offset
                movwf   offset                  ;|

                movlw   LOW BatIDL2             ;get low address of the table
                addwf   offset, f               ;add the low address of the offset value
                movlw   HIGH BatIDL2            ;get high adress of the table
                btfsc   STATUS, C               ;check if carry bit is set from the add operation
                addlw   1                       ;if carry set add 1 to w
                movwf   PCLATH                  ;place the high address in PCLATH
                movf    offset, w               ;place low address in w
                
                call    BatIDL2                 ;get a character from the text table
                xorlw   0x00                    ;is it a zero?
                btfsc   STATUS, Z               ;check if zero bit is set from the above compare
                goto    DisplayBatID_4          ;if zero set get out of here
                call    LCD_Char                ;zero not set, display character
                incf    count, f                ;increment count register
                goto    DisplayBatID_3          ;start again and get next character in table
DisplayBatID_4  bcf     flags,  change
                retlw   0x00

Well after a good nights sleep and alot of dreaming of ASM code. It came to me that my tables started with a standard "addwf PCL, f" and should not be adding the w register to the PCL but replace the PCL with the calculated value so I changed the start of my tables with the instruction "movwf PCL" and all works now.

After looking at the application note from Microchip, it flashed in my face that this is what they were doing also but just did not notice it before!!!

Now that it works, I try to optimise the code a little, I probably can cut down on the variable registers (offset and count) so that only one is required and save a few instructions in the process.


In reply to Matt...

Not sure how your code works but from what I can see it should not work at all because the "incf HU_LOW,F" does not affect the Carry bit. So your "incf LU_HIGH,F" right after your carry test would never be executed.

This is why I use the "addwf" instead of a standard "incf" instruction in my code instead of incrementing it. It's also why I must use two different registers to keep track of where I am in my offset calculations and carry over test!


In reply to Nigel and motion...

I tought of doing this (changing the location of my tables) but I have so many messages to display I'm going over 3 memory boundaries. If I would add other tables in the middle of them so that relevant messages are grouped together, I would have to recode a bunch of code to take in to account the changes each time!


Anyway thanks to everyone for the suggestions, I think all I needed was a good 5 hours of sleep :)
 
nclark said:
In reply to Matt...

Not sure how your code works but from what I can see it should not work at all because the "incf HU_LOW,F" does not affect the Carry bit. So your "incf LU_HIGH,F" right after your carry test would never be executed.

You should check for the Z flag in stead of carry. when the file overflows it will go back to zero, in wich case Z is set
 
:wink:

Yes you are right exo,nclark, I relised last night, when I checked my code, I should have checked it first instead of guessing!!! :wink:

Check the Z flag, the staus is not affected.... opps! but you get the idea I hope! :oops:

Anyway I hope this helps..... whoever it was meant to help!! :lol:
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top