Deploying assembly code across multiple cogs - jm_freqin help
scocioba
Posts: 19
in Propeller 1
Hello Everyone,
This is my first post and it has to do with making the really lovely jm_freqin code work across multiple cogs. I am fairly new to the propeller system and am a biologist by training so please pardon my naivete in all this! So far, I tried just copying every single method and variable and labeled it incrementally from 1 through 6 representing the six signals I would like to read simultaneously. Every time I run the code for a single cog (original jm_freqin code), it works perfectly but when I set it up to initialize 6 cogs, I get zeros across the board as the signal value in hertz. I am using the Parallax Serial Terminal to output six independent values in one line separated by commas and a carriage return and new line so that every second a read of the six signal sources are printed as CSV values down the serial line. My question is: How does one deploy assembly code (specifically the jm_freqin code) properly across multiple cogs such that each cog runs the same method and outputs its own unique value at the same time as the other cogs. Below is the bastardization of the jm_freqin code I thought would "work" as reference. All I need is a way to read six signals at the same time and output their frequency values down the serial line. I am certain there is waaaay more elegant way to do this and any input would be much appreciated!
Assembly code repeating regions were removed so the code would fit the post. The serial demo side of the code is below:
This is my first post and it has to do with making the really lovely jm_freqin code work across multiple cogs. I am fairly new to the propeller system and am a biologist by training so please pardon my naivete in all this! So far, I tried just copying every single method and variable and labeled it incrementally from 1 through 6 representing the six signals I would like to read simultaneously. Every time I run the code for a single cog (original jm_freqin code), it works perfectly but when I set it up to initialize 6 cogs, I get zeros across the board as the signal value in hertz. I am using the Parallax Serial Terminal to output six independent values in one line separated by commas and a carriage return and new line so that every second a read of the six signal sources are printed as CSV values down the serial line. My question is: How does one deploy assembly code (specifically the jm_freqin code) properly across multiple cogs such that each cog runs the same method and outputs its own unique value at the same time as the other cogs. Below is the bastardization of the jm_freqin code I thought would "work" as reference. All I need is a way to read six signals at the same time and output their frequency values down the serial line. I am certain there is waaaay more elegant way to do this and any input would be much appreciated!
var
long cog1
long cog2
long cog3
long cog4
long cog5
long cog6
long fcPin1
long fcPin2
long fcPin3
long fcPin4
long fcPin5
long fcPin6
long fcCycles1
long fcCycles2
long fcCycles3
long fcCycles4
long fcCycles5
long fcCycles6
pub init1(p)
fcPin1 := p
fcCycles1 := 0
cog1 := cognew(@frcntr1, @fcPin1) + 1
pub init2(p)
fcPin2 := p
fcCycles2 := 0
cog2 := cognew(@frcntr2, @fcPin2) + 1
pub init3(p)
fcPin3 := p
fcCycles3 := 0
cog3 := cognew(@frcntr3, @fcPin3) + 1
pub init4(p)
fcPin4 := p
fcCycles4 := 0
cog4 := cognew(@frcntr4, @fcPin4) + 1
pub init5(p)
fcPin5 := p
fcCycles5 := 0
cog5 := cognew(@frcntr5, @fcPin5) + 1
pub init6(p)
fcPin6 := p
fcCycles6 := 0
cog6 := cognew(@frcntr6, @fcPin6) + 1
pub period1
return fcCycles1
pub period2
return fcCycles2
pub period3
return fcCycles3
pub period4
return fcCycles4
pub period5
return fcCycles5
pub period6
return fcCycles6
pub freq1 | p1, f1
p1 := period1
f1 := clkfreq * 10 / p1
fcCycles1 := 0
return f1
pub freq2 | p2, f2
p2 := period2
f2 := clkfreq * 10 / p2
fcCycles2 := 0
return f2
pub freq3 | p3, f3
p3 := period3
f3 := clkfreq * 10 / p3 ' calculate frequency
fcCycles3 := 0 ' clear for loss of input
return f3
pub freq4 | p4, f4
p4 := period4
f4 := clkfreq * 10 / p4 ' calculate frequency
fcCycles4 := 0 ' clear for loss of input
return f4
pub freq5 | p5, f5
p5 := period5
f5 := clkfreq * 10 / p5 ' calculate frequency
fcCycles5 := 0 ' clear for loss of input
return f5
pub freq6 | p6, f6
p6 := period6
f6 := clkfreq * 10 / p6 ' calculate frequency
fcCycles6 := 0 ' clear for loss of input
return f6
dat
org
frcntr1 mov tmp11, par ' start of structure
rdlong tmp12, tmp11 ' get pin#
mov ctra, POS_DETECT1 ' ctra measures high phase
add ctra, tmp12
mov frqa, #1
mov ctrb, NEG_DETECT1 ' ctrb measures low phase
add ctrb, tmp12
mov frqb, #1
mov mask1, #1 ' create pin mask
shl mask1, tmp12
andn dira, mask1 ' input in this cog
add tmp11, #4
mov cyclepntr1, tmp11 ' save address of hub storage
restart1 waitpne mask1, mask1 ' wait for 0 phase
mov phsa, #0 ' clear high phase counter
highphase1 waitpeq mask1, mask1 ' wait for pin == 1
mov phsb, #0 ' clear low phase counter
lowphase1 waitpne mask1, mask1 ' wait for pin == 0
mov cycles1, phsa ' capture high phase cycles
endcycle1 waitpeq mask1, mask1 ' let low phase finish
add cycles1, phsb ' add low phase cycles
wrlong cycles1, cyclepntr1 ' update hub
jmp #restart1
' --------------------------------------------------------------------------------------------------
POS_DETECT1 long %01000 << 26
NEG_DETECT1 long %01100 << 26
tmp11 res 1
tmp12 res 1
mask1 res 1 ' mask for frequency input pin
cyclepntr1 res 1 ' hub address of cycle count
cycles1 res 1 ' cycles in input period
fit
dat
org 0
frcntr2 mov tmp21, par ' start of structure
rdlong tmp22, tmp21 ' get pin#
mov ctra, POS_DETECT2 ' ctra measures high phase
add ctra, tmp22
mov frqa, #1
mov ctrb, NEG_DETECT2 ' ctrb measures low phase
add ctrb, tmp22
mov frqb, #1
mov mask2, #1 ' create pin mask
shl mask2, tmp22
andn dira, mask2 ' input in this cog
add tmp21, #4
mov cyclepntr2, tmp21 ' save address of hub storage
restart2 waitpne mask2, mask2 ' wait for 0 phase
mov phsa, #0 ' clear high phase counter
highphase2 waitpeq mask2, mask2 ' wait for pin == 1
mov phsb, #0 ' clear low phase counter
lowphase2 waitpne mask2, mask2 ' wait for pin == 0
mov cycles2, phsa ' capture high phase cycles
endcycle2 waitpeq mask2, mask2 ' let low phase finish
add cycles2, phsb ' add low phase cycles
wrlong cycles2, cyclepntr2 ' update hub
jmp #restart2
' --------------------------------------------------------------------------------------------------
POS_DETECT2 long %01000 << 26
NEG_DETECT2 long %01100 << 26
tmp21 res 1
tmp22 res 1
mask2 res 1 ' mask for frequency input pin
cyclepntr2 res 1 ' hub address of cycle count
cycles2 res 1 ' cycles in input period
fit 492
dat
Assembly code repeating regions were removed so the code would fit the post. The serial demo side of the code is below:
con
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
obj
fc : "jm_freqin"
pst : "Parallax Serial Terminal"
pub main
EnablePST
fc.init1(1)
fc.init2(2)
fc.init3(3)
fc.init4(4)
fc.init5(5)
fc.init6(6)
repeat
pst.dec(fc.freq1)
pst.char(",")
pst.dec(fc.freq2)
pst.char(",")
pst.dec(fc.freq3)
pst.char(",")
pst.dec(fc.freq4)
pst.char(",")
pst.dec(fc.freq5)
pst.char(",")
pst.dec(fc.freq6)
pst.NewLine
pst.LineFeed
waitcnt(clkfreq + cnt)
PRI EnablePST
pst.start(115200)
pst.Home
pst.Clear

Comments
obj fc[ 6 ] : "jm_freqin"
To initialize the six channels, each in its own cog, you'd do this (with i a local variable):
Obviously, if you need to use I/O pins other than 1-6, you'd have to change the above.
To display the results, you'd do something like:
Here's my version. It's pretty much the same as what Mike wrote.
con _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 con #0, CLS, HOME, #8, BKSP, TAB, LF, CLREOL, CLRDN, CR ' PST formmatting control obj fc[6] : "jm_freqin" term : "jm_txserial" pub main | f, index repeat index from 0 to 5 fc[index].init(index) term.init(30, 115_200) ' start terminal waitcnt(clkfreq/10 + cnt) term.tx(CLS) '' removed frequency generator code repeat term.tx(HOME) repeat index from 0 to 5 term.str(string(11, 13, "Freq[")) term.dec(index) term.str(string("]: ")) f := fc[index].freq ' get frequency if f > 0 ' valid? term.dec(f/10) ' print whole part term.tx(".") term.dec(f//10) ' print fractional part term.str(string(" Hz")) else term.str(string("???")) waitcnt(clkfreq + cnt)One difference with Mike's code is the I/O pins used. Mike used pins 1 through 6, I used 0 through 5. As Mike points out, you'll need to modify the code to use different pins.
As you can see, I prefer to unroll objects of the same time so that I can name them -- it's more verbose, an I prefer to code this way.
What I want to point out is that I'm marking cog use. In your case you've got the main Spin cog and six frequency counters; you're down to one cog left for serial communications via Bluetooth - you're out of cogs.