Issue with multiple cogs sharing the same object.
Paul K.
Posts: 150
I'm running the MCP3208 object in two cog's . It wont work unless I define the object differently for each cog.
This works just fine:
OBJ
LCD : "SparkFun_Serial_LCD.spin"
XB : "XBee_Object_2"
ADC : "MCP3208_Fast"
ADCA : "MCP3208_Fast"
Can two cogs share the same object so it would look like this:
OBJ
LCD : "SparkFun_Serial_LCD.spin"
XB : "XBee_Object_2"
ADC : "MCP3208_Fast"
Above code won't work.
Are my first few lines the correct way or am I missing something?
Paul
This works just fine:
OBJ
LCD : "SparkFun_Serial_LCD.spin"
XB : "XBee_Object_2"
ADC : "MCP3208_Fast"
ADCA : "MCP3208_Fast"
Can two cogs share the same object so it would look like this:
OBJ
LCD : "SparkFun_Serial_LCD.spin"
XB : "XBee_Object_2"
ADC : "MCP3208_Fast"
Above code won't work.
Are my first few lines the correct way or am I missing something?
Paul
Comments
You can design an object in a way that it can be used in several COGs without any problem. To answer this question you have to a) look into the object and b) understand the difference of variables defined locally, in a VAR or in a DAT section.
The question in your case is: What do you want?
Do you want to attach one MCP3208 and access it from 2 COGs or do you have 2 MCP3208 and you want to access one per COG?
Your "just fine" example is meant for the 2 MCP3208-case. Both objects have their own copy of VAR variables and each driver can be connected to a different device.
Your "won't work" example can be fine for some objects - for example for objects that only work with local variables. The object which hosts string-functions (don't remember the name) should be a candidate for that). The SimpleSerial should also work this way.
Like in your example:
You could also write:
What you see in MCP3208_Fast.spin is, that this object provides a start-function which is calling a COGNEW to start a driver written in PASM to do the direct communication with the hardware.
Each instance of this object has it's own copy of the VAR-section, which is responsible to store some configuration which might be different from instance to instance and a communication buffer which is used to talk to the PASM-COG. (To be honest it would be pretty fine to move the delay variable from the VAR section to a DAT section as you can not change it later on anyways and it will be the same for each instance.)
So ... when you have 2 instances of this object these are completely separated. You'd "connect" one to device A - giving dpin, cpin, spin and mode of that device - and the other one you'd connect to device B using the pins of that while calling start.
If you have 2 COGs in your main-program which should use 1 instance of MCP3208 connected to one device you have to do this very carefully. As the hardware-driver is running in it's own COG it's possible in general, because this COG is driving the pins and the DIRA settings are fine. In other drivers, where no separate COG is started, you can not rely on that fact and you need to have a closer look into the code. In SimpleSerial it would work because there the pins are correctly defined (DIRA) with each call - as far as I remember. In other drivers you might face the problem that DIRA is set by the start-function which means that the correct settings are only available in the COG that called the start-function. So, calling functions of such an object from another COG would not do what you expect.
Back to the careful-part: The problem calling 1 instance of MCP3208 from within 2 different COGs is, that both would access the same communication buffer to instruct the PASM COG to do something. Across several COGs there is no way of having an atomic read/modify/write to a variable. So, something like:
1. COGn check if an instruction is pending
2. If yes, wait (goto 1. ;o)
3. If no, write the parameters and then the instruction
will not work. Both COGs reaching step 1 at the same time would see a free instruction buffer and go on with 3 where one COG overwrites parameter/instruction of the other and in the end the PASM COG will see an inconsistent communication-buffer.
So, either you are pretty sure that both COGs will never ever try to access the same MCP3208 at the same time or you have to use locks.
Having a look at the MCP3208_fast.spin-file also shows that there should only little changes be needed to make this driver multi device capable, which means with 1 object you can drive more than one hardware device. You only need to make this (taken from start) a new PUB function: and the PASM will accept a changed setup.
Using two instances of mcp3208 is not a issue for me it was more why won't it work.
But understand it a lot more now.
I'll try play around with the code to see if I can get this to work. And post any progress/my solution.
Thanks for the great info.
Paul
As the driver code leaves enought room in COG-RAM, I'd now suggest to change that (the PASM part of MCP3208)! A modified driver would allow to setup the pins of 2 devices and wait for commands in 2 different instruction buffers. The SPIN code of the MCP3208 also need little changes, as it has to send instructions either in this or in that buffer.
The benefit of this is, that you don't care in your 2 COGs that use the object whether there could be a collision or not.
The only drawback is, that you should be aware that the driver might be busy for a while with reading the other device (for example for COG2) at the time that COG1 also wants to read it's device. So, you have to decide if your time-restrictions allow to do it this way.
If you have very tight timing requirements in your application, you might want to have a look at the serial object that allows to have 4 simultaneous serial connections. There you can see how you can several PASM 'threads' in one COG to read/write several devices sametime. But this will be a complete rewrite of the driver.
Let us know if you need some help!