MOTOR_ENABLE_BIT_bp, // bit 2 (low = enabled)
CHIP_SELECT_BIT_bp, // bit 3
FAULT_BIT_bp, // bit 4
- GPIO1_OUT_BIT_bp, // bit 5 (4 gpio1 output bits; 1 from each axis)
- SW_MIN_BIT_bp, // bit 6 (4 input bits for homing/limit switches)
- SW_MAX_BIT_bp // bit 7 (4 input bits for homing/limit switches)
+ GPIO1_OUT_BIT_bp, // bit 5 (gpio1 output bit; 1 from each axis)
+ SW_MIN_BIT_bp, // bit 6 (input bit for homing/limit switches)
+ SW_MAX_BIT_bp // bit 7 (input bit for homing/limit switches)
};
#define STEP_BIT_bm (1 << STEP_BIT_bp)
// Handle an initial switch closure by backing off the closed switch
// NOTE: Relies on independent switches per axis (not shared)
- if (sw.state[hm.homing_switch] == SW_CLOSED)
+ if (sw.switches[hm.homing_switch].state == SW_CLOSED)
_homing_axis_move(axis, hm.latch_backoff, hm.search_velocity);
- else if (sw.state[hm.limit_switch] == SW_CLOSED)
+ else if (sw.switches[hm.limit_switch].state == SW_CLOSED)
_homing_axis_move(axis, -hm.latch_backoff, hm.search_velocity);
return _set_homing_func(_homing_axis_search);
static stat_t _homing_axis_latch(int8_t axis) {
// verify assumption that we arrived here because of homing switch closure
// rather than user-initiated feedhold or other disruption
- if (sw.state[hm.homing_switch] != SW_CLOSED)
+ if (sw.switches[hm.homing_switch].state != SW_CLOSED)
return _set_homing_func(_homing_abort);
_homing_axis_move(axis, hm.latch_backoff, hm.latch_velocity);
// Can't because switch mode is global and our probe is NO, not NC.
pb.probe_switch = SW_MIN_Z; // FIXME: hardcoded...
- pb.saved_switch_mode = sw.mode[pb.probe_switch];
+ pb.saved_switch_mode = sw.switches[pb.probe_switch].mode;
- sw.mode[pb.probe_switch] = SW_MODE_HOMING;
+ sw.switches[pb.probe_switch].mode = SW_MODE_HOMING;
// save the switch type for recovery later.
- pb.saved_switch_type = sw.switch_type;
+ pb.saved_switch_type = sw.switches[pb.probe_switch].type;
// contact probes are NO switches... usually
- sw.switch_type = SW_TYPE_NORMALLY_OPEN;
+ sw.switches[pb.probe_switch].type = SW_TYPE_NORMALLY_OPEN;
// re-init to pick up new switch settings
switch_init();
static stat_t _probing_start() {
// initial probe state, don't probe if we're already contacted!
- int8_t probe = sw.state[pb.probe_switch];
+ int8_t probe = sw.switches[pb.probe_switch].state;
- if( probe==SW_OPEN )
+ if (probe == SW_OPEN)
ritorno(cm_straight_feed(pb.target, pb.flags));
return _set_pb_func(_probing_finish);
static stat_t _probing_finish() {
- int8_t probe = sw.state[pb.probe_switch];
- cm.probe_state = (probe==SW_CLOSED) ? PROBE_SUCCEEDED : PROBE_FAILED;
+ int8_t probe = sw.switches[pb.probe_switch].state;
+ cm.probe_state = probe == SW_CLOSED ? PROBE_SUCCEEDED : PROBE_FAILED;
for (uint8_t axis = 0; axis < AXES; axis++) {
// if we got here because of a feed hold keep the model position correct
// we should be stopped now, but in case of switch closure
mp_flush_planner();
- sw.switch_type = pb.saved_switch_type;
- sw.mode[pb.probe_switch] = pb.saved_switch_mode;
+ sw.switches[pb.probe_switch].type = pb.saved_switch_type;
+ sw.switches[pb.probe_switch].mode = pb.saved_switch_mode;
switch_init(); // re-init to pick up changes
// restore axis jerk
static bool report_full = false;
static uint32_t last_report = 0;
-static float velocity;
-static float positions[AXES];
-
-
-void report_init() {
- velocity = 0;
-
- for (int axis = 0; axis < AXES; axis++)
- positions[axis] = 0;
-}
-
void report_request() {
report_requested = true;
#include "status.h"
-void report_init();
void report_request();
void report_request_full();
stat_t report_callback();
* complete
*/
void stepper_init() {
- memset(&st_run, 0, sizeof(st_run)); // clear all values, pointers and status
+ /// clear all values, pointers and status
+ memset(&st_run, 0, sizeof(st_run));
+ memset(&st_pre, 0, sizeof(st_pre));
// Setup ports
- for (uint8_t i = 0; i < MOTORS; i++) {
- hw.st_port[i]->DIR = MOTOR_PORT_DIR_gm;
- hw.st_port[i]->OUTSET = MOTOR_ENABLE_BIT_bm; // disable motor
+ for (int motor = 0; motor < MOTORS; motor++) {
+ hw.st_port[motor]->DIR = MOTOR_PORT_DIR_gm;
+ hw.st_port[motor]->OUTSET = MOTOR_ENABLE_BIT_bm; // disable motor
}
// Setup step timer
- TIMER_STEP.CTRLA = STEP_TIMER_DISABLE; // turn timer off
- TIMER_STEP.CTRLB = STEP_TIMER_WGMODE; // waveform mode
- TIMER_STEP.INTCTRLA = STEP_TIMER_INTLVL; // interrupt mode
+ TIMER_STEP.CTRLA = STEP_TIMER_DISABLE; // turn timer off
+ TIMER_STEP.CTRLB = STEP_TIMER_WGMODE; // waveform mode
+ TIMER_STEP.INTCTRLA = STEP_TIMER_INTLVL; // interrupt mode
st_pre.owner = PREP_BUFFER_OWNER_EXEC;
- // Defaults
+ // Reset steppers to known state
+ for (int motor = 0; motor < MOTORS; motor++)
+ st_pre.mot[motor].prev_direction = STEP_INITIAL_DIRECTION;
+
+ // Motor configuration defaults
st_cfg.motor_power_timeout = MOTOR_IDLE_TIMEOUT;
st_cfg.mot[MOTOR_1].motor_map = M1_MOTOR_MAP;
for (int motor = 0; motor < MOTORS; motor++)
_update_steps_per_unit(motor);
- // reset steppers to known state
- for (uint8_t motor = 0; motor < MOTORS; motor++) {
- st_pre.mot[motor].prev_direction = STEP_INITIAL_DIRECTION;
- st_pre.mot[motor].timer_clock = 0;
- st_pre.mot[motor].timer_period = 0;
- st_pre.mot[motor].steps = 0;
- st_pre.mot[motor].corrected_steps = 0; // diagnostic only - no effect
- }
-
+ // Reset position, must be after update steps per unit
mp_set_steps_to_runtime_position();
}
uint8_t st_runtime_isbusy() {return st_run.busy;}
-/// returns 1 if motor is enabled (motor is actually active low)
-static uint8_t _motor_is_enabled(uint8_t motor) {
- uint8_t port = motor < MOTORS ? hw.st_port[motor]->OUT : 0xff;
- return port & MOTOR_ENABLE_BIT_bm ? 0 : 1;
+/// returns true if motor is enabled (motor is actually active low)
+static bool _motor_is_enabled(uint8_t motor) {
+ return !(hw.st_port[motor]->OUT & MOTOR_ENABLE_BIT_bm);
+}
+
+/// returns true if motor is in an error state
+static bool _motor_error(uint8_t motor) {
+ return st_run.mot[motor].flags & MOTOR_FLAG_ERROR_bm;
}
/// Remove power from a motor
-static void _deenergize_motor(const uint8_t motor) {
- if (motor < MOTORS) hw.st_port[motor]->OUTSET = MOTOR_ENABLE_BIT_bm;
- st_run.mot[motor].power_state = MOTOR_OFF;
+static void _deenergize_motor(uint8_t motor) {
+ if (_motor_is_enabled(motor)) {
+ hw.st_port[motor]->OUTSET = MOTOR_ENABLE_BIT_bm;
+ st_run.mot[motor].power_state = MOTOR_OFF;
+ st_run.mot[motor].flags &= MOTOR_FLAG_ENABLED_bm;
+ report_request(); // request a status report when motors change state
+ }
}
/// Apply power to a motor
-static void _energize_motor(const uint8_t motor) {
- if (st_cfg.mot[motor].power_mode == MOTOR_DISABLED) _deenergize_motor(motor);
-
- else {
- if (motor < MOTORS) hw.st_port[motor]->OUTCLR = MOTOR_ENABLE_BIT_bm;
+static void _energize_motor(uint8_t motor) {
+ if (!_motor_is_enabled(motor) && !_motor_error(motor)) {
+ hw.st_port[motor]->OUTCLR = MOTOR_ENABLE_BIT_bm;
st_run.mot[motor].power_state = MOTOR_POWER_TIMEOUT_START;
+ st_run.mot[motor].flags |= MOTOR_FLAG_ENABLED_bm;
+ report_request(); // request a status report when motors change state
}
}
// Manage power for each motor individually
for (int motor = 0; motor < MOTORS; motor++)
switch (st_cfg.mot[motor].power_mode) {
- case MOTOR_ALWAYS_POWERED:
- if (!_motor_is_enabled(motor)) _energize_motor(motor);
- break;
+ case MOTOR_ALWAYS_POWERED: _energize_motor(motor); break;
case MOTOR_POWERED_IN_CYCLE: case MOTOR_POWERED_ONLY_WHEN_MOVING:
if (st_run.mot[motor].power_state == MOTOR_POWER_TIMEOUT_START) {
// Run the countdown if not in feedhold and in a countdown
if (cm_get_combined_state() != COMBINED_HOLD &&
st_run.mot[motor].power_state == MOTOR_POWER_TIMEOUT_COUNTDOWN &&
- rtc_get_time() > st_run.mot[motor].power_systick) {
- st_run.mot[motor].power_state = MOTOR_IDLE;
+ rtc_get_time() > st_run.mot[motor].power_systick)
_deenergize_motor(motor);
- report_request(); // request a status report when motors shut down
- }
break;
default: _deenergize_motor(motor); break; // Motor disabled
}
+void st_motor_error_callback(uint8_t motor, cmMotorFlags_t errors) {
+ st_run.mot[motor].flags |= MOTOR_FLAG_ERROR_bm & errors;
+ if (_motor_error(motor)) _deenergize_motor(motor);
+}
+
+
/// Special interrupt for X-axis
ISR(TCE1_CCA_vect) {
PORT_MOTOR_1.OUTTGL = STEP_BIT_bm;
static inline void _load_motor_move(int motor) {
- stRunMotor_t *run_mot = &st_run.mot[motor];
stPrepMotor_t *pre_mot = &st_pre.mot[motor];
const cfgMotor_t *cfg_mot = &st_cfg.mot[motor];
// Energize motor and start power management
if ((pre_mot->timer_clock && cfg_mot->power_mode != MOTOR_DISABLED) ||
- cfg_mot->power_mode == MOTOR_POWERED_IN_CYCLE) {
- hw.st_port[motor]->OUTCLR = MOTOR_ENABLE_BIT_bm; // energize motor
- run_mot->power_state = MOTOR_POWER_TIMEOUT_START; // start power management
- }
+ cfg_mot->power_mode == MOTOR_POWERED_IN_CYCLE)
+ _energize_motor(motor);
}
} cmMotorPolarity_t;
+typedef enum {
+ MOTOR_FLAG_ENABLED_bm = 1 << 0,
+ MOTOR_FLAG_STALLED_bm = 1 << 1,
+ MOTOR_FLAG_OVERTEMP_WARN_bm = 1 << 2,
+ MOTOR_FLAG_OVERTEMP_bm = 1 << 3,
+ MOTOR_FLAG_SHORTED_bm = 1 << 4,
+ MOTOR_FLAG_ERROR_bm = (MOTOR_FLAG_STALLED_bm |
+ MOTOR_FLAG_OVERTEMP_WARN_bm |
+ MOTOR_FLAG_OVERTEMP_bm |
+ MOTOR_FLAG_SHORTED_bm)
+} cmMotorFlags_t;
+
+
/// Min/Max timeouts allowed for motor disable. Allow for inertial stop.
/// Must be non-zero
#define MOTOR_TIMEOUT_SECONDS_MIN (float)0.1
typedef struct { // one per controlled motor
motorPowerState_t power_state; // state machine for managing motor power
uint32_t power_systick; // for next motor power state transition
+ cmMotorFlags_t flags;
} stRunMotor_t;
uint8_t st_runtime_isbusy();
stat_t st_motor_power_callback();
+void st_motor_error_callback(uint8_t motor, cmMotorFlags_t errors);
void st_request_exec_move();
void st_prep_null();
*
* The normally closed switch modes (NC) trigger an interrupt on the
* rising edge and lockout subsequent interrupts for the defined
- * lockout period. Ditto on the method.
+ * lockout period.
*/
#include "switch.h"
#include <stdbool.h>
+swSingleton_t sw;
+
+
/* Initialize homing/limit switches
*
* This function assumes sys_init() and st_init() have been run previously to
* bind the ports and set bit IO directions, repsectively.
*/
-#define PIN_MODE PORT_OPC_PULLUP_gc // pin mode. see iox192a3.h for details
-
-
void switch_init() {
- for (uint8_t i = 0; i < NUM_SWITCH_PAIRS; i++) {
+ for (int i = 0; i < NUM_SWITCH_PAIRS; i++) {
// setup input bits and interrupts (previously set to inputs by st_init())
- if (sw.mode[MIN_SWITCH(i)] != SW_MODE_DISABLED) {
- // set min input - see 13.14.14
- hw.sw_port[i]->DIRCLR = SW_MIN_BIT_bm;
- hw.sw_port[i]->PIN6CTRL = PIN_MODE | PORT_ISC_BOTHEDGES_gc;
- // interrupt on min switch
- hw.sw_port[i]->INT0MASK = SW_MIN_BIT_bm;
+ if (sw.switches[MIN_SWITCH(i)].mode != SW_MODE_DISABLED) {
+ hw.sw_port[i]->DIRCLR = SW_MIN_BIT_bm; // set min input - see 13.14.14
+ hw.sw_port[i]->PIN6CTRL = PORT_OPC_PULLUP_gc | PORT_ISC_BOTHEDGES_gc;
+ hw.sw_port[i]->INT0MASK = SW_MIN_BIT_bm; // min on INT0
} else hw.sw_port[i]->INT0MASK = 0; // disable interrupt
- if (sw.mode[MAX_SWITCH(i)] != SW_MODE_DISABLED) {
- // set max input - see 13.14.14
- hw.sw_port[i]->DIRCLR = SW_MAX_BIT_bm;
- hw.sw_port[i]->PIN7CTRL = PIN_MODE | PORT_ISC_BOTHEDGES_gc;
+ if (sw.switches[MAX_SWITCH(i)].mode != SW_MODE_DISABLED) {
+ hw.sw_port[i]->DIRCLR = SW_MAX_BIT_bm; // set max input - see 13.14.14
+ hw.sw_port[i]->PIN7CTRL = PORT_OPC_PULLUP_gc | PORT_ISC_BOTHEDGES_gc;
hw.sw_port[i]->INT1MASK = SW_MAX_BIT_bm; // max on INT1
- } else hw.sw_port[i]->INT1MASK = 0;
+ } else hw.sw_port[i]->INT1MASK = 0; // disable interrupt
// set interrupt levels. Interrupts must be enabled in main()
- hw.sw_port[i]->INTCTRL = GPIO1_INTLVL; // see gpio.h for setting
+ hw.sw_port[i]->INTCTRL = SWITCH_INTLVL;
}
// Defaults
- sw.switch_type = SWITCH_TYPE;
- sw.mode[0] = X_SWITCH_MODE_MIN;
- sw.mode[1] = X_SWITCH_MODE_MAX;
- sw.mode[2] = Y_SWITCH_MODE_MIN;
- sw.mode[3] = Y_SWITCH_MODE_MAX;
- sw.mode[4] = Z_SWITCH_MODE_MIN;
- sw.mode[5] = Z_SWITCH_MODE_MAX;
- sw.mode[6] = A_SWITCH_MODE_MIN;
- sw.mode[7] = A_SWITCH_MODE_MAX;
+ for (int i = 0; i < SWITCHES; i++)
+ sw.switches[i].type = SWITCH_TYPE;
+
+ sw.switches[0].mode = X_SWITCH_MODE_MIN;
+ sw.switches[1].mode = X_SWITCH_MODE_MAX;
+ sw.switches[2].mode = Y_SWITCH_MODE_MIN;
+ sw.switches[3].mode = Y_SWITCH_MODE_MAX;
+ sw.switches[4].mode = Z_SWITCH_MODE_MIN;
+ sw.switches[5].mode = Z_SWITCH_MODE_MAX;
+ sw.switches[6].mode = A_SWITCH_MODE_MIN;
+ sw.switches[7].mode = A_SWITCH_MODE_MAX;
reset_switches();
}
* increment positive until the lockout is exceeded.
*/
-static void _switch_isr_helper(uint8_t sw_num) {
- if (sw.mode[sw_num] == SW_MODE_DISABLED) return; // never supposed to happen
- if (sw.debounce[sw_num] == SW_LOCKOUT) return; // switch is in lockout
+static void _switch_isr(uint8_t sw_num) {
+ switch_t *s = &sw.switches[sw_num];
+
+ if (s->mode == SW_MODE_DISABLED) return; // never supposed to happen
+ if (s->debounce == SW_LOCKOUT) return; // switch is in lockout
// either transitions state from IDLE or overwrites it
- sw.debounce[sw_num] = SW_DEGLITCHING;
+ s->debounce = SW_DEGLITCHING;
// reset deglitch count regardless of entry state
- sw.count[sw_num] = -SW_DEGLITCH_TICKS;
+ s->count = -SW_DEGLITCH_TICKS;
// sets the state value in the struct
read_switch(sw_num);
// Switch interrupt handler vectors
-ISR(X_MIN_ISR_vect) {_switch_isr_helper(SW_MIN_X);}
-ISR(Y_MIN_ISR_vect) {_switch_isr_helper(SW_MIN_Y);}
-ISR(Z_MIN_ISR_vect) {_switch_isr_helper(SW_MIN_Z);}
-ISR(A_MIN_ISR_vect) {_switch_isr_helper(SW_MIN_A);}
-ISR(X_MAX_ISR_vect) {_switch_isr_helper(SW_MAX_X);}
-ISR(Y_MAX_ISR_vect) {_switch_isr_helper(SW_MAX_Y);}
-ISR(Z_MAX_ISR_vect) {_switch_isr_helper(SW_MAX_Z);}
-ISR(A_MAX_ISR_vect) {_switch_isr_helper(SW_MAX_A);}
+ISR(X_MIN_ISR_vect) {_switch_isr(SW_MIN_X);}
+ISR(Y_MIN_ISR_vect) {_switch_isr(SW_MIN_Y);}
+ISR(Z_MIN_ISR_vect) {_switch_isr(SW_MIN_Z);}
+ISR(A_MIN_ISR_vect) {_switch_isr(SW_MIN_A);}
+ISR(X_MAX_ISR_vect) {_switch_isr(SW_MAX_X);}
+ISR(Y_MAX_ISR_vect) {_switch_isr(SW_MAX_Y);}
+ISR(Z_MAX_ISR_vect) {_switch_isr(SW_MAX_Z);}
+ISR(A_MAX_ISR_vect) {_switch_isr(SW_MAX_A);}
/// Called from RTC for each RTC tick
void switch_rtc_callback() {
- for (uint8_t i = 0; i < SWITCHES; i++) {
- if (sw.mode[i] == SW_MODE_DISABLED || sw.debounce[i] == SW_IDLE)
+ for (int i = 0; i < SWITCHES; i++) {
+ switch_t *s = &sw.switches[i];
+
+ if (s->mode == SW_MODE_DISABLED || s->debounce == SW_IDLE)
continue;
// state is either lockout or deglitching
- if (++sw.count[i] == SW_LOCKOUT_TICKS) {
- sw.debounce[i] = SW_IDLE;
+ if (++s->count == SW_LOCKOUT_TICKS) {
+ s->debounce = SW_IDLE;
// check if the state has changed while we were in lockout...
- uint8_t old_state = sw.state[i];
+ uint8_t old_state = s->state;
if (old_state != read_switch(i)) {
- sw.debounce[i] = SW_DEGLITCHING;
- sw.count[i] = -SW_DEGLITCH_TICKS;
+ s->debounce = SW_DEGLITCHING;
+ s->count = -SW_DEGLITCH_TICKS;
}
continue;
}
- if (!sw.count[i]) { // trigger point
- sw.sw_num_thrown = i; // record number of thrown switch
- sw.debounce[i] = SW_LOCKOUT;
+ if (!s->count) { // trigger point
+ sw.switch_thrown = i; // record number of thrown switch
+ s->debounce = SW_LOCKOUT;
// regardless of switch type
if (cm.cycle_state == CYCLE_HOMING || cm.cycle_state == CYCLE_PROBE)
cm_request_feedhold();
// should be a limit switch, so fire it.
- else if (sw.mode[i] & SW_LIMIT_BIT)
- sw.limit_flag = true; // triggers an emergency shutdown
+ else if (s->mode & SW_LIMIT_BIT)
+ sw.limit_thrown = true; // triggers an emergency shutdown
}
}
}
/// return switch mode setting
-uint8_t get_switch_mode(uint8_t sw_num) {return sw.mode[sw_num];}
+swMode_t get_switch_mode(uint8_t sw_num) {return sw.switches[sw_num].mode;}
/// return true if a limit was tripped
-uint8_t get_limit_switch_thrown() {return sw.limit_flag;}
-
-/// return switch number most recently thrown
-uint8_t get_switch_thrown() {return sw.sw_num_thrown;}
+bool get_limit_switch_thrown() {return sw.limit_thrown;}
/// reset all switches and reset limit flag
void reset_switches() {
for (uint8_t i = 0; i < SWITCHES; i++) {
- sw.debounce[i] = SW_IDLE;
+ sw.switches[i].debounce = SW_IDLE;
read_switch(i);
}
- sw.limit_flag = false;
+ sw.limit_thrown = false;
}
uint8_t read_switch(uint8_t sw_num) {
if (sw_num < 0 || sw_num >= SWITCHES) return SW_DISABLED;
- uint8_t read = 0;
+ bool hi = false;
switch (sw_num) {
- case SW_MIN_X: read = hw.sw_port[AXIS_X]->IN & SW_MIN_BIT_bm; break;
- case SW_MAX_X: read = hw.sw_port[AXIS_X]->IN & SW_MAX_BIT_bm; break;
- case SW_MIN_Y: read = hw.sw_port[AXIS_Y]->IN & SW_MIN_BIT_bm; break;
- case SW_MAX_Y: read = hw.sw_port[AXIS_Y]->IN & SW_MAX_BIT_bm; break;
- case SW_MIN_Z: read = hw.sw_port[AXIS_Z]->IN & SW_MIN_BIT_bm; break;
- case SW_MAX_Z: read = hw.sw_port[AXIS_Z]->IN & SW_MAX_BIT_bm; break;
- case SW_MIN_A: read = hw.sw_port[AXIS_A]->IN & SW_MIN_BIT_bm; break;
- case SW_MAX_A: read = hw.sw_port[AXIS_A]->IN & SW_MAX_BIT_bm; break;
+ case SW_MIN_X: hi = hw.sw_port[AXIS_X]->IN & SW_MIN_BIT_bm; break;
+ case SW_MAX_X: hi = hw.sw_port[AXIS_X]->IN & SW_MAX_BIT_bm; break;
+ case SW_MIN_Y: hi = hw.sw_port[AXIS_Y]->IN & SW_MIN_BIT_bm; break;
+ case SW_MAX_Y: hi = hw.sw_port[AXIS_Y]->IN & SW_MAX_BIT_bm; break;
+ case SW_MIN_Z: hi = hw.sw_port[AXIS_Z]->IN & SW_MIN_BIT_bm; break;
+ case SW_MAX_Z: hi = hw.sw_port[AXIS_Z]->IN & SW_MAX_BIT_bm; break;
+ case SW_MIN_A: hi = hw.sw_port[AXIS_A]->IN & SW_MIN_BIT_bm; break;
+ case SW_MAX_A: hi = hw.sw_port[AXIS_A]->IN & SW_MAX_BIT_bm; break;
}
// A NO switch drives the pin LO when thrown
- if (sw.switch_type == SW_TYPE_NORMALLY_OPEN)
- sw.state[sw_num] = read ? SW_OPEN : SW_CLOSED;
- else sw.state[sw_num] = read ? SW_CLOSED : SW_OPEN;
+ if (sw.switches[sw_num].type == SW_TYPE_NORMALLY_OPEN)
+ sw.switches[sw_num].state = hi ? SW_OPEN : SW_CLOSED;
+ else sw.switches[sw_num].state = hi ? SW_CLOSED : SW_OPEN;
- return sw.state[sw_num];
+ return sw.switches[sw_num].state;
}
uint8_t get_switch_type(int index) {
- return 0;
+ return sw.switches[index].type;
}
-void set_switch_type(int axis, uint8_t value) {
+void set_switch_type(int index, uint8_t value) {
+ sw.switches[index].type = value;
}
#include "config.h"
#include <stdint.h>
+#include <stdbool.h>
// timer for debouncing switches
#define SW_LOCKOUT_TICKS 25 // 25=250ms. RTC ticks are ~10ms each
#define SW_DEGLITCH_TICKS 3 // 3=30ms
// switch modes
-enum {
+typedef enum {
SW_MODE_DISABLED,
SW_HOMING_BIT,
SW_LIMIT_BIT
-};
+} swMode_t;
#define SW_MODE_HOMING SW_HOMING_BIT // enable switch for homing only
#define SW_MODE_LIMIT SW_LIMIT_BIT // enable switch for limits only
#define SW_MODE_HOMING_LIMIT (SW_HOMING_BIT | SW_LIMIT_BIT) // homing & limits
-enum swType {
+typedef enum {
SW_TYPE_NORMALLY_OPEN,
SW_TYPE_NORMALLY_CLOSED
-};
+} swType_t;
-enum swState {
+typedef enum {
SW_DISABLED = -1,
SW_OPEN,
SW_CLOSED
-};
+} swState_t;
// macros for finding the index into the switch table give the axis number
#define MIN_SWITCH(axis) (axis * 2)
#define MAX_SWITCH(axis) (axis * 2 + 1)
-enum swDebounce { // state machine for managing debouncing and lockout
+typedef enum { // state machine for managing debouncing and lockout
SW_IDLE,
SW_DEGLITCHING,
SW_LOCKOUT
-};
+} swDebounce_t;
-enum swNums { // indexes into switch arrays
+typedef enum { // indexes into switch arrays
SW_MIN_X,
SW_MAX_X,
SW_MIN_Y,
SW_MAX_Z,
SW_MIN_A,
SW_MAX_A
-};
+} swNums_t;
#define SW_OFFSET SW_MAX_X // offset between MIN and MAX switches
#define NUM_SWITCH_PAIRS (SWITCHES / 2)
/// Interrupt levels and vectors - The vectors are hard-wired to xmega ports
/// If you change axis port assignments you need to change these, too.
-#define GPIO1_INTLVL (PORT_INT0LVL_MED_gc | PORT_INT1LVL_MED_gc)
+#define SWITCH_INTLVL (PORT_INT0LVL_MED_gc | PORT_INT1LVL_MED_gc)
// port assignments for vectors
#define X_MIN_ISR_vect PORTA_INT0_vect
#define Y_MIN_ISR_vect PORTD_INT0_vect
#define Z_MIN_ISR_vect PORTE_INT0_vect
#define A_MIN_ISR_vect PORTF_INT0_vect
+
#define X_MAX_ISR_vect PORTA_INT1_vect
#define Y_MAX_ISR_vect PORTD_INT1_vect
#define Z_MAX_ISR_vect PORTE_INT1_vect
#define A_MAX_ISR_vect PORTF_INT1_vect
+typedef struct {
+ swState_t state;
+ swType_t type;
+ swMode_t mode;
+ swDebounce_t debounce; // debounce state
+ int8_t count; // deglitching and lockout counter
+} switch_t;
+
/* Switch control structures
* Note 1: The term "thrown" is used because switches could be normally-open
* or normally-closed. "Thrown" means activated or hit.
*/
-struct swStruct { // switch state
- uint8_t switch_type; // 0=NO, 1=NC - applies to all switches
- uint8_t limit_flag; // 1=limit switch thrown - do a lockout
- uint8_t sw_num_thrown; // number of switch that was just thrown
- /// 0=OPEN, 1=CLOSED (depends on switch type)
- uint8_t state[SWITCHES];
- /// 0=disabled, 1=homing, 2=homing+limit, 3=limit
- volatile uint8_t mode[SWITCHES];
- /// debouncer state machine - see swDebounce
- volatile uint8_t debounce[SWITCHES];
- volatile int8_t count[SWITCHES]; // deglitching and lockout counter
-};
-struct swStruct sw;
+typedef struct {
+ bool limit_thrown;
+ uint8_t switch_thrown; // number of switch that was just thrown
+ switch_t switches[SWITCHES];
+} swSingleton_t;
+
+extern swSingleton_t sw;
void switch_init();
uint8_t read_switch(uint8_t sw_num);
-uint8_t get_switch_mode(uint8_t sw_num);
+swMode_t get_switch_mode(uint8_t sw_num);
void switch_rtc_callback();
-uint8_t get_limit_switch_thrown();
-uint8_t get_switch_thrown();
+bool get_limit_switch_thrown();
void reset_switches();
-void sw_show_switch();
#include "tmc2660.h"
#include "status.h"
+#include "stepper.h"
+#include "hardware.h"
#include <avr/io.h>
#include <avr/interrupt.h>
static volatile uint8_t driver;
-static tmc2660_driver_t drivers[TMC2660_NUM_DRIVERS];
+static tmc2660_driver_t drivers[MOTORS];
static volatile spi_state_t spi_state;
static volatile uint8_t spi_byte;
static volatile uint32_t spi_in;
-static void spi_cs(int driver, int enable) {
- if (enable)
- switch (driver) {
- case 0: TMC2660_SPI_SSX_PORT.OUTCLR = 1 << TMC2660_SPI_SSX_PIN; break;
- case 1: TMC2660_SPI_SSY_PORT.OUTCLR = 1 << TMC2660_SPI_SSY_PIN; break;
- case 2: TMC2660_SPI_SSZ_PORT.OUTCLR = 1 << TMC2660_SPI_SSZ_PIN; break;
- case 3: TMC2660_SPI_SSA_PORT.OUTCLR = 1 << TMC2660_SPI_SSA_PIN; break;
- case 4: TMC2660_SPI_SSB_PORT.OUTCLR = 1 << TMC2660_SPI_SSB_PIN; break;
- }
- else
- switch (driver) {
- case 0: TMC2660_SPI_SSX_PORT.OUTSET = 1 << TMC2660_SPI_SSX_PIN; break;
- case 1: TMC2660_SPI_SSY_PORT.OUTSET = 1 << TMC2660_SPI_SSY_PIN; break;
- case 2: TMC2660_SPI_SSZ_PORT.OUTSET = 1 << TMC2660_SPI_SSZ_PIN; break;
- case 3: TMC2660_SPI_SSA_PORT.OUTSET = 1 << TMC2660_SPI_SSA_PIN; break;
- case 4: TMC2660_SPI_SSB_PORT.OUTSET = 1 << TMC2660_SPI_SSB_PIN; break;
- }
+static void _report_error_flags(int driver) {
+ uint8_t dflags = drivers[driver].flags;
+ uint8_t mflags = 0;
+
+ if ((TMC2660_DRVSTATUS_SHORT_TO_GND_A | TMC2660_DRVSTATUS_SHORT_TO_GND_B) &
+ dflags) mflags |= MOTOR_FLAG_SHORTED_bm;
+ if (TMC2660_DRVSTATUS_OVERTEMP_WARN & dflags)
+ mflags |= MOTOR_FLAG_OVERTEMP_WARN_bm;
+ if (TMC2660_DRVSTATUS_OVERTEMP & dflags)
+ mflags |= MOTOR_FLAG_OVERTEMP_bm;
+
+ st_motor_error_callback(driver, mflags);
+}
+
+
+static void spi_cs(int motor, int enable) {
+ if (enable) hw.st_port[motor]->OUTCLR = CHIP_SELECT_BIT_bm;
+ else hw.st_port[motor]->OUTSET = CHIP_SELECT_BIT_bm;
}
drv->sguard = (uint16_t)((spi_in >> 14) & 0x1ff);
drv->flags = spi_in >> 4;
+ _report_error_flags(driver);
+
if (drv->reset) {
drv->state = TMC2660_STATE_RESET;
drv->reset = 0;
- } else if (++driver == TMC2660_NUM_DRIVERS) {
+ } else if (++driver == MOTORS) {
driver = 0;
spi_delay = 500;
- //spi_state = SPI_STATE_QUIT;
break;
}
break;
memset(drivers, 0, sizeof(drivers));
// Configure motors
- for (int i = 0; i < TMC2660_NUM_DRIVERS; i++) {
+ for (int i = 0; i < MOTORS; i++) {
drivers[i].state = TMC2660_STATE_CONFIG;
drivers[i].reg = 0;
uint32_t mstep = 0;
switch (MOTOR_MICROSTEPS) {
- case 1: mstep = TMC2660_DRVCTRL_MRES_1; break;
- case 2: mstep = TMC2660_DRVCTRL_MRES_2; break;
- case 4: mstep = TMC2660_DRVCTRL_MRES_4; break;
- case 8: mstep = TMC2660_DRVCTRL_MRES_8; break;
- case 16: mstep = TMC2660_DRVCTRL_MRES_16; break;
- case 32: mstep = TMC2660_DRVCTRL_MRES_32; break;
- case 64: mstep = TMC2660_DRVCTRL_MRES_64; break;
+ case 1: mstep = TMC2660_DRVCTRL_MRES_1; break;
+ case 2: mstep = TMC2660_DRVCTRL_MRES_2; break;
+ case 4: mstep = TMC2660_DRVCTRL_MRES_4; break;
+ case 8: mstep = TMC2660_DRVCTRL_MRES_8; break;
+ case 16: mstep = TMC2660_DRVCTRL_MRES_16; break;
+ case 32: mstep = TMC2660_DRVCTRL_MRES_32; break;
+ case 64: mstep = TMC2660_DRVCTRL_MRES_64; break;
case 128: mstep = TMC2660_DRVCTRL_MRES_128; break;
case 256: mstep = TMC2660_DRVCTRL_MRES_256; break;
default: break; // Invalid
TMC2660_SPI_PORT.OUTSET = 1 << TMC2660_SPI_MOSI_PIN; // High
TMC2660_SPI_PORT.DIRSET = 1 << TMC2660_SPI_MOSI_PIN; // Output
- TMC2660_SPI_SSX_PORT.OUTSET = 1 << TMC2660_SPI_SSX_PIN; // High
- TMC2660_SPI_SSX_PORT.DIRSET = 1 << TMC2660_SPI_SSX_PIN; // Output
- TMC2660_SPI_SSY_PORT.OUTSET = 1 << TMC2660_SPI_SSY_PIN; // High
- TMC2660_SPI_SSY_PORT.DIRSET = 1 << TMC2660_SPI_SSY_PIN; // Output
- TMC2660_SPI_SSZ_PORT.OUTSET = 1 << TMC2660_SPI_SSZ_PIN; // High
- TMC2660_SPI_SSZ_PORT.DIRSET = 1 << TMC2660_SPI_SSZ_PIN; // Output
- TMC2660_SPI_SSA_PORT.OUTSET = 1 << TMC2660_SPI_SSA_PIN; // High
- TMC2660_SPI_SSA_PORT.DIRSET = 1 << TMC2660_SPI_SSA_PIN; // Output
- TMC2660_SPI_SSB_PORT.OUTSET = 1 << TMC2660_SPI_SSB_PIN; // High
- TMC2660_SPI_SSB_PORT.DIRSET = 1 << TMC2660_SPI_SSB_PIN; // Output
+ for (int motor = 0; motor < MOTORS; motor++) {
+ hw.st_port[motor]->OUTSET = CHIP_SELECT_BIT_bm; // High
+ hw.st_port[motor]->DIRSET = CHIP_SELECT_BIT_bm; // Output
+ hw.st_port[motor]->DIRCLR = FAULT_BIT_bm; // Input
+ }
// Configure SPI
PR.PRPC &= ~PR_SPI_bm; // Disable power reduction
uint8_t tmc2660_flags(int driver) {
- return driver < TMC2660_NUM_DRIVERS ? drivers[driver].flags : 0;
+ return driver < MOTORS ? drivers[driver].flags : 0;
}
void tmc2660_reset(int driver) {
- if (driver < TMC2660_NUM_DRIVERS) drivers[driver].reset = 1;
+ if (driver < MOTORS) drivers[driver].reset = 1;
}
int tmc2660_all_ready() {
- for (int i = 0; i < TMC2660_NUM_DRIVERS; i++)
+ for (int i = 0; i < MOTORS; i++)
if (!tmc2660_ready(i)) return 0;
return 1;
}
-void tmc2660_get_flags(uint8_t flags, char buf[35]) {
- buf[0] = 0;
-
- if (TMC2660_DRVSTATUS_STST & flags) strcat(buf, "stst,");
- if (TMC2660_DRVSTATUS_OLB & flags) strcat(buf, "olb,");
- if (TMC2660_DRVSTATUS_OLA & flags) strcat(buf, "ola,");
- if (TMC2660_DRVSTATUS_S2GB & flags) strcat(buf, "s2gb,");
- if (TMC2660_DRVSTATUS_S2GA & flags) strcat(buf, "s2ga,");
- if (TMC2660_DRVSTATUS_OTPW & flags) strcat(buf, "otpw,");
- if (TMC2660_DRVSTATUS_OT & flags) strcat(buf, "ot,");
- if (TMC2660_DRVSTATUS_SG & flags) strcat(buf, "sg,");
-
- if (buf[0] != 0) buf[strlen(buf) - 1] = 0; // Remove last comma
-}
-
-
uint8_t get_status_flags(int index) {
return drivers[driver].flags;
}
#define TMC2660_SPI_MISO_PIN 6
#define TMC2660_SPI_MOSI_PIN 7
-#define TMC2660_SPI_SSX_PORT PORTA
-#define TMC2660_SPI_SSX_PIN 3
-#define TMC2660_SPI_SSY_PORT PORTF
-#define TMC2660_SPI_SSY_PIN 3
-#define TMC2660_SPI_SSZ_PORT PORTE
-#define TMC2660_SPI_SSZ_PIN 3
-#define TMC2660_SPI_SSA_PORT PORTD
-#define TMC2660_SPI_SSA_PIN 3
-#define TMC2660_SPI_SSB_PORT PORTB
-#define TMC2660_SPI_SSB_PIN 3
-
-#define TMC2660_NUM_DRIVERS MOTORS
-
#define TMC2660_TIMER TCC1
void tmc2660_init();
#define TMC2660_DRVCONF_RDSEL_SG (1UL << 4)
#define TMC2660_DRVCONF_RDSEL_SGCS (2UL << 4)
-#define TMC2660_DRVSTATUS_STST (1UL << 7)
-#define TMC2660_DRVSTATUS_OLB (1UL << 6)
-#define TMC2660_DRVSTATUS_OLA (1UL << 5)
-#define TMC2660_DRVSTATUS_S2GB (1UL << 4)
-#define TMC2660_DRVSTATUS_S2GA (1UL << 3)
-#define TMC2660_DRVSTATUS_OTPW (1UL << 2)
-#define TMC2660_DRVSTATUS_OT (1UL << 1)
-#define TMC2660_DRVSTATUS_SG (1UL << 0)
-
-
+#define TMC2660_DRVSTATUS_STANDSTILL (1UL << 7)
+#define TMC2660_DRVSTATUS_OPEN_LOAD_B (1UL << 6)
+#define TMC2660_DRVSTATUS_OPEN_LOAD_A (1UL << 5)
+#define TMC2660_DRVSTATUS_SHORT_TO_GND_B (1UL << 4)
+#define TMC2660_DRVSTATUS_SHORT_TO_GND_A (1UL << 3)
+#define TMC2660_DRVSTATUS_OVERTEMP_WARN (1UL << 2)
+#define TMC2660_DRVSTATUS_OVERTEMP (1UL << 1)
+#define TMC2660_DRVSTATUS_STALLED (1UL << 0)