Stack Space and Program Flow Questions
laser-vector
Posts: 118
I've got a few questions about how stack space, loading new cogs and calling objects differ from each other and how that effects the way the propeller runs the code.
assume this program only as an example:
VARIATION 1:
I see that the MAIN method launches the TX method in a new cog (via cognew) with a runtime stack space 30 elements wide. however MAIN does not launch the RX method in a new cog and doesnt define any stack space.
where is the RX method running (in cog 0??) and what is the stack size and address??
Ok so im intrested in knowing what the difference is between the program above and just launching two cogs to do RX and TX. for example
VARIATION 2:
so which cogs are being used now?? and what happens to the main method, does it stay dormant in cog 0 just taking up space??
lastly what if this were done with an object call??
VARIATION 3:
ok so what makes this different?
do RX and TX launch in different cogs??
how do i know their stack size and address (if those even matter here)??
and what happens to the original Main method?????
This is something thats been baffling me for some time. i'm really trying to visualize the flow of things and where they currently are running. plus pros and cons to launching cogs and calling other objects.
And id really like to give thanks to everyone, youve all been awesome support!!
assume this program only as an example:
VARIATION 1:
{VARIATION #1} CON { ==[ CLOCK SET ]== } _CLKMODE = XTAL1 + PLL16X _XINFREQ = 6_250_000 RX_pin = 12 TX_pin = 11 OBJ DEBUG : "FullDuplexSerial" PCRX : "PROP_COMM_RX" PCTX : "PROP_COMM_TX" VAR LONG tx_stack[30] ' probably be safe at 22 longs PUB Main | rx_buff, i, seed, v DEBUG.start(31, 30, 0, 57600) waitcnt(clkfreq + cnt) DEBUG.tx($D) DEBUG.str(string("If 'Warning' shows up, input does not match expected value",$D)) cognew(tx, @tx_stack) ' start transmit cog '' ----------------------------------------------------- '' setup recieve cog rx_buff := PCRX.recieve(RX_pin) ' start RX cog seed := $9876_5432 ' make sure it is the same as tx cog REPEAT PCRX.waitrx_wd(100) ' wait up to 100ms for information to be recieved. REPEAT i FROM 0 TO constant(PCRX#BUFFER_SIZE - 1) IF (?seed <> long[rx_buff][i]) ' if information differs from what it is supposed to be DEBUG.str(string("Warning",$D)) DEBUG.str(string("Buffer Good",$D)) PUB tx | tx_buff, i, seed '' setup transmit cog tx_buff := PCTX.send(TX_pin) ' start TX cog seed := $9876_5432 ' make sure it is the same as rx cog REPEAT REPEAT i FROM 0 TO constant(PCTX#BUFFER_SIZE - 1) long[tx_buff][i] := ?seed ' fill buffer PCTX.transmitwait_wd(100) ' send buffer, then wait up to 100ms for it to complete waitcnt(120000 + cnt) ' give enough time for RX cog to "analize" data
I see that the MAIN method launches the TX method in a new cog (via cognew) with a runtime stack space 30 elements wide. however MAIN does not launch the RX method in a new cog and doesnt define any stack space.
where is the RX method running (in cog 0??) and what is the stack size and address??
Ok so im intrested in knowing what the difference is between the program above and just launching two cogs to do RX and TX. for example
VARIATION 2:
{VARIATION #2} CON { ==[ CLOCK SET ]== } _CLKMODE = XTAL1 + PLL16X _XINFREQ = 6_250_000 RX_pin = 12 TX_pin = 11 OBJ DEBUG : "FullDuplexSerial" PCRX : "PROP_COMM_RX" PCTX : "PROP_COMM_TX" VAR LONG tx_stack[30] ' probably be safe at 22 longs LONG rx_stack[30] PUB Main DEBUG.start(31, 30, 0, 57600) waitcnt(clkfreq + cnt) DEBUG.tx($D) DEBUG.str(string("If 'Warning' shows up, input does not match expected value",$D)) cognew(tx, @tx_stack) ' start transmit cog cognew(rx, @rx_stack) ' start receive cog PUB rx | rx_buff, i, seed, v '' ----------------------------------------------------- '' setup recieve cog rx_buff := PCRX.recieve(RX_pin) ' start RX cog seed := $9876_5432 ' make sure it is the same as tx cog REPEAT PCRX.waitrx_wd(100) ' wait up to 100ms for information to be recieved. REPEAT i FROM 0 TO constant(PCRX#BUFFER_SIZE - 1) IF (?seed <> long[rx_buff][i]) ' if information differs from what it is supposed to be DEBUG.str(string("Warning",$D)) DEBUG.str(string("Buffer Good",$D)) PUB tx | tx_buff, i, seed '' setup transmit cog tx_buff := PCTX.send(TX_pin) ' start TX cog seed := $9876_5432 ' make sure it is the same as rx cog REPEAT REPEAT i FROM 0 TO constant(PCTX#BUFFER_SIZE - 1) long[tx_buff][i] := ?seed ' fill buffer PCTX.transmitwait_wd(100) ' send buffer, then wait up to 100ms for it to complete waitcnt(120000 + cnt) ' give enough time for RX cog to "analize" data
so which cogs are being used now?? and what happens to the main method, does it stay dormant in cog 0 just taking up space??
lastly what if this were done with an object call??
VARIATION 3:
{VARIATION #3} CON { ==[ CLOCK SET ]== } _CLKMODE = XTAL1 + PLL16X _XINFREQ = 6_250_000 RX_pin = 12 TX_pin = 11 OBJ DEBUG : "FullDuplexSerial" PCRX : "PROP_COMM_RX" PCTX : "PROP_COMM_TX" RX : "RXfile" 'RXfile's main method contains the same instructions as the previous rx method TX : "TXfile" 'TXfile's main method contains the same instructions as the previous tx method PUB Main DEBUG.start(31, 30, 0, 57600) waitcnt(clkfreq + cnt) DEBUG.tx($D) DEBUG.str(string("If 'Warning' shows up, input does not match expected value",$D)) RX.main(RX_pin) TX.main(TX_pin)
ok so what makes this different?
do RX and TX launch in different cogs??
how do i know their stack size and address (if those even matter here)??
and what happens to the original Main method?????
This is something thats been baffling me for some time. i'm really trying to visualize the flow of things and where they currently are running. plus pros and cons to launching cogs and calling other objects.
And id really like to give thanks to everyone, youve all been awesome support!!
Comments
Without the source for PROP_COMM_RX and PROP_COMM_TX, it's impossible to tell what they're doing internally, but I suspect they're starting their own cogs or cog. If their cog code is in assembly, there's no stack needed. Only Spin code uses an implicit stack.
The most important thing to remember is that objects and cogs are two separate (orthogonal) concepts. Objects are a way to encapsulate some function. There's nothing about objects that requires the use of a cog. If part of your program calls an object's method, that method is executed by the same cog that executes the code that calls it.
Similarly, you can have a program completely contained in the main object that uses all the cogs. Each cog running a Spin method has to have its own stack area.
Most commonly, objects are used to implement I/O device drivers and frequently these will use a cog to implement the low level I/O functionality. Whether these objects use a cog or not is mostly hidden from the caller. The driver initialization routine usually does the COGNEW and the object has the declaration for the stack area, any buffers, and any other shared variables.