Homebrew EFI Project
Beavis3215
Posts: 229
in Propeller 1
Suppose I have a spinning plastic wheel(camshaft), with a very narrow steel target on its circumference. The target is strategically placed at 30 degrees before top dead center of the cam. There is a Hall effect sensor, sensing the passing of the target. The TTL nature of the Hall sensor is being buffered to a propeller friendly voltage level and connected to pin 15. The goal, time a revolution of the cam, defined as the time between any 2 target passings. Calculate the delay necessary for the cam at its present speed to move 30 degrees. Make pin 16 high for a certain duration(fire ignition coil), starting after this delay is over. After my first 100 or so attempts I have had limited success. The code that I'm attaching seems to waist time cog launching or somewhere else, causing the 2 methods to loose sync. I have 2 led's, one led tied to the hall sensor output, and one to pin 16. I have had a 2 channel oscilloscope monitoring the relationship between the two signals. When I say loose sync, I mean that there are certain cam speeds where I get output from pin 16, which is highly delayed, but no output at most speeds. For prototyping purposes I am using an electric motor to turn the cam. A representative cam speed is a cam period of .115 seconds which translates to about 519 RPM. Any ideas of what I'm doing wrong, or a better way of doing this? Look at my comments to see what I'm trying to do. It seems straight forward but its not.
Comments
Rather than launch the cog when needed, launch at the start of your program once. Then communicate via a shared memory location in hum memory, setting the flag when the other cog needs to fire the coil. This way you will have reduced lag between detection and and firing as you will not have to execute a cognew. It does take a certain time to load a cog.
That is entirely correct. I think you know how to program in spin (I don't much, but I can work out what it's doing), so I'll give you psuedo code for to program.
In you master cog where it currently launches a new cog, change that to setting the flag, just once, as in launching the cog just one. In you second cog, which you are now launching at program start, you need to detect the flag and act on it. Also resetting it so you don't continually fire.
That should be a big improvement, as you are now ready an waiting to act on your master cog.
However, spin is an interpreted language and as such it takes a while to process its' own byte code commands which have to be read from hub before being decoded. A better approach would be do this as pasm, which will very fast, which we can do a little later. With pasm your only delay is waiting for the hub slot to access memory.
First, the Spin compiler which runs on your computer knows how to compile *.spin file which contains assembly. Here's an example: of basic assembly on the Propeller when using Spin and Prop Tool.
http://pi.gadgetoid.com/article/starting-with-spin-on-the-parallax-propeller
Second, are you at all familiar with C or C++? I ask not because I want to start (yet another) Spin vs C/C++ language war, but because there is lots of help with homebrew EFI systems outside the parallax forums and, though Spin is pretty darned legible, you're likely to get even better help if it's a more common language.
If you're not sure which is right, see this thread for one of the more polite language war threads
Cheers,
David
That is because the way SPIN works I think (not entirely sure) it needs to know about, fire_flag explicitly. The way to do that which I can see is to pass it as another parameter in your call to cognew, so that line becomes:
Now a second parameter is passed to FIRE, but at present it only accepts one. Therefore the PUB needs to be amended thus: Now both your Cognew and PUB FIRE parameter lists agree.
I think you will save a little time too if you move the DIRA setting from within the repeat loop to between the PUB FIRE and repeat. This means it will only be set once on entry. It only needs to be set the once as you don't change direction in you code. Don't do that yet though.
As you have an oscilloscope, I suggest you don't move the DIRA yet, but try the parameter passing first with DIRA where you have it. Then once we get the fire_flag recognised and firing your coil, move the DIRA to where I suggest and check with the scope to see if there is an improvement in response time of trigger to action.
First off, the highlighting. If you look above the yellowish block you type your text into when replying, you will see a C as the fifth item in on a ribbon. Clicking on that inserts a couple of marker blocks to signify start of a code block and its end. I normally type [ code ] and [ /code ] , without the spaces as it save scrolling up and back down again. Tabs and spaces are handled differently within these markers. You do not see it whilst composing the message, but if you click the Preview button to the left of Post Comment, you will see a preview of what you have written and how it will be displayed on this message board.
Ah, my lack of SPIN knowledge is the porblem here. With your Cognew and the added @ for address of the fire_flag symbol, ie a pointer to a data object in memory, its' location, we also need to amend PUB FIRE to use that parameter as a pointer.
So now in PUB FIRE if you change all occurances of fire_flag to ptr_fire_flag, include on the PUB FIRE line. This is a reminder to us that it is really pointer to the memory location contain the data which is fire_flag.
Then you need to do the following, on the repeat line change ptr_fire_flag to: and also where it is set to 0 change to The long[ ] means to treat the memory adress specified within as a variable of long type, ie 32 bits. It requires an address to act on, this is supplies in the variable ptr_fire_flag as it really does contain the address of the memory location for fire_flag, because you have specified @fire_flag in your Cognew statement.
A variable is being defined and is being used to pass a parameter, and maybe not a pointer.
It definitely didn't run differently
I could be totally wrong but that is my first instinct.
Would you please post you current code so I can view. It may just be a small typographical problem? You may use the code posting as explained in previous message, you will get a scrolling window if it's over a certain size, but it is a short program at present.
AH I think I see the problem. I think reading the manual that fire_flag should be in a DAT block. So:
Then we need to undo passing fire_flag to PUB fIRE so:
Then:
That may work.
Question: Should it matter that the delays are calculated to milliseconds, microseconds, or left in ticks?
I had a faulty but right idea implementation that would run in millisecond format, .1 millisecond format and unstable on .01 millisecond format, but wouldn't ever fire on 1 microsecond format.
This program runs but the output is faulty due to the time in the firing delay being unaccounted for in the timing loop. Just a lot of bad ideas here I am trying to get away from.
That program could be speed up a lot if you were to change all your clkfreq/1000 to clk_cnt_milliseconds and use that throughout as a constant throughout. clkfreq is constant, not dynamic, so put clk_cnt_milliseconds goes in your VAR section and you set it to clkfreq/1000 before any of the repeat loops.
You don't need to do this at all if you do the above, but clkfreq / 1000 is close to ( clkfreq >> 10 ) which is equivalent to clkfreq / 1024. Then do all your timings, not on millisecond, but on this faster binary method. You will need to analyse your code to make sure you don not mix real milliseconds and the near binary version, and to adjust results accodingly, but it will be a lot faster if you ever need to use a value which changes during the loop.
Does that make sense?
What do you mean by "method"
Paste this in for pub fire. I've removed the @ as ptr_fireflag already contains an address.
being just a variable.
We tried that already, and shouldn't be different from
or the parameter
In the Propeller education manual, they show parameter passing during the starting of cognew, not after the cog has started. This may be the problem.
You may be right but I'm sure it can be done in some manner.
However, I am WRONG about the DAT block because that is local to the cog you run in I think, or maybe they both get local copies, not sure yet, too much manual to read and take in in a single sitting.
Please try this bit of code it should be quicker. It is your very original version 1 with the clkfreq / 1000 outside the loop.
I have dug out my Propeller Starter Kit, hopefully still functional, and even a bag of resistors and leds to hook up on the breadboard to monitor output pins.
It's late-ish here, currently 11PM, and I am getting rather tired, are you able to continue this tomorrow? That way we can try and learn SPIN togther, and I'll realise where I have been going wrong?
Just a word of caution here:
Spin might work as a proof of concept at slow speeds, but on a practical scale you will need to use PASM for realistic RPMs.
If one were to take a cam speed of 3600 RPM (high, but not outrageous) that is 60 revolutions every second. That translates to 21600 cam degrees per second, or 46 usec per degree.
There is no way a SPIN loop can reliably deal with those higher speeds with any accuracy of, say, one degree. If there was only a single speed, then possibly offsets could be made to fake out the correct timings, but I assume you will want the speeds to be variable. And in that case the overhead of the loop will itself be a serious and varying proportion of the desired time elements. A non linear proportion for each speed, leading you down a nightmare of frustration.
PASM, however, can do this all very easily..... time to jump in!
Cheers,
Peter (pjv)