Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Time between change of direction pin and step pin #103

Closed
TML22 opened this issue May 23, 2012 · 36 comments
Closed

Time between change of direction pin and step pin #103

TML22 opened this issue May 23, 2012 · 36 comments

Comments

@TML22
Copy link

TML22 commented May 23, 2012

Hi!
I wonder how to add a delay between status change of direction pin and activation of step pulse.
The problem is that my stepper driver is opto coupled and need at least 15 microseconds of a steady status on direction pin before it can handle a step pulse.
Current code in stepper .c only have very short delay.

// Set the direction pins a couple of nanoseconds before we step the steppers
STEPPING_PORT = (STEPPING_PORT & ~DIRECTION_MASK) | (out_bits & DIRECTION_MASK);
// Then pulse the stepping pins
STEPPING_PORT = (STEPPING_PORT & ~STEP_MASK) | out_bits;

// Regards
TML22

@jgeisler0303
Copy link
Contributor

My first shot would be to use the second timer twice, first for setting the step pins and then to reset them. The direction would still be set in the first timer interrupt. But obviously this needs some careful extra coding and testing. Keeping the setting of the step pins in the main timer interrupt with a delay between direction and step pins is not an option in my view.

@chamnit
Copy link
Member

chamnit commented May 23, 2012

I agree with Jens. To make this configurable would be fairly difficult, given that we don't have an extra timer to handle this easily, or would require some careful and time consuming coding and testing.

But I think there are work around that might work. Depending on the stepper driver, some of them step only on the falling edge of the pulse, so if you set your pulse time greater than your 15 microseconds delay you need, your steppers should move in the correct direction. Or, if your stepper steps on the rising edge, you can try to invert your stepper pins with the 'step port invert pins' settings (these invert direction and step pins). This should get you the same result.

Give this a try and let us know if it works and we'll post it as a solution in the Wiki.

@langwadt
Copy link

inverting the clock should work. the delay between direction and step and the time step is inactive before the edge will be tied to the same value but assuming they have the same requirements that should be ok

I haven't used AVR much but I think it should be easy enough to use both the overflow and compare interrupt on timer2.
use one to set the step pins the other to clear them.

@chamnit
Copy link
Member

chamnit commented May 23, 2012

Timer2 is used to clear the step pins, as you may know. I ran into an issue that if it was not disabled between step pulses, Timer2 would occasionally interrupt in the time between resetting the timer counter and setting the step pin. This would cause a problem where the step pulse would be severely truncated to about 2 microseconds or not step at all. So, to have Timer2 pull double duty may cause some issues.

@langwadt
Copy link

I'd just leave the overflow irq as it is, clearing steps and disabling the interrupt.
I'd use the compare interrupt to set the step outputs.

in timer1, set timer2 so that compare is after the needed delay, and overflow is after delay + step pulse width

@chamnit
Copy link
Member

chamnit commented May 23, 2012

Ahh. I see what you mean. I suppose this would be possible to do. Overflow should be step pulse width to not change functionality, and the compare delay must be shorter than the step pulse width, occurring before the step clearing and timer is disabled.

Personally, I'm not much of a fan of adding another interrupt, unless truly needed, but this trick may come in handy for something else down the line. I think the pin inversion work-around should work for this just as well without having to add anything. Thanks for the idea!

@TML22
Copy link
Author

TML22 commented May 24, 2012

Hi, all!
Thanks for the fast reply.

So far i have tested different combinations with rising/falling edge on both dir/step pins, as chamnit suggested.
Sorry to say it did not improve the performance of the driver rather the opposite.

The issue is that the motors do spin, and change direction as you might expect, but if you let the motors toggle between two position repeatedly they will start to deviate in one direction during time.

Changing speed and acceleration to lower values will not help, it will only take a little longer time before you see the problem.

I have done the exact same test using Mach3, without any issues.
Stress testing works like a charm up to the point there the motor loose synchronization, as expected.

So this led me to the conclusion that there has to bee some difference in how mach3 and grbl is handling dir/step pins.
I have measured the output from both systems and there is a huge difference.

GRBL has a delay of 0.25 microseconds between status change of dir pin to activation of step pin.
Mach3 has a delay of 22.5 microseconds between status change of dir pin to activation of step pin.

I do not think that the delay has to be that long, but there is no way to change it that I know of to test this.

I think langwadt is on to something, but I haven't had time to wrap my mind around how GRBL generates dir/step pulses.

If anybody feel up to it I gladly test any code attempt to fix this issue in my rig.
I will try myself, but for the moment i just concentrate on to understand how GRBL works.

@TML22 TML22 closed this as completed May 24, 2012
@TML22 TML22 reopened this May 24, 2012
@jgeisler0303
Copy link
Contributor

Let me try to write you a quick "patch" according to langwadt's suggestion:
create function:

ISR(TIMER2_COMPA_vect) {
  STEPPING_PORT = (STEPPING_PORT & ~STEP_MASK) | out_bits;
}

and remove the out_bits line from ISR(TIMER1_COMPA_vect)

to enable the new interrupt and set the time it should trigger add these two lines to void st_init()

TIMSK2 |= (1<<OCIE2); // Enable Timer2 Compare Match A interrupt
OCR2A = -(((settings.dir_step_delay_microseconds-2)*TICKS_PER_MICROSECOND) >> 3); // set delay between direction pin write and step command

Of course the variable settings.dir_step_delay_microseconds has to be defined.
Finally, in ISR(TIMER1_COMPA_vect) change the "reload timer" line to let the stepper pins be cleared after dir-to-step-delay PLUS pulse-delay:

TCNT2 = -(((settings.pulse_microseconds+settings.dir_step_delay_microseconds-2)*TICKS_PER_MICROSECOND) >> 3); // Reload timer counter

Make sure the total delay is well below 255/16*8=127 micro seconds, otherwise the TIMER2_COMPA_vect might trigger a second time before the timer is disabled!
All not tested!
Let us know the results in any case.

@chamnit
Copy link
Member

chamnit commented May 24, 2012

Hmm, I'm hoping that your tests aren't a harbinger for a deeper problem that is inherent to Grbl. Typically direction pins need only a fraction of a microsecond to trigger a step in the correct direction. I've done a directionality test before on my setup, and have noticed some minor drift on occasion, but I've attributed this to inertia. On my setup the drift, if it is there, has never a large enough issue to cause problems with machining parts.

Just curious, can you provide the make and model of your stepper drivers? Also, of your general setup of motors and such? I'd like to take a look at the datasheets and see if I can identify any hardware-specific problems that Grbl may have problems with.

Lastly, what exactly do you mean by inverting the pins make things worse? How so? Does it still move? Or does the drift seem to get worse? How long does it take to see this drift and by how much (like a few 0.1deg or a whole rotation)?

@jgeisler0303
Copy link
Contributor

TML22 said that his drivers are opto coupled, so I wouldn't worry too much about a deeper "problem in grbl". I'm not an electronics engineer, but I imagine the opto transistors could have some sort of jittery delay.

@chamnit
Copy link
Member

chamnit commented May 24, 2012

Jens: True. The opto transistors could have a jittery delay, but I'd like to know for certain how much and how the step input sensing differs. I say this because the step input pin inversion should have worked for an Allegro IC like I use.

Also, looking now at the Allegro datasheets, these require a 0.2 microsecond delay to sense a direction change for a step. Pretty close if TML22's 0.25 usec time measurements are correct. I wonder if this lack of wiggle-room or buffer, would cause some steps to move incorrectly, very intermittenly. Almost inperceptible, but enough to cause problems on some setups.

I'm in the process of moving (with x3 workshop space!) and everything is packed away, but I'm hoping that I can get the oscilloscope setup and see if I can test and visualize some of this.

@TML22
Copy link
Author

TML22 commented May 24, 2012

Hi!
Well the only information on my drivers that I have is that they are marked 3128A, google on that and you will find them on ebay. 0.9 - 3A, 10 - 40VDC.

Step and dir pins from avr is routed to a low side driver (ULN2803A) which in turn drives each of the opto coupler in the stepper driver.

I hope that the retailer here in sweden can give some further information on the used driver chip.
I will not open them myself since they have a warranty seal.

What i meant with "inverting pins" was that I changed the step signal from active high to active low.
Just to see if there was any change in performance due to different time in rise / fall time of the opto-coupler.

That was actually done with Mach3 and a active low setting made the motors to perform worse.
Lower max speed and so on.

It's hard to give any exact details of the drift, but what I have noticed is:
It always drift in one direction.
If I move between two position, let's say from 0 to 1mm, (1 mm = 1600 steps in my setup) 500 times
I will have in the end a deviation of 50 - 150 pulses.
If I increase the distance I will still end up with the same deviation.
So my conclusion is that the amount of lost/added pulses are in a direct correlation of changes in direction.

Jens I will try to find some time this weekend to implement your patch.

@langwadt
Copy link

It is not unlikely that the optocoupler is slower in one direction than the other, if the delay dir-to-step is right on the edge that could explain why it losses steps in one direction

But it makes no sense that inverting the clock doesn't work. if you make the delay big enough

remember that the delay will also set the pulse width on the step pins, some driver required tens of us pulse
widths on step, so you might need a bigger delay than you think.

I think a quick thing you could try before you start inventing something is to add a delay_us(25); after setting the direction pins. It should tell you if adding a delay will fix the problem

(assuming that doesn't make the interrupt too slow )

@chamnit
Copy link
Member

chamnit commented May 24, 2012

Thanks TML22. I'll take a look into your ICs and see if I can dig up anything. Let us know if you discover more details about your driver.

I agree with langwadt that it doesn't make much sense that the inverting the clock doesn't work, or what would make it behave differently. When you changed the step input, have you tried increasing the microsecond step pulse value? This would effectively make this work as a delay. (langwadt: we can't use delay_us() in the interrupt as it is blocking and also uses one of the timers.)

Also, how are you running the movements? Are you inputting by hand and allowing Grbl to complete the motion? Or are you streaming the motions from a file? This can matter, since Grbl will disable the stepper motors if there are no motions left in the queue. It will by default pause for 25usec to lock the motor, to keep it from drifting, then disable them. I wonder if there is a difference between the two methods.

Lastly, have you changed the amount of distance in your experiments? Does this change the amount of drift that you see or the direction of it? (EDIT: Already answered. My bad.)

@langwadt
Copy link

A bit OT but, are you sure you cannot use delay_us() in an interrupt and that it uses a timer? isn't it just a busy wait loop around a number of nops calculated from the defined CPU clk?

A busy wait wastes time in the interrupt, but as long as the step rate isn't too high so the stepper interrupt can still keep up it should be ok for a quick test

@chamnit
Copy link
Member

chamnit commented May 24, 2012

You may be right. I've always been under the impression that the delay_us() function uses one of the AVR timers, or maybe this might be in terms of the Arduino IDE doing this rather than avr-gcc. Either way, it generally shouldn't be used in an interrupt since it is blocking, but for a test as you suggested, this should be fine.

Sorry for the confusion. Late in the day, exhausted, and out-of-the-game for a little while.

@TML22
Copy link
Author

TML22 commented May 25, 2012

Some short replies on langwadt´s comments:

It is not unlikely that the optocoupler is slower in one direction than the other, if the delay dir-to-step is right on the edge that could explain why it losses steps in one direction

"That is exactly what i believe is happening here."

But it makes no sense that inverting the clock doesn't work. if you make the delay big enough

remember that the delay will also set the pulse width on the step pins, some driver required tens of us pulse
widths on step, so you might need a bigger delay than you think.

"I understand, and I will redo this test by inverting step pins in GRBL, as I have mentioned earlier i did this test using Mach3, but realize now that I used a to short time on the step pulse, which made that test totally useless.
If I set the step pulse to 15us everything works perfectly (Mach3 no inverted output)."

I think a quick thing you could try before you start inventing something is to add a delay_us(25); after setting the direction pins. It should tell you if adding a delay will fix the problem.

" I sort of did that test by using Mach3, when using correct time on step pin, it works.
The reason is that Mach3 by default add a delay by 22us between between direction pin and step pin each time a change of direction is performed."

chamnit:

I stream from a file.
G90 G21 G17 F500
G01 X1
X0
X1
......... repeated for around 500 times

I do not use the disabling feature of GRBL, since my drivers do have a automatic current saving mode.

@chamnit
Copy link
Member

chamnit commented May 25, 2012

Great thanks for the update TML22. The file streaming rules out some things that are "reaches", but sometimes you never know with programming. If I understand correctly, increasing the step pulse width and inverting on Mach3 performed exactly the same as normal operation, and that you haven't yet tried this on Grbl. Let us know what happens.

langwadt: Now that I've gotten some sleep, one of the reasons that you don't put a delay in an interrupt is that these block out other interrupts. For the step pulsing, this is not a problem, but for the serial interrupt, this is. If we install this delay, there can be instances that the receiving bit may be lost or a transmitted bit is not sent on-time.

@langwadt
Copy link

interrupts are re-enabled in the timer1 interrupt it can be interrupted by the serial interrupt so that shouldn't be a problem.

also interrupt latency is only an issue for receive, because you risk missing a byte, for transmit there will just be a short delay between bytes which isn't a problem

@jgeisler0303
Copy link
Contributor

Well, interrupts are enabled only after the stepper bits are set and for precise timing I would keep it that way. But since the UART is in hardware, the receive interrupt has is invoked at most every 1ms (10bits/9600bits/sec). So, a delay of some tens of microseconds shouldn't hurt. Transmit is truly not affected at all.
Still, I wouldn't waste any of the precious processor time in production use. But for a quick and dirty experiment it's definitely worth a try.

@chamnit
Copy link
Member

chamnit commented May 29, 2012

Ah, thanks for the clarification. I was under the impression serial comm was interruptable, but only the transfer of data byte from the hardware to the CPU may be interrupted. My bad. I just wanted to make it clear that adding too much processing time to interrupts can have unintended concenquences and can cause more problems than solve. In this case, this shouldn't, but this should be in no way be something that should be done in a release, only a test.

TML22: Have you had any new developments?

@TML22
Copy link
Author

TML22 commented May 29, 2012

Hi all!
Sorry for the delay.
But I managed to do some test.

I tried langwadt´s suggestion of invering the step pins to add some time since my stepper driver will read the rising flank on the inverted pulse.
It works I can´t see any signs of a missed position.

However my drivers seems to dislike a normally high state on step input.
After have reached it's target position there are times when the motors starts to buzz in a way that will not happen if the drivers have a step pulse that is normally low.
The drivers allways buzz (current regulation) but invering the step pulse givs it a more angry and nervous sound.
I dont't know if this really is a problem or not.

I also tried to insert a delay after setting the direction pins.
This worked better then expected, streaming file, high stepping speed.. all test worked flawlessly.

Until i decided to reduce the delay from 20us to 15us since delay_us(20) results in a total delay of around 27us wich is more than needed.
The new delay introduced a interrupt in the step pulse train for about 4ms.
Changing back to previous setting did not help, the only thing was to remove the delay to get rid of the interrupt.
So basically there is not a good idea to have a delay inside a interrupt service. (which we all knew)

I also made i quick attempt to implement jgeisler0303's patch.
but I only manged to disable all step / dir pins.
Have to take closer look at this as soon as i have time.

@chamnit
Copy link
Member

chamnit commented May 29, 2012

TML22: Great to hear that inverting the stepper pins worked. I assume that you increased the step pulse time to get it to work this time around?

That's odd that you are experiencing increased motor buzzing. I'm not sure what would be causing it unless it makes your setup more susceptible to electronic noise for some reason.

Jens: What do you think of this? It's hard to tell if this motor buzzing is an isolated problem, but, if it isn't, I'm still resistant to adding another interrupt to the core stepper module, assuming that adding the timer2 compare interrupt will add another layer of interrupt overhead. I'm concerned with it affecting the max stepper frequencies that Grbl can support or other things that could be problematic.

I think adding this delay feature is a good idea, but not so inclined to make it a standard feature, since the stepper pin inversion should work. So I'm thinking that we should install this as a compile-time option for specific user issues. This should be straight forward to integrate.

@jgeisler0303
Copy link
Contributor

Chamnit: I agree with you on both, a) to use a nop-delay for testing only and b) to implement an interrupt driven delay only if it's really needed, i.e with as compile time option.

Regarding the buzzing I have no idea. I only know that those seemingly nice and clean digital electronics are - on the lowest level - also only analogue circuits and a mathematical negation is far from what happens inside the chip. So, if some chip developer wanted to save some resources he might have used some tricks that saved him a couple of gates but cannot handle longer periods of high state. You never know. Before TML22 reported that the signal inversion does work in principal, I thought that maybe the direction is only acknowledged when the step pin is low ... you never know ... So, the specs to this chip would be really nice to have.

@langwadt
Copy link

it the avr really that hard stressed that the extra interrupt would matter? I just had a look at the list file and the ovf2 irq (code in compare irq should be similar) is ~20 cycles even with the few cycles it takes to get in and out of the interrupt that is only ~2-3us

@chamnit
Copy link
Member

chamnit commented Jun 1, 2012

Unfortunately it may be. In v0.6, the G02/03 arc generation or complex curves with rapid, short line segments would cause Grbl to choke, especially at the higher feedrates. Sincte then, we have done a lot of work optimizing the acceleration planner, arc generation function, and the overall internal processes, still while adding more functionality and features. Right now, we have been fortunate not to run into anymore significant issues nor anything that seems to effect robust performance. If we add another interrupt, this may disturb this balance without a lot of testing and validating. Anyhow, if we have any spare cycles, I'd like to invest these into new features for all, not a nice-to-have (which may be added as an unsupported compile-time feature.)

@chamnit
Copy link
Member

chamnit commented Jun 27, 2012

TML22: Not sure if you've moved past this issue, but I've posted the necessary changes to Grbl for the direction pin time delay this evening in the 'edge' branch. To enable it, you will need to download the edge branch code and change the STEP_PULSE_DELAY to something other than 0 (about 25 for your case should work.) Compile and flash it and you should be go.

I've tested the code on my oscilloscope, and it looks good. But I have not had a chance to setup my mill, since I'm still in the process of moving in and setting up. If you happen to use it, let me know how this works.

@TML22
Copy link
Author

TML22 commented Jun 27, 2012

Hi Sonny!
I really appreciate your effort!
I have not moved past this issue I simply used other means to control my little machine.
Any way I will not give up GRBL since I really like the concept.

I Can not find your changes in the edge branch, and the commit history doesn't show any changes?
Have I missed something?
cvx

@TML22 TML22 closed this as completed Jun 27, 2012
@TML22
Copy link
Author

TML22 commented Jun 27, 2012

Hi Sonny!
I really appreciate your effort!
I have not moved past this issue I simply used other means to control my little machine.
Any way I will not give up GRBL since I really like the concept.

I Can not find your changes in the edge branch, and the commit history doesn't show any changes?
Have I missed something?

@chamnit
Copy link
Member

chamnit commented Jun 27, 2012

Weird. Github for Mac was forcing me to commit files that didn't have any changes. It was holding the up branch syncing. It should be fixed now.

@TML22 TML22 reopened this Jun 27, 2012
@TML22
Copy link
Author

TML22 commented Jun 27, 2012

Ok now it's updated.
I will test it out and let you know the result.
Many thanks!

@chamnit
Copy link
Member

chamnit commented Oct 12, 2012

@TML22 : How did this work out for you? Hoping that radio silence means it's all good. :)

@chamnit chamnit closed this as completed Oct 12, 2012
@blinkenlight
Copy link

If posting to closed issue is a no-no please forgive this newbie; I know I'm late to this particular party, especially since the code to implement this feature has already been written, but I have an idea bugging me and I'm curious what you guys think of it;

I understand that "normally" grbl sets the dir then the step signals in quick succession in the same interrupt, while the edge version does this using an extra interrupt to create a delay between them if so compiled, and this new interrupt is undesirable because of the extra strain it places on the MCU. I'm also aware of the suggested workaround of inverting the pulse polarity, but that has its own set of drawbacks and it's not really a clean solution.

So here's the idea - what if the dir pin would not be delayed from the active step edge by using an extra interrupt, but by being set by the already existing interrupt implementing the falling edge of the step pulse? As in, the direction pin for a given step would get set at the falling (inactive) edge of the previous step pulse? This would seem to not require any extra interrupts. It would obviously require a single "extra" firing to set the dir the first time before the first step pulse, but that doesn't sound too bad I think. Am I just being stupid here...?

@chamnit
Copy link
Member

chamnit commented Oct 13, 2012

Nope. You're right on. That idea popped into my head when I when I wrote that last post too. But, I think we would have to make sure this would work for all stepper drivers. I'm unsure whether or not they all detect a rising edge or a falling edge.

I too am not a fan of adding another interrupt, especially at the high frequency that the stepper pulse train operates at. That's the reason that it's experimental. I think what we can do is to add a compile-time option for where the direction pin is set, at the falling or rising edge. This would be a pretty good solution for most people I think. If you agree, I'll add this option when I push next.

@blinkenlight
Copy link

Glad you like it. My thinking was that since the step pulse polarity is also reversible, attaching the dir setup to the "inactive" edge of the step pulse (ie. the "end" of the timed pulse) whether that ends up being an actual falling or rising edge would guarantee compatibility with any driver - regardless of the polarity of the edge they need, as long as they latch the direction signal at the beginning of a timed pulse, they would all be fine.

@TML22
Copy link
Author

TML22 commented Oct 14, 2012

Hi Sonny!
Sorry for such a late reply.
You're implementation of a delay between dir and step pulse, works like a charm!
It was exactly the medecine my drivers needed to work properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants