PDA

View Full Version : Making Program Code Space your playground...



Melanie
- 17th November 2003, 15:58
Whilst this has also been posted to the piclist here it is for reference - and also that several hours after posting it's still somewhere 'lost in space'.

>
> Can you provide a quick example of writing data to
> code space and reading it back?
>

This is relatively simple... and there's many ways of doing this... so I'll keep it short with just one method...

The PBP command to read data from codespace is READCODE address,data.

For example 16F pics that support READCODE like the 16F876, and the 16F877 (amongst others) allow you to save and extract 14-bits of data per memory location. For those that haven't got enough fingers and toes to do the math, that gives you a range of 0-16383. Let's call this PCWord (for Program Code Word rather than a real word which is 16 bits). Naturally you define 'data' as a word if you want to grab all 14-bits, and if you define it as a byte you just get the lower 8 bits. The 'address' is also a WORD (a real 16-bit variety) and is any spot in valid codespace.

WRITING to codespace should be restricted, it's not as resilient as EEPROM and theoretically wears out quicker, but for use as sporadic storage or for giant Lookup tables, it saves on an external EEPROM if you're tight for cash or PCB Real-Estate. READING from codespace is unlimited, doesn't wear out your PIC, doesn't use any calories and can be used without restriction - so go do it.

WRITECODE is the opposite to READCODE and allows you to write to those memory locations. But it's kinda wasteful having to use WRITECode to create a 1000 word table before having to use it. Whilst WRITECODE and READCODE are the equivalents of READ and WRITE on a bigger scale, what's missing is the equivalent of the DATA statement which allows you to preset those memory locations.

For this we have to jump into some lines of Assembler which I'll teach you here...

Let's say we wish to create a 1000 word table in Program space. First choose a memory location well away from your code. So an PIC16F876/877 has 8K (8192) words of Program Codespace. If we put our data table out of the way starting at address 7190, it means we can create a program that uses up to 7190 words. Any bigger and it risks overwriting our data table.

Our Data table is created thus (note caps for CODE and DB)... and shove it at the end of your code... PLEASE NOTE that I am using PBP's Assembler mnemonics here, there are some variances for MPASM but the theory is the same.


Asm
CODE 7190
DB 254
DB 1
DB "Hey, Beautiful"
DB 254
DB 192
DB "What's Cookin?"
DB 0
Endasm

(Note: Here on this forum, the display above will corrupted and left-justified. The CODE and DB statements must be indented and must NOT start at column 1 in your code. The left-hand edge is reserved in Assembler for Labels ONLY.)

This is the equivalent of sequentially storing...


$FE,$01,"Hey, Beautiful",$FE,$C0,"What's Cookin?",0

Let's now read that data in and display it on our LCD... here's a couple of ways rolled into one demo program...


PCAddress var WORD
PCData var BYTE

DoitAgain:
PCAddress=7190
'
' Read & Display till we get a stop character
'
ReadCodeLoop:
READCODE PCAddress,PCData
If PCData>0 then
LCDOut PCData
PCAddress=PCAddress+1
Goto ReadCodeLoop
endif
Pause 2000
'
' Read a set number of locations
' (two in this case - to Clear the LCD)
'
For PCAddress=7190 to 7191
READCODE PCAddress,PCData
LCDOut PCData
Next PCAddress
Pause 1000
Goto DoitAgain
End

(Download the accompanying pcode.txt file for a pretty example).

There are a number of things you have to remember. So here's the rules of the game - don't disregard them or they'll come back and bite you...

1. Don't spill your data out of available memory... you'll get stacks of compiler error messages anyway. Remember, be nice, leave some space for your program. Every PCWord you steal from Program Memory is one word less you've got available in programming.

2. Remember how many data elements you've preset. If you've preset 1000 PCWords, don't access 1001 because it probably won't contain things relevant to your data table.

3. When using WRITECODE, if you access the WRONG memory locations, you run the risk of corrupting your program code. Stick rigidly to the addresses for your data. Remember the golden rule of programming... "if you put it into memory, remember where you put it".

The downside... OK there's no free lunch (unless you're buying it for me). No gain without pain, and this little niggle is significant...

4. Whilst you can WRITECODE with 14 bits, and READCODE with 14 bits, you can't preset 14-bits with the assembler DB statement. You can ONLY preset 8 bits, and the upper 6 bits (remember 14-bits for our PCWord) will always be preset to %110100. Hey, I didn't write the assemblers - so don't lay this one on me. Consider the DB statement as standing for 'Data Byte'. BYTE being the appropriate thing to notice. So each 8-bit BYTE you store, gets saved as a 14-bit PCWord... example...

You want to save a value of ONE...

DB 1

That memory location will actually contain in 14-bits...

11010000000001

You can however within your PBP Program do this...


MyWord var Word
MyWord=1
WRITECODE address,MyWord

and that address will have in 14-bits...

00000000000001

(when reading or writing with WRITECODE and READCODE into/from a 16-bit word, the upper two bits should always be considered zero)...

You might think that instead of using the DB statement, I'll go and use DW (Data Word rather than Data Byte)... but look what happens...


CODE 7190
DW 1

You would think you would get 00000000000001 stored into location 7190... but hey, they've thought of that and you actually get the lower 8-bits stored into location 7190, and the upper eight bits (yes of a whole 16-bit word) gets stored in location 7191. The upper six bits of both memory locations stubbornly still get preset to %110100. Like I said, don't lay this on me.

Finally... if there is such a thing as 'finally'...

5. Playing with the CODE directive (as in example CODE 7190), kinda screws the compiler reporting the true value of the words used in your program. If you need to know the actual size of your compiled program (useful to determine how much Program Code space it's used), just remove the Asm...Endasm section and compile. Drop it back in for your final program. Some folks will argue that the Asm...Endasm section should be lower down in your code and just jump over it. Sure you could do that. Personally I like to keep the data blocks that I'm tampering with well away from my Program Code.

The appended file is a ready-to-run demonstrator. Go create and have fun.

So I lied about keeping it short...

Melanie

lester
- 18th November 2003, 09:09
To all, from Greg Yent, San Diego, CA




Another way to write/read to code space that I've used for Font
tables is to use an @ ORG XXXXh then Pokecode (v2.42) to write, and
Peekcode or Readcode to read. Pokecode/Peekcode works great with table
because you don't need the address for each byte. But Pokecode can only
be used at program time. You can edit individual bytes during operation
with Writecode. Loading an Image file into the graphic LCD, as an
example:



To Write:

DISABLE
'Introduction Image File
@ org 12C0h
Pokecode $00,$00,$00,$80,$C0,$E0,$E0,$F0, etc for 80 bytes
Pokecode $07,$3F,$7F,$FF,$F0,$E0,$C0,$C0, etc for 80 bytes
Pokecode $80,$F8,$FE,$FF,$1F,$07,$03,$01, etc for 80 bytes
Pokecode $00,$00,$00,$00,$01,$01,$01,$03, etc for 80 bytes
Etc......

To Read:
StrAddr = $12C0
for j = 0 to 3
CharAddr = StrAddr + (80*j) '80 for the example given
for k = 0 to 79
PeekCode CharAddr+k, x
Shiftout SDA, SCL, 1, [ x ]

next k
next j



Greg Yent
San Diego, CA

Don Mario
- 10th January 2005, 17:48
Hi Melanie

Is this your code space solution ?
I can't understand the final part !
Please explain me !


Thank you very much

Don Mario

Homerclese
- 7th October 2005, 21:43
Hello,

This project uses ports A-B and C to drive a display containing 21 LED's.
To generate the patterns I started with arrays but quickly ran out of space. The following is a partial sample of an array pattern setup. Using binary helps to visualize what the pattern will look like.

ARRAYDATA5:

ARRAY5C[0]=%00000111:ARRAY5B[0]= %00000111:ARRAY5A[0]=%000001
ARRAY5C[1]=%00001110:ARRAY5B[1]= %00001110:ARRAY5A[1]=%000011
ARRAY5C[2]=%00011100:ARRAY5B[2]= %00011100:ARRAY5A[2]=%000111
ARRAY5C[3]=%00111000:ARRAY5B[3]= %00111000:ARRAY5A[3]=%001110
.
.
.
.
RETURN

I looked at the code space playground thread and got some good results, but not perfect. I disabled the LCD code and instead have the data output to portb with led monitors. I put in a 2 second delay between each read.
Decimal DB values give the expected display results however using binary values produces some extra bits within the expected pattern. I tried 14 bits and 8 bits and using the % symbol which the compiler dosen't like.


test pattern does not work properly
Asm
CODE 7190
DB 00000000000001
DB 00000000000010
DB 00000000000100
DB 00000000001000
DB 00000000010000
DB 00000000100000
DB 0
endasm

........................................

this code works
Asm
CODE 7190
DB 1
DB 2
DB 4
DB 8
DB 16
DB 0
endasm

Is there something wrong with entering binary values this way? I must be able to develop patterns in binary. It is just too hard to visualize decimal values.
Maybe I could use the arrays just to develop the patterns then have some utility program convert binary to decimal and generate "DB (decimal}" code somehow. This would make things easier. Any ideas?


Thanks

"Weaseling out of things is important to learn. It's what separates us from the animals... Except the weasel."

mister_e
- 8th October 2005, 11:00
if i can suggest one thing, use the internal EEPROM of your PIC if he have one. Really easy to do with DATA to load your value, later use READ to read your aray from the internal EEPROM.

Can you start another thread and post your whole code? That way we will be able to point you some idea.

Homerclese
- 8th October 2005, 20:08
Hi,

Yes I was using EEPROM for array storage but the 16f877 has only 256 bytes available. I will need about 4k just for pattern storage. That is why I'm looking at using the code program space. The problem seems to be my use of binary data input. Here's the code i'm using for testing.


' PCode.bas
' Quick Demo Program
' showing how you can play with
' Program Code Space

Define debug_pacing 1000 'serial setup
Define debug_reg porta
Define debug_bit 0
Define debug_baud 2400
Define debug_mode 1
TRISB= %00000000
TRISa= %00000 '
'

' RAM Assignments & Variables
' ---------------------------
PCAddress var WORD ' Used to determine ADDRESS of Data
' within Program Code space
PCData var BYTE ' Data Variable - in this example a BYTE
' but could be a WORD as each memory
' address is capable of storing 14-bits
PCWord var WORD
'
' Start Program
' =============
Pause 2000
DoitAgain:
PCAddress=7190 ' Pointer to start of Data area
'
' Read & Display till we get a stop character
' -------------------------------------------
ReadCodeLoop:
READCODE PCAddress,PCData ' Sequentially read bytes
If PCData>0 then ' Until a Stop character is found

debug "ADD=", dec pcaddress 'lcd display
debug 254,192
debug "DAT=", dec pcdata

PCAddress=PCAddress+1 ' Remembering to increment our address
portB=pcdata 'output data to portB LEDs

Pause 300
Goto ReadCodeLoop
endif
Pause 50

Goto DoitAgain

End


Asm
CODE 7190



DB 00000001
DB 00000010
DB 00000100
DB 00001000
DB 00010000
DB 00100000
DB 01000000
DB 10000000
DB 0

Endasm




........................
RESULTS

debug LCD readout values
00000001 = 1 OK
00000010 = 10 NG
00000100 = 100 NG
00001000 = 232 NG
00010000 = 16 OK
00100000 = 160 NG
01000000 = 64 OK
10000000 = 128 OK

El_AMPo
- 17th January 2006, 07:44
The first method shown work only on 16F87X flash memory PICs as far as i know.

The second method posted that used PEEKCODE and POKECODE works great in smaller pics.

...for the ones that didn'd get it in the first example

--[To Write]--
Just include after the END tag of the program:

POKECODE @[start address],[byte0],[byte1],[byte2]....(up to 79)

(note: start address must be bigger than your program size, and the command only works when programming the pic)

--[To Read]--

(use something like...)

OUT var byte
y var word

For y = [start address] to [start address + nºbytes]
PEEKCODE y, OUT
Next y


hope it helps...

flotulopex
- 6th July 2008, 13:32
How do I determine the free memory space?

PBP manual: The listing file may be examined to determine program addresses.

I've appended a test list file (original .LST file, renamed .TXT for uploading) generated by MCS.

How must I read & understand this file?

PIC16F690's Memory Map looks like this:
<img src="http://www.picbasic.co.uk/forum/attachment.php?attachmentid=2728&stc=1&d=1215343850">

Acetronics2
- 6th July 2008, 13:54
Hi, Roger

MPLAB, Program window ... does it sound something to You ???

... Lol

With MCS, have a look to the SMALL characters at the bottom left part of your screen ...

...

Alain

flotulopex
- 6th July 2008, 14:14
Bonjour Alain,

Sorry, I'm still an amateur and I don't use MPLAB... ;)

Are you meaning I just have to add the amount of words in MCS to the memory starting adress?

It can't be that simple?!

Acetronics2
- 6th July 2008, 16:57
Hi, Roger

Not so simple ...

say it is a 16F628 with 2k memory ( 2048 words )

2048 minus the "little number" is the first memory adress you can use for placing tables ... ( remember the default DEC radix for PbP !!! )

to be sure ... you can let some "blank lines" ... before the Table. Or begin your table on a "round" adress ... 2FF, or 1200 i.e. ( Remember A good programmer NEVER adds mods to his programs !!! ... LoL ...)


Alain

Acetronics2
- 6th July 2008, 17:43
Bonsoir Roger,

Have a look to those nice Subroutines ...

as you see they are placed at the end of the Basic File ...




END ' This is the Program END


'************************************************* ****************************
'************************************************* ****************************
'Tables de linéarisation
'************************************************* ****************************
'************************************************* ****************************


'************************************************* ****************************
Linearisation2:'Linearisation complète Courbe A(15A)> Linéaire B(1B)
'************************************************* ****************************

LOOKUP Lecture, [ 0, 0, 0, 0, 0, 0, 4, 16, 16, 16, 18, 21, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29, 30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34, 35, 35, 35, 36, 36, 37, 37, 37, 38, 38,_
38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 45, 45, 45, 46, 46, 46, 47, 47, 47, 48, 48, 48, 49, 49, 49, 50, 50, 50, 51, 51, 52, 52, 52, 53, 53, 53, 54, 54, 54, 55, 55, 55,_
56, 56, 56, 57, 57, 57, 58, 58, 59, 59, 59, 60, 60, 60, 61, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 65, 65, 65, 66, 66, 67, 67, 67, 68, 68, 68, 69, 69, 69, 70, 70, 70, 71, 71, 71, 72, 72, 72, 73,_
73, 74, 74, 74, 75, 75, 75, 76, 76, 76, 77, 77, 78, 78, 79, 80, 80, 81, 82, 83, 83, 84, 85, 85, 86, 87, 87, 88, 89, 89, 90, 91, 92, 92, 93, 94, 94, 95, 96, 96, 97, 98, 99, 99,100,101,101,102,104,106,_
108,110,112,114,116,118,120,122,124,126, 128,130,132,134,136,138,140,142,144,146, 148,150,152,155,157,159,161,163,165,167, 169,171,173,175,177,179,181,183,185,187, 189,191,193,195,197,199,201,205,208,214,_
220,230,240,250,255,255], Result

RETURN

END

'************************************************* ****************************
Linearisation1:'Linéarisation exp simple à 26 points
'************************************************* ****************************

LOOKUP Lecture, [ 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12, 12], Result

RETURN

END

'************************************************* ****************************
'************************************************* ***



PbP will AUTOMATICALLY place them in the free memory space ... with some blanks lines before !!!

just use a "Gosub Linearisation2 " in your program and PbP will do all the Work !!!

Yes ..., you can cry ...

Alain

flotulopex
- 6th July 2008, 18:28
As often, I don't see simple things at the first glance.

I should have thought about the PicKit2 prog and its Program Memory viewer...
<img src="http://www.picbasic.co.uk/forum/attachment.php?attachmentid=2729&stc=1&d=1215361371">
Thank you, Microchip.

skimask
- 7th July 2008, 06:15
As often, I don't see simple things at the first glance.
I should have thought about the PicKit2 prog and its Program Memory viewer...

Something else to keep in the back of your head...
If/When you switch over to 18F series PICs and start using MPASM, if you set MCS up to generate a .LST file, in the last few lines of the .LST file, it'll tell you exactly how many bytes/words of program space you've used.

flotulopex
- 19th July 2008, 09:08
...
You can however within your PBP Program do this...
MyWord var Word
MyWord=1
WRITECODE address,MyWord
and that address will have in 14-bits...
00000000000001This is working fine with WRITECODE.

Is it really impossible using POKECODE? Isn't there any workaround?

skimask
- 19th July 2008, 09:26
As far as I can tell, according to the manual...
POKECODE puts 'data' into program memory in the middle of your program, during 'program time', when your programmer is actually programming the chip.
WRITECODE allows you to change the 'data' in the program memory space while your program is executing (after the PIC has been programmed, etc).

Disregard...I see what you're saying...Statement above almost completely irrelevant! :)