📄 5i2x_stepgen.c
字号:
/******************************************************************************Copyright (C) 2007 John Kasunich <jmkasunich AT sourceforge DOT net>$RCSfile: 5i2x_stepgen.c,v $$Author: jmkasunich $$Locker: $$Revision: 1.2 $$State: Exp $$Date: 2007/05/16 03:07:27 $This is the driver for hardware step generation on the MesaElectronics 5i20 board. It works pretty much like the softwarebased stepgen, only faster.**********************************************************************This program is free software; you can redistribute it and/ormodify it under the terms of version 2 of the GNU GeneralPublic License as published by the Free Software Foundation.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USATHE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FORANY HARM OR LOSS RESULTING FROM ITS USE. IT IS _EXTREMELY_ UNWISETO RELY ON SOFTWARE ALONE FOR SAFETY. Any machinery capable ofharming persons must have provisions for completely removing powerfrom all motors, etc, before persons enter any danger area. Allmachinery must be designed to comply with local and national safetycodes, and the authors of this software can not, and do not, takeany responsibility for such compliance.This code was written as part of the EMC HAL project. For moreinformation, go to www.linuxcnc.org.**********************************************************************/#ifndef RTAPI#error This is a realtime component only!#endif#include <asm/io.h>#include "rtapi.h" // RTAPI realtime OS API.#include "hal.h" // HAL public API decls.#include "hal_5i2x.h" // Hardware dependent defines./*************************************************************************** typedefs and defines***************************************************************************//* register widths - these need to match the VHDL */#define ACC_SIZE 48#define POS_SIZE 32#define RATE_SIZE 24#define TIMER_SIZE 14/* Step generator ports *//* offsets from base address */#define RATE_REG_ADDR 0x00#define RATE_REG_LEN RATE_SIZE#define RATE_REG_SHIFT 0#define LEN_MODE_ADDR 0x04#define STEP_LEN_BITS TIMER_SIZE#define STEP_LEN_SHIFT 0#define MODE_BITS 2#define MODE_SHIFT 16#define ENABLE_SHIFT 18#define HOLD_SETUP_ADDR 0x08#define DIR_HOLD_BITS TIMER_SIZE#define DIR_HOLD_SHIFT 0#define DIR_SETUP_BITS TIMER_SIZE#define DIR_SETUP_SHIFT 16#define POS_ADDR 0x00/* number of fractional bits in position (accumulator readback) register */#define POS_SHIFT (POS_SIZE-(ACC_SIZE-(RATE_SIZE+1)))/* timing stuff */#define STEPGEN_MASTER_CLOCK 33000000#define COUNTS_PER_HZ ((double)(1ll << (RATE_SIZE+1))/(double)STEPGEN_MASTER_CLOCK)#define STEPGEN_MASTER_PERIOD (1000000000/STEPGEN_MASTER_CLOCK)/*************************************************************************** Data Structures***************************************************************************//* one stepgen */typedef struct stepgen_t { struct stepgen_t *next; hal_s32_t *counts; hal_float_t *pos_fb; hal_bit_t *enable; hal_float_t *vel_cmd; hal_u32_t step_type; hal_float_t frequency; hal_float_t maxaccel; hal_float_t maxvel; hal_float_t scale; hal_u32_t steplen; hal_u32_t stepspace; hal_u32_t dirsetup; hal_u32_t dirhold; void __iomem *addr; hal_bit_t old_enable; hal_u32_t old_step_type; hal_float_t old_maxaccel; hal_float_t old_maxvel; hal_float_t old_scale; u32 old_steplen; u32 old_stepspace; u32 old_dirsetup; u32 old_dirhold; u32 hold_setup_value; u32 len_mode_value; double internal_maxvel; double max_deltav; double current_vel; int update_max; s32 old_accum; long long int counts_hires;} stepgen_t;/****************************************************************************** Realtime Code ******************************************************************************/static void read_stepgen(stepgen_t *s, long period){ s32 accum, delta; if ( s->scale != s->old_scale ) { s->old_scale = s->scale; /* validate the new scale value */ if ((s->scale < 1e-20) && (s->scale > -1e-20)) { /* value too small, divide by zero is a bad thing */ s->scale = 1.0; } /* flag the change for write_stepgen() */ s->update_max = 1; } /* read the position accumulator - this is fixed point, with POS_SHIFT fractional bits */ accum = ioread32(s->addr+POS_ADDR); /* compute delta */ delta = accum - s->old_accum; s->old_accum = accum; /* update integer and high resolution counts */ s->counts_hires += delta; *(s->counts) = s->counts_hires >> POS_SHIFT; /* convert high res counts to position */ *(s->pos_fb) = (((double)s->counts_hires) / s->scale) * ( 1.0 / ( 1 << POS_SHIFT ));}static void read_stepgens(void *arg, long period){ stepgen_t *s; s = arg; while ( s != NULL ) { read_stepgen(s, period); s = s->next; }}static void write_stepgen(stepgen_t *s, long period){ u32 clocks, max; s32 addval; u32 min_period_ns; double max_freq, vel_cmd, vel_diff; int write; /* lots of parameter processing, do only if something has changed */ write = 0; if ( s->dirhold != s->old_dirhold ) { /* convert dirhold in ns to clock periods */ clocks = s->dirhold * (STEPGEN_MASTER_CLOCK / 1000000000.0); if ( clocks == 0 ) { clocks = 1; } max = ((1<<DIR_HOLD_BITS)-1); if ( clocks > max ) { clocks = max; } /* set parameter to actual (post rounding & limiting) value */ s->old_dirhold = clocks * (1000000000.0 / STEPGEN_MASTER_CLOCK); s->dirhold = s->old_dirhold; /* merge new hold with previous setup */ s->hold_setup_value &= ~(max << DIR_HOLD_SHIFT); s->hold_setup_value |= clocks << DIR_HOLD_SHIFT; /* force write */ write = 1; } if ( s->dirsetup != s->old_dirsetup ) { clocks = s->dirsetup * (STEPGEN_MASTER_CLOCK / 1000000000.0); if ( clocks == 0 ) { clocks = 1; } max = ((1<<DIR_SETUP_BITS)-1); if ( clocks > max ) { clocks = max; } s->old_dirsetup = clocks * (1000000000.0 / STEPGEN_MASTER_CLOCK); s->dirsetup = s->old_dirsetup; /* merge new setup with previous hold */ s->hold_setup_value &= ~(max << DIR_SETUP_SHIFT); s->hold_setup_value |= clocks << DIR_SETUP_SHIFT; /* force write */ write = 1; } if ( write ) { /* write setup and hold to hardware */ iowrite32(s->hold_setup_value, s->addr + HOLD_SETUP_ADDR); write = 0; } if ( s->steplen != s->old_steplen ) { clocks = s->steplen * (STEPGEN_MASTER_CLOCK / 1000000000.0); if ( clocks == 0 ) { clocks = 1; } max = ((1<<STEP_LEN_BITS)-1); if ( clocks > max ) { clocks = max; } s->old_steplen = clocks * (1000000000.0 / STEPGEN_MASTER_CLOCK); s->steplen = s->old_steplen; /* merge new step len with previous mode and enable */ s->len_mode_value &= ~(max << STEP_LEN_SHIFT); s->len_mode_value |= clocks << STEP_LEN_SHIFT; /* force write */ write = 1; /* force recalc of max frequency */ s->update_max = 1; } if ( s->step_type != s->old_step_type ) { if ( s->step_type > 2 ) { s->step_type = 0; } s->old_step_type = s->step_type; /* merge new mode with previous step len and enable */ max = ((1<<MODE_BITS)-1); s->len_mode_value &= ~(max << MODE_SHIFT); /* add one - mode 00 is off, mode 01 is step type 0, etc. */ s->len_mode_value |= (s->step_type + 1) << MODE_SHIFT; /* force write */ write = 1; } if ( *(s->enable) != s->old_enable ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -