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