Running MCP3208.spin continously in a cog
Erlend
Posts: 612
I want to structure my program such that in Main there are a number of global variables that hold I/O input values. Most of them are acquired by objects running in separate cogs, eg quad encoder, RTC, IR sensor, and ADC MCP3208. Therefore, I also want to have the MCP3208 continously running in a cog, do specific scaling of each input, and - a guess using LONGMOVE - the values in engineering units to the global values in Main. It could also - as I progress - be coded to do all sorts of things like monitoring levels, raise flags, sound warnings, etc.
e.g. PUB Main could do something like this:
IF gTemperature > 32
LCD("Human detected")
I am not good at assembly, and I need advice how to do this. Maybe it can even be done in the spin part of the objects code.
I guess there is no point in posting the obex code since it is part of the standard library.
Erlend
e.g. PUB Main could do something like this:
IF gTemperature > 32
LCD("Human detected")
I am not good at assembly, and I need advice how to do this. Maybe it can even be done in the spin part of the objects code.
I guess there is no point in posting the obex code since it is part of the standard library.
Erlend
Comments
the MCP3208.spin starts one cog with a PASM-driver to read-out the ADC whenever you call method "In" or method "Average"
To update variables continuosly you just start another cog with a method that has an infinite loop that is doing
Variables can be updated this way across cogs. variables of the VAR-section are accessible from all methods in the same *.SPIN-file
where the varables are defined. It doesn't matter which cog is executing the method.
here is a demo how this works
best regards
Stefan
ps: please don't duplicate post.
So do I understand it correctly that your code start two new cogs to run M1 and M2, and since they are defined in the top level spin code, the adresses of the variables are passed along to the new cogs? -makes sense to me. And, in your first example the deliverADCvalues is defined in and object code to be a repeat-forever reading of ADC channels, so that in the main code I can do
OBJ
adc: "deliverADCvalues"
PUB M1
adc.start(gValue1, gValue2,gValue3,..gValue8)
- is this correct?
Thanks, I will read your code and see if it makes me wiser. Reading and writing to the HUB is new to me though, and I am not sure I want to go there yet. I still believe that somehow using LONGMOVE from within an object running in an other cog is what I need. I am thinking something like adc_read_forever.start(@gValue1, gValue2...) early in my Main code.
But how to do that?
The parameter required is a pointer (the hub address of) the array (or group of eight longs) to store the readings. This method can be launched like this:
You also need to define an array for the stack. As this method doesn't call anything outside itself and only has one parameter and three locals, 16 longs should be enough.
* Follow-up: I did a little timing test and on an 80MHz system that loop that reads all eight channels and reports them to the hub takes about 5.6ms.
It is from my forthcoming book for beginners.
You can run this program as a stand alone.
The read routine can be called as a method from outside this Object
Much more will be in my book for beginners.
Harprit
Think I will manage now. Thanks to all of you!
Btw, all AI's are slow-changing, so speed is not an issue.
I'll save you the trouble (see attached) as I pulled that example from an object I use. Now... I am of the opinion that when you create an object it should be very general-purpose -- don't put specifics in it for one program that will just get in the way of another. Also, an array is simply a block of variables. My friend uses this object in a professional pan/tilt/dolley camera controller. In the variables section of his program we have this:
We instantiate the adc object like this:
As you can see, I'm telling it how many channels to read and pointing to the first variable in a list; I use those names in the program.
What about if I extend your object with something like PRI (1) EU_eTape, (2) EU_lm34, (3)EU_dsspd300, etc. Make it into a (almost) general purpose object with conversion of raw adc into engineering units? To control which channel gets what kind of conversion, the adc.startx() could pass 8 parameters that specifies conversion method for each channel, e.g. adc.startx(ADC_CS, ADC_CLK, ADC_DIO, 8, @firstvalue, 1, 2, 2, 1, 3, 3, -1, -1) - and in this instance the two last channels gets no conversion, with parameter= -1. Obviously these parameters can be packed into one array too.
I appreciate the help, and also all advice on 'coding ethics'.
The compiler organizes RAM by type, starting with longs, then words, then bytes. Within a type (e.g., longs) the variables are put in the order they appear in your listing.
You're free to do anything you like, of course, but if you decide to republish your modifications please take my name off of the listing. There's nothing in it that I feel the need to have credit for, but I don't like my name on listings that I would not have produced myself. If you want the listing to say "based on code by Jon McPhalen" then that is fine.
Another idea you could use for your new object: instead of passing so many parameters you could past the address of a DAT block that has your conversion values (I'm still not clear on what you're doing with that). Let's say, for example, you just want multiply by some value. You could express those values in 0.001 units and do something like this at the end of the adc loop:
After cleaning-up the newly read level, it grabs the adjustment factor from the table (p_multiplier is a pointer to it), then divides by 1000 to get back to whole units. By doing it this way you still have a general-purpose object and the program (you or whomever you share it with) can adjust the behavior by pointing to their own conversion table; building a table into the object is not a good idea in my opinion.
ADCbit resolution
Scaling: positve means multiply, negative means divide
Offset: in scaled units
Linearisation amount log e: negative means inverse
Linerarisation amount log 10: negative means inverse
Averaging period: positive means in n samples, negative means in n mS
Noise removal filter: percent of outlier samples removed from average
FloorL: minimum value to be allowed
FloorH: maximum level to be allowed
Time tagging y/n - seconds since yr 2000 ( will be put in msw)
-have I forgot anything?