- Error on unexpected AVR reboot.
Fixed estop fault pin.
Use switch inputs for DRV8711 stall and fault
Buildbotics CNC Controller Firmware Change Log
==============================================
+## v0.3.11
+ - Supressed ``firmware rebooted`` warning.
+ - Error on unexpected AVR reboot.
+ - Enabled switch input slew rate limiting.
+
## v0.3.10
- Fixed "Flood" display, changed to "Load 1" and "Load 2". #108
- Highlight loads when on.
{
"name": "bbctrl",
- "version": "0.3.10",
+ "version": "0.3.11",
"homepage": "http://buildbotics.com/",
"repository": "https://github.com/buildbotics/bbctrl-firmware",
"license": "GPL-3.0+",
#define AXES 6 // number of axes
#define MOTORS 4 // number of motors on the board
-#define SWITCHES 10 // number of supported switches
#define OUTS 5 // number of supported pin outputs
#include "drv8711.h"
#include "status.h"
#include "stepper.h"
+#include "switch.h"
#include "report.h"
#include <avr/interrupt.h>
typedef struct {
uint8_t status;
uint16_t flags;
+ bool stalled;
drv8711_state_t state;
current_t drive;
stall_callback_t stall_cb;
uint8_t cs_pin;
- uint8_t stall_pin;
+ switch_id_t stall_sw;
} drv8711_driver_t;
static drv8711_driver_t drivers[DRIVERS] = {
- {.cs_pin = SPI_CS_X_PIN, .stall_pin = STALL_X_PIN},
- {.cs_pin = SPI_CS_Y_PIN, .stall_pin = STALL_Y_PIN},
- {.cs_pin = SPI_CS_Z_PIN, .stall_pin = STALL_Z_PIN},
- {.cs_pin = SPI_CS_A_PIN, .stall_pin = STALL_A_PIN},
+ {.cs_pin = SPI_CS_X_PIN, .stall_sw = SW_STALL_X},
+ {.cs_pin = SPI_CS_Y_PIN, .stall_sw = SW_STALL_Y},
+ {.cs_pin = SPI_CS_Z_PIN, .stall_sw = SW_STALL_Z},
+ {.cs_pin = SPI_CS_A_PIN, .stall_sw = SW_STALL_A},
};
ISR(SPIC_INT_vect) {_spi_send();}
-ISR(STALL_ISR_vect) {
- for (int i = 0; i < DRIVERS; i++) {
- drv8711_driver_t *driver = &drivers[i];
- if (driver->stall_cb) driver->stall_cb(i);
+static void _stall_change(int driver, bool stalled) {
+ drivers[driver].stalled = stalled;
+
+ // Call stall callback
+ if (stalled && drivers[driver].stall_cb)
+ drivers[driver].stall_cb(driver);
+}
+
+
+static void _stall_switch_cb(switch_id_t sw, bool active) {
+ switch (sw) {
+ case SW_STALL_X: _stall_change(0, active); break;
+ case SW_STALL_Y: _stall_change(1, active); break;
+ case SW_STALL_Z: _stall_change(2, active); break;
+ case SW_STALL_A: _stall_change(3, active); break;
+ default: break;
}
}
-ISR(FAULT_ISR_vect) {motor_fault = !IN_PIN(MOTOR_FAULT_PIN);} // TODO
+static void _motor_fault_switch_cb(switch_id_t sw, bool active) {
+ motor_fault = active; // TODO
+}
void drv8711_init() {
for (int i = 0; i < DRIVERS; i++) {
uint8_t cs_pin = drivers[i].cs_pin;
- uint8_t stall_pin = drivers[i].stall_pin;
-
OUTSET_PIN(cs_pin); // High
DIRSET_PIN(cs_pin); // Output
- DIRCLR_PIN(stall_pin); // Input
- // Stall interrupt
- PINCTRL_PIN(stall_pin) = PORT_ISC_FALLING_gc;
- PORT(stall_pin)->INT1MASK |= BM(stall_pin);
- PORT(stall_pin)->INTCTRL |= PORT_INT1LVL_HI_gc;
+ switch_id_t stall_sw = drivers[i].stall_sw;
+ switch_set_type(stall_sw, SW_NORMALLY_OPEN);
+ switch_set_callback(stall_sw, _stall_switch_cb);
}
- // Fault interrupt
- DIRCLR_PIN(MOTOR_FAULT_PIN);
- PINCTRL_PIN(MOTOR_FAULT_PIN) = PORT_ISC_RISING_gc;
- PORT(MOTOR_FAULT_PIN)->INT1MASK |= BM(MOTOR_FAULT_PIN);
- PORT(MOTOR_FAULT_PIN)->INTCTRL |= PORT_INT1LVL_HI_gc;
+ switch_set_type(SW_MOTOR_FAULT, SW_NORMALLY_OPEN);
+ switch_set_callback(SW_MOTOR_FAULT, _motor_fault_switch_cb);
// Configure SPI
PR.PRPC &= ~PR_SPI_bm; // Disable power reduction
uint16_t get_status_strings(int driver) {return get_driver_flags(driver);}
+bool get_driver_stalled(int driver) {return drivers[driver].stalled;}
// Command callback
#include "hardware.h"
#include "config.h"
#include "state.h"
+#include "outputs.h"
#include "exec.h"
#include <avr/eeprom.h>
if (estop.triggered) state_estop();
// Fault signal
- SET_PIN(FAULT_PIN, estop.triggered);
- DIRSET_PIN(FAULT_PIN); // Output
+ outputs_set_active(FAULT_PIN, estop.triggered);
}
if (estop.triggered) return;
estop.triggered = true;
+ // Set fault signal
+ outputs_set_active(FAULT_PIN, true);
+
// Hard stop the motors and the spindle
st_shutdown();
spindle_stop();
}
// Clear fault signal
- OUTCLR_PIN(FAULT_PIN); // Low
+ outputs_set_active(FAULT_PIN, false);
estop.triggered = false;
// Order must match indices in var functions below
-static switch_t switches[SWITCHES] = {
- {.pin = ESTOP_PIN, .type = SW_DISABLED},
- {.pin = PROBE_PIN, .type = SW_DISABLED},
- {.pin = MIN_X_PIN, .type = SW_DISABLED},
- {.pin = MAX_X_PIN, .type = SW_DISABLED},
- {.pin = MIN_Y_PIN, .type = SW_DISABLED},
- {.pin = MAX_Y_PIN, .type = SW_DISABLED},
- {.pin = MIN_Z_PIN, .type = SW_DISABLED},
- {.pin = MAX_Z_PIN, .type = SW_DISABLED},
- {.pin = MIN_A_PIN, .type = SW_DISABLED},
- {.pin = MAX_A_PIN, .type = SW_DISABLED},
+static switch_t switches[] = {
+ {.pin = ESTOP_PIN, .type = SW_DISABLED},
+ {.pin = PROBE_PIN, .type = SW_DISABLED},
+ {.pin = MIN_X_PIN, .type = SW_DISABLED},
+ {.pin = MAX_X_PIN, .type = SW_DISABLED},
+ {.pin = MIN_Y_PIN, .type = SW_DISABLED},
+ {.pin = MAX_Y_PIN, .type = SW_DISABLED},
+ {.pin = MIN_Z_PIN, .type = SW_DISABLED},
+ {.pin = MAX_Z_PIN, .type = SW_DISABLED},
+ {.pin = MIN_A_PIN, .type = SW_DISABLED},
+ {.pin = MAX_A_PIN, .type = SW_DISABLED},
+ {.pin = STALL_X_PIN, .type = SW_DISABLED},
+ {.pin = STALL_Y_PIN, .type = SW_DISABLED},
+ {.pin = STALL_Z_PIN, .type = SW_DISABLED},
+ {.pin = STALL_A_PIN, .type = SW_DISABLED},
+ {.pin = MOTOR_FAULT_PIN, .type = SW_DISABLED},
};
+const int num_switches = sizeof(switches) / sizeof (switch_t);
+
+
static bool _read_state(const switch_t *s) {return IN_PIN(s->pin);}
static void _switch_isr() {
- for (int i = 0; i < SWITCHES; i++) {
+ for (int i = 0; i < num_switches; i++) {
switch_t *s = &switches[i];
if (s->type == SW_DISABLED || s->triggered) continue;
s->triggered = _read_state(s) != s->state;
void switch_init() {
- for (int i = 0; i < SWITCHES; i++) {
+ for (int i = 0; i < num_switches; i++) {
switch_t *s = &switches[i];
- // Pull up and trigger on both edges
- PINCTRL_PIN(s->pin) = PORT_OPC_PULLUP_gc | PORT_ISC_BOTHEDGES_gc;
+ // Pull up, trigger on both edges and enable slew rate limiting
+ PINCTRL_PIN(s->pin) =
+ PORT_OPC_PULLUP_gc | PORT_ISC_BOTHEDGES_gc;// | PORT_SRLEN_bm;
DIRCLR_PIN(s->pin); // Input
PORT(s->pin)->INTCTRL |= SWITCH_INTLVL; // Set interrupt level
/// Called from RTC on each tick
void switch_rtc_callback() {
- for (int i = 0; i < SWITCHES; i++) {
+ for (int i = 0; i < num_switches; i++) {
switch_t *s = &switches[i];
if (s->type == SW_DISABLED || !s->triggered) continue;
switch_type_t switch_get_type(int index) {
- return (index < 0 || SWITCHES <= index) ? SW_DISABLED : switches[index].type;
+ return
+ (index < 0 || num_switches <= index) ? SW_DISABLED : switches[index].type;
}
void switch_set_type(int index, switch_type_t type) {
- if (index < 0 || SWITCHES <= index) return;
+ if (index < 0 || num_switches <= index) return;
switch_t *s = &switches[index];
if (s->type != type) {
SW_MIN_Y, SW_MAX_Y,
SW_MIN_Z, SW_MAX_Z,
SW_MIN_A, SW_MAX_A,
+ SW_STALL_X, SW_STALL_Y,
+ SW_STALL_Z, SW_STALL_A,
+ SW_MOTOR_FAULT,
} switch_id_t;
if (!strcmp(IF_ELSE(INDEX)(name + 1, name), #CODE)) { \
IF(INDEX) \
(i = strchr(INDEX##_LABEL, name[0]) - INDEX##_LABEL; \
- if (INDEX <= i) return false); \
+ if (i < 0) return false); \
\
info->type = TYPE_##TYPE; \
info->index = i; \
VAR(active_current, ac, f32, MOTORS, 0, 1, "Motor current now")
VAR(driver_flags, df, u16, MOTORS, 0, 1, "Motor driver flags")
VAR(status_strings, ds, flags, MOTORS, 0, 1, "Motor driver status")
+VAR(driver_stalled, sl, bool, MOTORS, 0, 1, "Motor driver status")
VAR(encoder, en, s32, MOTORS, 0, 0, "Motor encoder")
VAR(error, ee, s32, MOTORS, 0, 0, "Motor position error")
// System
VAR(velocity, v, f32, 0, 0, 1, "Current velocity")
-VAR(acceleration, a, f32, 0, 0, 1, "Current acceleration")
+VAR(acceleration, ax, f32, 0, 0, 1, "Current acceleration")
VAR(jerk, j, f32, 0, 0, 1, "Current jerk")
VAR(hw_id, hid, str, 0, 0, 1, "Hardware ID")
VAR(echo, ec, bool, 0, 1, 1, "Enable or disable echo")
self.queue = deque()
self.in_buf = ''
self.command = None
+ self.reboot_expected = False
try:
self.sp = serial.Serial(ctrl.args.serial, ctrl.args.baud,
self.ctrl.state.machine_cmds_and_vars(msg)
self.queue_command(Cmd.DUMP) # Refresh all vars
+ # Set axis positions
+ for axis in 'xyzabc':
+ position = self.ctrl.state.get(axis + 'p', 0)
+ self.queue_command(Cmd.set_axis(axis, position))
+
except Exception as e:
log.warning('AVR reload failed: %s', traceback.format_exc())
self.ctrl.ioloop.call_later(1, self.connect)
self._log_msg(msg)
elif 'firmware' in msg:
- log.warning('firmware rebooted')
+ if self.reboot_expected: log.info('AVR firmware rebooted')
+ else: log.error('Unexpected AVR firmware reboot')
+ self.reboot_expected = False
self.connect()
else: self.ctrl.state.update(msg)
log.warning('Serial handler error: %s', traceback.format_exc())
+ def reboot(self):
+ self.queue_command(Cmd.REBOOT)
+ self.reboot_expected = True
+
+
def connect(self):
try:
# Call connect callback
ctrl.state.set('cycle', 'idle')
ctrl.state.add_listener(self._update)
- self.comm.queue_command(Cmd.REBOOT)
+ self.comm.reboot()
def _get_cycle(self): return self.ctrl.state.get('cycle')
log = logging.getLogger('State')
-machine_state_vars = '''xp yp zp ap bp cp t fo so'''.split()
-
-
class State(object):
def __init__(self, ctrl):
self.ctrl = ctrl
else: self.machine_var_set.add(code)
self.ctrl.config.reload() # Indirectly configures AVR
- self.restore_machine_state()
-
-
- def restore_machine_state(self):
- for name in machine_state_vars:
- if name in self.vars:
- value = self.vars[name]
- if isinstance(value, str): value = '"' + value + '"'
- if isinstance(value, bool): value = int(value)
-
- self.ctrl.mach.set(name, value)
def find_motor(self, axis):