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 skpnc 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' .... etcAs 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 here: endm ;(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 skpnz incf OffsetH NoUp movlw Low(d'3000') xorwf OffsetL,W skpnz goto SoundLoop movlw High(d'3000') xorwf OffsetH,W skpnz goto SoundLoop goto Start ; ; SOUND DATA TABLE 3000 ELEMENTS ; Table movlw High(TStart) addwf OffsetH,W movwf PCLATH movlw Low(TStart) addwf OffsetL,W skpnc 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 endPS: 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:
;******************************************************************* ;write_string ; ; 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 ; LCD_WRITE_DATA ; Inputs ; W = String Number ; write_string ; 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 string incfsz buffer2,f decf PCLATH,f goto ws1 ; end of write_string subroutine ws2 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. ws_table: 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
also:
David A Cary of Motorguide Pinpoint Says:
Someone mentioned
SoundLoop: ... incf OffsetL ; add 1 to data pointer btfsc STATUS,C incf OffsetHbut 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 ? ]
Comments:
I think "David A Cary of Motorguide Pinpoint" has right: There has to be a bug in the first code on this page (from Tony Nixon). I used this code to convert a value from my ADC to another value. It works fine, until the code crosses a page... But the code from Dmitry Kiryashov works fine for me, even after page crossings! Thanks!+
See pages.htm for more information about PCLATH.
Interested:
See:
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 11:39, local time: 2024/12/25 09:40,
owner: DAV-MP-E62a,
18.225.55.42:LOG IN
|
©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? <A HREF="http://linistepper.com/Techref/microchip/bigtable.htm"> PIC Microcontoller Memory Method Big Table lookups</A> |
Did you find what you needed? |