I would like this object critiqued please
Hi,
This is code to simulate a hall effect sensor. I think it's harder to scope this, than a regular/consistent frequency, since it has the [X] amount of teeth missing. I get 3.14khz at 10000rpm and 504hz at 1000rpm?
The purpose of the code is to simulate a 36-2 trigger wheel and hall effect sensor, so for each rotation, there are 34 teeth and then 2 missing (assuming it started on the first tooth). Please let me know if there can be improvements, this is the first object I've tried to write, be it very basic. Attached is a working version to be loaded into the propeller.
Thanks for reading.
This is code to simulate a hall effect sensor. I think it's harder to scope this, than a regular/consistent frequency, since it has the [X] amount of teeth missing. I get 3.14khz at 10000rpm and 504hz at 1000rpm?
The purpose of the code is to simulate a 36-2 trigger wheel and hall effect sensor, so for each rotation, there are 34 teeth and then 2 missing (assuming it started on the first tooth). Please let me know if there can be improvements, this is the first object I've tried to write, be it very basic. Attached is a working version to be loaded into the propeller.
Thanks for reading.
PUB simulateCrankWheel(simCrankWheelPinNum, crankTeethSimToothCnt, crankTeethSimMissingToothCnt, crankTeethSimRPM) | localIndex, pstSimulateCrankWheel ' Initialize variables here dira[simCrankWheelPinNum]~~ outa[simCrankWheelPinNum]~ localIndex := 0 pstSimulateCrankWheel := 0 ' Set this to 0 if you don't want to see the pst troubleshooting code lines, 1 if you do { This is for a Hall effect signal/sensor simulation For 1000rpms on a 36-2 crank trigger wheel, it'd be (1000(36*2)) = 72000, then 72000/60 = 1200 pulses per clkfreq. 80000000(clkfreq)/1200 = a pulse every 133333.3 clk cycles that stayed on for 66666.67 cycles and then was off for every 66666.67 cycles So you'd loop on for 66666.67 cycles and then off for 66666.67 cycles and after 34 times, you'd wait for 66666.67 cycles * 4, to simulate the 2 missing teeth on and accompanying 2 teeth off (or gaps in between each tooth) An example to start the method would be simulateCrankWheel(7, 36, 2, 1000) } repeat if pstSimulateCrankWheel == 1 pst.Str(String("start")) pst.Dec(simCrankWheelPinNum) pst.Str(String(pst#NL)) pst.Dec(crankTeethSimToothCnt) pst.Str(String(pst#NL)) pst.Dec(crankTeethSimMissingToothCnt) pst.Str(String(pst#NL)) pst.Dec(crankTeethSimRPM) pst.Str(String(pst#NL, pst#NL)) repeat localIndex from 1 to (crankTeethSimToothCnt - crankTeethSimMissingToothCnt) ' loop number of physical teeth on and off outa[simCrankWheelPinNum]~~ if pstSimulateCrankWheel == 1 pst.Dec(localIndex) pst.Str(string(pst#NL)) pst.Str(string("pin high ")) pst.Dec(cnt) pst.Str(string(pst#NL)) waitcnt((clkfreq/((crankTeethSimRPM*(crankTeethSimToothCnt*2))/60))+cnt) ' on for 1 tooth outa[simCrankWheelPinNum]~ if pstSimulateCrankWheel == 1 pst.Str(string("pin low ")) pst.Dec(cnt) pst.Str(string(pst#NL)) waitcnt((clkfreq/((crankTeethSimRPM*(crankTeethSimToothCnt*2))/60))+cnt) ' off for 1 tooth repeat localIndex from 1 to (crankTeethSimMissingToothCnt) ' loop number of times for each missing tooth outa[simCrankWheelPinNum]~ if pstSimulateCrankWheel == 1 pst.Dec(localIndex) pst.Str(string(pst#NL)) pst.Str(string("pin low ")) pst.Dec(cnt) pst.Str(string(pst#NL)) waitcnt((clkfreq/((crankTeethSimRPM*(crankTeethSimToothCnt*2))/60))+cnt) ' on for 1 tooth outa[simCrankWheelPinNum]~ if pstSimulateCrankWheel == 1 pst.Str(string("pin low again ")) pst.Dec(cnt) pst.Str(string(pst#NL)) waitcnt((clkfreq/((crankTeethSimRPM*(crankTeethSimToothCnt*2))/60))+cnt) ' off for 1 space in between teeth if pstSimulateCrankWheel == 1 pst.Str(string(pst#NL)) pst.Str(string("finish")) pst.Str(string(pst#NL, pst#NL))
Comments
Since your using "waitcnt(time + cnt)" type of statements, your program wont take into account the overhead of running the code. In the waitcnt section of the Propeller manual there are examples of using waitcnt to more accurately make regular pauses in a program.
It will show you how to add an interval to the time to wait so each section of code takes a pradictable amount of time.
Here's a quick example:
The above example will "do stuff" every interval.
But, If you use:
Then each loop will take a little longer than "interval".
Play the propeller ace card! The propeller has 8 COGs, so it's easy to move all the debug-instructions into it's own COG. It's then like one COG is watching the other COG and reporting to you what it sees without adding any execution-time to the COG that runs the real code.
The problem is that the other COG will not see the local variables and function parameters by label, if you leave them as local variables/function parameters. So, for the time being you could make them global variables. Later you can change the debug-code to work with long[ address_of_parameters ][ x ].
As we learned before: Do one step after the other, so first remove the debug-code easiest way, then switch code to use constant interval, then you can change debugging showing local variables.
Some general comments:
(clkfreq/((crankTeethSimRPM*(crankTeethSimToothCnt*2))/60))
this term is used 4 times without changing any of the involved variables somewhere in between. In this case you should create a local variable which stores the result and use that in all waitcnt. This saves HUB-RAM and runtime. Ok ... you might say that runtime is not that important because you'd wait anyways in this case, but during a waitcnt the COG needs less current and saves energy and in other cases it might give you the right boost ;o)
;o)
It will take processr cycles to process the IF even if it's false. The true state will take even more time based on when the True condition executes.
I have a few objects i recently wrote that allow you to simulate a signal from the Crank Shaft and Cam Shaft of a car. Both are in PASM and are pretty fast. You simply layout your signal in data statements and the objects flip your outputs to match the rotation of the shaft.
You could easily write a small program to create the teeth pattern and even inject missing teeth of you wanted.
It can easily change between different patterns on the fly if need be.
Let me know if it's something that you may want to look at.
Jim Fouch
I'd love to see your code, although I cannot read PASM, so I don't know how well I'd be able to merge my ambitions with it.
When I turned it off I was able to go to 10000rpm without issue and the frequency showed 5.98kHz on the propscope, which fits my math much better than 3.14kHz
10000rpm/60sec per min = 166.67 166.67 * 36 pulses per rotation = 6000hz, sometimes it will fluctuate to 5.5x kHz because of the missing two teeth, but I believe it is working well now. Now on to moving the variables to another cog.
Here is the entire code, as the work firewall blocks the attachment feature of the parallax forum
Here is an example of the code I use.
To define the pattern you simply enter the location of chages in you pattern like this...
This is what the pattern looked on a scope...
The two objects I wrote are here...
Spinner.spin
Rotator.spin
One thing to note is that the rotator has code to write to specific pins and has LEDs to indicate the output. The actual output pins for the signal are INVERTED because I was driving 2N3904's to drive the outputs. You will need to change the pins and maybe the states to match your project.
Defined in you main spin program...
The two cogs are controlled by the values in these VARs that are in your main spin object...
I created a sub to set these for my pattern...
Once you have set the vars then you can start the two objects...
Once the objects are started, simply changing the VARs show above will allow you to change the pattern. Changing the AdvanceRate and or the IncrementCount will change the RPM. There are limits for how low you can set these values. For example if you set them too low you will actually get too much of a pause between steps. This is just like the WAITCNT method. If you go below 381 you will have to wait for the CNT to roll over.
The real value in these objects is they are very flexable and could be used to make almost any repeating signal.
You could also write a VB.Net or C# app to help create the patterns. Not sure I'd want to hand enter some 100 tooth signal.
For this example it shoud have been....
The example shown on the previous post was for this pattern....
What this shows is how flexable the objects are. Two totally different patterns defined in different ways. One with degrees of rotation and the other simpy by measuring the pattern on paper.
This solution could easily be modified to have more than two outputs if we moved to a LONG for the pattern and shifted the location portion further left and made room for the outputs. I could see making an eight output one.
I love the degrees of rotation, that is brilliant. It is going to take me some time to understand the ins and outs of the code, but I like that. I also have to measure cam position and my cam sensor has 3 triggers on it, I believe they are something like 105/105/150 degrees apart or something offset like that. I have to write code for that next.
I desiged it to work with 360 Degrees of rotation in mind but then later realized I had to account for two rotations of the cam. So, I just modified the code to rotate on any bondry. This way it could account for ANY number of rotation or really any signal that repeats.
The hardest part is entering the changes in outputs. One downside is ALL outputs are locked and if you want to shift one output you have to recalculate the entire data set. This is where a helper app would be greate to define the data statements.
Entire code since I can't upload .spin attachments
Looks pretty good. Not sure how fast your scope is or how fast you need to simulate the rotation.
I know in my project, when I had it all in SPIN it would skip updates once in a while even when simulating a ~700 RPM signal. Once I split the Rotator out into PASM the signal became rock solid. I'm looking at the output with a logic analyzer that runs at 500Ms/s.
Basically as I would siulate the rotation of the shaft, the other object could not keep pace 100% of the time in SPIN. Kind of funny the we're using a language called SPIN to simulate a spinning shaft...lol PASM is up to 200x faster than SPIN in some cases. I was able to simulate the larger pattern at speeds way above what a real motor could ever run at. One thing to increase the simulated RPM is to increase the IncrementCount. In the examples I showed above we advanced 1/10 of a unit with a resolution of 0.1 Degrees. By doubling this to a value of 2 would double the rate or rotation but cut in half the resolution as 0.2 Degrees. So setting it to 10 would spin 10x as fast but only have the resolution of 1.0 Degrees.
I also have an Arbitrary Waveform Generator ( http://www.tequipment.net/RigolDG1022.html ) that would do the same thing. But to do it with a $20 protoboard is so much more fun.
The crank works great at 10000 rpm, but the cam is not showing up well on my oscope, and I cannot drag the oscope display screen any larger either.
This is where a Logic Anaylizer has an advantage. Most can compress the signal and the display it back expanded in realtime. Where as a scope does not compress and has a much more limited view window.
Here is an exampe scree shot from my Logic Anaylizer (http://www.pctestinstruments.com/ ) It's not a cheap date, but boy does it make troubleshooting a lot easier.
At 10000rpm, I'm at 2677 clk cycles for a single degree of cam rotation or 30000 degrees rotated per second, I guess this is too fast for spin
I don't want to take on assembly, but I guess I have no choice and will try and use your object, thank you for that.
I think I have something that might be working in spin, would you mind testing it for me with the test environment you have setup already? Sorry I can't attach the .spin files because of the work firewall. It's probably too good to be true, but I'm a little optimistic it might actually be a viable solution.
I tested this at 15000 engine rpm with my scope and I'm seeing the groups of 3 registering on the scope with a slightly longer delay/space in between each group of 3. I will clean up the parameters for the method later after I verify for sure if this is working or not.
What do you think?
BTW pasm is not that difficult compared to most other assemblers. Its a nice and regular instruction set.
I actually wrote the simulator code, so I could feed it back into the prop and write code to read it, rather than sit out in the car for hours testing it and reading the actual sensors themselves.
Now that I *think* I have the simulators written, I was going to try and write the code to read the simulators/sensors and see how that goes?
Maybe I'll give PASM a try, I just don't even know where to start with it. Spin was/is such a chore, it really makes me scared to even try PASM.