PDA

View Full Version : Help Please. Variables with multiple cogs and objects



archerbrad700
11-09-2011, 08:54 PM
I read that a variable defined in the VAR block can be seen by all the methods of that object, but what about in other Cogs running other objects?

What I have is a method in one object that polls the user for input and saves the input to a variable (say desiredX) in another object I have a method that looks for that variable (desiredX) to change and when it does it executes a subroutine. The problem is that the subroutine never gets executed. I imagine it is because one object/cog can't see what is going on in another.

So the question is how do I get the second cog to see that the variable has changed in the first cog?

Thanks for your help,
-Brad

Mike G
11-09-2011, 08:59 PM
Assuming this is all SPIN, then pass the address(es) of HUB memory to each process, I'd use a DAT block not VAR. You'll also need to setup a semaphore to lock memory so one process does not step on the other. There are some great examples in the Propeller Manual under memory locking.

If we're talking about PASM there is an extra step of getting the COG data to HUB memory.

It helps if you post your code.

archerbrad700
11-09-2011, 09:21 PM
Thanks for your reply,

I am coding in Spin and here is my code:


{{________________________________________________ __________


Author: Bradley Bauer
Date: 11-3-11
__________________________________________________ ________




}}


CON


_clkmode = xtal1 + pll16x 'Crystal and PLL settings.
_xinfreq = 5_000_000 '5 MHz crystal (5 MHz x 16 = 80 MHz)


VAR


Word desiredX 'Variable to store desired X position
Word desiredY 'Variable to store desired Y position


Byte XResolveCog 'Stores cog ID that runs XResolve
Byte YResolveCog 'Stores cog ID that runs YResolve
Byte PotWatchCog 'Stores cod ID that runs PotWatch
Byte SwitchMonitorCog 'Stores cog ID that runs SwitchMonitor


Byte laserState 'Variable to store desired laser state (ON/OFF)
Byte laserB 'Variable to store desired laser brightness level (0-100)


OBJ


Resolve : "ResolveXY" 'Used to resolve X-Y disparities
SerialCom : "Extended_FDSerial" 'Used for serial communications
Pot : "PotResolve" 'Used to resolve laser brightness disparities
Switch : "Switch Monitor" 'Watches for input from foot pedal


'delete below after testing
Debug : "Parallax Serial Terminal"'Calls "Parallax Serial Terminal" object "Debug"


Pub Main
{Starts all the objects and methods then runs SerialMonitor on Cog 0}


Resolve.Start 'Starts 2 Cogs
Pot.Start 'Starts 1 Cog
Switch.Start 'Starts 1 Cog
'SerialMonitor 'Uses Cog 0
'Total of 5 Cogs running


'Delete remaining code in method when done testing
Debug.Start(115_200)
repeat
Debug.Str(String("Enter an X value: ")) 'Prompt user to enter a number; uses immediate string.
desiredX := Debug.DecIn
Debug.Str(String("Enter an Y value: ")) 'Prompt user to enter a number; uses immediate string.
desiredY := Debug.DecIn



Other object:

{{________________________________________________ __________


Author: Bradley Bauer
__________________________________________________ ________


Known bug: Does not accept negative "RX_______" values


}}


CON


_clkmode = xtal1 + pll16x 'Crystal and PLL settings.
_xinfreq = 5_000_000 '5 MHz crystal (5 MHz x 16 = 80 MHz)


XPlus = 13 'Defines pin for CW motion input on M1
XMinus = 15 'Defines pin for CCW motion input on M1
YPlus = 19 'Defines pin for CW motion input on M2
YMinus = 16 'Defines pin for CCW motion input on M2


XDir = 4 'Defines pin for X direction output
XStep = 5 'Defines pin for X axis step output
YDir = 6 'Defines pin for Y direction output
YStep = 7 'Defines pin for Y axis step output

XMAX = 200 'Defines positive X step limit
XMIN = 0 'Defines negative X step limit
YMAX = 200 'Defines negative Y step limit
YMIN = 0 'Defines negative Y step limit


MS1 = 14 'Pin for Mode select 1 Microstep resolution selection
MS2 = 13 'Pin for Mode select 2 See Allegro A4983 data sheet
MS3 = 12 'Pin for Mode select 3 for truth table


CW = 1 'Defines CW direction
CCW = 0 'Defines CCW direction


StepWait = 500 'Defines step pulse intervals (clkfreq/StepWait + cnt)


Count = 10 '-----Defines a default count value


VAR


Word XCount 'Variable to keep track of X steps
Word YCount 'Variable to keep track of Y steps


Word desiredX 'Variable to store desired X position
Word desiredY 'Variable to store desired Y position


Byte XResolveCog 'Stores cog ID that runs XResolve
Byte YResolveCog 'Stores cog ID that runs YResolve


Long Stack1[100] 'Cog stack space
Long Stack2[100] 'Cog stack space


OBJ


Debug : "Parallax Serial Terminal" 'Calls "Parallax Serial Terminal" object "Debug"

PUB Main


Debug.Start(115_200)


waitcnt(clkfreq/100 + cnt)


Debug.Str(String("Program is running..."))
Debug.NewLine


Start


PUB Start


XResolveCog := cognew(XResolve, @Stack1)
YResolveCog := cognew(YResolve, @Stack2)


dira[MS1..MS3]~~ 'Sets Stepper drivers to 1/16 microstep mode
!outa[MS1..MS3] 'by setting MS1, MS2, and MS3 pins high


PRI XResolve


dira[XDir..XStep]~~ 'Set stepper control pins as outputs


repeat


if (XCount < desiredX)
repeat while (XCount < desiredX) and (XCount < XMax)
Resolver(CW, XStep)
XCount++


else
repeat while (XCount > desiredX) and (XCount > XMin)
Resolver(CCW, XStep)
XCount--

PRI YResolve


dira[YDir..YStep]~~ 'Set stepper control pins as outputs


repeat

if (YCount < desiredY)
repeat while (YCount < desiredY) and (YCount < YMax)
Resolver(CW, YStep)
YCount++


else
repeat while (YCount > desiredY) and (YCount > YMin)
Resolver(CCW, YStep)
YCount--


PRI Resolver (direction, motorSelect) | DirPin
{{Sets step direction and steps motor once}}


if (motorSelect == XStep)
DirPin := XDir
else
DirPin := YDir


outa[DirPin] := direction
!outa[motorSelect]
waitcnt(clkfreq/StepWait + cnt)
!outa[motorSelect]
waitcnt(clkfreq/StepWait + cnt)

In a nutshell... Ask user for X and Y points then run the Resolve subroutine until there is no more disparity between desiredX and Xcount and desiredY and YCount

I don't see how I can store a variable in the DAT block, maybe someone could show me?

Thanks

Duane Degn
11-09-2011, 10:24 PM
Brad,

Your going to need have the parent object pass a pointer, to the variable, to the child object.

Look for information in the manual about the "@" operator.

The child method would then read the variable with word[addressOfWord].

I don't see an advantage to having the variable in the DAT section unless muliple instances of an object are used.

Locks are sometimes needed. It depends on the situation.

I'll look around for an example of passing a pointer and post one if someone else doesn't bet me to it.

Duane

Duane Degn
11-09-2011, 10:42 PM
Brad,

I haven't found a clear example yet.

When the parent starts the child use:




Child.Start(@desiredX)



Modify the child object to:



PUB Start(desiredXAddress)

if (xCount < word[desiredXaddress])



Hopefully that's enough to get you started.

Look up "@" and word to see what the code above is doing.

Duane

archerbrad700
11-09-2011, 10:44 PM
Duane,

Thank you, an example would be great!

Mike G
11-10-2011, 03:14 AM
Simple Example, one process writes the other reads.



CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000

DAT
command byte $00
SemID byte $00


VAR
long ReadStack[20]
long WriteStack[20]


OBJ
pst : "Parallax Serial Terminal"


PUB Main

'Start PST
pst.Start(115_200)
pause(200)

' Get a lock ID
if(semId := locknew) == -1
pst.str(string("Error, semaphore Id available", 13))
else
pst.str(string("Semaphore Id : "))
pst.dec(SemID)
pst.char(13)

' Start the Read and Write processes
cognew(Write, @WriteStack)
cognew(Read, @ReadStack)


PUB Read | value
'' Write to the terminal when
'' the command equals $10

repeat 'forever
'Wait for the lock to clear
repeat until not lockset(SemID)
if(command == $10)
pst.str(string("We got a winner!: "))
pst.hex(command, 2)
pst.char(13)
'Clear the lock
lockclr(SemID)

' Give Write some time to write
pause(1)


PUB Write | i
repeat 'forever
'Wait for the lock to clear
repeat until not lockset(SemID)
command := i++
pause(10)
'Clear the lock
lockclr(SemID)

' Give Read some time to read
pause(1)


PRI Pause(Duration)
waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt)
return


If the Read and Write processes were encapsulated in an object, then you would pass the address (pass by reference) of the command variable, @command, to the object's Start method. In this example, you would also pass the ID of the memory lock. Pass by value should be fine. Hope that helps.

archerbrad700
11-10-2011, 02:07 PM
Sweet, thank you both for your help. Progress has been made.

I still have two questions though:

1) I followed Duane's example and it is working except something is happening to the values. The code works perfectly in the single object, but when I use another cog to store the values are getting changed somehow.


DAT

XSpace Long $AAAAAA
YSpace Long $BBBBBB


OBJ


Resolve : "ResolveXY" 'Used to resolve X-Y disparities
SerialCom : "Extended_FDSerial" 'Used for serial communications
Pot : "PotResolve" 'Used to resolve laser brightness disparities
Switch : "Switch Monitor" 'Watches for input from foot pedal


'delete below after testing
Debug : "Parallax Serial Terminal"'Calls "Parallax Serial Terminal" object "Debug"


Pub Main
{Starts all the objects and methods then runs SerialMonitor on Cog 0}


Resolve.Start(@XSpace, @YSpace) 'Starts 2 Cogs
Pot.Start 'Starts 1 Cog
Switch.Start 'Starts 1 Cog
'SerialMonitor 'Uses Cog 0
'Total of 5 Cogs running


'Delete remaining code in method when done testing
Debug.Start(115_200)
waitcnt(clkfreq/100 + cnt)
repeat
Debug.Str(String("Enter an X value: ")) 'Prompt user to enter a number; uses immediate string.
long[@XSpace] := Debug.DecIn
debug.dec(long[@XSpace])
Debug.Str(String("Enter an Y value: ")) 'Prompt user to enter a number; uses immediate string.
long[@YSpace] := Debug.DecIn
debug.dec(long[@YSpace])




Resolve Object:


DAT

XSpace Long $AAAAAA
YSpace long $BBBBBB

OBJ


Debug : "Parallax Serial Terminal" 'Calls "Parallax Serial Terminal" object "Debug"

PUB Main


Debug.Start(115_200)


waitcnt(clkfreq/100 + cnt)


Debug.Str(String("Program is running..."))
Debug.NewLine


Start(@XSpace,@YSpace)


PUB Start(desiredXaddress, desiredYaddress)


XResolveCog := cognew(XResolve(desiredXaddress), @Stack1)
YResolveCog := cognew(YResolve(desiredYaddress), @Stack2)


dira[MS1..MS3]~~ 'Sets Stepper drivers to 1/16 microstep mode
!outa[MS1..MS3] 'by setting MS1, MS2, and MS3 pins high


'Delete remaining code in method when interfaced with LaserPOP-Parent
{ repeat
Debug.Str(String("Enter an X value: ")) 'Prompt user to enter a number; uses immediate string.
long[@XSpace] := Debug.DecIn
Debug.Str(String("Enter an Y value: ")) 'Prompt user to enter a number; uses immediate string.
long[@YSpace] := Debug.DecIn
}
PRI XResolve(desiredXaddress)


dira[XDir..XStep]~~ 'Set stepper control pins as outputs


repeat


if (XCount < long[desiredXaddress])
repeat while (XCount < long[desiredXaddress]) and (XCount < XMax)
Resolver(CW, XStep)
XCount++


else
repeat while (XCount > long[desiredXaddress]) and (XCount > XMin)
Resolver(CCW, XStep)
XCount--

PRI YResolve(desiredYaddress)


dira[YDir..YStep]~~ 'Set stepper control pins as outputs


repeat

if (YCount < long[desiredYaddress])
repeat while (YCount < long[desiredYaddress]) and (YCount < YMax)
Resolver(CW, YStep)
YCount++


else
repeat while (YCount > long[desiredYaddress]) and (YCount > YMin)
Resolver(CCW, YStep)
YCount--




2) I'm still not sure how Mike's code applies to this, but I'm all for an explanation... It perhaps is what's causing my problem?

Thanks again

Mike G
11-10-2011, 07:40 PM
1) I followed Duane's example and it is working except something is happening to the values. The code works perfectly in the single object, but when I use another cog to store the values are getting changed somehow.


Sounds like you need a memory lock.



I'm still not sure how Mike's code applies to this, but I'm all for an explanation... It perhaps is what's causing my problem?

The code simply spins up two process in separate COGs; 1 and 2. Each process has access to the variable created in the top level object. You could, move the Read and Write process to separate files, reference the objects, and start the objects in the top level object. Pass the command variable by reference; @command, to the referenced objects (as you did) along with the semaphore. In the child objects, make sure memory access is not checked out by another process. If memory is available check out the memory lock, Read/Write, release the lock.

The Propeller manual has an excellent explanation of memory locks.