Hi Tom,
Currently on 4.33q kflop controller firmware.
I have a machine where chan[4] is normally used for step+direction (which works fine with I/O bits 36, 37) but it's possible to swap the motor out for a laser which needs to use the step output as a GPIO to switch the laser on and off.
The trouble is, I have not been able to figure out how to switch between those two modes. In fact, I have not been able to use those GPIOs at all, even if I never set up the channel or enable it. Note that I have the FPGA option set which sets active high for step pulses.
Assuming step/dir has been in use on chan[4], what steps to I need to take to disable the step/dir and set a state where I can use SetBit(36)/ClearBit(36) to manually toggle the output? I could also use the dir output (37) if necessary.
Regards,
SJH
Change from step/dir to direct GPIO program control
Moderators: TomKerekes, dynomotion
- TomKerekes
- Posts: 2676
- Joined: Mon Dec 04, 2017 1:49 am
Re: Change from step/dir to direct GPIO program control
Hi Steve,
If the Step/Dir Generator is enabled it overrides the GPIO mode.
There is a 32-bit register that controls the Step Frequency for the generators, the mode, and whether it is enabled or not. The Enable is bit 31.
Note the +8 on the channel number to restore TTL mode for the output.
Also writing the 4 bytes should not be interrupted or the result might be corrupted. So you might want a WaitNextTimeSlice before the writes.
If the Step/Dir Generator is enabled it overrides the GPIO mode.
There is a 32-bit register that controls the Step Frequency for the generators, the mode, and whether it is enabled or not. The Enable is bit 31.
Note the +8 on the channel number to restore TTL mode for the output.
Also writing the 4 bytes should not be interrupted or the result might be corrupted. So you might want a WaitNextTimeSlice before the writes.
Code: Select all
#include "KMotionDef.h"
main()
{
int v=0;
int chan=4;
int Enable=0;
v = (v & 0x007fffff) | ((chan+8)<<24) | (Enable<<31);
FPGA(STEP_RATE_ADD) = v;
FPGA(STEP_RATE_ADD+1) = v>>8;
FPGA(STEP_RATE_ADD+2) = v>>16;
FPGA(STEP_RATE_ADD+3) = v>>24;
}
Regards,
Tom Kerekes
Dynomotion, Inc.
Tom Kerekes
Dynomotion, Inc.
Re: Change from step/dir to direct GPIO program control
Thanks Tom, that works like a charm. I'm a bit puzzled by the initial 3 bytes of zeros, though. Does that mean "no change to anything else"?
One followup question: the code below is run in a loop. While the laser PWM is enabled, it tracks the accumulated amount of XY motion, and the amount of time the laser has been on. It then turns it on or off according to the desired amount of on-time per unit distance. It is basically working, although it seems to come up a bit short regarding the distance moved.
One requirement is that the laser is off for rapid motion, and only comes on for feeds. The initial setting of the 'run' variable is showing how this is determined.
If I use G-code G91 G1 X50 to move 50mm, the lpwm_accum_d field ends up with something like 49.247mm which, although close, is not as good as I would expect. Can you see anything wrong in the following?
Regards.
SJH
One followup question: the code below is run in a loop. While the laser PWM is enabled, it tracks the accumulated amount of XY motion, and the amount of time the laser has been on. It then turns it on or off according to the desired amount of on-time per unit distance. It is basically working, although it seems to come up a bit short regarding the distance moved.
One requirement is that the laser is off for rapid motion, and only comes on for feeds. The initial setting of the 'run' variable is showing how this is determined.
If I use G-code G91 G1 X50 to move 50mm, the lpwm_accum_d field ends up with something like 49.247mm which, although close, is not as good as I would expect. Can you see anything wrong in the following?
Regards.
SJH
Code: Select all
#if LASER_PWM
if (supe->lpwm_enabled) {
int run = !CS0_DoingRapid && CS0_TimeExecuted < CS0_TimeDownloaded; // Only run for normal feeds
if (run && supe->lpwm_enabled == 1) {
// Initial start
supe->lpwm_enabled = 2;
supe->lpwm_last_samp = Time_sec();
supe->lpwm_accum_t = 0.;
supe->lpwm_accum_d = 0.;
supe->lpwm_samp_pos[0] = chan[0].Dest;
supe->lpwm_samp_pos[1] = chan[1].Dest;
supe->lpwm_on = 0;
printf("supe: lpwm start\n");
}
else if (!run && supe->lpwm_enabled == 2) {
// Stopping after run
supe->lpwm_enabled = 1;
set_output(STEPB, 0);
printf("supe: lpwm stop\n");
}
else if (run) {
// PWM run state
double T = Time_sec();
double dt = T - supe->lpwm_last_samp;
double dx = chan[0].Dest - supe->lpwm_samp_pos[0];
double dy = chan[1].Dest - supe->lpwm_samp_pos[1];
double d = sqrt(dx*dx + dy*dy);
supe->lpwm_last_samp = T;
supe->lpwm_samp_pos[0] = chan[0].Dest;
supe->lpwm_samp_pos[1] = chan[1].Dest;
if (supe->lpwm_on)
supe->lpwm_accum_t += dt;
supe->lpwm_accum_d += d;
supe->lpwm_on = supe->lpwm_accum_d * supe->lpwm_q > supe->lpwm_accum_t;
set_output(STEPB, supe->lpwm_on);
}
}
#endif
- TomKerekes
- Posts: 2676
- Joined: Mon Dec 04, 2017 1:49 am
Re: Change from step/dir to direct GPIO program control
Hi Steve,
May lose some motion if the code is interrupted and the Dest changes between the time is used and when it is saved. How often is this code executed? The double precision sqrt is a somewhat expensive call so that might increase the chances of this. I think a better approach would be to sample it first and then use that for both the calculation and the save.
The first 3 bytes are the Step Frequency. The 4 bytes form a 32-bit word that is written to the Generators after the 4th byte is written. Actually I suppose if the generator is being disabled then writing garbage as the frequency wouldn't matter, so only writing the 4th byte should work and that would avoid any interrupt issue.I'm a bit puzzled by the initial 3 bytes of zeros, though. Does that mean "no change to anything else"?
The only thing I can see is this code:If I use G-code G91 G1 X50 to move 50mm, the lpwm_accum_d field ends up with something like 49.247mm which, although close, is not as good as I would expect.
Code: Select all
double dx = chan[0].Dest - supe->lpwm_samp_pos[0];
double dy = chan[1].Dest - supe->lpwm_samp_pos[1];
double d = sqrt(dx*dx + dy*dy);
supe->lpwm_last_samp = T;
supe->lpwm_samp_pos[0] = chan[0].Dest;
supe->lpwm_samp_pos[1] = chan[1].Dest;
Regards,
Tom Kerekes
Dynomotion, Inc.
Tom Kerekes
Dynomotion, Inc.
Re: Change from step/dir to direct GPIO program control
The code is called in my supervisor loop, so it should return here every couple of 90us intervals - confirmed this on the scope since the minimum pulse widths are a few hundred microseconds. Maybe there are some "flyers" which I don't pick up, which would make sense if sqrt is slow. Probably for this application I could change it to use single precision for the summations. Good point about the inconsistency of Dest - normally I would do that, but I was pretty sure there would be no interrupts.
...a few minutes later...
Tried that, and it works! So now it accumulates distance increments using float instead of double, uses sqrtf(), and single access to Dest. Comes out exact now.
FYI this is a pretty nifty app. The nice thing about doing it this way is that when laser cutting, if it needs to slow down around a corner, the power is automatically reduced so that the corners don't get "burned". Originally, I was just using the step signal as a PWM, but that has the disadvantage that every G1,2,3 has to be edited to output the correct 5th axis movement. The other disadvantage was that the PWM is then quite high frequency and the laser driver tends to filter that into a quasi analog signal - this causes the laser gain to drop so that it becomes an ordinary LED, and I was finding that below about 10% duty cycle it would completely stop cutting. With this "manual" bit toggle, the relatively slow toggle can get very low duty cycle for slow moves.
Thanks for the prompt help!
...a few minutes later...
Tried that, and it works! So now it accumulates distance increments using float instead of double, uses sqrtf(), and single access to Dest. Comes out exact now.
FYI this is a pretty nifty app. The nice thing about doing it this way is that when laser cutting, if it needs to slow down around a corner, the power is automatically reduced so that the corners don't get "burned". Originally, I was just using the step signal as a PWM, but that has the disadvantage that every G1,2,3 has to be edited to output the correct 5th axis movement. The other disadvantage was that the PWM is then quite high frequency and the laser driver tends to filter that into a quasi analog signal - this causes the laser gain to drop so that it becomes an ordinary LED, and I was finding that below about 10% duty cycle it would completely stop cutting. With this "manual" bit toggle, the relatively slow toggle can get very low duty cycle for slow moves.
Thanks for the prompt help!
- TomKerekes
- Posts: 2676
- Joined: Mon Dec 04, 2017 1:49 am