This thread is becoming an interesting study in so many things that may or may not be helpful to Harprit and his efforts. This posting certainly follows those lines!
...
This is one of the most wonderful posts I've read in a while. Thank you for taking the time to write it.
Back to basic guys!
I know this is not quite right but...
Why does this not open up a third cog and toggle line 12
It compiles but I get a dead line 12
In other word, how do you start two PASM cogs
PUB null | P_Val, Delay_Val
cognew(@generate, @P_Val) ' start second cog at "generate"
cognew(@Toggle, @Delay_Val) 'start third cog at toggle
repeat
'do something unrelated to other cogs
DAT
Org 0
generate mov outa, set_dira
jmp #generate
org 30
toggle mov dira, set_dira
mov outa, pin_hi
mov outa, pin_lo
jmp #toggle
'Constants. This section is similar to the CON block in SPIN
Set_dira long %00000001_00000000_00010000_00000000 'Set dira register
Pin_Hi long %00000000_00000000_00010000_00000000
Pin_Lo long %00000000_00000000_00010000_00000000
My goal is to provide enough information to allow someone who knows nothing about
binary math
PASM
assembly language
jargon infested writings
to want to mess around with PASM and his propeller chip
Maybe inspire him or her to learn more from you guys.
I will keep in very simple and disappoint some of you who think there is no way I can get this done
Here is letter from some one who know very little but is very excited. I got it this morning.
All he is really turned on about is controlling a few LEDs.
Hopefully some day he will make a great Tech or even an Engineer. Made my day.
Dear Sir:
I am enjoying your book immensely! I especially enjoyed seeing your section on page 23/24, A Fundamental Reality We Have to Consider, as I need to have LEDs on all my I/O pins (not multiplexed, and more than 10 ma. per pin -- very bright). I plan on using a LYP47F reverse mount LED from OSRAM (sold by Mouser). (The reverse mount and small size are why I chose that style.)
I was a bit surprised to see the 7404 driving LEDs, so I set up six on a chip with 470 ohms as you suggested. Ran all afternoon until I had to shut down and go home! I measured the total chip current (ICCL = 49.2 ma). This exceeded the data sheet spec (33 ma max) a bit but did not blow any outputs. As a personal hobby application or learning situation I can see the 7404 working fine.
However, I have been looking for a long time for a chip for product development where reliability and safety margins can be considered in the design. I am wondering if you might know of anything more robust (and as simple as the 7404) that you could suggest where I would have more driving current per LED. You are the only author that has addressed the situation I face. (Another issue was how to interface a 5 volt family to the Propeller. So I thank you for moving me forward on my project!)
I am looking forward to the remainder of your book. Very well done.
(I like that fact that you do not repeat all the material in other reference sources, but direct the reader to the sources. That makes your book a faster/easier read and more pages for what it is you want to guide us through.)
Lots of things going on here - not sure most of them are what you intend.
First, the startup state on a reset or freshly started COG for the direction register (DIRA) is 0, that is, all pins set as INPUT
Your first COGNEW starts a COG at address 0 (generate) and begins program execution there
1) move the contents of Set_dira to the outa register (this sets bits 12 and 24 to 1, BUT the DIRA register is still INPUT
2) jump back to 1
You've never set DIRA to output, you'll never see bits 12 and 24 anywhere.
Your second COGNEW starts execution in a new cog at address toggle
1) you set DIRA bits 12 and 24 to output
2) you set OUTA bit 12 HIGH
3) you set OUTA bit 12 HIGH (even though the label says Pin_Lo, you still have a 1 bit at bit 12)
4) you jump back to #1 and do the same things
Even if you did set bit 12 LO in #3, it woudl be toggling so fast, you would need an oscilscope or logic probe to see it.
Here's code from Potatohead's tutorial that does what you want - two cogs blinking two leds. I was running this on a Quickstart, so it blinks pin 16 and 17
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB Main
' a freshly started COG has OUTA = 0 and DIRA = 0 - this is where understanding the HW is important
cognew(@Toggle, 0) ' start a COG at address Toggle
cognew(@Toggle1, 0) ' start a COG at address Toggle1
DAT
{Toggle Pin 16}
ORG 0 ' Begin at COG RAM address 0
Toggle
mov dira, Pin16 ' move CONTENTS of COG Memory Pin16 to DIRA register
' This sets PIN 16 to OUTPUT
mov Time, cnt ' move CONTENTS of CNT register to COG Memory address Time
add Time, #$f ' bump the counter a bit (trust me on this one for now)
:loop
waitcnt Time, Delay ' Tell this COG to wait until the CNT register equals the contents of Time
' when CNT = Time, start the COG and add contents of Delay to Time for the next loop
xor outa, Pin16 ' toggle bit 16 of OUTA (this is where understanding BINARY operations
' comes into play)
jmp #:loop ' jump to :loop - need the # in this case since you want the IMMEDIATE address
'
Pin16 long |< 16 ' %00000000_00000001_0000000_00000000 if you prefer
Delay long 5_000_000 ' delay for 5_000_000 clock ticks
Time res 1 ' a place to save the WAITCNT value
{Toggle Pin 17} ' similar code for the second PIN (PIN#17)
ORG 0
Toggle1 mov dira, Pin17
mov Time1, cnt
add Time1, #$F
:loop waitcnt Time1, Delay1
xor outa, Pin17
jmp #:loop
Pin17 long |< 17
Delay1 long 80_000_000
Time1 res 1
When I was learning assembler way back when, I was always told to "play computer" it might sound dumb but it really helps to go through each instruction and do everything the computer has to do. If you understand how the computer works for each instruction, you can "play computer" through ANY program.
P.S. This is not how I usually comment code but for instructional purposes, step by step comments are often helpful. I normally despise code such as:
For now, just FYI
If I eliminate the initial "jmp generate" instruction,
the I/O works fine and I can see it on the scope just fine so that part seems OK
Pin 24 should not make any difference to the cog running.
It was a mistake but its not critical.
I removed it, nothing changed
That's a tough call
I will add LEDs to this code for now but eventually we will need a scope.
Its really a very basic piece of equipment every serious beginner need to learn how to use.
Just too much stuff that goes too fast to not own one. Its our eyes in electronics.
Note to self: After building things since 1975, I need to buy a scope to be a serious beginner.
@Harpirt: I removed the jmp #generate and I got no output on either pin when I watched it through the logic probe on Gear. If you watch COG1 and COG2 run, you see them looping through all of COG memory and they just happen to execute your instructions as they loop.
If I remove the jmp #generate AND the 'ORG 30' I get a steady HIGH on PIN 12 and a pulsed pin 24. COG1 and COG2 are at least inthe tight loop inside your code.
Both COGs are running through the same code path pulsing the same pin at the same rate. I can't imagine this is what you intended by your example. I'm not sure what concept this shows your reader.
The example I attached from Potatohead's tutorial shows two COGs pulsing two LEDs at two different rates - this at least shows independent COG funtions.
I'm not trying to be difficult, just providing feedback from 'a PASM beginner'.
Back to basic guys!
I know this is not quite right but...
Why does this not open up a third cog and toggle line 12
It compiles but I get a dead line 12
In other word, how do you start two PASM cogs
PUB null | P_Val, Delay_Val
cognew(@generate, @P_Val) ' start second cog at "generate"
cognew(@Toggle, @Delay_Val) 'start third cog at toggle
repeat
'do something unrelated to other cogs
DAT
Org 0
generate mov outa, set_dira
jmp #generate
org 30
toggle mov dira, set_dira
mov outa, pin_hi
mov outa, pin_lo
jmp #toggle
'Constants. This section is similar to the CON block in SPIN
Set_dira long %00000001_00000000_00010000_00000000 'Set dira register
Pin_Hi long %00000000_00000000_00010000_00000000
Pin_Lo long %00000000_00000000_00010000_00000000
Some observations:
As mentioned in #127: Pin_Hi and Pin_Lo both have bit 12 set and thus no toggling.
Referring to post #128: removing "jmp #generate" just makes both cogs run the same loop.
"toggle" is at "generate" cog's address 2 (or address 1 if you get rid of "jmp #generate").
Remember that saying org 30 does not change the cog start address.
What was strange (and unexpected to PASM newbie, me) The code generated sequentially, 0 thru 4 or 5 but the ORG 30 caused the label 'toggle' to be at $1E. This caused the jmp to go to $1E and then execute code from there to the end of COG memory. This is a least how GEAR simulated it.
I was expecting the ORG 30 to cause a hole in the COG memory.....I expected incorrectly. I have much to learn!
@Steve, it's an honor to be quoted!
I guess MOV OUTA, PEACE only shows if you're sure of your direction!
2) I don't know Kuroneko but respect his knowledge and talent and genius. I assume he didn't just walk in one day from being a frustrated musician and decide to download the Propeller datasheet and start writing complex PASM code.
Apologies when this came accross as you only need the datasheet. At the time I already had lots of experience with different chips so the datasheet was sufficient. Also, I started simple, working my way up ... and I can't even play an instrument ...
Well, I finally got two Cogs working at the same time in PASM. Took all day.
My problem was that I did not appreciate that each cog has to be defined completely with
all its subroutines, variables and constants before you enter ORG 0 and start
defining the second Cog and all its goodies.
And you cannot duplicate variable names even across cogs (Which I thought was rather strange)
And you cannot duplicate variable names even across cogs (Which I thought was rather strange).
Global (variable) labels that is. After all, it's still the same DAT block. You could work around that issue by using local labels (which are sufficently separated by the main label), e.g.
DAT org 0
one mov :b, :a
' ...
:a long 0
:b res 1
DAT org 0
[COLOR="orange"]two[/COLOR] neg :b, :a
' ...
:a long 0
:b res 1
And be careful with multi cog images in the same file. You can easily end up with one image referencing a symbol in another.
I will post complete listing after I clean it up tomorrow. But essentially......
The problem I am having is that I read a potentiometer into a global variable in one Cog
I add the global variable to another variable in a second Cog and it acts like it is 0 all the time. (I know that for sure)
(It actually varies 12 bits from 0 to 4095. And I know that for sure)
What up?
I though it might be something really silly on my part that you have seen 1000 times.
No, not using HUB instruction
Lets wait till I can post the code.
Using PAR for transfer to the SPIN cog but both my other cogs are using PASM
Par to SPIN works fine, thats how I know variable is being read right.
One PASM cog determines variable (and xfers to SPIN via PAR) but the other one will not read it as same global name.
There is the shared HUB-RAM and to each cog exclusive COG-RAM
If you want to transfer a value from one cog to another the only way is
writing the value from COG1-RAM WRLONG ==> HUB-RAM
then reading the HUB-RAM with COG2 RDLONG COG2-RAM <=== HUB_RAM
I think it is the same with the HUB-RAM-adress itself too.This means declare a SPIN-variable and start the two cogs
from SPIN. If you want to start the second cog from PASM do I remember right that DIRB and OUTB are existing as registers that are just not connected to any hardware?
But can be used as some kind of global scratchpad-RAM that is easy adressable?
If you want to transfer a value from one cog to another the only way is writing the value from COG1-RAM WRLONG ==> HUB-RAM then reading the HUB-RAM with COG2 RDLONG COG2-RAM <=== HUB_RAM
Have a look at [thread=129585]this thread[/thread] when you have a minute
I agree there is more than one way to communicate between cogs.
Would you mind answering the question about DIRB/OUTB as scratchpad-RAM
or do you insist on test it yourself :-)
Would you mind answering the question about DIRB/OUTB as scratchpad-RAM or do you insist on test it yourself :-)
I wasn't quite sure about your use of global (unless you meant that in the context of a single cog). Both registers are just that, registers. No side effects, no outside connection(s). So feel free to use them. If you don't actively use counters then those registers are free as well. Which is true for nearly every SPR. Personally I stay away from dira for storage/code and vscl for code.
I think Cluso's debugger uses the first four SPRs and somewhere there is a cog storage object which uses the whole SPR area.
I am ready to post my program but the read/write routine is not working to my satisfaction (or at all)
So the program is not runnable.
The problem is that I can not read and write across two PASM cogs accurately.
I am using WRLONG and RDLONG to main memory per the PASM manual (and Stephan in #143)
I have a question (here is what I am doing)
If I have a variable "data_read"
in a PASM cog and then write
WRLONG data_read, temp_var
data_read res 1 'later on in the program to set up the variable
and then read Temp_var into a second PASM cog with
RDLONG time, temp_var
should it work?..It should the way I read it.
It does not for some reason, in my program. I get 0.
It would be so much easier to help if you just post your code. No guessing.
Is temp_var an address pointing to a hub memory location?
RDLONG D, S ' D is the variable you want to read to and S is where you want to read from.
WRLONG D, S ' D is the variable you want to write and S is where you want to write to.
I am ready to post my program but the read/write routine is not working to my satisfaction (or at all)
So the program is not runnable.
The problem is that I can not read and write across two PASM cogs accurately.
I am using WRLONG and RDLONG to main memory per the PASM manual (and Stephan in #143)
I have a question (here is what I am doing)
If I have a variable "data_read"
in a PASM cog and then write
WRLONG data_read, temp_var
data_read res 1 'later on in the program to set up the variable
and then read Temp_var into a second PASM cog with
RDLONG time, temp_var
should it work?..It should the way I read it.
It does not for some reason, in my program. I get 0.
I am hesitant to do this because it is not cleaned up
I will clean it up later. This is per JAZZED request
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB null | P_Val
cognew(@generate, @P_Val) ' start new cog at "generate" and read variable at P_Val
cognew(@Toggle, 0) ' start new cog at Toggle
'===========================================================================================================================
'=======================================COG 1 works fine====================================================================
'===========================================================================================================================
dira[0 ..11]~~ ' all lines are outputs except 26
repeat ' endless loop to display data
outa[0..11] := P_Val ' displays 1.5 bytes of data
DAT
'===========================================================================================================================
'=======================================COG 2 works fine====================================================================
'===========================================================================================================================
org 0 'sets the starting point in Cog
generate mov dira, set_dira 'sets direction of the prop pins
call #chip_sel_lo 'selects chip by pulling line low
call #Clk_lo 'START. Clock needs to be low to load data
call #Din_hi 'must start with Din high to set up 3208
call #Tog_clk 'clk hi to read data
call #Din_Hi 'SINGLE DIFF Low to load
call #Tog_Clk 'toggle clock line hi then low to read in the data
call #Din_Lo 'D2 Low to load input line selection sequence 000 for line 0
call #Tog_Clk 'toggle clock line hi then low to read in the data
call #Din_Lo 'D1 Low to load input line selection sequence 000 for line 0
call #Tog_Clk 'toggle clock line hi then low to read in the data
call #Din_Lo 'D0 Low to load input line selection sequence 000 for line 0
call #Tog_Clk 'toggle clock line hi then low to read in the data
call #Din_Lo 'blank bit needs a clock cycle, next
call #Tog_Clk 'toggle clock line hi then low to read in the data
'next toggle is for the null bit, nothing read
call #Tog_Clk 'toggle clock line hi then low to read in the data
mov dat_red, #0 'Clear register we will read data into
mov count, #12 'Counter for number of bits we will read
read_bit mov temp, ina 'read in what is in all the input lines
andn temp, inputmask wz 'mask off everything except Dout line. Set Z flag
if_nz add Dat_red, #1 'if value is still positive add 1 to data register
ror Dat_red, #1 'roll register right 1 bit to get ready for next bit
call #Tog_Clk 'toggle clock to get next bit ready in Dout
sub count, #1 wz 'decrement the "bits read" counter. Set Z flag
if_nz jmp #read_bit 'go up and do it again if counter not 0
rol dat_red, #12 'roll back 12 bits to get data into 12 LSBits of register
wrlong dat_red, par 'put it in PAR to share it as P.Val
call #Chip_Sel_Hi 'Put chip to sleep by delselecting it, for low power usage
rdlong dat_red, temp2 'get data that as read **********************************************************
jmp #generate 'go back to do it all again
'Subroutines
Clk_Hi mov temp, outa 'Get the OUTA register
or temp, clk_bit 'OR it with the Clock Bit to male high
mov outa, temp 'put it back in OUTA register
Clk_Hi_ret ret
Clk_Lo mov temp, outa 'Get the OUTA register
andn temp, clk_bit 'ANDN it with the Clock Bi to make lowt
mov outa, temp 'put it back in OUTA register
Clk_Lo_ret ret 'return from this subroutine
Tog_Clk call #Clk_hi 'make clock bit high
call #clk_lo 'make clock bit low
Tog_Clk_ret ret 'return from this subroutine
Din_Hi mov temp, outa 'Get the OUTA register
or temp, din_Bit 'Makes the Din high
mov outa, temp 'put it back in OUTA register
Din_Hi_ret ret 'return from this subroutine
Din_Lo mov temp, outa 'Get the OUTA register
andn temp, din_Bit 'makes Din low
mov outa, temp 'put it back in OUTA register
Din_Lo_ret ret 'return from this subroutine
Chip_Sel_Hi mov temp, outa 'Get the OUTA register
or temp, chs_Bit 'Makes Chip select high
mov outa, temp 'put it back in OUTA register
Chip_Sel_Hi_ret ret 'return from this subroutine
Chip_Sel_Lo mov temp, outa 'Get the OUTA register
andn temp, chs_Bit 'makes chip select low
mov outa, temp 'put it back in OUTA register
Chip_Sel_Lo_ret ret 'return from this subroutine
Read_Dout mov temp, ina 'Get the INA register
Read_Dout_ret ret 'return from this subroutine
Read_Next_Bit mov temp, ina 'Get the INA register
or temp, inputmask 'mask all but Din bit
Read_Next_Bit_ret ret 'return from this subroutine
'Constants. This section is similar to the CON block in SPIN
Set_dira long %00001011_00000000_00000000_00000000 '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
inputmask long %11111011_11111111_11111111_11111111 'Mask for reading the Dout bit only
'Variables. This section is similar to the VAR block in SPIN
temp res 1 'temporary storage variable
temp2 res 1 'temporary storage variable
count res 1 'temporary storage variable
Dat_Red res 1 'temporary storage variable
'===========================================================================================================================
'=======================================COG 3 can't move temp2 into variable effectively====================================
'===========================================================================================================================
org 0 'begin a 0
toggle mov dira, pin_12 'set pin 12 as output
toggle1 mov temp1, outa 'read in outa
or temp1, pin_12 'make pin 12 lo
mov outa, temp1 'put it back in outa
call #clkdelay 'call the delay subroutine
mov temp1, outa 'read in outa
andn temp1, pin_12 'make pin 12 high
mov outa, temp1 'put it back in outa
call #clkdelay 'call the delay subroutine
jmp #toggle1 'repeat
clkdelay rdlong time, temp2 'the delay subroutine,load TEMP2 into time ********ACTS LINE TEMP2=0************************
add time, #$1f 'delay added to skip past underflow of CNT
dloop sub time, #1 wz 'sub 1 from time and set flag if 0
if_nz jmp #dloop 'if flag not 0 go back to take4
clkdelay_ret ret 'return for delay subroutine
'Constants. This section is similar to the CON block in SPIN
Pin_12 long %00000000_00000000_00010000_00000000
del_time long 400
'Variables. This section is similar to the VAR block in SPIN
deltime2 res 1 'temporary storage variable
temp1 res 1 'temporary storage variable
time res 1 'temporary storage variable
You have to create variables for each cog that contains the hub address for rdlong/wrlong.
Using temp2 will not work because it contains some other data (it can be forced to work with advanced understanding of SPIN/PASM).
Here's a simple sharedmem.spin example (as simple as i know how to make it).
''
'' SIMPLE share data demo
''
con ' clock setup
_clkmode = xtal1 + pll16x
_clkfreq = 80_000_000
var ' hub shared memory section. variables must be kept in this order
long share ' share is set to par
long data ' data is at share address + 4
'===============================
' test harness
obj
sx : "FullDuplexSerial"
pub main
'' program main entry point
sx.start(31,30,0,115200) ' start console at 115200 for debug output
start ' start the producer and consumer cogs
repeat ' print shared data every second
sx.hex(share, 8)
sx.tx(" ")
sx.hex(data, 8)
sx.tx($d)
waitcnt(_clkfreq+cnt)
'===============================
pub start
'' start producer and consumer cogs
cognew(@producer, @share)
cognew(@consumer, @share)
waitcnt(_clkfreq+cnt)
dat org
'---------------------------------
' producer is used to write incrementing data to two shared hub variables
'
producer
' par will have the hub address of share
' padr will have the hub address of data
' let's put the address of data in padr
mov padr, par ' save par to padr
add padr, #4 ' reference the second long in the shared memory
' will increment pshare and pdata in the loop for writing
' set pshare and pdata to known values
mov pshare, #0 ' could have used "pshare long 0" instead below
mov pdata, #0 ' could have used "pdata long 0" instead below
'---------------------------------
' main program loop
'
:loop
add pshare, #1 ' increment variable
wrlong pshare, par ' write pshare to hub share variable
add pdata, #1 ' increment variable
wrlong pdata, padr ' write pdata to hub data variable
jmp #:loop
'---------------------------------
' variables
'
pshare res 1
pdata res 1
padr res 1
dat org
'---------------------------------
' consumer is used to read producer data from two shared hub variables
'
consumer
' par will have the hub address of share
' cadr will have the hub address of data
' let's put the address of data in cadr
mov cadr, par ' save par to padr
add cadr, #4 ' reference the second long in the shared memory
'---------------------------------
' main program loop simply reads from shared memory
'
:loop
rdlong cshare, par ' read pshare from hub share variable
rdlong cdata, cadr ' read pdata from hub data variable
jmp #:loop
'---------------------------------
' variables
'
cshare res 1
cdata res 1
cadr res 1
if I remember right all predefined longs (constants) like
'Constants. This section is similar to the CON block in SPIN Set_dira long %00001011_00000000_00000000_00000000 '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 inputmask long %11111011_11111111_11111111_11111111 'Mask for reading the Dout bit only
and all reserved longs (not predefined) acting as variables
'Variables. This section is similar to the VAR block in SPIN temp res 1 'temporary storage variable temp2 res 1 'temporary storage variable count res 1 'temporary storage variable Dat_Red res 1 'temporary storage variable
should be placed behind the last PASM-command.
temp2 that should contain the HUB-RAM-adress is never initialised with a valid HUB-RAM-adress.
You start a second cog for toggling the IO-pin 12
The code uses temp2 as the HUB-RAM-adress. But here it is the same temp2 is not initialised with a valid HUB-RAM-adress
As you start the second cog from SPIN too you simply use the second parameter there too.
instead of
cognew(@Toggle, 0) ' start new cog at Toggle
use
cognew(@Toggle, @P_Val) ' start new cog at Toggle
With this cognew the second cog has the HUB-RAM-adress of variable P_Val in its PAR-register
and can be accessed with
clkdelay rdlong time, par 'the delay subroutine,load TEMP2 into time ********ACTS LINE TEMP2=0************************
another comment on your variable names
using temp1, temp2 is bad programming style. The names temp1, temp2 don't say anything about their purpose.
If you think about the code your brain has to do some extra work translating temp1 contains bitpattern of outa
temp2 contains HUB-RAM-adress of P_Val. This extra brain-work makes it harder to understand for beginners.
Variable-names should be selfexplaining.
P_Val says almost nothing. "MCP3802_ADC_Val1" is self-explaining
As you write a book for PASM-beginners I even would define a variable for par.
So the codeline looks like this
'the delay subroutine
'the value of the SPIN-variable P_Val accessed through its HUB-RAM-adress "HUB_RAM_Adr_of_ADC_Val1"
'is used as start-value for the variable named "time" which is counted down to zero
'in a loop to generate a delay
clkdelay rdlong time, HUB_RAM_Adr_of_ADC_Val1
I also added a comment of 4 lines to explain its purpose in detail.
That's what I would call easy to understand
"HUB_RAM_Adr_of_ADC_Val1" is a quite long name I guess for 50-90% of all programmers too long but it is self-explaining
maybe something like "HR_Ptr_ADC1" is still saying enough if you use the leading characters "HR_Ptr" as a short name for H)ub-R)am-Pointer all the the time
whenever you use RDLONG or WRLONG.
If somebody says: "too many characters to type". I'm using Ctrl-Cursor Ctrl-Shift-curcor Ctrl-C, Ctrl-v all the time and this even avoids typos.
When writing the variable names with ctrl-c/v it doesn't matter how long they are. always the same amount of keypresses.
I guess if you use self-explaining variable-names it will be easier for yourself to find bugs.
And you are giving a good model for beginners how to write code in a good style.
keep the questions coming and continue to post your code
if I remember right all predefined longs (constants) like
'Constants. This section is similar to the CON block in SPIN
Set_dira long %00001011_00000000_00000000_00000000 'Set dira register ...
and all reserved longs (not predefined) acting as variables
'Variables. This section is similar to the VAR block in SPIN temp res 1 'temporary storage variable temp2 res 1 'temporary storage variable count res 1 'temporary storage variable Dat_Red res 1 'temporary storage variable
should be placed behind the last PASM-command.
Longs can be put anywhere. Any long that does not have the upper 16 bits (more or less) set will be treated as a NOP instruction. Often when pressed for space, variables are put in an initialization section where the init code can be over-written. The "RES" variables absolutely must be put at the end of a DAT section for a COG because RES does not allocate space for the variables.
Just my personal preference and you can ignore this if you like, but I like shorter variable names and comment decorations. Variable names should communicate their purpose without expanding into sentences like VariableNamesShouldCommunicateTheirPurpose. Huge comment decorations are wasteful and generally tell the reader things about the programmer that may not be interpreted as intended.
Please consider trimming any code or comment line which has more than 70 characters.
Comments
--Steve
I know this is not quite right but...
Why does this not open up a third cog and toggle line 12
It compiles but I get a dead line 12
In other word, how do you start two PASM cogs
binary math
PASM
assembly language
jargon infested writings
to want to mess around with PASM and his propeller chip
Maybe inspire him or her to learn more from you guys.
I will keep in very simple and disappoint some of you who think there is no way I can get this done
Here is letter from some one who know very little but is very excited. I got it this morning.
All he is really turned on about is controlling a few LEDs.
Hopefully some day he will make a great Tech or even an Engineer. Made my day.
Dear Sir:
I am enjoying your book immensely! I especially enjoyed seeing your section on page 23/24, A Fundamental Reality We Have to Consider, as I need to have LEDs on all my I/O pins (not multiplexed, and more than 10 ma. per pin -- very bright). I plan on using a LYP47F reverse mount LED from OSRAM (sold by Mouser). (The reverse mount and small size are why I chose that style.)
I was a bit surprised to see the 7404 driving LEDs, so I set up six on a chip with 470 ohms as you suggested. Ran all afternoon until I had to shut down and go home! I measured the total chip current (ICCL = 49.2 ma). This exceeded the data sheet spec (33 ma max) a bit but did not blow any outputs. As a personal hobby application or learning situation I can see the 7404 working fine.
However, I have been looking for a long time for a chip for product development where reliability and safety margins can be considered in the design. I am wondering if you might know of anything more robust (and as simple as the 7404) that you could suggest where I would have more driving current per LED. You are the only author that has addressed the situation I face. (Another issue was how to interface a 5 volt family to the Propeller. So I thank you for moving me forward on my project!)
I am looking forward to the remainder of your book. Very well done.
(I like that fact that you do not repeat all the material in other reference sources, but direct the reader to the sources. That makes your book a faster/easier read and more pages for what it is you want to guide us through.)
Thanking you in advance,
First, the startup state on a reset or freshly started COG for the direction register (DIRA) is 0, that is, all pins set as INPUT
Your first COGNEW starts a COG at address 0 (generate) and begins program execution there
1) move the contents of Set_dira to the outa register (this sets bits 12 and 24 to 1, BUT the DIRA register is still INPUT
2) jump back to 1
You've never set DIRA to output, you'll never see bits 12 and 24 anywhere.
Your second COGNEW starts execution in a new cog at address toggle
1) you set DIRA bits 12 and 24 to output
2) you set OUTA bit 12 HIGH
3) you set OUTA bit 12 HIGH (even though the label says Pin_Lo, you still have a 1 bit at bit 12)
4) you jump back to #1 and do the same things
Even if you did set bit 12 LO in #3, it woudl be toggling so fast, you would need an oscilscope or logic probe to see it.
Here's code from Potatohead's tutorial that does what you want - two cogs blinking two leds. I was running this on a Quickstart, so it blinks pin 16 and 17
When I was learning assembler way back when, I was always told to "play computer" it might sound dumb but it really helps to go through each instruction and do everything the computer has to do. If you understand how the computer works for each instruction, you can "play computer" through ANY program.
P.S. This is not how I usually comment code but for instructional purposes, step by step comments are often helpful. I normally despise code such as:
oh, wait, I don't normally comment code.........
I'll take a closer look at the code you sent
For now, just FYI
If I eliminate the initial "jmp generate" instruction,
the I/O works fine and I can see it on the scope just fine so that part seems OK
Pin 24 should not make any difference to the cog running.
It was a mistake but its not critical.
I removed it, nothing changed
Finally, Thanks I think I can make it work now.
Regards
HSS
I didn't know I was going to need a scope to see the examples in your book work, I need to find a new book since I don't have a scope.
That's a tough call
I will add LEDs to this code for now but eventually we will need a scope.
Its really a very basic piece of equipment every serious beginner need to learn how to use.
Just too much stuff that goes too fast to not own one. Its our eyes in electronics.
HSS
@Harpirt: I removed the jmp #generate and I got no output on either pin when I watched it through the logic probe on Gear. If you watch COG1 and COG2 run, you see them looping through all of COG memory and they just happen to execute your instructions as they loop.
If I remove the jmp #generate AND the 'ORG 30' I get a steady HIGH on PIN 12 and a pulsed pin 24. COG1 and COG2 are at least inthe tight loop inside your code.
Both COGs are running through the same code path pulsing the same pin at the same rate. I can't imagine this is what you intended by your example. I'm not sure what concept this shows your reader.
The example I attached from Potatohead's tutorial shows two COGs pulsing two LEDs at two different rates - this at least shows independent COG funtions.
I'm not trying to be difficult, just providing feedback from 'a PASM beginner'.
Some observations:
As mentioned in #127: Pin_Hi and Pin_Lo both have bit 12 set and thus no toggling.
Referring to post #128: removing "jmp #generate" just makes both cogs run the same loop.
"toggle" is at "generate" cog's address 2 (or address 1 if you get rid of "jmp #generate").
Remember that saying org 30 does not change the cog start address.
"MOV OUTA, PEACE" - @mindrobots
--Steve
I was expecting the ORG 30 to cause a hole in the COG memory.....I expected incorrectly. I have much to learn!
@Steve, it's an honor to be quoted!
I guess MOV OUTA, PEACE only shows if you're sure of your direction!
Indeed. I quoted you precisely since PEACE is variable but normally understood.
#PEACE would mean "immediately" within a smaller range
Yes, "jmp #toggle" is adjusted by org 30. The rules of org have been mentioned in this thread.
My problem was that I did not appreciate that each cog has to be defined completely with
all its subroutines, variables and constants before you enter ORG 0 and start
defining the second Cog and all its goodies.
And you cannot duplicate variable names even across cogs (Which I thought was rather strange)
And you still have to watch for I/O conflicts..
I will post my program soon.
Thanks for all the help guys.
Harprit
The problem I am having is that I read a potentiometer into a global variable in one Cog
I add the global variable to another variable in a second Cog and it acts like it is 0 all the time. (I know that for sure)
(It actually varies 12 bits from 0 to 4095. And I know that for sure)
What up?
Harprit
(This is why PAR is a great idea, BTW)
No, not using HUB instruction
Lets wait till I can post the code.
Using PAR for transfer to the SPIN cog but both my other cogs are using PASM
Par to SPIN works fine, thats how I know variable is being read right.
One PASM cog determines variable (and xfers to SPIN via PAR) but the other one will not read it as same global name.
Thanks
HSS
If you want to transfer a value from one cog to another the only way is
writing the value from COG1-RAM WRLONG ==> HUB-RAM
then reading the HUB-RAM with COG2 RDLONG COG2-RAM <=== HUB_RAM
I think it is the same with the HUB-RAM-adress itself too.This means declare a SPIN-variable and start the two cogs
from SPIN. If you want to start the second cog from PASM do I remember right that DIRB and OUTB are existing as registers that are just not connected to any hardware?
But can be used as some kind of global scratchpad-RAM that is easy adressable?
keep the questions coming
best regards
Stefan
I agree there is more than one way to communicate between cogs.
Would you mind answering the question about DIRB/OUTB as scratchpad-RAM
or do you insist on test it yourself :-)
keep the improving comments coming
best regards
Stefan
I think Cluso's debugger uses the first four SPRs and somewhere there is a cog storage object which uses the whole SPR area.
So the program is not runnable.
The problem is that I can not read and write across two PASM cogs accurately.
I am using WRLONG and RDLONG to main memory per the PASM manual (and Stephan in #143)
I have a question (here is what I am doing)
If I have a variable "data_read"
in a PASM cog and then write
WRLONG data_read, temp_var
data_read res 1 'later on in the program to set up the variable
and then read Temp_var into a second PASM cog with
RDLONG time, temp_var
should it work?..It should the way I read it.
It does not for some reason, in my program. I get 0.
Harprit
Is temp_var an address pointing to a hub memory location?
RDLONG D, S ' D is the variable you want to read to and S is where you want to read from.
WRLONG D, S ' D is the variable you want to write and S is where you want to write to.
I will clean it up later. This is per JAZZED request
Harprit
Using temp2 will not work because it contains some other data (it can be forced to work with advanced understanding of SPIN/PASM).
Here's a simple sharedmem.spin example (as simple as i know how to make it).
Let me get your ideas implemented and I will get back with the forum when I get it working
Thanks
Harprit
if I remember right all predefined longs (constants) like
and all reserved longs (not predefined) acting as variables
should be placed behind the last PASM-command.
temp2 that should contain the HUB-RAM-adress is never initialised with a valid HUB-RAM-adress.
You start a second cog for toggling the IO-pin 12
The code uses temp2 as the HUB-RAM-adress. But here it is the same temp2 is not initialised with a valid HUB-RAM-adress
As you start the second cog from SPIN too you simply use the second parameter there too.
instead of
use
With this cognew the second cog has the HUB-RAM-adress of variable P_Val in its PAR-register
and can be accessed with
another comment on your variable names
using temp1, temp2 is bad programming style. The names temp1, temp2 don't say anything about their purpose.
If you think about the code your brain has to do some extra work translating temp1 contains bitpattern of outa
temp2 contains HUB-RAM-adress of P_Val. This extra brain-work makes it harder to understand for beginners.
Variable-names should be selfexplaining.
P_Val says almost nothing. "MCP3802_ADC_Val1" is self-explaining
As you write a book for PASM-beginners I even would define a variable for par.
So the codeline looks like this
I also added a comment of 4 lines to explain its purpose in detail.
That's what I would call easy to understand
"HUB_RAM_Adr_of_ADC_Val1" is a quite long name I guess for 50-90% of all programmers too long but it is self-explaining
maybe something like "HR_Ptr_ADC1" is still saying enough if you use the leading characters "HR_Ptr" as a short name for H)ub-R)am-Pointer all the the time
whenever you use RDLONG or WRLONG.
If somebody says: "too many characters to type". I'm using Ctrl-Cursor Ctrl-Shift-curcor Ctrl-C, Ctrl-v all the time and this even avoids typos.
When writing the variable names with ctrl-c/v it doesn't matter how long they are. always the same amount of keypresses.
I guess if you use self-explaining variable-names it will be easier for yourself to find bugs.
And you are giving a good model for beginners how to write code in a good style.
keep the questions coming and continue to post your code
best regards
Stefan
Just my personal preference and you can ignore this if you like, but I like shorter variable names and comment decorations. Variable names should communicate their purpose without expanding into sentences like VariableNamesShouldCommunicateTheirPurpose. Huge comment decorations are wasteful and generally tell the reader things about the programmer that may not be interpreted as intended.
Please consider trimming any code or comment line which has more than 70 characters.
"MOV OUTA, PEACE"