- Improved GCode error messages.
- Put controller into estop when in power shutdown.
- Don't reset global offsets on M2.
+ - Test shunt and show error on failure.
## v0.4.9
- Enforce 6A per motor channel peak current limit.
td(:class="{error: state.shunt_overload}")
| {{state.shunt_overload ? 'True' : 'False'}}
th.separator
- th(:class="{error: state.motor_overload}") Motor overload
- td(:class="{error: state.motor_overload}")
- | {{state.motor_overload ? 'True' : 'False'}}
+ th(:class="{error: state.shunt_error}") Shunt error
+ td(:class="{error: state.shunt_error}")
+ | {{state.shunt_error ? 'True' : 'False'}}
tr
th(:class="{error: state.load1_shutdown}") Load 1 shutdown
td(:class="{error: state.load1_shutdown}")
td(:class="{error: state.motor_under_voltage}")
| {{state.motor_under_voltage ? 'True' : 'False'}}
th.separator
+ th(:class="{error: state.motor_overload}") Motor overload
+ td(:class="{error: state.motor_overload}")
+ | {{state.motor_overload ? 'True' : 'False'}}
+
+ tr
th(:class="{error: state.power_shutdown}") Power shutdown
td(:class="{error: state.power_shutdown}")
| {{state.power_shutdown ? 'True' : 'False'}}
+ th.separator
+ th
+ td
table.motor_fault
tr
#include "pins.h"
-#define VERSION 4
+#define VERSION 5
// Pins
};
-#define CAP_CHARGE_TIME 50 // ms
-#define VOLTAGE_MIN 11
-#define VOLTAGE_MAX 39
-#define CURRENT_MAX 25
-#define CURRENT_OVERTEMP 19 // Should read as ~21A but over 11.86A in an error
-#define LOAD_OVERTEMP_MAX 10
-#define MOTOR_SHUTDOWN_THRESH 15
-#define VOLTAGE_SETTLE_COUNT 5
-#define VOLTAGE_SETTLE_PERIOD 20 // ms
+#define SHUNT_FAIL_VOLTAGE 5
+#define CAP_CHARGE_TIME 20 // ms
+#define VOLTAGE_MIN 11
+#define VOLTAGE_MAX 39
+#define CURRENT_MAX 25
+#define CURRENT_OVERTEMP 19 // Should read ~21A but > 11.86A is error
+#define LOAD_OVERTEMP_MAX 10
+#define MOTOR_SHUTDOWN_THRESH 15
+#define VOLTAGE_SETTLE_COUNT 5
+#define VOLTAGE_SETTLE_PERIOD 20 // ms
#define VOLTAGE_SETTLE_TOLERANCE 0.01
-#define VOLTAGE_EXP 0.01
-
-#define SHUNT_WATTS 5
-#define SHUNT_OHMS 5.1
-#define SHUNT_PERIOD 65000 // ms
-#define SHUNT_JOULES 25 // Power per shunt period
-#define SHUNT_JOULES_PER_MS ((float)SHUNT_JOULES / SHUNT_PERIOD)
-#define SHUNT_MIN_V 2
-
-#define VOLTAGE_REF 1.1
-#define VOLTAGE_REF_R1 37400
-#define VOLTAGE_REF_R2 1000
-#define CURRENT_REF_R2 137
+#define VOLTAGE_EXP 0.01
+
+#define SHUNT_WATTS 5
+#define SHUNT_OHMS 5.1
+#define SHUNT_PERIOD 65000 // ms
+#define SHUNT_JOULES 25 // Power per shunt period
+#define SHUNT_JOULES_PER_MS ((float)SHUNT_JOULES / SHUNT_PERIOD)
+#define SHUNT_MIN_V 2
+
+#define VOLTAGE_REF 1.1
+#define VOLTAGE_REF_R1 37400
+#define VOLTAGE_REF_R2 1000
+#define CURRENT_REF_R2 137
#define CURRENT_REF_MUL (100.0 * 2700 / CURRENT_REF_R2) // 2700 from datasheet
-#define AVG_SCALE 3
-#define BUCKETS (1 << AVG_SCALE)
+#define AVG_SCALE 3
+#define BUCKETS (1 << AVG_SCALE)
// Addresses 0x60 to 0x67
-#define I2C_ADDR 0x60
-#define I2C_MASK 0b00001111
+#define I2C_ADDR 0x60
+#define I2C_MASK 0b00001111
-#define I2C_ERROR_BM (1 << TWBE)
-#define I2C_DATA_INT_BM (1 << TWDIF)
-#define I2C_READ_BM (1 << TWDIR)
-#define I2C_ADDRESS_STOP_INT_BM (1 << TWASIF)
-#define I2C_ADDRESS_MATCH_BM (1 << TWAS)
+#define I2C_ERROR_BM (1 << TWBE)
+#define I2C_DATA_INT_BM (1 << TWDIF)
+#define I2C_READ_BM (1 << TWDIR)
+#define I2C_ADDRESS_STOP_INT_BM (1 << TWASIF)
+#define I2C_ADDRESS_MATCH_BM (1 << TWAS)
typedef enum {
LOAD1_SHUTDOWN_FLAG = 1 << 6,
LOAD2_SHUTDOWN_FLAG = 1 << 7,
MOTOR_UNDER_VOLTAGE_FLAG = 1 << 8,
+ SHUNT_ERROR_FLAG = 1 << 15,
// Sense errors
MOTOR_VOLTAGE_SENSE_ERROR_FLAG = 1 << 9,
static volatile uint64_t time = 0; // ms
static volatile uint8_t motor_overload = 0;
static volatile float shunt_joules = 0;
+static volatile bool auto_shunt = false;
static volatile float vnom = 0;
+void delay(uint16_t ms) {
+ uint64_t end = time + ms;
+ while (time < end) continue;
+}
+
+
static void shutdown();
static void update_shunt() {
- if (flags_get(POWER_SHUTDOWN_FLAG)) return;
+ if (!auto_shunt || flags_get(POWER_SHUTDOWN_FLAG)) return;
static float joules = SHUNT_JOULES; // Power disipation budget
static void update_shunt_power() {
- if (flags_get(POWER_SHUTDOWN_FLAG)) return;
+ if (!auto_shunt || flags_get(POWER_SHUTDOWN_FLAG)) return;
float vout = get_reg(VOUT_REG);
float vlast = 0;
while (settle < VOLTAGE_SETTLE_COUNT) {
- _delay_ms(VOLTAGE_SETTLE_PERIOD);
+ delay(VOLTAGE_SETTLE_PERIOD);
// Check that voltage is with in range and settled
float vin = get_reg(VIN_REG);
static void charge_caps() {
IO_PORT_SET(SHUNT_PIN); // Disable shunt (hi)
IO_PORT_SET(MOTOR_PIN); // Motor voltage on
- _delay_ms(CAP_CHARGE_TIME);
+ delay(CAP_CHARGE_TIME);
+}
+
+
+static void shunt_test() {
+ charge_caps();
+
+ // Discharge caps
+ IO_PORT_CLR(MOTOR_PIN); // Motor voltage off
+ IO_PORT_CLR(SHUNT_PIN); // Enable shunt (lo)
+ delay(CAP_CHARGE_TIME);
+
+ if (SHUNT_FAIL_VOLTAGE < get_reg(VOUT_REG)) flags_set(SHUNT_ERROR_FLAG);
}
(1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0);
ADCSRB = 0;
- // Timer 0 (Fast PWM, clk/1)
- TCCR0A = (1 << WGM01) | (1 << WGM00);
+ // Timer 0, normal, clk/1
+ TCCR0A = (0 << WGM01) | (0 << WGM00);
TCCR0B = (0 << WGM02) | (0 << CS02) | (0 << CS01) | (1 << CS00);
TIMSK = 1 << TOIE0; // Enable overflow interrupt
init();
adc_conversion(); // Start ADC
validate_input_voltage();
+ shunt_test();
charge_caps();
validate_measurements();
+ auto_shunt = true;
while (true) continue;
def i2c_command(self, cmd, byte = None, word = None, block = None):
self.log.info('I2C: %s b=%s w=%s d=%s' % (cmd, byte, word, block))
- retry = 5
+ retry = 10
cmd = ord(cmd[0])
while True:
if retry:
self.log.warning('I2C failed, retrying: %s' % e)
- time.sleep(0.1)
+ time.sleep(0.25)
continue
else:
LOAD2_SENSE_ERROR_FLAG = 1 << 12
VDD_CURRENT_SENSE_ERROR_FLAG = 1 << 13
POWER_SHUTDOWN_FLAG = 1 << 14
+SHUNT_ERROR_FLAG = 1 << 15
reg_names = 'temp vin vout motor load1 load2 vdd pwr_flags pwr_version'.split()
flags = self.regs[FLAGS_REG]
if self.check_fault('under_voltage', flags & UNDER_VOLTAGE_FLAG):
- self.log.error('Device under voltage')
+ self.log.warning('Device under voltage')
if self.check_fault('over_voltage', flags & OVER_VOLTAGE_FLAG):
- self.log.error('Device over voltage')
+ self.log.warning('Device over voltage')
if self.check_fault('over_current', flags & OVER_CURRENT_FLAG):
- self.log.error('Device total current limit exceeded')
+ self.log.warning('Device total current limit exceeded')
if self.check_fault('sense_error', flags & SENSE_ERROR_FLAG):
- self.log.error('Power sense error')
+ self.log.warning('Power sense error')
if self.check_fault('shunt_overload', flags & SHUNT_OVERLOAD_FLAG):
- self.log.error('Power shunt overload')
+ self.log.warning('Power shunt overload')
if self.check_fault('motor_overload', flags & MOTOR_OVERLOAD_FLAG):
- self.log.error('Motor power overload')
+ self.log.warning('Motor power overload')
if self.check_fault('load1_shutdown', flags & LOAD1_SHUTDOWN_FLAG):
- self.log.error('Load 1 over temperature shutdown')
+ self.log.warning('Load 1 over temperature shutdown')
if self.check_fault('load2_shutdown', flags & LOAD2_SHUTDOWN_FLAG):
- self.log.error('Load 2 over temperature shutdown')
+ self.log.warning('Load 2 over temperature shutdown')
if self.check_fault('motor_under_voltage',
flags & MOTOR_UNDER_VOLTAGE_FLAG):
- self.log.error('Motor under voltage')
+ self.log.warning('Motor under voltage')
if self.check_fault('motor_voltage_sense_error',
flags & MOTOR_VOLTAGE_SENSE_ERROR_FLAG):
- self.log.error('Motor voltage sense error')
+ self.log.warning('Motor voltage sense error')
if self.check_fault('motor_current_sense_error',
flags & MOTOR_CURRENT_SENSE_ERROR_FLAG):
- self.log.error('Motor current sense error')
+ self.log.warning('Motor current sense error')
if self.check_fault('load1_sense_error',
flags & LOAD1_SENSE_ERROR_FLAG):
- self.log.error('Load1 sense error')
+ self.log.warning('Load1 sense error')
if self.check_fault('load2_sense_error',
flags & LOAD2_SENSE_ERROR_FLAG):
- self.log.error('Load2 sense error')
+ self.log.warning('Load2 sense error')
if self.check_fault('vdd_current_sense_error',
flags & VDD_CURRENT_SENSE_ERROR_FLAG):
- self.log.error('Vdd current sense error')
+ self.log.warning('Vdd current sense error')
if self.check_fault('power_shutdown', flags & POWER_SHUTDOWN_FLAG):
- self.log.error('Power shutdown')
+ self.log.warning('Power shutdown')
self.ctrl.mach.i2c_command(Cmd.SHUTDOWN)
+ if self.check_fault('shunt_error', flags & SHUNT_ERROR_FLAG):
+ self.log.warning('Shunt error')
+
def _update_cb(self, now = True):
if now: self._update()