please dont rip this site

PIC Microcontoller Memory Method

Big Table lookups

Today I'm going to discuss how to read data from a table that crosses a 256 byte boundary.

The easiest and fastest way to do this is to use special "table read" instructions. See table lookups for details. [FIXME: should I move that information from there to here ?]

But some PIC processors don't have those special "table read" instructions. Are we out of luck ? No. We can extend the 'computed GOTO/RETW-style' table so it can handle tables that cross a 256 byte boundary.

Tony Nixon says:

Table can access 1 to 8178 bytes (assuming max ROM of 8K)

        fcall    Table
; will be returned here with data in W.

        ; Tony Nixon
        ; plus tweak from Dmitry Kiryashov [zews at AHA.RU]
Table   movlw High(TStart)
        addwf OffsetH,W
        movwf PCLATH
        movlw Low(TStart)
        addwf OffsetL,W
          incf PCLATH,F

        movwf   PCL     ;computed goto with right PCLATH
        ; end of Table subroutine.

        ; ...
        org 0x????
TStart  Retlw d'0'
        Retlw d'255'
        Retlw d'9'

As an example of how to use it, say you want to output speech data at 5K samples per second. A simple R2R ladder is on PortB. The speech table has 3000 data points

        ; Tony Nixon
        ; modified by David Cary

;(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

;(execution starts here)

Start   clrf OffsetH
        clrf OffsetL

SoundLoop       ; 200uS loop time = 5000 samples per second
        fcall Table
        movwf PORTB
        ;[FIXME: wait the remaining 200 microseconds]

        incf OffsetL    ; add 1 to data pointer
          incf OffsetH

NoUp    movlw Low(d'3000')
        xorwf OffsetL,W
          goto SoundLoop

        movlw High(d'3000')
        xorwf OffsetH,W
          goto SoundLoop
        goto Start
Table   movlw High(TStart)
        addwf   OffsetH,W
        movwf   PCLATH
        movlw Low(TStart)
        addwf OffsetL,W
          incf PCLATH,F

        movwf   PCL     ;computed goto with right PCLATH
        ; end Table subroutine

TStart  DT "Hello. I'm Mr Ed"
; plus another 2984 data points


PS: the text won't sound like that coming from PORTB ;-)

PPS :if you want an easy way to create a 3000 point data table ready for MPASM see

Scott Dattalo says:

;  The purpose of this routine is to display a string on the LCD module.
;On entry, W contains the string number to be displayed. The current cursor
;location is the destination of the output.
;  This routine can be located anywhere in the code space and may be
;larger than 256 bytes.
; psuedo code:
; char *string0 = "foo";
; char *string1 = "bar";
; char *strings[] = { string0, string1};
; char num_strings = sizeof(strings)/sizeof(char *);
; void write_string(char string_num)
; {
;   char *str;
;   str = strings[string_num % num_strings];
;   for( ; *str; str++)
;     LCD_WRITE_DATA(*str);
; }
; Memory used
;    buffer2, buffer3
; Calls
; Inputs
;    W = String Number
        ; Make sure the input string_num is in range.
        andlw   WS_TABLE_MASK

        ; get pointer into the ws_table array:
        ; [w,buffer3] = wstable + 2*string_num
        movwf   buffer3
        addwf   buffer3,w
        ; [FIXME: the carry from doubling w is lost,
        ; limiting us to a maximum of 128 strings --
        ; add code here to handle up to 256 strings]
        addlw   LOW(ws_table) ; carry set ...
        movwf   buffer3
        movlw   HIGH(ws_table)
        skpnc                 ; ... carry used.
          addlw 1
        ; now [w,buffer3] points to the lo byte of the address of the string.
        movwf   PCLATH
        ; now [PCLATH,buffer3] points to the lo byte of the address of the string.

        ; get lo byte of the address of the string
        movf    buffer3,w
        call    ws2
        ; buffer2 = lo byte of the address of the string
        movwf   buffer2

        ; get hi byte of the address of the string
        ; (handle special case of ws_table starting on odd address AND
        ; ws_table crossing a 256 byte page boundary)
        incf    PCLATH,f
        incfsz  buffer3,w
          decf   PCLATH,f
        call    ws2                     ;get the high word (of the offset)

        ; now we have address of the start of the string in
        ; [w, buffer2]
        movwf   PCLATH                  ;
ws1:                                    ;Now loop through the string
        movf    buffer2,w
        call    ws2

        andlw   0xff
        skpnz                           ;If the returned byte is zero,
          return                        ;we've reached the end of the string
          ; exit point of write_string subroutine

        ; WARNING: we're holding the hi part address of the start of string
        ; in PCLATH right now --
        ; -- so the LCD_WRITE_DATA subroutine,
        ; any subroutines it calls, and the actual string data
        ; must be on the same 2048 byte page.
        ; FIXME: remove this silly limitation.
        call    LCD_WRITE_DATA

        incf    PCLATH,f                ;Point to the next character in the
        incfsz  buffer2,f
         decf   PCLATH,f

        goto    ws1
        ; end of write_string subroutine

        movwf   PCL

; WS_TABLE_MASK must be one less than the number of entries in the ws_table.
#define WS_TABLE_MASK  3
; #define WS_TABLE_MASK  127   ; use this when you have 128 strings

; The first part of the table contains pointers to the start of the
; strings. Each string has a two word pointer for the low
; and high bytes.

; no restrictions on table start location
; the number of entries in the ws_table must be a power of 2 ...
; 2, 4, 8, 16 ... up to 256 strings.
; If you only need, say, 5 strings, put 8 entries in the ws_table.
; It's OK for several entries in the ws_table
; to point to the same string.
        retlw   LOW(string0)
        retlw   HIGH(string0)

        retlw   LOW(string1)
        retlw   HIGH(string1)

        retlw   LOW(hello_string)
        retlw   HIGH(hello_string)

        retlw   LOW(hello_string)
        retlw   HIGH(hello_string)

; no restrictions on string start location
string0:        dt      "GPSIM WROTE THIS",0
hello_string:        dt      "Hello world."
string1:        dt      "A STRING ON ROW 2",0


David A Cary of Motorguide Pinpoint Says:

Someone mentioned

        incf OffsetL    ; add 1 to data pointer
        btfsc STATUS,C
          incf OffsetH

but my little cheat sheet claims that `incf' only affects the Z bit, not the C bit. Is my cheat sheet leaving something out ? Or is there a bug in this code ? Or am I missing something ? SoundLoop: ... incf OffsetL ; add 1 to data pointer btfsc STATUS,Z ; also known as skpnz incf OffsetH

The heavy use of btfsc STATUS,C ; also known as skpnc elsewhere on this page looks OK, because they follow the ``addwf'' or ``addlw'' instructions, which do affect the carry bit. -- David Cary

[FIXME: Is there a page that lists "skpnz" "skpnc" etc. other than compcon.htm ? ]




Guy Griffin Says:

PCLATH is only modified explicitly, i.e. the PIC never changes it. Multiple computed GOTOs must set PCLATH appropriately before each PCL write, otherwise you'll get a jump to an unexpected address.

For example, a moving-message display: a small table lookup uses ADDWF PCL,f to returns the next ASCII code from a series. Then a large page-crossing table returns a column of pixels for display, probably modifying PCLATH in the process. This works OK the first iteration only - as the little table doesn't setup PCLATH, it gets implicitly loaded into PC the next time around... resulting in a jump to some unknown place in the middle of the code, and a large headache to debug.
file: /Techref/microchip/bigtable.htm, 10KB, , updated: 2006/4/27 12:39, local time: 2024/7/23 05:17, 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 Microcontoller Memory Method Big 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?

  PICList 2024 contributors:
o List host: MIT, Site host, Top posters @none found
- Page Editors: James Newton, David Cary, and YOU!
* Roman Black of Black Robotics donates from sales of Linistep stepper controller kits.
* Ashley Roll of Digital Nemesis donates from sales of RCL-1 RS232 to TTL converters.
* Monthly Subscribers: Gregg Rew. on-going support is MOST appreciated!
* Contributors: Richard Seriani, Sr.

Welcome to!