/ src / hal / drivers / pluto_step.comp
pluto_step.comp
  1  //    Copyright (C) 2007 Jeff Epler
  2  //
  3  //    This program is free software; you can redistribute it and/or modify
  4  //    it under the terms of the GNU General Public License as published by
  5  //    the Free Software Foundation; either version 2 of the License, or
  6  //    (at your option) any later version.
  7  //
  8  //    This program is distributed in the hope that it will be useful,
  9  //    but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11  //    GNU General Public License for more details.
 12  //
 13  //    You should have received a copy of the GNU General Public License
 14  //    along with this program; if not, write to the Free Software
 15  //    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 16  
 17  component pluto_step """Hardware driver and firmware for the Pluto-P parallel-port FPGA, for use with stepper machines.
 18  
 19  .B loadrt pluto_step ioaddr=\\fIaddr\\fB ioaddr_hi=\\fIaddr\\fB epp_wide=\\fI[0|1]\\fB
 20  
 21  .RS 4
 22  .TP
 23  \\fBioaddr\\fR [default: 0x378]
 24  The base address of the parallel port.
 25  
 26  .TP
 27  \\fBioaddr_hi\\fR [default: 0]
 28  The secondary address of the parallel port, used to set EPP
 29  mode.  0 means to use ioaddr + 0x400.  -1 means there is no
 30  secondary address.
 31  
 32  .TP
 33  \\fBepp_wide\\fR [default: 1]
 34  Set to zero to disable "wide EPP mode".  "Wide" mode allows 16- and 32-bit EPP
 35  transfers, which can reduce the time spent in the read and write functions.
 36  However, this mode may not work on all EPP parallel ports.
 37  
 38  .TP
 39  \\fBwatchdog\\fR [default: 1]
 40  Set to zero to disable the "hardware watchdog".  "Watchdog" will tristate all
 41  outputs approximately 6ms after the last execution of
 42  \\fBpluto-step.write\\fR, which adds some protection in the case of LinuxCNC
 43  crashes.
 44  
 45  .TP
 46  \\fBspeedrange\\fR [default: 0]
 47  Selects one of four speed ranges:
 48  .RS
 49  .RS 4
 50  .TQ
 51  0: Top speed 312.5kHz; minimum speed 610Hz
 52  .TQ
 53  1: Top speed 156.25kHz; minimum speed 305Hz
 54  .TQ
 55  2: Top speed 78.125kHz; minimum speed 153Hz
 56  .TQ
 57  3: Top speed 39.06kHz; minimum speed 76Hz
 58  .RE
 59  Choosing the smallest maximum speed that is above the maximum for any one axis
 60  may give improved step regularity at low step speeds.
 61  .RE
 62  .RE""";
 63  
 64  description """
 65  Pluto_step is a LinuxCNC software driver and associated firmware that allow the Pluto-P board to be used to control a stepper-based CNC machine.
 66  
 67  The driver has 4 step+direction channels, 14 dedicated digital outputs, and 16
 68  dedicated digital inputs.
 69  
 70  .SS Step generators
 71  The step generator takes a position input and output.
 72  
 73  The step waveform includes step length/space and direction hold/setup time.
 74  Step length and direction setup/hold time is enforced in the FPGA.  Step space
 75  is enforced by a velocity cap in the driver.
 76  
 77  \\fI(all the following numbers are subject to change)\\fR
 78  In \\fIspeedrange=0\\fR, the maximum step rate is 312.5kHz.  For position
 79  feedback to be accurate, the maximum step rate is 512 pulses per servo cycle
 80  (so a 1kHz servo cycle does not impose any additional limitation).  The maximum
 81  step rate may be lowered by the step length and space parameters, which are
 82  rounded up to the nearest multiple of 1600ns.
 83  
 84  In successive speedranges the maximum step rate is divided in half, as is the
 85  maximum steps per servo cycle, and the minimum nonzero step rate.
 86  
 87  .SS Digital I/O
 88  The digital output pins conform to the `canonical digital output' interface
 89  described in the HAL manual.
 90  
 91  The digital input pins conform to the `canonical digital input' interface
 92  described in the HAL manual.
 93  """;
 94  pin in float stepgen.#.position-cmd[4];
 95  pin out float stepgen.#.velocity-fb[4];
 96  pin out float stepgen.#.position-fb[4];
 97  pin out s32 stepgen.#.counts[4];
 98  pin in bit stepgen.#.enable[4];
 99  pin in bit stepgen.#.reset[4] "When TRUE, reset position-fb to 0";
100  param rw float stepgen.#.scale[4] = 1.0;
101  param rw float stepgen.#.maxvel[4] = 0;
102  param rw bit stepgen.step_polarity;
103  
104  param rw u32 stepgen.steplen "Step length in ns.";
105  param rw u32 stepgen.stepspace "Step space in ns";
106  param rw u32 stepgen.dirtime "Dir hold/setup in ns.  Refer to the pdf documentation for a diagram of what these timings mean.";
107  
108  pin in bit dout.##[14]
109  """dout.\\fIMM\\fR corresponds to the pin labeled
110  OUT\\fIM\\fR on the pinout diagram.""";
111  param rw bit dout.##-invert[14]
112  "If TRUE, the output on the corresponding \\fBdout.\\fIMM\\fR is inverted.";
113  
114  pin out bit din.##[16];
115  pin out bit din.##_not[16]
116  """din.\\fIMM\\fR corresponds to the pin labeled
117  IN\\fIM\\fR on the pinout diagram.""";
118  
119  param rw u32 communication_error """Incremented each time 
120  pluto-step.read detects an error code in the EPP status register.  While
121  this register is nonzero, new values are not being written to the Pluto-P
122  board, and the status of digital outputs and the PWM duty cycle of the PWM
123  outputs will remain unchanged.  If the hardware watchdog is enabled, it will
124  activate shortly after the communication error is detected by LinuxCNC.  To continue
125  after a communication error, set this parameter back to zero.""";
126  
127  param rw s32 debug_0;
128  param rw s32 debug_1;
129  param rw float debug_2=.5;
130  param rw float debug_3=2.0
131   """Registers that hold debugging information of interest to developers""";
132  
133  option singleton;
134  option extra_setup;
135  option extra_cleanup;
136  
137  option data internal;
138  
139  function read "Read all the inputs from the pluto-step board";
140  function write "Write all the outputs on the pluto-step board";
141  
142  see_also """The \\fIpluto_step\\fR section in the HAL User Manual, which shows the location of each physical pin on the pluto board.""";
143  
144  license "GPL";
145  include "rtapi_math.h";
146  include "hal/drivers/pluto_common.h";
147  ;;
148  
149  static int speedrange=0;
150  RTAPI_MP_INT(speedrange, "Speed range 0..3");
151  
152  #define PLUTO_SPEED_NS (1600)
153  #define PLUTO_SPEED    (PLUTO_SPEED_NS * 1e-9)
154  #define PLUTO_FREQ     (1e9 / PLUTO_SPEED_NS)
155  #define TMAX           ((1<<5)-1)
156  
157  #define W 10
158  #define F 11
159  #define MODULO ((1<<(W+F))-1)
160  #define MASK ((1<<(W+F))-1)
161  #define MAXDELTA (MASK/2)
162  
163  typedef struct {
164      int64_t last_count[4];
165      int64_t reset_count[4];
166      double old_position_cmd[4];
167      double old_velocity_cmd[4];
168  } internal;
169  
170  #define ONE (1<<F)
171  #define MAX_STEP_RATE (1<<(F-1))
172  FUNCTION(write) {
173      int r = 0;
174      int i;
175      int stepspace_ticks = stepgen_stepspace/PLUTO_SPEED_NS;
176      int steplen_ticks = stepgen_steplen/PLUTO_SPEED_NS;
177      int dirtime_ticks = stepgen_dirtime/PLUTO_SPEED_NS;
178      int rate, maxrate = MAX_STEP_RATE;
179      double fmax;
180  
181      if(steplen_ticks > TMAX) {
182          steplen_ticks = TMAX;
183          rtapi_print_msg(RTAPI_MSG_ERR,
184              "Requested step length %dns decreased to %dns "
185              "due to hardware limitations\n",
186              stepgen_steplen, TMAX * PLUTO_SPEED_NS);
187          stepgen_steplen = TMAX * PLUTO_SPEED_NS;
188      }
189  
190      if(dirtime_ticks > TMAX) {
191          dirtime_ticks = TMAX;
192          rtapi_print_msg(RTAPI_MSG_ERR,
193              "Requested direction change time %dns decreased to %dns "
194              "due to hardware limitations\n",
195              stepgen_dirtime, TMAX * PLUTO_SPEED_NS);
196          stepgen_dirtime = TMAX * PLUTO_SPEED_NS;
197      }
198  
199      // Speed limits come from several sources
200      // First limit: step waveform timings
201      fmax = 1. / PLUTO_SPEED / (2 + steplen_ticks + stepspace_ticks);
202      // Second limit: highest speed command
203      if(fmax > PLUTO_FREQ / (2<<speedrange))
204          fmax = PLUTO_SPEED * (2<<speedrange);
205      // Third limit: max sign-extenable counts per period
206      if(fmax > MAXDELTA / fperiod / (1<<speedrange))
207          fmax = MAXDELTA / fperiod / (1<<speedrange);
208  
209      if(communication_error) return;
210  
211      EPP_ADDR(0);
212  
213      for(i=0; i<4; i++) {
214  	double new_position_cmd = stepgen_position_cmd(i);
215  	double v = new_position_cmd - data.old_position_cmd[i];
216  	double est_err = stepgen_position_fb(i) + data.old_velocity_cmd[i] * fperiod - new_position_cmd;
217          double actual_max;
218  	double scale_abs = fabs(stepgen_scale(i));
219  
220  	v = v - debug_2 * est_err / fperiod;
221          if(v > 0) v = v + .5/scale_abs;
222          else if(v < 0) v = v - .5/scale_abs;
223  
224  	data.old_position_cmd[i] = new_position_cmd;
225  	data.old_velocity_cmd[i] = v;
226          actual_max = fmax / scale_abs;
227          if(stepgen_maxvel(i) < 0) stepgen_maxvel(i) = -stepgen_maxvel(i);
228          if(stepgen_maxvel(i) != 0 && stepgen_maxvel(i) > actual_max) {
229              static int message_printed[4] = {0,0,0,0};
230              if(!message_printed[i]) {
231                  rtapi_print_msg(RTAPI_MSG_ERR,
232                      "Requested step rate %dHz decreased to %dHz "
233                      "due to hardware or timing limitations\n",
234                      (int)(stepgen_maxvel(i) * scale_abs),
235                      (int)(fmax));
236                  message_printed[i] = 1;
237              }
238              stepgen_maxvel(i) = actual_max;
239          }
240  
241          if(stepgen_maxvel(i) == 0) {
242              if(v < -actual_max) v = -actual_max;
243              if(v > actual_max) v = actual_max;
244          } else {
245              if(v < -stepgen_maxvel(i)) v = -stepgen_maxvel(i);
246              if(v > stepgen_maxvel(i)) v = stepgen_maxvel(i);
247          }
248  	rate = v * stepgen_scale(i) * ONE * PLUTO_SPEED / (1<<speedrange);
249  
250  	if(rate > maxrate) rate = maxrate;
251  	if(rate < -maxrate) rate = -maxrate;
252  
253  	if(!stepgen_enable(i)) rate = 0;
254          if(i == 0) debug_1 = rate;
255  	write16(rate);
256      }
257  
258      r = 0;
259      for(i=0; i<14; i++) {
260          if(!dout(i) ^ !dout_invert(i)) r |= (1<<i);
261      }
262      write16(r);
263  
264      r = steplen_ticks | (dirtime_ticks << 8);
265      if (stepgen_step_polarity) r |= 0x8000;
266      write16(r);
267  }
268  
269  
270  FUNCTION(read) {
271      int i;
272      __u32 ppdata;
273  
274      EPP_ADDR(0);
275      EPP_DIR_READ();
276  
277      for(i=0; i<4; i++) {
278          int64_t count;
279          double fcount;
280  	int newlow;
281          int reset;
282          ppdata = read32();
283          reset = stepgen_reset(i);
284          if(i == 0) {
285              int status = inb(ioaddr+1) & 1;
286              if(status) {
287                  communication_error ++;
288  		pluto_clear_error_register();
289              }
290              if(communication_error) { EPP_DIR_WRITE(); return; }
291          }
292  
293  	newlow = ppdata & MASK;
294  
295          count = extend(data.last_count[i], newlow, W+F);
296  	stepgen_velocity_fb(i) = (count - data.last_count[i]) / stepgen_scale(i) / fperiod / (1 << F);
297          data.last_count[i] = count;
298          if(reset) data.reset_count[i] = count;
299          fcount = (count - data.reset_count[i]) * 1. / (1<<F);
300          stepgen_counts(i) = fcount;
301          stepgen_position_fb(i) = fcount / stepgen_scale(i);
302  
303          if(i == 0) { debug_0 = ppdata; }
304      }
305  
306      ppdata = read32();
307  
308      for(i=0; i<16; i++) {
309          int b = ppdata & (1<<i);
310          din(i) = !!b; din_not(i) = !b;
311      }
312  
313      EPP_DIR_WRITE();
314  }
315  
316  #include "hal/drivers/pluto_step_rbf.h"
317  
318  EXTRA_SETUP() {
319      return pluto_setup(firmware);
320  }
321  
322  EXTRA_CLEANUP() {
323      pluto_cleanup();
324  }
325  
326  // vim:sts=4:sw=4:et