There is a lot of code.
There Are three programs. Each will run on its own also. They are called within each other
The mother program is the first one. Also run the Propeller Serial Terminal to see what is going on.
For best results copy them and run them in your prop tool as three files
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
bits=12
pots=4
VAR
long P_Val[7]
long pot_sub
long clear
OBJ
'fds : "FullDuplexSerial"
ms : "MsecDelay" 'pulses line 1
PUB Main 'P_VAL is a local variable here
dira[0..4]~~
'fds.start(31,30,0,115200) 'start console at 115200 for debug output
cognew(@Chirper, @P_Val) 'start new cog at "tone", read var to P_Val
ms.main
waitcnt(clkfreq/40 +cnt)
repeat 'endless loop
DAT org 0 'sets the starting point in Cog
Chirper mov dira, set_dira 'set direction of ports
mov mem, par
rdlong delta, mem
mov mem1, mem
add mem1, #4
rdlong delta2, mem1
loop1 mov temp, ina 'read inputs
and temp, read_bit wz 'isolate pin 1
if_z jmp #loop1 'stay here if bit is 0
call #chirp 'call chirp
loop2 mov temp, ina 'read inputs
and temp, read_bit wz 'isolate pin 1
if_nz jmp #loop2 'stay here if 1
call #chirp 'call chirp
jmp #loop1 'stay here if bit is not 0
'subroutines
Chirp mov count, #4 'counter for chirps
mov delay, cnt 'load counter with clock counter
add delay, #12 'increment delay to get over overflow
loop waitcnt delay, delta 'delay
or outa, out_bit 'make bit high
waitcnt delay, delta 'delay
andn outa, out_bit 'make bit low
sub count, #1 wz 'subtract 1 from counter
if_nz jmp #loop 'loop back if not done w/counts
Chirp_ret ret 'return from chirp sub
set_dira long %00001011_00000000_00000000_00000111 'Set dira register
out_bit long %00000000_00000000_00000000_00000100 'out bit for speaker
Read_bit long %00000000_00000000_00000000_00000001 'read bit
'delta long 4000 'interval between changes in chirp
'code_val long 3000
delta res 1
delta2 res 1
temp res 1 'temporary storage location
count res 1 'memory location for PAR variable
delay res 1 'delay constant for CNT
mem res 1
mem1 res 1
{{
022 PASM Read4Pots.spin
Program to read 4 pots
Repeats the program GOOD 006 PASM ReadPot 4 times
Installs in separate cog.
Reads resistances to 12 bits appears in POT_RES global variable
15 Dec 2011
By Harprit Sandhu
}}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
bits=12
pots=4
VAR
long P_Val[7]
long pot_sub
long clear
OBJ
fds : "FullDuplexSerial"
PUB Main 'P_VAL is a local variable here
fds.start(31,30,0,115200) 'start console at 115200 for debug output
cognew(@Read_Pots, @P_Val) 'start new cog at "generate", read var to P_Val
waitcnt(clkfreq/40 +cnt)
dira[0..3]~~
repeat 'endless loop
pot_sub:=0 'reset id of pot to be printed
fds.tx($1) 'home to 0,0
repeat pots 'loop to display data
fds.bin(P_val[pot_sub], bits) 'print to the PST in binary
repeat 2 'two spaces
fds.tx(" ") 'space to erase old data overflow
fds.dec(P_val[pot_sub]) 'print value as decimal value
repeat 2 'two spaces
fds.tx(" ") 'space to erase old data overflow
fds.dec(pot_sub) 'print value as decimal value
repeat 3 'three spaces
fds.tx(" ") 'space to erase old data overflow
fds.tx($d) 'new line
pot_sub:=(pot_sub)+1 'increment display counter
waitcnt(clkfreq/60+cnt) 'flicker free wait
clear:=clear+1 'increment counter. This routine clears up screen
if clear>10 'decision point by erasing extra lines of bot
fds.tx(16) 'clear screen of PST display every 10 loops
clear:=0 'reset counter
'----------------------------------end of first Cog------------------------------------------
DAT org 0 'sets the starting point in Cog
Read_Pots 'first set up all the counters and addresses needed
mov pots_read, #4 'number of pots to read [also change data]
mov bits_read, #12 'bit resolution of 3208 IC, can be less
mov mem, par 'get address of mem for PAR
mov dira, set_dira 'sets direction of the prop pins
mov pot_id, #0 'first pot read is pot 0
Next_pot or outa , chs_Bit 'makes Chip select high
andn outa, chs_Bit 'makes chip select low
andn outa , clk_bit 'ANDN it with the Clock Bit to make low
or outa , din_Bit 'makes the Din high
call #Tog_clk 'toggle clock line hi-low to read data
or outa , din_Bit 'makes the Din high
call #Tog_Clk 'toggle clock line hi-low to read data
mov temp2, pot_id 'we will read three bits from this pot
call #get_third_bit 'get bit
if_nz jmp #its_one 'jump to set it as needed
jmp #its_zero 'jump to set it as needed
its_one call #Set_next_bit1 'setting bit subroutine call
jmp #continue1 'go to next bit
its_zero call #Set_next_bit0 'setting bit subroutine call
continue1 call #get_second_bit 'get bit
if_nz jmp #its_one1 'jump to set it as needed
jmp #its_zero1 'jump to set it as needed
its_one1 call #Set_next_bit1 'setting bit subroutine call
jmp #continue2 'go to next bit
its_zero1 call #Set_next_bit0 'setting bit subroutine call
continue2 call #get_first_bit 'get bit
if_nz jmp #its_one2 'jump to set it as needed
jmp #its_zero2 'jump to set it as needed
its_one2 call #Set_next_bit1 'setting bit subroutine call
jmp #continue3 'go to next bit
its_zero2 call #Set_next_bit0 'setting bit subroutine call
continue3 andn outa , din_Bit 'makes Din low
call #Tog_Clk 'toggle clock line hi-low to read data
call #Tog_Clk 'toggle clock line hi-low to read data
mov Data_read, #0 'clear register we will read data into
mov bit_count, bits_read 'counter for number of bits we will read
read_bit mov temp, ina 'read in what is in all the input lines
andn temp, mask26 wz 'mask off except Dout line. Set Z flag
shl Data_read, #1 'shift register left 1 bit for next bit
if_nz add Data_read, #1 'if value + add 1 to data register
call #Tog_Clk 'toggle clock get next bit ready in Dout
sub bit_count, #1 wz 'decr the "bits read" counter. Set Z flag
if_nz jmp #read_bit 'go up do it again if counter not yet 0
wrlong Data_read, mem 'write it in PAR to share it as P.Val
add mem, #4 'add 4 to hub address for next long
add pot_id, #1 'so we can look at next pot
mov temp2, pot_id 'recall what pot we are reading
sub temp2, pots_Read wz 'check if it is how many we want to read
if_nz jmp #Next_pot 'if it is not 0 go up and read next pot
jmp #Read_pots 'go back beginning and do all pots again
'subroutines used
Set_next_bit0 andn outa , din_Bit 'makes Din low in 000 for line
call #Tog_Clk 'toggle clock line hi-low to read data
Set_next_bit0_ret ret 'return from this subroutine
Set_next_bit1 or outa , din_Bit 'makes Din high in 000 for line
call #Tog_Clk 'toggle clock line hi-low to read data
Set_next_bit1_ret ret 'return from this subroutine
Tog_Clk nop 'nop to settle signals
or outa, clk_bit 'make clock bit high
nop 'nop to settle signals
andn outa, clk_bit 'make clock bit low
nop 'nop to settle signals
Tog_Clk_ret ret 'return from this subroutine
Get_first_bit mov temp2, pot_id 'get current pot number
andn temp2, mask0 wz 'get last bit
Get_first_bit_ret ret 'return
Get_second_bit mov temp2, pot_id 'get current pot number
shr temp2, #1 'shift right 1 bit to get second bit
andn temp2, mask0 wz 'return
Get_second_bit_ret ret
Get_third_bit mov temp2, pot_id 'get current pot number
shr temp2, #2 'shift right 2 bits to get third bit
andn temp2, mask0 wz 'return
Get_third_bit_ret ret
Set_dira long %00001011_00000000_00000000_00001111 'Set dira register
Chs_Bit long %00000001_00000000_00000000_00000000 'Chip select bit 24
Din_Bit long %00000010_00000000_00000000_00000000 'Data in bit 25
Dout_Bit long %00000100_00000000_00000000_00000000 'Data out bit 26
Clk_Bit long %00001000_00000000_00000000_00000000 'Clock bit 27
mask26 long %11111011_11111111_11111111_11111111 'Mask to read Dout bit
mask0 long %11111111_11111111_11111111_11111110 'Mask to read 0 bit
mem res 1 'Par location
temp res 1 'temporary storage variable, misc
temp2 res 1 'temporary storage variable, misc
bit_count res 1 'temporary storage variable, read bit counter
Data_Read res 1 'temporary storage variable, data being read
pot_id res 1 'current pot id number
pots_read res 1 'total number of pots to be read.
bits_Read res 1 'resolution of data read, 12 bits max
{
Read pot and displa on PST through 022 PASM Rea4PotsX
set up basic count oscillator
}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
VAR
long P_Val2[7]
obj
msd2 : "msecdelay2" 'reqads 4 pots
PUB Main
dira[0..4]~~
cognew(@MilSecDelay, @P_val2)
msd2.main
waitcnt(clkfreq/20 +cnt)
repeat 'endless loop
DAT org 0
MilSecDelay mov dira, set_dira 'sets direction of the prop pins
mov beats, #0 'clear the beats register
loop2 mov Clock_spd, Clk_speed 'set counter to clock speed
mov mem, par 'get par address
add mem, #4
rdlong pot_zero, mem
Add_To_Count sub Clock_spd, pot_zero wc 'subtract beats from counter and set carry bit
add beats, #1 'add 1 to the answer
if_nc jmp #Add_To_Count 'if the carry is not set, do it again
sub beats, #1 'subtract one to answer to make correction
mov delay, cnt 'read in CNT
add delay, #100 'add to skip over counter fill
loop andn outa, test_bit 'bits low
waitcnt delay, beats 'pause
or outa, test_bit 'bits high
waitcnt delay, beats 'pause
'wrlong beats, mem
jmp #loop 'loop back
Set_dira long %00001011_00000000_00000000_00000111 'Set dira register
test_bit long %00000000_00000000_00000000_00000001
Clk_Speed long 80_000_000
pot_zero long 400
'pot_zero res 1
bps res 1
mem res 1 'memory location for PAR variable
delay res 1 'delay constant for CNT
beats res 1 'the divider for the clock
mem1 res 1
Clock_spd res 1 'counter for clock
Assuming you have a top level object (which references other objects) please archive said object (File->Archive) and attach it here. No-one is going to guess what the relationship of those three fragments is. For example, how should I name these objects (if important)? What are those msecdelay objects?
The second "022....." cog reads 4 potentiometers and stores the values in hub memory. It calls nothing. Only the first pot read will be used.
The third file "mSecDelay2" takes what is in the first pot and divides the clock values by it to get a frequency. It then generates this freq on line 1. This is the frequency of the metronome.
File one "MSecdelay" looks at line 1 and provides a chirp on line 3 every time the signal changes. The output goes to a speaker.
The problem is that I cannot read the pot all the way to the first file.
Not sure I got the right idea here but it should do. The main program generates 4 pseudo random values and stores them in an array. Two helper objects monitor entry 0 of said array and indicate change or generate a frequency based on the stored value. Important bit here is that all objects need to have an idea where the shared data (block) is.
Change is indicated on pin 16 (inverts LED every time a change is detected), the other object generates a square wave on pin 17 using the data value for NCO setup.
The role(s) of each object can be changed, i.e. data can be generated in a child object.
I just wanted to tell you that I found this thread about a week ago and I have read every entry. I am learning PASM and your learning experience has proven to be a real treasure trove for my own. There have been a great number of things I have learned to do including getting up and going with the PASD debugger which, although simple, is a great way to watch variables... especially pointers to variables.
You are a real trooper to joust with the pros and I think your effort is a noble one.
As for the pros, these guys are awesome and it is a real delight for me to see how the mystery of their code gets figured out by running on my own props.
I look forward to seeing your book someday and I also hope some more advanced treatments may get published by the experts in this forum.
Propeller assembler is loads of fun to work with and a great way for me to keep my mind active during the winter months.
Please run this program on your computer
Use PST to see what is going on
Tell me why I dont get a clean two line display on the PST.
{{ Program 017 PASM minimum PAR.spin
This program is a minimal implementation for two variables and PAR.
There are two Cogs in this program, one in SPIN and one in PASM
Cog 1 in SPIN displays the variables on the console
Cog 2 in PASM sets the variables to 1111 and 2222
Finds the location of PAR and moves it to mem1
Then mem2 is set to mem1 +4.
The two variables are transferred to mem1 and mem2
and become available to the SPIN environment
Loop.
}}
VAR
long sharedVar[2]
word clear
OBJ
fds: "FullDuplexSerial"
PUB Main 'displays values on console
fds.start(31,30,0,115200) 'start console at 115200 for debug output
cognew(@SecondCog, @SharedVar) 'start the second Cog in PASM
waitcnt(clkfreq/40+cnt) 'wait 1/4 for everything to stabilize.
clear:=0
repeat 'loop
fds.tx($1) 'home to 0,0
fds.dec(SharedVar) 'display first value
fds.tx($d) 'new line
fds.dec(SharedVar[1]) 'display second value
clear:=clear+1 'increment counter. This routine clears up screen
if clear>10 'decision point by erasing extra lines of bot
fds.tx(16) 'clear screen of PST display every 10 loops
clear:=0 'reset counter
waitcnt(clkfreq/6+cnt) 'flicker free wait
DAT
org 0 'start at 0 location in the cog
SecondCog 'start point identification
mov mem1, PAR 'find location of PAR, put in MEM1
mov mem2, mem1 'make MEM2=MEM1
add mem2, #4 'add 4 to MEM2
re_do wrlong var_one, mem1 'write variable to location MEM1
wrlong var_two, mem2 'write variable to location MEM2
jmp #re_do 'jump back, do it again
var_one long 1111 'variable declaration
var_two long 2222 'variable declaration
mem1 res 1 'first address storage space
mem2 res 1 'second address storage space
I don't have PST here so I can't see any screen clearing. Your variables seem to be written out just fine though.
Where are your clock settings. I had to add them:
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
I'm not so happy with the commenting style. Having a comment "loop" next to a "repeat" statement is pointless, clutters up the page and is annoying. As this a book on PASM not Spin one should not have to be explaining what the Spin keywords are all the time.
Similarly the "add 4 to MEM2" conveys no information, presumably the operation of ADD is explained by now.
That fixed it but I was under the impression that if you did not specify the clock, there was a slow speed default value that the system assumed. Am I wrong?
PST is the parallax serial terminal and is provided with the propeller tool. Start it and the screen will appear.
Parallax Serial Terminal.exe
Will take your other comments into account. Thanks for the help
That fixed it but I was under the impression that if you did not specify the clock, there was a slow speed default value that the system assumed. Am I wrong?
It's simply not accurate enough. The compiler fixes e.g. RCFAST at 12MHz. My chips usually run at 13.5MHz which sort of upsets the timing calculations for the serial driver.
I don't have a Propeller Tool because I don't have Windows to run it on. Mac an Linux users have the serial terminal built into BST which does not support special codes for screen clearing etc. You might want to bear this in mind for the non-Windows users in your audience.
Please run this program on your computer
Use PST to see what is going on
Tell me why I dont get a clean two line display on the PST.
{{ Program 017 PASM minimum PAR.spin
This program is a minimal implementation for two variables and PAR.
There are two Cogs in this program, one in SPIN and one in PASM
Cog 1 in SPIN displays the variables on the console
Cog 2 in PASM sets the variables to 1111 and 2222
Finds the location of PAR and moves it to mem1
Then mem2 is set to mem1 +4.
The two variables are transferred to mem1 and mem2
and become available to the SPIN environment
Loop.
}}
VAR
long sharedVar[2]
word clear
OBJ
fds: "FullDuplexSerial"
PUB Main 'displays values on console
fds.start(31,30,0,115200) 'start console at 115200 for debug output
cognew(@SecondCog, @SharedVar) 'start the second Cog in PASM
waitcnt(clkfreq/40+cnt) 'wait 1/4 for everything to stabilize.
clear:=0
repeat 'loop
fds.tx($1) 'home to 0,0
fds.dec(SharedVar) 'display first value
fds.tx($d) 'new line
fds.dec(SharedVar[1]) 'display second value
clear:=clear+1 'increment counter. This routine clears up screen
if clear>10 'decision point by erasing extra lines of bot
fds.tx(16) 'clear screen of PST display every 10 loops
clear:=0 'reset counter
waitcnt(clkfreq/6+cnt) 'flicker free wait
DAT
org 0 'start at 0 location in the cog
SecondCog 'start point identification
mov mem1, PAR 'find location of PAR, put in MEM1
mov mem2, mem1 'make MEM2=MEM1
add mem2, #4 'add 4 to MEM2
re_do wrlong var_one, mem1 'write variable to location MEM1
wrlong var_two, mem2 'write variable to location MEM2
jmp #re_do 'jump back, do it again
var_one long 1111 'variable declaration
var_two long 2222 'variable declaration
mem1 res 1 'first address storage space
mem2 res 1 'second address storage space
HSS
What do you think is wrong with this code? What have you done to isolate the failures so that 1) we know that it is not just being thrown out there for the others to solve gaining you nothing in additional knowledge to pass on, and 2) so that the extra eyes on this code do not have to guess what you may have already tried and end up needlessly duplicating your efforts?
FF
I thought that was way stronger than it needed to be.
I did not think there was anything wrong with the code but it would not work right. I don't ask for help unless I am really stuck and I do like to understand every line of code that I hope to include in my book. As it turned out it is more important to specify the clock frequency than I had imagined. And the clock has to be precisely defined. I was oblivious to that and it was explained to me in a very kind way. The code would have been OK if there was no communication to the PST. These are the finer points in the calculus. The kind of stuff beginners like me are likely to miss. And I did miss it. It was not a useless exercise. If there was already a book for beginners out there (written by someone like you) I would be reading it instead of puzzling all this out for myself and for others like me. On the other hand I do think that a book for beginners, written by you, would not be suitable for beginners like me. It would be way too advanced.
Maybe you need to consider notching it down a tad. I'm not in this to irritate you. I'm trying to learn and then teach.
As I was adding your comments on my commenting to my notes it occurred to me that it would be very helpful to my style if I had an example of a well commented file from you (and others). Could you re-comment my program (or another program of your choice) is a way that you felt was exemplar and re-post it.
Good idea Harprit. However it relies on the assumption that my actual commenting style is as good as I say your should be:)
The arguments about commenting style are endless as it is quite subjective. Part of the problem is that the style of commenting should be targeted at the reader audience. Rather like the style of the book itself.
When learning a new language or library API I find my self creating experimental code with excessively detailed comments. Basically because I have to remind myself of every little feature all the time. I've just been going through that recently with the OpenGL functions. But then when I am familiar with things the production code gets a lot more terse comments.Mainly because eventually it's tedious to see the same comments explaining the same little details all the time. It's partly because I know the future audience of my code will be more familiar with things, if they are not they will have to go through the same learning steps I did.
I think a good general rule is not say things in the comments that the programming language can say for itself. Hence my advice not to put a comment like "loop" next to a "repeat" statement. Or a comment like "increment A" next to a statement like A := A + 1".
Comments should tell what the intended function of objects and methods is. How the user can actually use them, what the parameters are etc.
Comments should point out any non-obvious things going on in the code, or surprises, or the reason why things are done as they are done. Things that the language cannot tell you for itself.
That was very illuminating. Lets keep in mind that I am writing to a beginner. Usually not the kind of guy that wants to find it all out for himself. My purpose in commenting every line is kind of strange and unusual. If you ignore to PASM code in my listings and read just the comments a line at a time if gives you a pseudo code of what needs to be done. Here is a listing. See if what I am trying to do is actually working. Since you are not supposed to read the PASM each line needs a comment.
Do you think this is an unsatisfactory way to do it for beginners?
This code reads a signal on a pin and chirps the speaker ever time the signal changes.
DAT org 0 'sets the starting point in Cog
Chirper mov dira, set_dira 'set direction register
loop1 mov temp, ina 'read inputs into temp
andn temp, mask0 wz 'isolate pin 1
if_nz jmp #loop1 'stay here if pin is 1
call #chirp 'call chirp routine
loop2 mov temp, ina 'read inputs
andn temp, mask0 wz 'isolate pin 1
if_z jmp #loop2 'stay here if pin is 0
call #chirp 'call chirp routine
jmp #loop1 'return to top
'subroutine
Chirp mov count, #6 'counter for number of chirps
mov delay, cnt 'load delay with clock counter
add delay, #9 'increment delay to get over overflow
:loop waitcnt delay, beat_delay 'delay
or outa, out_bit 'make speaker bit high
waitcnt delay, beat_delay 'delay
andn outa, out_bit 'make speaker bit low
sub count, #1 wz 'subtract 1 from counter
if_nz jmp #:loop 'loop back if not done w/counts
Chirp_ret ret 'return from chirp sub
set_dira long %00001011_00000000_00000000_00000111 'Set dira register
out_bit long %00000000_00000000_00000000_00000100 'out bit for speaker
mask0 long %11111111_11111111_11111111_11111110 'mask for bit 1
beat_delay long 70000
temp res 1 'temporary storage location
count res 1 'memory location for PAR variable
delay res 1 'delay constant for CNT
sub count, #1 wz 'subtract 1 from counter
if_nz jmp #:loop 'loop back if not done w/counts
...but an experienced programmer would use:
djnz count, #:loop ' decrement count, back to :loop if > 0
The djnz instruction has been optimized because it is so common. Your teaching the first way is akin to showing a child how to do a wobbly walk (which he/she will naturally do, anyway) instead of showing the correct practice in the first place....
I thought that was way stronger than it needed to be.
I did not think there was anything wrong with the code but it would not work right. I don't ask for help unless I am really stuck and I do like to understand every line of code that I hope to include in my book. As it turned out it is more important to specify the clock frequency than I had imagined. And the clock has to be precisely defined. I was oblivious to that and it was explained to me in a very kind way. The code would have been OK if there was no communication to the PST. These are the finer points in the calculus. The kind of stuff beginners like me are likely to miss. And I did miss it. It was not a useless exercise. If there was already a book for beginners out there (written by someone like you) I would be reading it instead of puzzling all this out for myself and for others like me. On the other hand I do think that a book for beginners, written by you, would not be suitable for beginners like me. It would be way too advanced.
Maybe you need to consider notching it down a tad. I'm not in this to irritate you. I'm trying to learn and then teach.
H
Not taken as irritant, just needed to know what you had checked and tried. Otherwise you could be swamped with multiple replies from the forum all telling you to check things you had already done probably twice over. Now that would be an irritant........
As to writing a book, I am way to incompetent on the prop. With over 16 years of writing and delivering technical training, the challenge to doing that would be time and desire to do it and the requisite time taken from family to do that since I gotta keep on working. Not happening, and that would be after I get to the level on the prop I would consider myself to be competent and experienced enough to consider such a project.
My main point was show us what you have done, how have you tried to solve your issue before throwing it to us. Most people prefer to help on this forum, but having all the data needed makes a big difference in how that help is given and how fast the issue is solved. In this case, you could have found it if you had a set starting checklist or framework if you did not realize that the clock set up was missing. If you had posted that you were trying to do this with the internal clock, someone would have immediately said that you were headed for shallow water on this one because unless as I saw somewhere you don't compensate for the fact that no prop is the exact same as another for internal clock, your serial comms will not work. From there someone would..... and so on.
I totally understand that your commenting style is geared to the beginner. Nothing wrong with that. I guess I got hooked up on that "repeat" - "loop" pair where the comment has no value at all, at least after the very first example of using "repeat" it is not required anymore.
In that last example I'd be careful with "jmp #loop1 'return to top". Problem here is that the "jmp" is not a "return" in the commonly accepted sense of calling a subroutine and returning from it. You see the room for confusion here.
As an aesthetic point, I like all my comments to begin with upper case letters and end with full stops They are written in the English language after all. Oh yea and one space between the comment marker and the first char of the comment.
Having Uppercase first chars and full stops means you can continue a comment over two or more lines, even at the side of code, and it reads nicely.
As for your chirping code, it chirps every time the pin changes. I'm sure detecting the pin change with XOR and having only one call to chirp would save some code in the "chirper" loop. Saving code space is not the point but less code is less to read and simpler understand.
Having done that there is only one call to chirp so it need not be a subroutine. There goes even more code....
OK. Lots of good stuff here. Thanks to every one. I will try to keep your ideas in mind as I proceed.
MY Next problem.
I cannot figure what makes everything in the par variables go to zero when I call a new method.
I start a new cog. I store four variables @someVariable
Sometimes I start a new cog and every thing stays in place and I call recall the @somevariables
Sometimes I start as new cog and everything goes to zeros
Lets not ask me to post code. Its gets too complicated. But I will if you insist.
Can we discuss what the rules are to keep from messing up. Simple rules suitable for beginners.
That was very illuminating. Lets keep in mind that I am writing to a beginner. Usually not the kind of guy that wants to find it all out for himself. My purpose in commenting every line is kind of strange and unusual. If you ignore to PASM code in my listings and read just the comments a line at a time if gives you a pseudo code of what needs to be done. Here is a listing. See if what I am trying to do is actually working. Since you are not supposed to read the PASM each line needs a comment.
Do you think this is an unsatisfactory way to do it for beginners?
This code reads a signal on a pin and chirps the speaker ever time the signal changes.
DAT org 0 'sets the starting point in Cog
Chirper mov dira, set_dira 'set direction register
loop1 mov temp, ina 'read inputs into temp
andn temp, mask0 wz 'isolate pin 1
if_nz jmp #loop1 'stay here if pin is 1
call #chirp 'call chirp routine
loop2 mov temp, ina 'read inputs
andn temp, mask0 wz 'isolate pin 1
if_z jmp #loop2 'stay here if pin is 0
call #chirp 'call chirp routine
jmp #loop1 'return to top
'subroutine
Chirp mov count, #6 'counter for number of chirps
mov delay, cnt 'load delay with clock counter
add delay, #9 'increment delay to get over overflow
:loop waitcnt delay, beat_delay 'delay
or outa, out_bit 'make speaker bit high
waitcnt delay, beat_delay 'delay
andn outa, out_bit 'make speaker bit low
sub count, #1 wz 'subtract 1 from counter
if_nz jmp #:loop 'loop back if not done w/counts
Chirp_ret ret 'return from chirp sub
set_dira long 001011_00000000_00000000_00000111 'Set dira register
out_bit long 000000_00000000_00000000_00000100 'out bit for speaker
mask0 long 111111_11111111_11111111_11111110 'mask for bit 1
beat_delay long 70000
temp res 1 'temporary storage location
count res 1 'memory location for PAR variable
delay res 1 'delay constant for CNT
H
Not sure what is meant by the statement "Since you are not supposed to read the PASM each line needs a comment."
As one progresses through PASM, it will become with repetition knowing what each instruction does, and can/should be read and understood. Teach to not comment the obvious, confusing and obfuscating the big picture. Many of the comments in this code are appropriate as they expose intent. A good comment on the function of the routine and comments on variable definitions go a long way to understanding. As PASM gets more understandable, many of your comments should drop out anyway. The chirp routine really only needs a description of what it does after which even the newbie should be able to puzzle it out because there are no real hidden or less than evident things going on here. Sure, the newb may have to bounce between the prop book and the code a few times, but if the vars are properly described as to their use, reading the code becomes quite clear and is a good exercise for the newb anyway.
I would comment the Chirp routine with a standalone comment that it is used to make a chirp sound when called. First comment ok, number of chirps. Cool. Second line obvious what code does, but what is the delay for? Third, why magic number 9? Newb won't know why unless the text or comment tells him it accounts for the time from when the count value was stored until the wait count was actually called and why it is needed (I had lots of fun with this one in my ADC objects.....). Maybe make the first comment get count and adjust n counts until waitcnt actually called. The text will hopefully explain thios concept prior to exploring the code.
Course as Heater has hinted at, only politics, religion, and coding methods and languages have caused as many flame wars as commenting and even coding style in general. Well may be OS's also......
Short answer, don't comment the obvious.
Frank
The more proficient one becomes reading and understanding, the faster they will be able to code in it as there won't be as much need to constantly go to references to figure out how to accomplish something.
I cannot figure what makes everything in the par variables go to zero when I call a new method.
re: [post=1065430]post #512[/post], are you sure you look at the same set of variables? Over there you have 3 (local) sets. And don't just think they are the same, prove it. If they are then someone is obviously clearing them. Find out where.
I'm still not clear about this passing variables bit:
Question
This is regard variable stored with the PAR pointer.
If I store 1 variable in the PAR area in one Cog, first location
and another variable in PAR, second location using Cog two
Should not I be able to read both variable from a third Cog if all cogs are started passing the same variable array
I am having trouble doing this.
Here is the code, use PST to view results
WHY IS THE SECOND VARIABLE SCREWED UP?
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
bits =32
pots=2
VAR
long P_Val[2]
long pot_sub
OBJ
fds : "FullDuplexSerial"
PUB Go
fds.start(31,30,0,115200) 'start console at 115200 for debug output
main
waitcnt(clkfreq/40 +cnt)
repeat 'endless loop
pot_sub:=0 'reset id of pot to be printed
fds.tx($1) 'home to 0,0
repeat pots 'loop to display data
fds.bin(P_val[pot_sub], bits) 'print to the PST in binary
repeat 2 'two spaces
fds.tx(" ") 'space to erase old data overflow
fds.dec(P_val[pot_sub]) 'print value as decimal value
repeat 2 'two spaces
fds.tx(" ") 'space to erase old data overflow
fds.dec(pot_sub) 'print value as decimal value
repeat 3 'three spaces
fds.tx(" ") 'space to erase old data overflow
fds.tx($d) 'new line
pot_sub:=(pot_sub)+1 'increment display counter
waitcnt(clkfreq/60+cnt) 'flicker free wait
PUB Main
dira[0..2]~~
Cog1(@P_Val)
Cog2(@P_Val)
PUB Cog1(address)
cognew(@C_og1, address)
PUB Cog2(address)
cognew(@C_og2, address)
Dat org 0
C_og1
loop1 mov mem, par
wrlong one, mem
jmp #loop1
C_og2
loop2 mov mem, par
add mem, #4
wrlong two, mem
jmp #loop2
one long 1
two long 2
mem res 1
Is it true that you can only start one new PASM Cog from any one object
(Though you can call many objects)
and is it because you can only have one "org 0" in any one DAT declaration
Dat org 0
C_og1
loop1 mov mem, par
wrlong one, mem
jmp #loop1
one long 1
two long 2
mem res 1
Dat org 0
C_og2
loop2 mov _mem, par
add _mem, #4
wrlong _two, _mem
jmp #loop2
_one long 1
_two long 2
_mem res 1
... and is it because you can only have one "org 0" in any one DAT declaration
There is no such limitation. Nothing is stopping you from having say 42 org directives in a single file (and any number of DAT blocks). Most commonly you'll have one each (single cog image) though.
Comments
There Are three programs. Each will run on its own also. They are called within each other
The mother program is the first one. Also run the Propeller Serial Terminal to see what is going on.
For best results copy them and run them in your prop tool as three files
HArprit
The second "022....." cog reads 4 potentiometers and stores the values in hub memory. It calls nothing. Only the first pot read will be used.
The third file "mSecDelay2" takes what is in the first pot and divides the clock values by it to get a frequency. It then generates this freq on line 1. This is the frequency of the metronome.
File one "MSecdelay" looks at line 1 and provides a chirp on line 3 every time the signal changes. The output goes to a speaker.
The problem is that I cannot read the pot all the way to the first file.
H
Change is indicated on pin 16 (inverts LED every time a change is detected), the other object generates a square wave on pin 17 using the data value for NCO setup.
The role(s) of each object can be changed, i.e. data can be generated in a child object.
I just wanted to tell you that I found this thread about a week ago and I have read every entry. I am learning PASM and your learning experience has proven to be a real treasure trove for my own. There have been a great number of things I have learned to do including getting up and going with the PASD debugger which, although simple, is a great way to watch variables... especially pointers to variables.
You are a real trooper to joust with the pros and I think your effort is a noble one.
As for the pros, these guys are awesome and it is a real delight for me to see how the mystery of their code gets figured out by running on my own props.
I look forward to seeing your book someday and I also hope some more advanced treatments may get published by the experts in this forum.
Propeller assembler is loads of fun to work with and a great way for me to keep my mind active during the winter months.
Thank you.
SM
Use PST to see what is going on
Tell me why I dont get a clean two line display on the PST.
HSS
Where are your clock settings. I had to add them:
I'm not so happy with the commenting style. Having a comment "loop" next to a "repeat" statement is pointless, clutters up the page and is annoying. As this a book on PASM not Spin one should not have to be explaining what the Spin keywords are all the time.
Similarly the "add 4 to MEM2" conveys no information, presumably the operation of ADD is explained by now.
PST is the parallax serial terminal and is provided with the propeller tool. Start it and the screen will appear.
Parallax Serial Terminal.exe
Will take your other comments into account. Thanks for the help
HSS
====================================
[FONT=Arial, sans-serif]SM
Thanks for your comments. I'm enjoying it. Book should be done some time late spring.
HSS [/FONT]
What do you think is wrong with this code? What have you done to isolate the failures so that 1) we know that it is not just being thrown out there for the others to solve gaining you nothing in additional knowledge to pass on, and 2) so that the extra eyes on this code do not have to guess what you may have already tried and end up needlessly duplicating your efforts?
FF
I thought that was way stronger than it needed to be.
I did not think there was anything wrong with the code but it would not work right. I don't ask for help unless I am really stuck and I do like to understand every line of code that I hope to include in my book. As it turned out it is more important to specify the clock frequency than I had imagined. And the clock has to be precisely defined. I was oblivious to that and it was explained to me in a very kind way. The code would have been OK if there was no communication to the PST. These are the finer points in the calculus. The kind of stuff beginners like me are likely to miss. And I did miss it. It was not a useless exercise. If there was already a book for beginners out there (written by someone like you) I would be reading it instead of puzzling all this out for myself and for others like me. On the other hand I do think that a book for beginners, written by you, would not be suitable for beginners like me. It would be way too advanced.
Maybe you need to consider notching it down a tad. I'm not in this to irritate you. I'm trying to learn and then teach.
H
As I was adding your comments on my commenting to my notes it occurred to me that it would be very helpful to my style if I had an example of a well commented file from you (and others). Could you re-comment my program (or another program of your choice) is a way that you felt was exemplar and re-post it.
H
The arguments about commenting style are endless as it is quite subjective. Part of the problem is that the style of commenting should be targeted at the reader audience. Rather like the style of the book itself.
When learning a new language or library API I find my self creating experimental code with excessively detailed comments. Basically because I have to remind myself of every little feature all the time. I've just been going through that recently with the OpenGL functions. But then when I am familiar with things the production code gets a lot more terse comments.Mainly because eventually it's tedious to see the same comments explaining the same little details all the time. It's partly because I know the future audience of my code will be more familiar with things, if they are not they will have to go through the same learning steps I did.
I think a good general rule is not say things in the comments that the programming language can say for itself. Hence my advice not to put a comment like "loop" next to a "repeat" statement. Or a comment like "increment A" next to a statement like A := A + 1".
Comments should tell what the intended function of objects and methods is. How the user can actually use them, what the parameters are etc.
Comments should point out any non-obvious things going on in the code, or surprises, or the reason why things are done as they are done. Things that the language cannot tell you for itself.
That was very illuminating. Lets keep in mind that I am writing to a beginner. Usually not the kind of guy that wants to find it all out for himself. My purpose in commenting every line is kind of strange and unusual. If you ignore to PASM code in my listings and read just the comments a line at a time if gives you a pseudo code of what needs to be done. Here is a listing. See if what I am trying to do is actually working. Since you are not supposed to read the PASM each line needs a comment.
Do you think this is an unsatisfactory way to do it for beginners?
This code reads a signal on a pin and chirps the speaker ever time the signal changes.
H
...but an experienced programmer would use:
The djnz instruction has been optimized because it is so common. Your teaching the first way is akin to showing a child how to do a wobbly walk (which he/she will naturally do, anyway) instead of showing the correct practice in the first place....
Not taken as irritant, just needed to know what you had checked and tried. Otherwise you could be swamped with multiple replies from the forum all telling you to check things you had already done probably twice over. Now that would be an irritant........
As to writing a book, I am way to incompetent on the prop. With over 16 years of writing and delivering technical training, the challenge to doing that would be time and desire to do it and the requisite time taken from family to do that since I gotta keep on working. Not happening, and that would be after I get to the level on the prop I would consider myself to be competent and experienced enough to consider such a project.
My main point was show us what you have done, how have you tried to solve your issue before throwing it to us. Most people prefer to help on this forum, but having all the data needed makes a big difference in how that help is given and how fast the issue is solved. In this case, you could have found it if you had a set starting checklist or framework if you did not realize that the clock set up was missing. If you had posted that you were trying to do this with the internal clock, someone would have immediately said that you were headed for shallow water on this one because unless as I saw somewhere you don't compensate for the fact that no prop is the exact same as another for internal clock, your serial comms will not work. From there someone would..... and so on.
Sorry if it sounded too harsh,
FF
I totally understand that your commenting style is geared to the beginner. Nothing wrong with that. I guess I got hooked up on that "repeat" - "loop" pair where the comment has no value at all, at least after the very first example of using "repeat" it is not required anymore.
In that last example I'd be careful with "jmp #loop1 'return to top". Problem here is that the "jmp" is not a "return" in the commonly accepted sense of calling a subroutine and returning from it. You see the room for confusion here.
As an aesthetic point, I like all my comments to begin with upper case letters and end with full stops They are written in the English language after all. Oh yea and one space between the comment marker and the first char of the comment.
Having Uppercase first chars and full stops means you can continue a comment over two or more lines, even at the side of code, and it reads nicely.
As for your chirping code, it chirps every time the pin changes. I'm sure detecting the pin change with XOR and having only one call to chirp would save some code in the "chirper" loop. Saving code space is not the point but less code is less to read and simpler understand.
Having done that there is only one call to chirp so it need not be a subroutine. There goes even more code....
MY Next problem.
I cannot figure what makes everything in the par variables go to zero when I call a new method.
I start a new cog. I store four variables @someVariable
Sometimes I start a new cog and every thing stays in place and I call recall the @somevariables
Sometimes I start as new cog and everything goes to zeros
Lets not ask me to post code. Its gets too complicated. But I will if you insist.
Can we discuss what the rules are to keep from messing up. Simple rules suitable for beginners.
H
Not sure what is meant by the statement "Since you are not supposed to read the PASM each line needs a comment."
As one progresses through PASM, it will become with repetition knowing what each instruction does, and can/should be read and understood. Teach to not comment the obvious, confusing and obfuscating the big picture. Many of the comments in this code are appropriate as they expose intent. A good comment on the function of the routine and comments on variable definitions go a long way to understanding. As PASM gets more understandable, many of your comments should drop out anyway. The chirp routine really only needs a description of what it does after which even the newbie should be able to puzzle it out because there are no real hidden or less than evident things going on here. Sure, the newb may have to bounce between the prop book and the code a few times, but if the vars are properly described as to their use, reading the code becomes quite clear and is a good exercise for the newb anyway.
I would comment the Chirp routine with a standalone comment that it is used to make a chirp sound when called. First comment ok, number of chirps. Cool. Second line obvious what code does, but what is the delay for? Third, why magic number 9? Newb won't know why unless the text or comment tells him it accounts for the time from when the count value was stored until the wait count was actually called and why it is needed (I had lots of fun with this one in my ADC objects.....). Maybe make the first comment get count and adjust n counts until waitcnt actually called. The text will hopefully explain thios concept prior to exploring the code.
Course as Heater has hinted at, only politics, religion, and coding methods and languages have caused as many flame wars as commenting and even coding style in general. Well may be OS's also......
Short answer, don't comment the obvious.
Frank
The more proficient one becomes reading and understanding, the faster they will be able to code in it as there won't be as much need to constantly go to references to figure out how to accomplish something.
I will be showing compacted, more efficient code in the programs as I get further down the book.
Not quite ready yet.
Thanks again.
K:
I'm taking a closer look at the code as suggested.
H
I'm still not clear about this passing variables bit:
Question
This is regard variable stored with the PAR pointer.
If I store 1 variable in the PAR area in one Cog, first location
and another variable in PAR, second location using Cog two
Should not I be able to read both variable from a third Cog if all cogs are started passing the same variable array
I am having trouble doing this.
Here is the code, use PST to view results
WHY IS THE SECOND VARIABLE SCREWED UP?
H
Cog 2 must be started in another object
H
Is it true that you can only start one new PASM Cog from any one object
(Though you can call many objects)
and is it because you can only have one "org 0" in any one DAT declaration
H
I thought it was because both cogs started at ORG 0 but I may be wrong
H
I would expect that according to your example. You are passing the same address to Cog1 and Cog2. I.E.
There is no such limitation. Nothing is stopping you from having say 42 org directives in a single file (and any number of DAT blocks). Most commonly you'll have one each (single cog image) though.