Tell me about it!
And I do agree with what you have said.
You are more right than you can imagine. I have been sincerely beating my head against this for a year and a half. Essentially more than full time. It is really very complicated and to do it right, this Propeller 102 effort (101 was my SPIN book) needs to be followed by Propeller 103 on slightly more advanced stuff like you are suggesting. Propeller 104 for advanced projects and 495 for what the experts need to know. I do not know that I am the guy for that.
I'll see what I can add but I am not hopeful to do it justice.
Given that, I highly recommend you perform an analysis of the COGS you cite in your text, decide how to start them consistently and at the least explain that.
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
vars=20
OBJ
fds : "FullDuplexSerial" 'for communications with PST
VAR
long stack2[25] 'space for pulser cog
long clk_Div,value[vars]
byte sub_scr
PUB Main|x 'x is a local variable here
fds.start(31,30,0,115200) 'start console at 115200 for debug output
Cognew(@Read_Sig, @value)
'dira[0..1]~~ 'set lines to outputs
fds.tx(16) 'home to 0,0
repeat
fds.tx(1)
fds.str(string("HUB memory display")) 'print to display
fds.tx($d) 'new line
fds.tx($d)
repeat sub_scr from 0 to 11
if sub_scr<10
fds.str(string(" "))
fds.dec(sub_scr)
fds.str(string(" "))
fds.dec(||value[sub_scr])
fds.str(string(" ")) 'print spaces to erase old data overflow
fds.tx($d) 'new line
waitcnt(clkfreq/60+cnt) 'flicker free wait
x:=x+1 'increment counter. This routine clears up screen
if x>100 'decision point by erasing extraneous lines of bottom
fds.tx(16) 'clear screen of PST display every 100 loops
x:=0 'reset counter
DAT Org 0 '
Read_Sig mov nmbr, #0 'initialize nmbr
mov mem, par 'read par into mem
mov mem1, mem 'make mem1= to mem
add mem1, #4 'add 4 to mem1 for next loc
'
do_again mov temp, cnt 'read counter to temp
wrlong temp, mem 'store in first location
add nmbr, #1 'increment number
add mem, #4 'add 4 to mem
'
mov varbl, nmbr ' remember nmbr
sub varbl, #5 wz ' has it reached 5
if_nz jmp #do_again ' if not do again
' reaches 5 at this point
rdlong temp, mem ' read temp from 1st location
wrlong temp, mem1 ' write it to second location
park jmp #park 'go into loop
mem res 1
mem1 res 1
temp res 1
Nmbr res 1
varbl res 1
You can run it, it needs no connections to anything. See results on PST.
The program creates two Hub location addresses relative to PAR, mem and mem1
It then reads the system counter 5 times and stores the results in Hub memory. first 5 locations.
It then read location mem and writes it to location mem1
However It stores a 0 in that location.
Creating mem1 seems to wipe out the contents at mem
What is wrong.
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
vars=8
OBJ
fds : "FullDuplexSerial" 'for communications with PST
VAR
long stack2[25] 'space for pulser cog
long counter,value[vars]
byte sub_scr
PUB Main '|x 'x is a local variable here
fds.start(31,30,0,57600) 'start console at 115200 for debug output
counter := vars
Cognew(@Read_Sig, @counter) ' start a cog sending the location of data array..
fds.tx(16) 'home to 0,0
fds.tx(1)
fds.str(string("HUB memory display")) 'print to display
fds.tx($d) 'new line
fds.tx($d)
fds.str(string("samples "))
fds.dec(||vars)
fds.tx($d) 'new line
fds.str(string("base address "))
fds.dec(||value[0])
fds.tx($d) 'new line
repeat sub_scr from 1 to (vars)
fds.dec(sub_scr)
fds.str(string(" "))
fds.dec(||value[sub_scr])
fds.tx($d) 'new line
DAT Org 0
Read_Sig mov mem, par ' save base address.
rdlong varbl, mem ' get the sample count from spin parameters
add mem, #4 ' point to start of hub storage + 1 long or we step on the count in hub memory
mov temp, par ' get base addx into temp; store this second location count is in first location
wrlong temp, mem ' save base in hub for later readback w/ spin code..
add mem, #4 ' now we point to the first count value location
do_again mov temp, cnt ' get count,
wrlong temp, mem ' store in value to hub.
add mem, #4 ' calc next location to store a long
djnz varbl, #do_again ' this falls through at 0,
park jmp #park ' loop here forever
varbl long 0
mem res 1
temp res 1
fit $1EF
I am debugging a project in the book
It creates a PASM interface for a standard Hitachi controlled 2 x 16 display.
I have an equivalent routine in SPIN that runs fine.
When I translate into PASM I write "A...H" to the first line.
Everything works but the last char H" does not print.
As a matter of fact the device is printing the previous character ever time I send out a new character.
The last character is held hostage.
I think it is some sort of timing problem but I cant figure out what, or which.
Here is the code. testdata packs "ABCD" in the long
{{-------------------------------------------------------------------------------
BookLCD_2x16.SPIN
Function of program
Implements the use of a 2 line by 16 character
in PASM. Data is written to the LCD in PASM or through the HUB memory.
See book for details and operation scheme
Connections are as follows
Prop LCD
16 Ground LED
15 5 volts through 220 ohms LED
0 14 data buss
1 13 "
2 12 "
3 11 "
4 10 "
5 9 "
6 8 "
7 7 data buss
20 6 ENable
21 5 Read Write
22 4 Reg Select
3 Ground
2 5 volt Power Logic
1 Ground
Program BookLCD_2x16.SPIN
Book PASM for beginners, Propeller 101
Section Projects
Programmer Harprit Sandhu
Date Feb 10 2013
Revisions: Report errors to harprit.sandhu@gmail.com
-------------------------------------------------------------------------------}}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
Vars =32 'hub variables to be displayed
VAR
long stack1[35]
long P_Val[vars]
byte subscr
OBJ
fds : "FullDuplexSerial"
r4p : "Read4Pots"
PUB Go|x
r4p.Read4Pots(@P_Val)
Cognew(@display, @P_val)
fds.start(31,30,0,115200) 'start PST console at 115200 for output
waitcnt(clkfreq/60+cnt)
'Cognew(@Write_LCD, @P_val)
waitcnt(clkfreq/60+cnt)
repeat
'{{
fds.tx(1) 'home
fds.str(string("Displaying Hub variables")) 'heading
fds.str(string(" ")) 'two spaces to erase old data overflow
fds.tx($d) 'new line
fds.tx($d) 'new line
' fds.str(string("7654321076543210"))
' fds.tx($d) 'add line 'reset subscript
repeat subscr from 0 to vars-1 'loop to display all vars
if subscr==2
fds.tx($d)
fds.bin(P_Val[subscr], 32) 'print to the PST in binary
fds.str(string(" ")) 'two spaces to erase old data overflow
if subscr<10
fds.str(string(" "))
fds.dec(subscr) 'print value as decimal value
fds.str(string(" ")) 'three spaces to erase old data overflow
fds.dec(P_Val[subscr]) 'print to the PST in binary
fds.tx($d)
waitcnt(clkfreq/60+cnt) 'wait 1/60 for everything to stabilize.
x:=x+1 'increment counter. (This routine clears up the screen )
if x>10 'decision point (by erasing extraneous lines of )
fds.tx(16) 'clear screen (bottom of PST display every 10 loops)
x:=0 'reset counter (Needed only once in most cases. )
'}}
DAT org 0
display mov mem, par 'Read Par into mem
mov dira, set_dir 'Set directions
mov ddata, half_sec 'load half second
call #wait 'wait half second
call #Init_LCD 'call initialize routine
mov ddata, half_sec 'load half sec
call #wait 'wait
display3 '=======================================
rdlong data, mem 'read forst Hub mem location
shr data, #5 'shift right 5 to reduce sensitivity
call #send_char 'lsend out what was read as ASCII code
mov data, #66 'load B
call #send_char 'send out B
mov data, #(00_0011) 'load C
call #send_char 'send out
mov data, #68 'load D
call #send_char 'send out
mov data, #69 'load E
call #send_char 'send out
mov data, #70 'load F
call #send_char 'send out
mov data, #71 'load G
call #send_char 'send out
mov data, #72 'load H
call #send_char 'send out
jmp #display3 'loop back
'stop jmp #stop
'subroutines=====================================================================
Init_LCD
andn outa, setRw 'RW set low
andn outa, setRs 'RS set low
andn outa, setEN 'set EN hi
mov data, #(11_0000) 'load instruction
call #send_Instr 'send out instruction
mov data, delay1 'load delay
call #wait 'wait
mov data, #(11_0000)'load instruction
call #send_Instr 'send out instruction
mov data, delay2 'load delay
call #wait 'wait
mov data, #(11_0000)'load instruction
call #send_Instr 'send out instruction
mov data, delay3 'load delay
call #wait 'wait
'====================== '
mov data, #(11_1000) 'clears blocks
call #send_Instr 'load instruction
call #wait_2ms 'wait
mov data, #(00_1111) 'cursor etc
call #send_Instr 'load instruction
call #wait_2ms 'wait
mov data, #(00_0001) 'clear
call #send_Instr 'load instruction
call #wait_2ms 'wait
mov data, #(00_0010) 'home
call #send_Instr 'load instruction
call #wait_2ms 'wait
Init_LCD_ret ret 'Return
'
'============================ '
wait mov temp, ddata 'load passed data
:loop djnz temp, #:loop 'wait loop
wait_ret ret 'return
'=========================== '
'
wait_2ms mov temp, d2ms 'load 2 ms
:loop djnz temp, #:loop 'wait loop
wait_2ms_ret ret 'return
'======================== '
Send_Instr call #busy 'Check busy flag
andn outa, setRw 'RW set low
andn outa, setRs 'RS set low
or outa, setEN 'set EN hi
call #wait_2ms 'wait 2 ms
mov outa, data 'load outa
call #wait_2ms 'wait 2 ms
andn outa, setEN 'toggle EN lo
call #wait_2ms 'wait 2 ms
Send_Instr_ret ret 'retuirn
'=========================================================
Send_Char call #busy '
andn outa, setRw 'RW set low
or outa, setRs 'RS set hi
or outa, setEN 'set EN hi
call #wait_2ms 'wait 2 ms
mov outa, data 'load outa
call #wait_2ms 'wait 2 ms
andn outa, setEN 'toggle EN lo
call #wait_2ms 'wait 2 ms
Send_Char_ret ret 'reutrn
'======================== '
Busy '
mov dira, Set_Inp 'change to input byte
or outa, setRw 'RW set hi
andn outa, setRs 'RS set lo
'
:loop or outa, setEN 'set EN hi
mov temp, ina 'read input lines
andn outa, setEN 'set EN hi
andn temp, mask7 wz 'look at busy bit
if_nz jmp #:loop 'loop back if not a 0
mov dira, Set_Dir 'set back to output lines
call #wait_2ms 'wait 2 ms
Busy_ret ret ' return
'constants=====================================================================
half_sec long 2_000_000 '0.5 sec approx values
delay1 long 5_000 '4.1 milli largest the system
delay2 long 300 '100 micro will still work
delay3 long 3_000 '1 milli with.
d2ms long 400 '2 ms
set_Dir long 000000_11111111_00000000_11111111
set_Inp long 000000_00000000_00000000_00000000
setEN long 000000_00010000_00000000_00000000
setRW long 000000_00100000_00000000_00000000
setRS long 000000_01000000_00000000_00000000
mask7 long 111111_11111111_11111111_01111111 'mask for pin 7
'variables====================================================================
Mem_Loc res 1
mem_Val res 1
sent res 1
cmd res 1
temp res 1
pip res 1
temp2 res 1
temp3 res 1
temp4 res 1
mem res 1
mem1 res 1
bits res 1
data res 1
ddata res 1
The problem whereby the routine is holding the last character hostage is due to raising the enable line high before setting the data lines. Setting the data lines first, and then toggling the enable line high and low causes the display to show the expected character, but it also reveals the bug that I was expecting to see from a read through; I am amazed that it managed to get up to G as written. With the enable line toggling after the data lines are set, the display only shows the "A" and "B", and then the cursor jumps. To set the data lines, you're copying the contents of data into outa, which is overwriting the R/W and RS lines. It's just dumb luck that because of the way test_data is packed with four ASCII bytes that the RS bit remains set the first two times through. Following the third shift, however, RS is clear.
I just read through the book and made a list of all the components needed to do the experiments.
Here it is as promised.
[COLOR=#000000][FONT=Arial, sans-serif][SIZE=5]Parts and equipment needs[/SIZE][/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]The following parts will allow you to do all the experiments in the book.[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]PDB from Parallax (certain unlisted parts are on the PDB)[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]4 potentiometers 5K to 10k[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]MCP 3208 8 line A to D chip[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]7404 buffer[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]LM34 Temp reading chip[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]2 x 16 LCD display with Hitachi controller[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]Memsic 2125 tilt indicator gravity chip[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]Resistors (10 each should be in every supplies drawers)[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif] 220 ohm[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif] 470 ohm[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif] 10K[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif] 1 meg[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]Small transistor for speaker[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]Small speaker[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]Seven segment display[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]Servo, R/C hobby (2 needed)[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]Small motor 12 VDC (Opt)[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]Motor amplifier (Opt)[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]Set of breadboard jumpers with steel tips (highly recommended because hook up wire tends to break in the breadboards after many uses and is then very hard to remove)[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif][B]Tools:-[/B][/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]Minimal Oscilloscope[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]Inexpensive VOM[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]Tool box scraps[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]Sources of parts.[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif] Jameco[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif] All electronics[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif] Mouser[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif] Suppliers on internet, eBay.[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif] Parallax Inc[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif] encodergeek.com[/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif]Please report omissions to me at [/FONT][/COLOR]
[COLOR=#000000][FONT=Arial, sans-serif][B]harprit.sandhu@gmail.com[/B][/FONT][/COLOR]
There might be a minor change or two to it but I think this is it.
I have a question for the experts
I have an object that read 4 pots and puts the values in the first 4 locations in hub ...P_Val
When I access the cog with
VAR
no mention of P_Val[ ] under VAR declarations
long number
OBJ
r4p : "read4pots" 'refers to the pots object
.....
.....
.....
r4p.Read4Pots(@P_Val) 'starts the method in object above and passes P_Val to it.
....
PUB .......
number:=P_Val[2]
...
I find that in my program I do not have to allow space for P_Val as an array under VAR in my program
and I can still use P_Val[0], P_Val[1], P_Val[2], P_Val[3] in my program and methods within.
Compiler does not flag it
Everything works fine
Is this the OK and proper use of the code
Is there something else that needs to be done to be right
r4p.Read4Pots(@P_Val) 'starts the method in object above and passes P_Val to it.
No... this actually passes the hub address (@) of P_Val, which should be the first of a group of four variables to hold the pot values. This could be an array of four variables, or it could be the first in a list of the same type. The object only needs the base address of the group to write to them all.
I have written a similar object for the MCP3208 which auto-scans the inputs and populates a designated set of variables. In my program I have something like this:
var
long xaxis
long yaxis
long zaxis
long speed
long ramp
In my object's start() method I specify the SPI pins, the number of channels used (5 for the above group), and the hub address of the output variables (@xaxis).
Of course you need to declare P_VAL somewhere! Either in VAR or in DAT section. Otherwise the compiler does not know what to do with the label P_VAL in the code and give you an error-message. AND of couse P_VAL needs to be declared in a way that you have reserved enough RAM, as you otherwise overwrite parts of the RAM used otherwise.
But yes, the compiler does not complain if you use a normal variable as an array. Maybe because in a DAT-section you don't have an array declaration but you definitely want to use labels like an array. So it was easier to allow the compiler to treat VAR variables in the same way.
Nevertheless you as a programmer have to be aware of the size of an array or label used in the array-style, as otherwise real strange things could happen.
Examples:
VAR
long P_VAL
long X_VAL
..
P_VAL[1]:=0
This would overwrite X_VAL
DAT
P_VAL long 1,2,3,4
This is propably why P_VAL can be used as an array even if it is not declared as such.
Harpit, I have seen some fairly negative comments about your SPIN book, and in this thread. Despite all that your spin book has fairly good amazon reviews. I went ahead and ordered it. Im really looking forward to reading it. While the PE-Kit is a great resource, your book has some stuff in it im really looking forward to, i.e. motor control with encoders, and im really hoping you show the user to write an hd47780 driver, not just use an object.
Anyways my point is I have Hi Hopes for this PASM book. I know it wont turn me in to a Chip, Phil or Jazzed, but im hoping it will be a good starting point. While both PotatoHead and Desilva both have excellent documents out there. There is a pretty big gap to fill between them. I learned PC assembly from this book http://www.amazon.com/Assembly-Language-Step---Step-Programming/dp/0470497025/ref=sr_1_6?s=books&ie=UTF8&qid=1361393192&sr=1-6&keywords=assembly+language it takes an awesome approach to teaching newbs about ASM, using the first half of the book to go over binary/hex math, and how PC architecture works. This is really what assembly is about, anyone can look at a table of instructions, but having an entament knowledge of the machines architecture is what its all about, thats the only way to figure out how to use those instructions properly.
I look forward to your reaction to my SPIN book. One of the reviewers liked it enough to wear the binding out. I hope it will help you understand the control of servo motors with encoders. I still provide hardware to support the book if you cant find it elsewhere. I don't know of any other author that does this. Both my books, on running motors and making instruments, along with their electronic copies, 4 of them together have been in the top 50 PIC books for three years now!! If you have a heavy interest in running motors you might want to take a look at the motors book.
As for some "fairly negative reviews" I can only say that these books are not for experts, never were, never will be. There is a need for another book that should come after my two books (Propeller 101 SPIN, and Propeller 102 PASM). I might do one but right now I am saturated and bushed and getting beaten on does not help. What you are really asking for, in my mind, would go in Propeller 495, for graduate students. Parsing, compiler design, arrays, look up tables, hairier stuff like that. However do me a favor and send me a table of contents that you think should be in Propeller 103. Others of course and invited to do so also. Lets see what we come up with. Could be very interesting.
However go to Amazon and read the reviews. The books are all well liked and are good sellers. My book on Robotics described the construction of a walking robot (my avatar on this forum) in 1996. 17 years ago!! It was the first weight shifting robot described and all the walking robots of today are based on my book yet only one supplier gives me the credit for figuring it out an telling.
Beats
P_Var long 400,555,6
mov mem, par
mov mem1, mem
add mem1, #8
wrlong P_Var, mem
wrlong P_Var, mem1
here jmp #here
Running this stores 400 at the first and 3rd Par referenced locations
How do I access the constants 555 and 6 that were specified
above from within a PASM program.
You could make life easy for yourself by naming all your constants:
const1 long 400
const2 long 55
const3 long 6
and using those meaningful names in your program.
Of course for numbers of 9 bits or less just define constants in a CON section and use the hash:
CON
const1 = 99
DAT
..
mov a, #const1
...
a long 0
If you really have an array of unnamed constants, a look up table, you will need to use self-modifying code to do it. That is to say use movs and movd to modify your instructions to address the correct location in the table prior to execution. See PASM reference manual.
I suggest that in general you do not declare your variable or constant longs prior to you executable instructions. Put them at the end.
Don't forget your ORG and FIT statements.
What you are really asking for, in my mind, would go in Propeller 495, for graduate students. Parsing, compiler design, arrays, look up tables, hairier stuff like that.
Compiler design might be Propeller 495, but indexing a table is Assembly 101, no matter what processor we're talking about. In fact I'd put it before spinning a motor or writing to a display.
Admittedly, the Prop does indexing differently than most chips. But it's still a basic operation that needs to be mastered right out of the gate.
PASM 101 should at least include arrays and look up tables. In HUB and in COG memory. It's basic memory indexing stuff. It may be a bit less obvious on the Prop due to it's lack of support in the instruction set but it is there with self-modifying code.
Parsers and compilers are an order of magnitude or so more complicated. I would not even think about creating those in PASM.
Yes, I knew you could access the clock from the Special purpose registers at $1F1 and as CNT but I had forgotten about #0 access. Now I wonder about the purpose of having a copy at a writable register at #0. What is the purpose of this?
I do not program like that! I had made up the spinets to ask the question I needed answered without posting large amounts of code. You will not see such constructs in the book!! But thanks for the good advise.
If we were to discuss writing a compiler in PASM, it would be about how to write the compiler in PASM and not about writing a compiler in PASM. The discussion of such a problem would greatly enhance one's knowledge about PASM. Climbing Everest v/s knowing how to climb Everest. Then you can climb any mountain. Well, maybe be not.
And now the confession. Yes it was about arrays and my brain is still pretty much MT on the subject. Specifically I was was interested in two aspects of the problem. How to enter the data for an array into the program and two how to access it properly. Say I have an array of over 150 constants (which is getting big for a small logic engine like the Prop). What is the best way and least tedious way to put these into the DAT area and what is the best way to access them on a random basis, meaning not serially. They need to be placed in in three areas. In the program under DAT. In the hub memory as referable by PAR and in the cog memory and accessed in, how I still don't know. How does one move between the three, meaning how does one tie it all into the PAR reference in a smooth and competent way?
This is about the last problem in getting the book done. Phew.
Can't code it for you just now but if you have an "array" of constants in DAT like so:
constants LONG 32, 43, 435, 66, 6
You can read the first one with:
mov someThing, constants
If you want to get the next one in the list you have a little problem as PASM does not have indexed addressing.
What you do is write the required source address into that move instruction to force it to pick up the right one. Something like:
mov ptr, #constants ' Get the COG address of constants into ptr
add ptr,2 ' Offset to third item in the constans array
movs ins, ptr ' Change the instruction at "ins" below to address that element
nop ' We need a nop to allow for the CPU pipeline.
ins mov something, 0 ' When we get here we are actually doing a "mov something, (constants + 2)
Well something like that. Others here were correct me I'm sure.
Of course that "2" above could be some register holding an varying index value.
movs ins, #constants
add ins, #2 ' Offset to third item in the constans array
nop ' We need a nop to allow for the CPU pipeline.
ins mov something, 0-0 ' When we get here we are actually doing a "mov something, (constants + 2)
>Now I wonder about the purpose of having a copy at a writable register at #0. What is the purpose of this?
That is Hub address 0, it stores the Spin value: clkfreq (how many ticks in one second)
The SPIN part of the program program display 8 HUB
location on the PST so you can see what is going on.
The PASM part toggles pin1 based on the value in Par/Hub(0)
which is a potentiometer.
In this program if I change the value that is passed to the DJNZ
loop from #500 to "reading", ("reading" was read from hub(0))
the pin will not toggle and the value "reading" will not be
written to the mem6 PAR referenced location.
What happens in the subroutine "Be_d" should not affect
the transfer of reading into mem6 location.
Please explain what I am doing wrong.
H
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
vars=8
OBJ
fds : "FullDuplexSerial" 'for communications with PST
r4p : "read4Pots"
VAR
long P_Val[vars]
byte subsc
PUB Main|x
fds.start(31,30,0,115200) 'start console at 115200 for debug output '
r4p.Read4Pots(@P_Val) '
waitcnt(clkfreq/100+cnt) 'wait for startup '
Cognew(@beats, @P_Val)
waitcnt(clkfreq/100+cnt) 'wait for startup '
repeat '
fds.tx($1) 'home to 0,0
fds.str(string("Data display")) 'print to display
fds.str(string(" ")) 'spaces to erase old data overflow
fds.tx($d) 'new line
fds.tx($d) 'new line
repeat subsc from 0 to vars-1
if subsc==4
fds.tx($d) 'new line spaces first 4 values apart
fds.dec(subsc)
fds.str(string(" ")) '
fds.dec(P_Val[subsc]) '
fds.str(string(" ")) '
fds.tx($d) 'new line
fds.tx($d) 'new line
fds.str(string("4 potentiometers and")) 'print to display
fds.tx($d) 'new line
fds.str(string("rest of misc variables"))'print to display
fds.tx($d) 'new line
fds.str(string("Beats = "))'print to display
fds.dec((P_Val[0]+19)/24+40)
P_Val[4]:=((P_Val[0]+19)/24+40)
P_Val[5]:=800000/((P_Val[0]+19)/24+40)
waitcnt(clkfreq/60+cnt) 'flicker free wait
x:=x+1 'increment counter. (This routine clears up the screen )
if x>10 'decision point (by erasing extraneous lines of bottom )
fds.tx(16) 'clear screen (of PST display every 10 loops )
x:=0 'reset counter
DAT org 0
Beats mov dira, set_Dira 'Set up DIRA
mov mem, par '
mov mem4, mem '
add mem4, #16 '
mov mem5, mem '
add mem5, #20 '
mov mem6, mem '
add mem6, #24 '
nop
nop
nop
reread rdlong reading, mem5 'Read location 0
wrlong reading, mem6 'Write it to location 6 XXXXXXXXXXXX the transfer that messes up XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
or outa, pin1 'pin1 high
call #Be_d 'call delay
andn outa, pin1 'pin1 low
call #Be_d 'call delay
jmp #reread 'loop back and read again
'=============================
Be_d mov pass, #500 ' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX problem area when #500 changed to 'readiing' XXXXXXXXXXXX
:loop djnz pass, #:loop '
Be_d_ret ret '
'=============================== '
set_dira long %00001011_00000000_00000000_00000011
pin1 long %00000000_00000000_00000000_00000010
'===============================================================================
mem res 1
mem4 res 1
mem5 res 1
mem6 res 1
mem0 res 1
mem04 res 1
mem05 res 1
reading res 1
pass res 1
ldelay res 1
FIT
Seems like even adding 1 to "reading" fixes the problem
and I can make it come and go
(The absolute test for a fix)
I tried adding nops all over the place and that does not work.
But why. Why should adding just 1 work.
And when does one have to add a 1
Be_d
add reading, #1 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX here XXXXXX
mov pass, reading '
:loop djnz pass, #:loop '
Be_d_ret ret '
Comments
Tell me about it!
And I do agree with what you have said.
You are more right than you can imagine. I have been sincerely beating my head against this for a year and a half. Essentially more than full time. It is really very complicated and to do it right, this Propeller 102 effort (101 was my SPIN book) needs to be followed by Propeller 103 on slightly more advanced stuff like you are suggesting. Propeller 104 for advanced projects and 495 for what the experts need to know. I do not know that I am the guy for that.
I'll see what I can add but I am not hopeful to do it justice.
Thanks
H
You can run it, it needs no connections to anything. See results on PST.
The program creates two Hub location addresses relative to PAR, mem and mem1
It then reads the system counter 5 times and stores the results in Hub memory. first 5 locations.
It then read location mem and writes it to location mem1
However It stores a 0 in that location.
Creating mem1 seems to wipe out the contents at mem
What is wrong.
H
mem is no longer 1st location because you have been adding to in in the do_again loop
John Abshier
H
Output
HUB memory display
samples 8
base address 1048
1 1003196230
2 1003196250
3 1003196282
4 1003196314
5 1003196346
6 1003196378
7 1003196410
8 1003196424
It will be of interest to beginners
I did not re-post here to keep down the clutter.
Please post comments that might need inclusion re: book.
The book is about done and ready for printers.
I give it two weeks for "in their hands"
H
It creates a PASM interface for a standard Hitachi controlled 2 x 16 display.
I have an equivalent routine in SPIN that runs fine.
When I translate into PASM I write "A...H" to the first line.
Everything works but the last char H" does not print.
As a matter of fact the device is printing the previous character ever time I send out a new character.
The last character is held hostage.
I think it is some sort of timing problem but I cant figure out what, or which.
Here is the code. testdata packs "ABCD" in the long
H
I sure hope the book is better looking than this.
I hope you will not be disappointed.
I am giving it my best shot but my lack of sophistication will no doubt show through.
H
Here it is as promised.
There might be a minor change or two to it but I think this is it.
Harprit
I have an object that read 4 pots and puts the values in the first 4 locations in hub ...P_Val
When I access the cog with
I find that in my program I do not have to allow space for P_Val as an array under VAR in my program
and I can still use P_Val[0], P_Val[1], P_Val[2], P_Val[3] in my program and methods within.
Compiler does not flag it
Everything works fine
Is this the OK and proper use of the code
Is there something else that needs to be done to be right
H
No... this actually passes the hub address (@) of P_Val, which should be the first of a group of four variables to hold the pot values. This could be an array of four variables, or it could be the first in a list of the same type. The object only needs the base address of the group to write to them all.
I have written a similar object for the MCP3208 which auto-scans the inputs and populates a designated set of variables. In my program I have something like this:
In my object's start() method I specify the SPI pins, the number of channels used (5 for the above group), and the hub address of the output variables (@xaxis).
But yes, the compiler does not complain if you use a normal variable as an array. Maybe because in a DAT-section you don't have an array declaration but you definitely want to use labels like an array. So it was easier to allow the compiler to treat VAR variables in the same way.
Nevertheless you as a programmer have to be aware of the size of an array or label used in the array-style, as otherwise real strange things could happen.
Examples: This would overwrite X_VAL
This is propably why P_VAL can be used as an array even if it is not declared as such.
clear up as much of it as I can.
Thanks to all for the tremendous help you all gave me in the last year and a half.
I hope to have the index done by the end of Feb
H
Anyways my point is I have Hi Hopes for this PASM book. I know it wont turn me in to a Chip, Phil or Jazzed, but im hoping it will be a good starting point. While both PotatoHead and Desilva both have excellent documents out there. There is a pretty big gap to fill between them. I learned PC assembly from this book http://www.amazon.com/Assembly-Language-Step---Step-Programming/dp/0470497025/ref=sr_1_6?s=books&ie=UTF8&qid=1361393192&sr=1-6&keywords=assembly+language it takes an awesome approach to teaching newbs about ASM, using the first half of the book to go over binary/hex math, and how PC architecture works. This is really what assembly is about, anyone can look at a table of instructions, but having an entament knowledge of the machines architecture is what its all about, thats the only way to figure out how to use those instructions properly.
Thanks for taking the time to post.
I look forward to your reaction to my SPIN book. One of the reviewers liked it enough to wear the binding out. I hope it will help you understand the control of servo motors with encoders. I still provide hardware to support the book if you cant find it elsewhere. I don't know of any other author that does this. Both my books, on running motors and making instruments, along with their electronic copies, 4 of them together have been in the top 50 PIC books for three years now!! If you have a heavy interest in running motors you might want to take a look at the motors book.
As for some "fairly negative reviews" I can only say that these books are not for experts, never were, never will be. There is a need for another book that should come after my two books (Propeller 101 SPIN, and Propeller 102 PASM). I might do one but right now I am saturated and bushed and getting beaten on does not help. What you are really asking for, in my mind, would go in Propeller 495, for graduate students. Parsing, compiler design, arrays, look up tables, hairier stuff like that. However do me a favor and send me a table of contents that you think should be in Propeller 103. Others of course and invited to do so also. Lets see what we come up with. Could be very interesting.
However go to Amazon and read the reviews. The books are all well liked and are good sellers. My book on Robotics described the construction of a walking robot (my avatar on this forum) in 1996. 17 years ago!! It was the first weight shifting robot described and all the walking robots of today are based on my book yet only one supplier gives me the credit for figuring it out an telling.
Thanks again
H
rdlong delay, #0 'get clock frequency
How do I know that this gets the clock frequency.
And why and how is/was it at location #0
I see no reference to this anywhere in the manual.
Will some one knowledgeable please expand on this.
H
Running this stores 400 at the first and 3rd Par referenced locations
How do I access the constants 555 and 6 that were specified
above from within a PASM program.
H
const1 long 400
const2 long 55
const3 long 6
and using those meaningful names in your program.
Of course for numbers of 9 bits or less just define constants in a CON section and use the hash:
If you really have an array of unnamed constants, a look up table, you will need to use self-modifying code to do it. That is to say use movs and movd to modify your instructions to address the correct location in the table prior to execution. See PASM reference manual.
I suggest that in general you do not declare your variable or constant longs prior to you executable instructions. Put them at the end.
Don't forget your ORG and FIT statements.
Compiler design might be Propeller 495, but indexing a table is Assembly 101, no matter what processor we're talking about. In fact I'd put it before spinning a motor or writing to a display.
Admittedly, the Prop does indexing differently than most chips. But it's still a basic operation that needs to be mastered right out of the gate.
PASM 101 should at least include arrays and look up tables. In HUB and in COG memory. It's basic memory indexing stuff. It may be a bit less obvious on the Prop due to it's lack of support in the instruction set but it is there with self-modifying code.
Parsers and compilers are an order of magnitude or so more complicated. I would not even think about creating those in PASM.
Now my Responses:
Yes, I knew you could access the clock from the Special purpose registers at $1F1 and as CNT but I had forgotten about #0 access. Now I wonder about the purpose of having a copy at a writable register at #0. What is the purpose of this?
I do not program like that! I had made up the spinets to ask the question I needed answered without posting large amounts of code. You will not see such constructs in the book!! But thanks for the good advise.
If we were to discuss writing a compiler in PASM, it would be about how to write the compiler in PASM and not about writing a compiler in PASM. The discussion of such a problem would greatly enhance one's knowledge about PASM. Climbing Everest v/s knowing how to climb Everest. Then you can climb any mountain. Well, maybe be not.
And now the confession. Yes it was about arrays and my brain is still pretty much MT on the subject. Specifically I was was interested in two aspects of the problem. How to enter the data for an array into the program and two how to access it properly. Say I have an array of over 150 constants (which is getting big for a small logic engine like the Prop). What is the best way and least tedious way to put these into the DAT area and what is the best way to access them on a random basis, meaning not serially. They need to be placed in in three areas. In the program under DAT. In the hub memory as referable by PAR and in the cog memory and accessed in, how I still don't know. How does one move between the three, meaning how does one tie it all into the PAR reference in a smooth and competent way?
This is about the last problem in getting the book done. Phew.
Its easy enough in SPIN.
H
H
constants LONG 32, 43, 435, 66, 6
You can read the first one with:
If you want to get the next one in the list you have a little problem as PASM does not have indexed addressing.
What you do is write the required source address into that move instruction to force it to pick up the right one. Something like:
Well something like that. Others here were correct me I'm sure.
Of course that "2" above could be some register holding an varying index value.
If I may I'd like to see how you would code it
10 variables
No hurry
H
>Now I wonder about the purpose of having a copy at a writable register at #0. What is the purpose of this?
That is Hub address 0, it stores the Spin value: clkfreq (how many ticks in one second)
The SPIN part of the program program display 8 HUB
location on the PST so you can see what is going on.
The PASM part toggles pin1 based on the value in Par/Hub(0)
which is a potentiometer.
In this program if I change the value that is passed to the DJNZ
loop from #500 to "reading", ("reading" was read from hub(0))
the pin will not toggle and the value "reading" will not be
written to the mem6 PAR referenced location.
What happens in the subroutine "Be_d" should not affect
the transfer of reading into mem6 location.
Please explain what I am doing wrong.
H
and I can make it come and go
(The absolute test for a fix)
I tried adding nops all over the place and that does not work.
But why. Why should adding just 1 work.
And when does one have to add a 1
H