Read from data table (PIC) - Page 1
Forum section: electronics / general

author: katzohki
author_rank: Frequent Contributor
timestamp: June 02, 2014, 05:08:04 pm
content: Hi all,My project is using a PIC10F322. I have a data table set up using the dt directive and I love the way that works, but I'm having difficulty reading from the table. I can read the data fine, but I can only get up to 10 characters from it (it's an ASCII string) before it stops working. I'm about 95% sure that it's the method I'm using:Code:maincall message ;I want to read letter at a message countermovwf lettercall sendcall message+1movwf lettercall sendcall message+2movwf lettercall send......call message+9movwf lettercall sendgoto mainI tried all the way up to "message+13" but either way it skipped any characters in the string after the 10th. I tried a few things to get this to work, "message+mc" and "incf mc" wouldn't compile... Probably "call" is not the way to go. Anyone have some advice or better method?Trying to refresh my knowledge on MCUs.Thanks--KatzEDIT: Whoops, should have mentioned that "message" is the name of my data table.

author: Mr Smiley
author_rank: Frequent Contributor
timestamp: June 02, 2014, 07:10:04 pm
content: Does your table pass over a page boundary ?I had lots of problems with very large tables on the 16F and 12F chips and mplab-x a while ago, it, for some unknown reason automatically updated pclath when it should not have done so and all worked perfectly in simulation but not on the hardware. I only found out by stepping through the code and watching the pclath register. When i started calculating my own pclath values it worked on the hardware.Machine code, you have to work out your own pclath values, in C i believe its all done for you behind the scenes.

author: westfw
author_rank: Super Contributor
timestamp: June 02, 2014, 07:19:18 pm
content: "The default radix for MPASM is Hex."So (if you haven't changed anything) after "message+9", you need to use something like "message+0A"Or include a "radix dec" at the top of your program...(that's a horrible way to read a table, BTW! "For more information refer to Application Note AN556, ?“Implementing a Table Read?” (DS00556).")

author: katzohki
author_rank: Frequent Contributor
timestamp: June 02, 2014, 07:26:57 pm
content: Quote from: Mr Smiley on June 02, 2014, 07:10:04 pmNope, the table is not that large.Quote from: westfw on June 02, 2014, 07:19:18 pmAhah! OK, I didn't realize that about the radix being hex. But yeah I sort of figured it's a horrible way. I'll read the app note. Here's my latest attempt:Code:movf message,wmovwf mcmainmovf mc,wmovwf PCL ;had addwf PCL,f heremovwf lettercall sendincf mcgoto main

author: Mr Smiley
author_rank: Frequent Contributor
timestamp: June 02, 2014, 07:35:54 pm
content: Quote from: katzohki on June 02, 2014, 07:26:57 pm

author: Mark Hennessy
author_rank: Frequent Contributor
timestamp: June 02, 2014, 07:47:59 pm
content: Quote from: katzohki on June 02, 2014, 07:26:57 pmDon't forget that incf requires a destination - it defaults to F when omitted, so often the code appears to work, but do get in the habit of including it always, then you won't forget about it when you need it to be W. The assembler will issue a warning about the missing dest, BTW...As you probably know, when using dt to make a lookup table, that gets turned into a series of retlw instructions. So you need to get to your table with call, not just by manipulating PCL in your main code. The first line of the lookup table subroutine is usually where you manipulate PCL, and it's normal to pass the required offset in W - that app-note should explain all.My template program includes "R=DEC" on the first line, along with the processor definition and that sort of stuff. Far better to actively define these things than make assumptionsGood luck,Mark

author: katzohki
author_rank: Frequent Contributor
timestamp: June 02, 2014, 08:02:33 pm
content: Quote from: Mark Hennessy on June 02, 2014, 07:47:59 pmYou have a point, I will try to remember to specify destinations.My latest version was indeed not using a call to get to the table. Perhaps where I need help then is in how and where to properly build my table subroutine? I tried this, but it did not work (this is before "MAIN CODE"):Code:STORAGE CODETableaddwf PCL,fmessage dt "DATADATA \n"I will try to re-implement a table subroutine correctly. Thanks for all the help! I'm edging closer to solution, which is to understand, not just to do.

author: 22swg
author_rank: Frequent Contributor
timestamp: June 02, 2014, 08:03:49 pm
content: I always put tables at the start of code memory like below. then at the end of the table(s) put an ORG xxxx . gets a bit sticky for large amount of data...ORG 0GOTO BOOTSTARTORG 4GOTO ISR;;-------- RETURNS ASCII MESSAGE ------------------------;DMTAB BRW ; BRANCH RELATIVE PC+W; MESSAGE 0 BOOTDT 0X0D,0X0D,"** qPIC-875x *BOOT* v1.03 **",0x0DDT "** PROGRAMMER

author: katzohki
author_rank: Frequent Contributor
timestamp: June 02, 2014, 08:24:19 pm
content: I decided to go back and scroll through my code to see if I made any mistakes. Here's what I did wrong:The table subroutine was above my main code, therefore started adding to the program counter and causing unexpected behavior. So I added a goto main and now it is reading the data correctly! YAY!Next step will be to check the length of the message and then reset the offset when that length is reached. Thank you everyone for all the help!

author: Mark Hennessy
author_rank: Frequent Contributor
timestamp: June 02, 2014, 11:07:40 pm
content: Good job - sounds like you're getting there.Yes, tables can be anywhere, providing you don't accidentally "flow" into them. The assembly process is "2-pass", so they (like subroutines, etc), don't need to appear before they are used. If you're coming from C or similar, then you might not be accustomed to doing that.Incidentally, I must admit that "BRW" was new to me. At first I wondered if it might be an assembler "shortcut", that gets translated into a 2 or more assembly instructions (like BANKSEL, PAGESEL, etc). But it seems that there are 14 new "native" instructions:ww1.microchip.com/downloads/en/DeviceDoc/41375A.pdfI have to say, from a quick read, that I like the thinking behind some of these - maybe it's time to explore some of the newer devices. In the meantime, thanks for (indirectly!) pointing this out to meOh, and when dealing with strings, you could make the first byte equal the string length (though it's a minor pain to make sure this is updated should you change the text. Alternatively, you might choose to terminate the string with a control code (I use 13). Either is valid, depending on your needs.Code:wordsmovwfPCLW_mutedt"Mute",13W_dbdt"dB",13W_volumedt"Volume",13scrollmovwfPCLS_recorddt42,"Press STORE to confirm Record selection..."S_accessdt24,"Press STORE to access..."In these extracts, the regular text routine just keeps writing characters to the display until it meets 13 (decimal). But the scrolling text routine is much easier to code when it is given the length of the string in advance. As I say, either approach is valid...All the best,Mark

author: katzohki
author_rank: Frequent Contributor
timestamp: June 03, 2014, 12:09:11 am
content: Yes, BRW and BRA sound very well suited to what I am doing, but alas I am not using a micro that accepts those instructions.As for handling the "end of string" scenario, I added a clrf command to reset the offset followed by a retlw "\n". In my code "\n" implements a long delay. For my purposes this is working perfectly and will be easy to change should a different behavior be required at end of string.As an aside, putting the data table before the main program makes me a little nervous because that means any time the message changes length, program locations shift around. I know it will be fine, but I can't help feeling uneasy about that so I may place the message data at a defined location instead.Thanks!--Katz

author: 22swg
author_rank: Frequent Contributor
timestamp: June 03, 2014, 09:03:46 am
content: In my example the end of "message" I have been using a null 0x00 , the message sub uses a pre loaded number and counts the nulls then TX's the ascii until the null hence the 0x0D , PIC's without the enhanced instructions I use addwf pcl,f the andlw limits the value in w ... just in case !SSTAB ANDLW 0X1F ; MAX 1FADDWF PCL,F ; LCD SEVEN SEG TABLE;0-9 a-f DIGITRETLW B'00111111' ; 0RETLW B'00000110' ; 1RETLW B'01011011' ; 2RETLW B'01001111' ; 3

author: Mark Hennessy
author_rank: Frequent Contributor
timestamp: June 03, 2014, 09:13:29 am
content: Quote from: katzohki on June 03, 2014, 12:09:11 amOops - the mention of BRW was in the post from "22swg". Sorry - that'll teach me to be posting so late at night! In which case, "thanks" to 22swg for bringing the mid-range enhancements to my attention. No idea how I missed that, but then I tend to stick with the "old school" processors like the 16F877...QuoteYes, I know what you mean. For a small program, it's rarely an issue, but as you cross page boundaries things start to get "interesting". Watch out for 256 byte boundaries too. In my code, I incf PCLATH if the pointer variable overflows - easy enough, but easily forgotten. For what it's worth, I tend to put my tables at the end of the code, and sometimes I'll use ORG to put them at a nice place. On larger processors, I'll often stick them away in another page. But every scenario is different...BTW, at the risk of stating the obvious, a lookup table doesn't have to contain retlw statements - it could be a bunch of goto statements. A nice way to do a "computed goto" that could deal with different scenarios. E.g., as you step through several menu screens, are you calling a bargraph routine, a list of options, or a binary choice?Cheers,Mark

author: bequest333
author_rank: Contributor
timestamp: June 03, 2014, 03:50:12 pm
content: Hi, AllI am New Here.This is My code.org 0040M001:DW 0x0D*0x80+0x0A ;new lineDW 'A'*0x80+'D' ;ADRS+00+01+02+03+04+05+06+07DW 'R'*0x80+'S'DW '+'*0x80+'0'DW '0'*0x80+'+'DW '0'*0x80+'1'DW '+'*0x80+'0'DW '2'*0x80+'+'DW '0'*0x80+'3'DW '+'*0x80+'0'DW '4'*0x80+'+'DW '0'*0x80+'5'DW '+'*0x80+'0'DW '6'*0x80+'+'DW '0'*0x80+'7'DW 0x0d*0x80+0x0A ;new lineDW 0 ;0=data endM002:DW 'T'*0x80+'e'DW 's'*0x80+'t'DW '1'*0x80+0 ;0=data endPUT2:MOVWF PMADRL ;set PMADRCLRF PMADRH ;Data Address<0x0100; INCF PMADRH,F ;if Data Address>=0x0100LOOP:BSF PMCON1,RD ;read flashNOP ;PMDATH <- 00ABCDEFNOP ;PMDATL <- GabcdefgINCF PMADRL,F ;PMADRL = PMADRL + 1RLF PMDATL,F ;Carry=G, PMDATL=abcdefgXRLF PMDATH,W ;Carry=0, W=0ABCDEFGRRF PMDATL,F ;Carry=X, PMDATL=0abcdefgCALL PUTC ;OUTPUT upper 7bitsMOVF PMDATL,W ;W=lower 7bitsSKPNZ ;skip if W<>0RETURNCALL PUTC ;OUTPUT lower 7bitsGOTO LOOP ;loopMOVLW M001CALL PUT2MOVLW M002CALL PUT2

author: westfw
author_rank: Super Contributor
timestamp: June 03, 2014, 07:23:22 pm
content: MPASM has a "DA" directive for packing two 7-bit ascii characters per 14bit instruction word...Code:msg: DA "\r\nADRS+00+01+02+03+04+05+06+07", 0(probably. I didn't check whether it does \r and \n)

author: bequest333
author_rank: Contributor
timestamp: June 04, 2014, 05:31:03 am
content: Hi, westfwThank you so much for letting me know.I appreciate it.

author: dannyf
author_rank: Super Contributor
timestamp: June 04, 2014, 09:20:50 pm
content: Alternatively, you can code in C and don't have to worry about that.

author: westfw
author_rank: Super Contributor
timestamp: June 04, 2014, 11:18:06 pm
content: Would a C compiler produce 7bit flash character strings? (or: what are the commands to make it do so?) (genuinely curious!)I seem to recall all sorts of problems trying to convince C to run on a system that used 7bit bytes for ascii strings (I don't THINK that was just because they were stored 5 per 36bit word...)

author: 22swg
author_rank: Frequent Contributor
timestamp: June 05, 2014, 08:04:56 am
content: And ... you could store strings bytes in the pic eeprom . move them to a data memory bank and output them from there , makes modifying them easy and you can include 8 bit custom / control characters. re PIC enhanced instructions , the 2 FSR registers and the INDF0++ etc improve asm code for data moves . I use C for PIC24's but still come back to asm for pic16's .

author: katzohki
author_rank: Frequent Contributor
timestamp: June 05, 2014, 01:36:16 pm
content: I thought I would share my solution with you guys. Once I got the hang of one data table I was able to implement another 2 for a drastic reduction in my code size:Code:Tableaddwf PCL,f ;add w to the program counter, so 0 goes to first char, 1 goes to 2nd etcmessage dt "MESSAGE GOES HERE" ;stores each character in ASCII format followed by retlw;so returns with current char in wclrf offset ;end of message reset - if you get here you've gone past the end of the messageretlw "\n" ;for me "\n" creates a long pause before moving on to the next charmainmovf offset,w ;put offset in wincf offset,f ;increment offset for next timecall Table ;go get the current char and return with it in wmovwf letter ;put it into letterclrf soffset ;clear thisclrw ; and this (probably don't need this here actually)call sendgoto mainAlphaTableaddwf PCL,f ;This addition here is setting the Z flag to zero!alphabet dt "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.? \n";;;letter not found if you make it this far, so...; need to handle error somehownextLincf soffset,f ;increment the alphabet offsetsend ;coming from main with current char stored in w and soffset set to 0movf soffset,w ;alphabet offsetcall AlphaTable ;return from alphabet with message char stored in "letter", alphabet char in "w", alphabet # in "soffset"subwf letter,w ; subtract the message char, from the alphabet charbtfss STATUS,Z ;if zero (STATUS,Z=1), character was a match, soffset holds offset of correct character to display/print/send so skip next inst.goto nextL ;otherwise check next lettermovf soffset,w ;put the alphabet offset into w and then add it to the program counteraddwf PCL,f ;if 0 sendA, if 1 sendB, if 2 send C...JumpTablegoto sendAgoto sendBgoto sendC.........goto hell ;("\n" long pause)

author: Jeroen3
author_rank: Super Contributor
timestamp: June 05, 2014, 02:27:10 pm
content: Quote from: westfw on June 04, 2014, 11:18:06 pmNo, since the typical minimum alignment width is one byte. There are bitfields, but the standard is rather undefined there.But if you type 'A' you will get 0x41. And if you type "A" you will get 0x41 0x00. So that won't change.If you want special bit width data types you'd have to manually shift them together, preferably not until you send to the special bit width device.Why on earth would someone use a 14 bit wide flash?