please dont rip this site

PIC Microcontroller Memory Methods: Tables

Conditionally replaceing one value with another

Big Table Lookups (example for sound playback)

Compressing large tables with linear interpolation by Peter Hemsley " +

SIMM interface

Ken Websters PIC16C74 serial port multiplexer. This includes a complete SRAM interface and memory test code.

Table lookups

This article discusses reading constant values from program memory (Flash).

See "File Select Register" fsr.htm and "Moving data blocks" memmove.htm for reading and writing values to RAM.

See "Electrically Eraseable Programmable Read Only Memory" for reading and writing values to EEPROM.

On SX chips, you can access program memory via the "IREAD" instruction. See SX tables /techref/scenix/lib/mem/tables_sx.htm .

Douglas Wood [dbwood at] says:

On the 17Cxxx and 18Cxxx PICs, you can access program memory via the 'table read' instructions. (The "TBLRD" and "TBLWT" instructions in the PIC Microcontroller Instruction Set Comparison Matrix )

On most 16Fxxx PICs, you can access all 14 bits of any word of program memory via a set of SFR (special function registers). For example, the PIC16F18877 datasheet shows the required sequence to write the Flash program memory using the registers: NVMCON1, NVMCON2, NVMDATL, NVMDATH, NVMADRL, NVMADRH. For example, the PIC 16F877A datasheet shows a slightly different required sequence to read and write the Flash program memory using the same registers with slightly different names: EECON1, EECON2, EEDATA, EEDATH, EEADR, EEADRH. The NVMCON1 register (aka EECON1 register) has a bit that must be cleared to access program flash or set to access data EEPROM. )

On all other PICs, you'll have to use a 'computed GOTO/RETW-style' table.

Drew Vassallo says:

More specifically, typically you access data tables through a call and modification of a program counter. For Microchip's MPLAB or MPASM, the instruction for "data" that is used is "dt" followed by your data, which will automatically be assembled into a data table, one line for each byte of data.
;;Call with byte to retrieve in W (in this case, W in range of 0-3)
      addwf PCL
dt 0x01, 0x02, 0x03, 0x04

The dts are actually assembled as RETW #'s one after another. But watch out for one little "gottcha": Any instruction, other than a jump, that modifies the PCL register, also clears the 9th bit (bit 8). So addwf PCL only works if the target is in the first half of any 512 address page. See paging

Mike Keitz says:

...There are two situations where "paging" of the program memory is an issue. For CALL or GOTO, the pages are 800h instructions long [on the more advanced PIC processors]. Most short programs don't need to be concerned with them. [HOWEVER] For writing to PCL, the pages are only 100h instructions long. So [any] 256-value table definitely crosses one of those pages. And the program will crash when the index into the table gets large enough if your table-access code doesn't set up PCLATH properly.

[Here is some code that sets up PCLATH correctly]

   movlw  high   (TABLE_START)
   movwf  pclath
   movf   index,w
   addlw  TABLE_START
    incf  pclath,f
   movwf  pcl
   retlw  ...

If the table is called such that W is the index:

   addlw  TABLE_START
   movwf  temp
   rlf    known_zero,w
   addlw  high(TABLE_START)
   movwf  pclath
   movf   temp,w
   movwf  pcl
   retlw ...

Andrew Warren of Fast Forward Engineering - San Diego, California says:

...write table-lookup code [with] automatic page-crossing checks built in.

I generally do it like this:

        ADDWF   PCL


        DT      "Test"

        IF ((HIGH ($)) != (HIGH (TABLE1)))

P.S. By the way, another common way that a newly-inserted CALL can screw up previously-working code is if the called routine changes the PCLATH register... Or if your previosuly-working code expected the W register or STATUS flags to remain unchanged across the portion of the program where you inserted your CALL.

Rich Leggitt says:

...something like this should work for arbitrary table of any length located anywhere in the program space.
                movlw high string       ; point to a string
                movwf look_hi           ; in reality, a macro...
                movlw low string
                movwf look_lo
                call process            ; go process it

; subroutine to process string at look_hi/look_lo
process         call lookup             ; get a byte (this is the magic)

                ; here, do something with byte in W
                ; also, return if end of string
                ; otherwise...

                goto process            ; do it again

; Jump to address in look_hi/look_lo, which presumably is an RETLW.
; Note pointer post increment.
; Equivalent to: W=*look_ptr++
lookup          movf look_hi,w          ; set PCLATH
                movwf PCLATH
                movf look_lo,w          ; and get PCL
                incf look_lo,f          ; but post inc
                incf look_hi,f
                movwf PCL               ; ok, now jump

Germain Morbe [GMorbe at CDSGMBH.COM] says:

...while still working on my cipher routine i need to inline read a short table without using ram. Here is what i found. Could be of interrest to some. Any shorter forms known?
Enter with pointer in w
Exit with Value1 to Value4 in w
addwf    pcl,f
xorlw    ( 0 xor VALUE1 xor VALUE2 xor 1 )
xorlw    ( 1 xor VALUE2 xor VALUE3 xor 2 )
xorlw    ( 2 xor VALUE3 xor VALUE4 xor 3 )
xorlw    ( 3 xor VALUE4 )

Rubenflc@yahoo asks:

Hello, I,m Rubén. I,m doing a project which I have to use a PIC16F873 and I,ve got a problem, I would like you tell me the bits of the PCLATH and PCL register. I,m doing the main program in page0 and where there is a table, but have to take a second table from page1 to compare and either of them has 128 positions.


Dear Rubén, your email bounced.

Dear Ruben,

I think you will enjoy reading Table lookups . Once you figure it out, it's pretty simple. Please tell me what you find confusing. Can you write a simpler explanation ?

Have you seen page ?

Have you seen the example program on page ?

I use the fcall macro. Then I don't have to ever deal with PCLATH. Perhaps something like this:

    ; (warning: untested code)

;(macros go here)

; the fcall macro
; by Roger Froud of Amytech Ltd.
fcall	macro subroutine_name
	local here
	lcall subroutine_name ; set PCLATH correctly
	pagesel here ; set PCLATH correctly

    ;(initialization code goes here)


    movlw 3
    fcall string_table
    movwf temp1
    movlw 4
    fcall offset_table
    movwf temp2
    goto main_loop

;(subroutines go here)
; doesn't matter if this is in page 0 or 1, as long as it's entirely within a 0x100 boundary
string_table: ADDWF pcl
             RETLW 'D'
             RETLW 'E'
             RETLW 'F'
             RETLW 'G'
        IF ((HIGH ($)) != (HIGH (string_table+1)))
            ERROR "string_table CROSSES PAGE BOUNDARY!"

; doesn't matter if this is in page 0 or 1, as long as it's entirely within a 0x100 boundary
offset_table: ADDWF pcl
             RETLW -3
             RETLW -3
             RETLW -2
             RETLW -1
             RETLW -0
             RETLW -0
             RETLW 1
        IF ((HIGH ($)) != (HIGH (offset_table+1)))
            ERROR "offset_table CROSSES PAGE BOUNDARY!"


Does that help ?

Some people prefer the RETLW data method because it works in all Microchip PIC processors.

Alternatively, you could use EEDATA and related registers instead of the RETLW instruction to read a table of data in FLASH.

Some people prefer the EEDATA method because it allows them to pack more information into each FLASH location (14 bits rather than 8 bits), although it only works with the PIC16F87X processors

The data sheet for the PIC16F87XA from describes this alternative method in section "3.5 Reading FLASH Program Memory"

	banksel MS_PROG_EE_ADDR
	MOVWF EEADRH ; MS Byte of Program Address to read
	MOVWF EEADR ; LS Byte of Program Address to read
	banksel EECON1
	BSF EECON1, EEPGD ; Point to PROGRAM memory
	NOP ; Any instructions here are ignored as program ...
	NOP ; ... memory is read in second cycle after BSF EECON1,RD
	banksel EEDATA
	MOVF EEDATA, W ; W = LS Byte of Program EEDATA
	MOVF EEDATH, W ; W = MS Byte of Program EEDATA

More information than you need about the interaction between PCLATH and PC is at which lists the fcall macro. -- David Cary

See Also:

David A Cary of Motorguide Pinpoint Says:

Bob Ammerman of Ram Systems says:
Here is a trick I use to avoid problems with PCLATH/PCLATU and interrupts on 18C chips:


rcall    lookup_func

instead of:

;align to page start if needed
addwf    PCL,F,A
retlw      1
retlw      2

I have used:

;align to page start if needed
rcall    lookup_index
retlw    1
retlw    2

addwf    TOSL,F,A

; For large tables you can:

addwf    TOSL,F,A
btfsc      STATUS,C
incf        TOSH,F,A

In the program where I use this, I consider PCLATH/PCLATU to be resources usable _only_ in my interrupt handler. I use the above trick for code at task level. This seems to work quite well. It saves me the requirement of saving PCLATH in my interrupt handler (which is _very_ pressed for time).

I have _not_ seen the pattern of MOVFF somehow being interrupted in the middle. Are you saying that the instruction is basically skipped when this happens (ie: it doesn't execute before entering the interrupt and it doesn't execute on return from the interrupt). I'd love more particulars here if possible.

Also, in regard to the LFSR instruction. As far as I know, all silicon currently available is broken. Just say _no_ to the instruction. It is a shame, because this would be a _very_ useful instruction.









I have PIC18F4550

I worked with computed goto for driving 7-seg LEDs and it's OK.

When I read the MPASM about data directives, most of them are for PIC12/PIC16.

So, what're the directives for PIC18?

If I want to change computed goto method, how to develop sets of bytes, because now I want to drive dot matrix display. And each character is a set of 8-bytes.

For example, char 'A' is 0x3C,0x7E,0x66,0xC3,0xFF,0xC3,0xC3,0xC3

With the char generator.

1. Now, if I want to call multiple chars, then how to call multiple tables?
2. How to move from char to another one?
3. Which directive to apply?

Thank you,
file: /Techref/microchip/tables.htm, 20KB, , updated: 2023/8/26 21:38, local time: 2024/7/15 04:19, owner: DAV-MP-E62a,

 ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE!

<A HREF=""> PIC microcontroller, table lookups</A>

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type a nice message (short messages are blocked as spam) in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.

Link? Put it here: 
if you want a response, please enter your email address: 
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
Did you find what you needed?


Welcome to!


Welcome to!