Shop OBEX P1 Docs P2 Docs Learn Events
I need a Spin counter expert to examine some code for me PLEASE :) - Page 3 — Parallax Forums

I need a Spin counter expert to examine some code for me PLEASE :)

1356

Comments

  • idbruceidbruce Posts: 6,197
    edited 2011-01-04 14:55
    Jon
    by changing the step count you could stop the driver in an emergency without having to shut-down and restart the cog.

    Great idea!

    Bruce
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-01-04 15:38
    Thanks for the feedback ... I only can see the pulses with my scope because I don't have steppers running yet.

    But what code you should use depends on the usecase. As I already stated in an early stage, PASM is the better choice. In the end I only wanted to know if the idea with a second COG would work.
    The stepper runs with my code, but the missing part is to control the number of steps. As the propeller is deterministic the easy solution is to find the waitcnt-value to be used between the ramps. So, usecase is: "if you don't have to much changes" related to stepcount.
    Otherwise some additional work is needed to make the code "general purpose".

    Stepcount is already included in Jonnys code, so this piece of code is more general right now.
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-01-04 15:56
    Oh ... the loop is fast enough to also count the steps. Easy change, define a variable in the VAR section named stepcnt and change the loop of the stepper function as following:
      repeat
        PHSA := minPulseWidth
        stepcnt++
        WAITCNT(nCounterTime += nCounterDelta)
    

    With this it should be easy to find the right timing.
  • idbruceidbruce Posts: 6,197
    edited 2011-01-04 16:08
    MagIO2

    Why are you guys increasing the step pulse width to 2us?

    Bruce
  • JonnyMacJonnyMac Posts: 9,208
    edited 2011-01-04 16:14
    I did it because in a practical world there will be some capacitance in the connection (cabling) that will affect the rise time of the pulse. Since the frequency you're using is fairly low there's no need to create a pulse that is on the ragged edge of acceptable, especially since connections are never perfect.
  • idbruceidbruce Posts: 6,197
    edited 2011-01-04 16:16
    Jon

    I am having trouble with you code. The starting frequency sounds like it is to high. Still trying to figure it out.

    Bruce
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-01-04 16:16
    Read Stefans post on page 3. You should never run a system at the edge of the specs. 40kHz means that we have a cycle time of 25us. So there is no need to use 1us pulse time. Imagine your device is run under harder conditions than you have em in your test-setup. For example you sell a thousand machines to a rich oil-baron in the desert. And there 65% of your machines fail because the optocouplers can't detect the 1us pulses just because of the heat.
  • JonnyMacJonnyMac Posts: 9,208
    edited 2011-01-04 16:29
    idbruce wrote: »
    Jon

    I am having trouble with you code. The starting frequency sounds like it is to high. Still trying to figure it out.

    Bruce

    The code I wrote just outputs a few pulses (so I could see them on a 'scope) -- you'll have to make the code "practical" in the main method.
  • LawsonLawson Posts: 870
    edited 2011-01-04 17:00
    MagIO2 wrote: »
    Oh ... the loop is fast enough to also count the steps. Easy change, define a variable in the VAR section named stepcnt and change the loop of the stepper function as following:
      repeat
        PHSA := minPulseWidth
        stepcnt++
        WAITCNT(nCounterTime += nCounterDelta)
    

    With this it should be easy to find the right timing.

    You know, you could do the same thing by putting CTRA in NCO mode (%00100) and CTRB in POSEDGE mode (%01010) to count how many pulses have actually been produced. (i.e. CTRB would count the output of CTRA) In this case you'd use the step count in PHSB to determine when to ramp down, and tweak the deceleration ramp a bit so you ended at the correct step count.

    Lawson
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-01-04 17:25
    That's right and wrong.

    Right is that you can setup counter B to count the output of counter A, but what you say sounds like you have to use counter B because counter A is already used. That's wrong. To be able to access PHSB from the COG that's doing the ramping you have to do it in that COG and not in the stepper COG. So you could also use counter A(1) to count the pulses generated by counter A(2) ;o)

    So, the advantage of having a variable that counts the steps is that this variable can be used in all other COGs. For example there could be a watchdog that's doing an emergency break in case the count gets to high.

    By the way ... Jonnys code will do a full stop if the step-counter is counted down to zero. Depending on the mass you move with the stepper this might be a bad idea. So, take care that you never reach the end of the step-counter when you run the stepper with full speed.
    You should also avoid changing the step counter when it's not zero! The stepper COG reads the counter, decreases it and then writes it back. So the chance is high that whatever another COG writes there is overwritten by the stepper.
  • JonnyMacJonnyMac Posts: 9,208
    edited 2011-01-04 17:46
    @Bruce,

    I've attached a better demo (of the V2) code that should be helpful.

    Note MagIO's comment about setting the steps to 0 while it's running -- you do have to be careful not to do this when it's running; slow the motor to a safe speed before stopping. You don't have to worry about setting the step count to 0 and then having the PASM cog decrement that; when it reads the new step count it treats negative values like zero (it stops).
  • Tracy AllenTracy Allen Posts: 6,666
    edited 2011-01-04 18:00
    It is possible to generate precise bursts of N pulses at quite high frequencies by overlapping two cog counters, even in Spin without much overhead. For example, the attached 'scope trace shows a burst of 15 pulses at 1 MHz produced in Spin. It works because an output pin is wired-OR for all of the sources that address it, so one cog counter can blank the output of another.

    NCOburst2a.jpg


    The attached program sets up ctra and ctrb in NCO mode to address the same output pin, and ctrb sets up a bpin (differential mode) to make a pulse to help visualize the blanking (bottom trace in the above photo) and to help obtain maximum speed. From a terminal, you can enter a frequency for pulses within the burst, and the number of pulses desired. The speed limitations of Spin come into play for the period of the burst, not the frequency within the burst. There is no limitation for frequencies up to 100kHz, however above that, there is a tradeoff between frequency and number of pulses. For example, you can get a burst of 11 or more pulses at 1MHz, but not less than 10. At 20 MHz, the minimum number of pulses is 106. There would not be much limitation in pasm, and this method might fit into in a multitasking scheme. It takes less babysitting than some of the alternatives. Comments welcome. (Kuroneko?)

    I don't know if this would work for motors. There is no ramping.
    400 x 300 - 35K
  • idbruceidbruce Posts: 6,197
    edited 2011-01-04 18:11
    Tracy

    I can't speak for everyone, but I appreciate all input, even if I don't agree with it.

    Thanks for responding

    Bruce
  • idbruceidbruce Posts: 6,197
    edited 2011-01-04 18:12
    MagIO2

    Does it really take 5 secs for a cog to load and initialize?
  • JonnyMacJonnyMac Posts: 9,208
    edited 2011-01-04 18:15
    idbruce wrote: »
    Does it really take 5 secs for a cog to load and initialize?

    No, it takes about 500 microseconds.
  • kuronekokuroneko Posts: 3,623
    edited 2011-01-04 19:37
    ... there is a tradeoff between frequency and number of pulses. For example, you can get a burst of 11 or more pulses at 1MHz, but not less than 10. At 20 MHz, the minimum number of pulses is 106. ... Comments welcome. (Kuroneko?)

    No such thing as limitations. Just use the slowest NCO frequency for the gate and open it with NEGX - (compensation + N * pulseCount). Then start the high frequency NCO. The attached demo is set for three 20MHz pulses (it does go down to 0).
  • LawsonLawson Posts: 870
    edited 2011-01-04 19:45
    MagIO2 wrote: »
    That's right and wrong.

    Right is that you can setup counter B to count the output of counter A, but what you say sounds like you have to use counter B because counter A is already used. That's wrong. To be able to access PHSB from the COG that's doing the ramping you have to do it in that COG and not in the stepper COG. So you could also use counter A(1) to count the pulses generated by counter A(2) ;o)

    *snip*

    Um... I was assuming that the pulse generation and ramping would all happen in one cog. I.e. CTRA would free-run generating a commanded frequency while CTRB keeps track of how many pulses are generated. The ramping code in that same cog could then run 5-10x SLOWER than the maximum output pulse rate as long as the deceleration ramp was adjusted to compensate for the uncertainty in exactly when the deceleration ramp would start.

    If this is ported to assembly, I'd use a different pulse generation method. First setup a loop that runs faster than the maximum pulse rate you need. (say 80KHz) Inside this loop you would have an acceleration, speed, fractional step, and optionally a full step variable. With each loop, the acceleration variable would be added to the speed variable and the speed variable would be added to the fractional step variable. The stepper would then be feed the carry bit of the fractional step variable. At the same time the full step variable would be incremented or decremented depending on the sign of the speed variable. (aka an extended precision add operation) This system works well because it mimics the physical system fairly closely. I.e the physical system has acceleration limits, speed limits, and position limits which the software can easily implement by limiting the values of the acceleration, speed, and position variables.

    Lawson
  • idbruceidbruce Posts: 6,197
    edited 2011-01-04 20:46
    WOW

    I had not realized that I missed so many posts. That hacker must have affected the output a little. And hello Lawson. You guys are talking way above me :)

    Bruce
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-01-05 01:30
    @Jonny: Again I want to mention the "set counter"-problem. There is only a fifty fifty chance that you can alter the counter variable from outside of the stepper COG. The whole loop has 11 instructions. You read the counter, do something (6 instructions) and then write it back without making sure that it might have been changed in between.

    @Tracy: Cool thing. You still can do the ramping from outside. We only have to find a formula to calculate the time for the blanking counter. As the code is deterministic there is definitely such a formula.

    @Lawson: If I would do such a driver in PASM I'd do it more luxury as well. A wait-time of 2_000 clocks means that we have 500 instructions (or 250@80kHz). This is for sure time enough to do the ramping inside of the stepper-COG ... an emergency brake flag could be checked which then switches to a fastest possible ramp-down mode ...
  • idbruceidbruce Posts: 6,197
    edited 2011-01-05 01:48
    MagIO2

    Why did you make nCounterDelta := 10_000

    And could you explain the effect of this loop on the value of nCounterDelta

    repeat nCounterDelta from 30_000 to 2_000

    I want to fully understand what is happening with this loop and that value

    Thanks Bruce
  • idbruceidbruce Posts: 6,197
    edited 2011-01-05 01:53
    By the way, I have some new code for you guys. :) Smooth running stuff, based on MagIO2's code
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-01-05 02:42
    Hi Bruce,

    the nCounterDelta := 10_000 is not correct. You should change it to 30_000 as well (the value should be the same as the start value of the ramp up loop). When cleaning up the code you should preferrably use nice constant names for such values.

    30_000 is the speed which is used when starting the motor. If my calculations are right this means 1.25 revolutions per second. So, I'd call the constant for that SLOW_SPEED.
    2_000 is the max speed.
    The loop counts down the nCounterDelta from 30_000 to 2_000. The waitcnt inside of that loop simply waits for a while which simply defines how fast the speed increases. As you told us that the motors can increase the speed at a rate of 4-5 revolutions per second I simply used a value that resulted in a ramp of round about 4 seconds.
    Remember, nCounterDelta is used by the stepper-loop. So if you change the value of nCounterDelta this will affect the waittime in the stepper-loop. With modifying this variable you directly set the frequency of the pulse generated by the stepper loop.

    When switching on the pulse the stepper COG finds 30_000 in the nCounterDelta and waits for that time.
    Meanwhile the rampup loop waits 4_000 and decreases nCounterDelta by 1, waits for 4_000, decreases and so on.
    When the stepper continues it finds 29_993 in nCounterDelta and waits for that time, which is shorter than before. That's why the frequency gets higher.
    This is continued until 2_000 has been reached.
  • idbruceidbruce Posts: 6,197
    edited 2011-01-05 02:55
    MagIO2

    Okay that is what I pretty much thought. I figured nCounterDelta := 10_000 might be incorrect because it just did not make any sense. And I thought that nCounterDelta was decreased by one with each iteration, but I just was not sure, because I am just not familiar with Spin repeats. In a couple hours, I will show you some pretty decent stuff that was achieved by that code. The ramping really gets good when you use STEP Delta on the loops. I am going to see if I can eliminate the WAITCNT's altogether. Thanks for clearing that up for me. I truly do owe you one. I was very serious about that vacation for you and Jon. I believe in my product, and I truly think it is going to make a lot of money. Having my steppers run to their best potential was of the utnost importance to me. And you guys helped me achieve that. THANK YOU

    Bruce
  • idbruceidbruce Posts: 6,197
    edited 2011-01-05 04:20
    Okay Guys

    I promised some new source code. Here is a cogless stepper driver based on MagIO2's original code.

    Bruce
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-01-05 04:24
    "Show some pretty decent stuff" ... does that mean you're going to show us a video? Would love to see that!

    Using STEP can make ramping faster but not slower. That's why I used the waitcnt. Here you can do both and a repeat loop without a waitcnt was simply to fast.

    So, good luck with your product ... and whenever you have additional questions don't hesitate to ask. Maybe I'll continue with the idea of using a second counter to do the accurate counting this evening
  • idbruceidbruce Posts: 6,197
    edited 2011-01-05 04:30
    Sorry I forgot to attach
  • idbruceidbruce Posts: 6,197
    edited 2011-01-05 04:31
    Another one coming soon
  • idbruceidbruce Posts: 6,197
    edited 2011-01-05 04:32
    I used STEP because the default rate was way to slow. So by using STEP it is highly adjustable.
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-01-05 04:35
    Shouldn't this be outside of the loop:

    Counter := CNT + CycleOffset

    ????
  • idbruceidbruce Posts: 6,197
    edited 2011-01-05 04:40
    MagIO2

    LOL Yes it should, but it ran fine with it in there. LOL

    Bruce
Sign In or Register to comment.