Calling a Table from Different Locations

Status
Not open for further replies.

Hi thanks a lot guys now I understood how the org 0x003 increments followed by the next instructions. And also I referred to the deassembly listing it was very helpful.

A small quick question to ask.

If I’m using PIC16F628A (2K) if I have a Table I can call it from any location of the memory without writing to PCLATH.
But if the Table has more than 255 lines then of course I have to write to the PCLATH & call the table.

Is this correct?
 
No, please reread this and the previous thread.

Mike.
 
Last edited:
If I’m using PIC16F628A (2K) if I have a Table I can call it from any location of the memory without writing to PCLATH.
No, you need to write to PCLATH.
For example, if the location of the table is 0x0123, when you call the table and involve PCL, the first returned value should be located at 0x0124. This is possible by writing 0x01 which is the high side of 0x0124 to PCLATH, otherwise the PCL will go to the location 0x0024.

But if the Table has more than 255 lines then of course I have to write to the PCLATH & call the table.
No, even the table consist of only 2 lines you need to write to PCLATH if the table is located out of the program memory 0x00ff (0x0100 onwards)
 
Excuse me..

i wanted to know .. what is the purpose of Data tables in pic microcontroller...

how can it help in various applicartions..

i got stuck in this chapter...

any help is appriciated..

regards,

simran..
 
simrantogether said:
i wanted to know .. what is the purpose of Data tables in pic microcontroller...

It's the same as a table in any other processor, a list of values which you can index in to - or you can have a jump table, a list of jump addresses you can index in to.
 
Last edited:
thanks..

Nigel Goodwin said:
It's the same as a table in any other processor, a list of values which you can index in to - or you can have a jump table, a list of jump addresses you can index in to.

i think i got it...

i.e. table meant for branching into various locations ...

thanks..

simran..
 
Thank you to all that contributed to this thread (reputation passed around!) -- I ran into the same problem Tuesday, came looking here for the answer yesterday (this thread just happened to be on page 1!) and fixed it last night (and understand it too!) -- all my tables are working well now (I've taken Nigels advise as well and started placing all my tables in the last page of code space, then started my program code at the beginning... and hope they never meet!

Now -- last night I passed my first CODE page boundary (which messed up my ISR because it was at the end of my code space) -- looks like I've got more reading to do today!
 
I thought I'd append my question to this thread as I believe it is relevant -- if it should be a new thread, Nigel, please feel free to split it off.

Since reading this thread, I have been able to work with calling tables from different locations (the title of this thread). Now, I have created a macro to handle setting PCLATH for me and would like some opinions on how this is being done. What I mean is, is what I am doing a valid technique, or am I wasting codespace? Obviously, a macro will only save you time/effort, but not codespace as it simply repeats the same code over everywhere the macro is called. Before I forget, here is the macro;

Code:
; macro to set the high bits of PCLATH for a specific table (or call/goto)
; call - _SET_PCLATH	<table/call/goto>
_SET_PCLATH		macro 	table
				movwf	temp					; save W
				movlw	HIGH table				; set the high bits of PCLATH
				movwf	PCLATH					; for the table to be read
				movfw	temp					; restore W
			endm

At first, I setup the above for my tables, but then figured I could use it for calls/gotos as well (just didn't change the attribute name of 'table').

Here is a snippet of code that I just finished "updating", due to my page boundaries. Why I ask these questions is that you can see I am having to call the macro for every call, goto and table to make sure PCLATH is set properly. Some within the module are already set, while others need to be "corrected" after a return from another module... I have included the macro call in ALL of them just to make sure -- and if anything changes in future code, I shouldn't have to worry about where the modules are -- but it does eat up codespace.

Code:
;----------------------------------------------------------------------------------------------
; Boot Information (Model, Version, etc.)
;----------------------------------------------------------------------------------------------

Boot_Info:
		_SET_PCLATH LCD_Clr				;
		call	LCD_Clr
		clrf	count
Boot_Msg:		
		movf	count, w				; put counter value in W
		_SET_PCLATH Boot_Text			;
		call	Boot_Text				; get a character from the text table
		xorlw	0x00					; is it a zero?
		_SET_PCLATH Boot_Version		;
		btfsc	STATUS, Z
		goto	Boot_Version
		_SET_PCLATH LCD_Char			; make sure the page bits are set
		call	LCD_Char
		incf	count, f
		_SET_PCLATH Boot_Msg				
		goto	Boot_Msg

Boot_Version:
		_SET_PCLATH LCD_Line2			; make sure the page bits are set
		call	LCD_Line2
		clrf	count
Boot_Msg2:
		movf	count, w				; put counter value in W
		_SET_PCLATH Boot_Text2			;
		call	Boot_Text2				; get a character from the text table
		xorlw	0x00					; is it a zero?
		_SET_PCLATH Boot_Finish			;
		btfsc	STATUS, Z
		goto	Boot_Finish
		_SET_PCLATH LCD_Char			; make sure the page bits are set
		call	LCD_Char
		incf	count, f
		_SET_PCLATH Boot_Msg2			;
		goto	Boot_Msg2

Boot_Finish:
		_SET_PCLATH Wait1Second			;
		call	Wait1Second				; Wait for 2 seconds
		call 	Wait1Second
		return

I guess I'm really asking -- is there a better way to do this?

TIA!
 
You can easily arrange for tables to be anywhere, and any length, with just a little more effort than usual - check my LED matrix tutorial which uses large tables for bit patterns.
 
Hi Nigel;

That, I am actually aware of -- but that is not the issue in this case. All of my tables are within their respective 256 byte boundaries -- I use the following checks, to ensure it;

Code:
Boot_Text:					addwf	PCL, f
							dt		"(Boot Text Here)"
Boot_Text_END:				retlw 	0x00

	IF (high (Boot_Text) != high (Boot_Text_END))
		ERROR "Boot_Text table hits page boundary!"
	ENDIF

All of my tables are small (like the above), so I was not really concerned with having to work with them across the 256 byte limit -- I just made sure they didn't cross it. I will probably update my code so that is not a concern at all, but I wanted to make sure I got it working right in the first place.

Anyway, the issue is that I have crossed a CODE page boundary (2K), so I have to make sure the page bits are set, not only for tables, but for calls and gotos as well.

As I said above, I have crossed my first code page boundary and am not familiar with dealing with it. I am learning to but would like feedback on HOW I am doing it (as can be seen in my code snippets above).

I am looking at LCALL and LGOTO in the MPASM psuedo instruction set -- and have also found other information on setting up your own lcall and lgoto macros. If I find the information I am looking for first, I will post it here.
 
OK, here's what I believe is a better solution...

First, I have decided to use the "caller fixes PCLATH" method of page management and use the following macro;

Code:
; far call macro  ** for far (long) gotos, use the MPASM psuedo lgoto k
_fcall			macro 	subroutine_name
				local	__fcall_here
				lcall 	subroutine_name
				pagesel __fcall_here
__fcall_here:
				endm

Basically, it defines a local variable so the current page can be restored upon return of the long call. The MPASM lcall psuedo generates the page selection code for the subroutine you are calling, and the subroutine is called. Upon return, the psuedo pagesel restores the original page bits.

However, I have found that the above code will not work properly when calling a table, so I have come up with the following routine;

Code:
; table call macro
_tcall			macro	 	table
				movwf		temp				; save W
				local		__tcall_here
				pageselw 	table				; select the proper page
				movfw		temp				; restore W
				call		table
				pagesel 	__tcall_here
__tcall_here:
				endm

Same basic principle, but notice the use of pageselw instead of pagesel for the table! This routine also preserves W as it is changed upon using pageselw.

So, all I have done now is gone back and changed "call" to "_tcall" for any table call I make. I am still using the above mentioned checks on the tables to make sure they don't cross the 256 word boundary.

Any "module" that I am working with has the page bits set before entering that module... any call outside of that module (table or otherwise) will use _tcall or _fcall to make sure the page bits are restored upon return -- so the page bits are always set to the active module. When calling to anything within the active module, simply use the standard call instruction -- Just make sure the active module doesn't cross any 2K page boundary! (I am going to also look into the MPASM keyword 'code'.) If you need to "goto" a far module, use the MPASM pseudo lgoto.
 
If you are only using 2 banks then your call macro can be shorted. By using bsf/bcf PCLATH,3 you can get the correct value for PCLATH and not need the temp variable.

I tried to write a fully automatic macro to do this but because mpasm is only 2 pass it failed. The only way I could get it to work was by inserting nops so the code length didn't change.

Here it is, maybe someone can figure out a way to make it work without the nops. It could of course be extended to handle 4 banks.

Mike.

Code:
_call	Macro	Address

	if	Address>0x7ff
		if	$>0x7ff
			call	Address
			nop
			nop
		else
			bsf	PCLATH,3
			call	Address
			bcf	PCLATH,3
		endif
	else
		if	$>0x7ff
			bcf	PCLATH,3
			call	Address
			bsf	PCLATH,3
		else
			call	Address
			nop
			nop
		endif
	endif
	endm
 
Whoops, didn't see your later code.

One other thing, if you are using a later pic with read/writable program space then using the data directive in combination with a read flash routine works a lot better. With this method you can also store 2 ascii characters per location. I used this method in a recent project where I had over 5K of ascii on a 16F88.

Mike.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…