diff --git a/v2/src/Extruder/Host.cc b/v2/src/Extruder/Host.cc index 55fdeec..15b8ff5 100644 --- a/v2/src/Extruder/Host.cc +++ b/v2/src/Extruder/Host.cc @@ -126,6 +126,10 @@ bool processQueryPacket(const InPacket& from_host, OutPacket& to_host) { motor.setOn((from_host.read8(2) & 0x01) != 0); to_host.append8(RC_OK); return true; + case SLAVE_CMD_SET_MOTOR_1_RPM: + motor.setRPMSpeed(from_host.read32(2)); + to_host.append8(RC_OK); + return true; case SLAVE_CMD_TOGGLE_FAN: board.setFan((from_host.read8(2) & 0x01) != 0); to_host.append8(RC_OK); diff --git a/v2/src/Extruder/MotorController.cc b/v2/src/Extruder/MotorController.cc index 2af79e2..a0fcf47 100644 --- a/v2/src/Extruder/MotorController.cc +++ b/v2/src/Extruder/MotorController.cc @@ -30,6 +30,7 @@ void MotorController::reset() { paused = false; on = false; speed = 0; + setWithRPM = false; backoff_state = BO_INACTIVE; loadBackoffParameters(); } @@ -74,14 +75,23 @@ void MotorController::update() { break; } } - } else { + } else if (!setWithRPM) { int new_speed = (!paused&&on)?(direction?speed:-speed):0; board.setMotorSpeed(new_speed); + } else { + board.setMotorSpeedRPM((!paused&&on) ? rpm : 0, direction); } + } void MotorController::setSpeed(int speed_in) { speed = speed_in; + setWithRPM = false; +} + +void MotorController::setRPMSpeed(uint32_t speed_in) { + rpm = speed_in; + setWithRPM = true; } void MotorController::pause() { diff --git a/v2/src/Extruder/MotorController.hh b/v2/src/Extruder/MotorController.hh index 882fddd..081b696 100644 --- a/v2/src/Extruder/MotorController.hh +++ b/v2/src/Extruder/MotorController.hh @@ -25,6 +25,7 @@ class MotorController { public: void update(); void setSpeed(int speed); + void setRPMSpeed(uint32_t speed); void setDir(bool dir); void setOn(bool on); void pause(); @@ -35,9 +36,11 @@ public: private: MotorController(); void loadBackoffParameters(); + bool setWithRPM; bool direction; bool on; int speed; + uint32_t rpm; bool paused; // Backoff instrumentation bool backoff_enabled; diff --git a/v2/src/Extruder/SConscript b/v2/src/Extruder/SConscript index 2d4b619..6c84758 100644 --- a/v2/src/Extruder/SConscript +++ b/v2/src/Extruder/SConscript @@ -25,6 +25,7 @@ from os.path import dirname # Parameters platform = ARGUMENTS.get('platform','ecv22') stepper = ARGUMENTS.get('stepper','false') +extstepper = ARGUMENTS.get('extstepper','false') relays = ARGUMENTS.get('relays','false') f_cpu='16000000L' @@ -80,6 +81,9 @@ flags=[ if (stepper == 'true'): flags.append('-DDEFAULT_STEPPER=1') +if (extstepper == 'true'): + flags.append('-DDEFAULT_EXTERNAL_STEPPER=1') + if (relays == 'true'): flags.append('-DDEFAULT_RELAYS=1') diff --git a/v2/src/Extruder/boards/ecv22/Configuration.hh b/v2/src/Extruder/boards/ecv22/Configuration.hh index 9b0da21..9e94365 100644 --- a/v2/src/Extruder/boards/ecv22/Configuration.hh +++ b/v2/src/Extruder/boards/ecv22/Configuration.hh @@ -70,6 +70,16 @@ #define HB2_ENABLE_PIN Pin(PortD,6) #define HB2_DIR_PIN Pin(PortB,0) +// define the tick length, or how often the interrupt is called, +// for the external stepper -- 100 is probably plenty +#define ES_TICK_LENGTH 100 + +// Enable = "D10" +#define ES_ENABLE_PIN Pin(PortB,2) +// Dir and step are in the quadrature +#define ES_DIR_PIN Pin(PortD,2) +#define ES_STEP_PIN Pin(PortD,3) + #define DEBUG_LED Pin(PortB,5) #define SAMPLE_INTERVAL_MICROS_THERMISTOR (50L * 1000L) diff --git a/v2/src/Extruder/boards/ecv22/ExtruderBoard.cc b/v2/src/Extruder/boards/ecv22/ExtruderBoard.cc index 2e4166e..a313072 100644 --- a/v2/src/Extruder/boards/ecv22/ExtruderBoard.cc +++ b/v2/src/Extruder/boards/ecv22/ExtruderBoard.cc @@ -72,7 +72,11 @@ void pwmBOn(bool on) { } } +#if !defined(DEFAULT_EXTERNAL_STEPPER) +#define SERVO_COUNT 1 +#else #define SERVO_COUNT 2 +#endif volatile int servoPos[SERVO_COUNT]; @@ -92,7 +96,11 @@ void ExtruderBoard::reset() { TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); TCCR1C = 0x00; ICR1 = INTERVAL_IN_MICROSECONDS * 16; +#if !defined(DEFAULT_EXTERNAL_STEPPER) TIMSK1 = _BV(ICIE1) | _BV(OCIE1A) | _BV(OCIE1B); // turn on ICR1 match interrupt +#else + TIMSK1 = _BV(ICIE1) | _BV(OCIE1A); // turn on ICR1 match interrupt +#endif TIMSK2 = 0x00; // turn off channel A PWM by default // TIMER2 is used to PWM mosfet channel B on OC2A, and channel A on // PC1 (using the OC2B register). @@ -122,13 +130,21 @@ void ExtruderBoard::reset() { // setUsingRelays((features & eeprom::RELAY_BOARD) != 0); // setStepperMode((features & eeprom::HBRIDGE_STEPPER) != 0); // Init servo ports: OC1A and OC1B as outputs when not linked to counter. +#if defined DEFAULT_STEPPER +#warning Using internal stepper! + setStepperMode(true, false); PORTB &= ~_BV(1) & ~_BV(2); DDRB |= _BV(1) | _BV(2); -#ifdef DEFAULT_STEPPER - setStepperMode(true); +#elif defined DEFAULT_EXTERNAL_STEPPER +#warning Using external stepper! + setStepperMode(true, true); + PORTB &= ~_BV(1); // We don't use D10 for a servo with external steppers, it's the enable pin + DDRB |= _BV(1); // but it's still an output #else +#warning Using DC Motor! setStepperMode(false); #endif + #ifdef DEFAULT_RELAYS setUsingRelays(true); #else @@ -140,6 +156,10 @@ void ExtruderBoard::setMotorSpeed(int16_t speed) { setExtruderMotor(speed); } +void ExtruderBoard::setMotorSpeedRPM(uint32_t speed, bool direction) { + setExtruderMotorRPM(speed, direction); +} + micros_t ExtruderBoard::getCurrentMicros() { micros_t micros_snapshot; ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { @@ -163,10 +183,14 @@ void ExtruderBoard::doInterrupt() { PORTB |= _BV(1); OCR1A = (600*16) + (servoPos[0]*160); } + + // figure out how to make this runtime settable... +#if defined(DEFAULT_EXTERNAL_STEPPER) if (servoPos[1] != -1) { PORTB |= _BV(2); OCR1B = (600*16) + (servoPos[1] * 160); } +#endif } servo_cycle++; if (servo_cycle > SERVO_CYCLE_LENGTH) { servo_cycle = 0; } diff --git a/v2/src/Extruder/boards/ecv22/ExtruderBoard.hh b/v2/src/Extruder/boards/ecv22/ExtruderBoard.hh index c9bd1eb..efbaf48 100644 --- a/v2/src/Extruder/boards/ecv22/ExtruderBoard.hh +++ b/v2/src/Extruder/boards/ecv22/ExtruderBoard.hh @@ -43,6 +43,7 @@ public: Heater& getExtruderHeater() { return extruder_heater; } Heater& getPlatformHeater() { return platform_heater; } void setMotorSpeed(int16_t speed); + void setMotorSpeedRPM(uint32_t speed, bool direction); void setFan(bool on); void setValve(bool on); UART& getHostUART() { return UART::getHostUART(); } diff --git a/v2/src/Extruder/boards/ecv22/ExtruderMotor.cc b/v2/src/Extruder/boards/ecv22/ExtruderMotor.cc index 63751c4..fe3ffce 100644 --- a/v2/src/Extruder/boards/ecv22/ExtruderMotor.cc +++ b/v2/src/Extruder/boards/ecv22/ExtruderMotor.cc @@ -21,6 +21,7 @@ #include #include "ExtruderMotor.hh" #include "EepromMap.hh" +#include using namespace eeprom; @@ -28,6 +29,7 @@ using namespace eeprom; int16_t last_extruder_speed; bool stepper_motor_mode; +bool external_stepper_motor_mode; int16_t stepper_accumulator; uint8_t stepper_phase; @@ -35,13 +37,21 @@ bool swap_motor = false; Pin motor_enable_pin = HB1_ENABLE_PIN; Pin motor_dir_pin = HB1_DIR_PIN; +Pin external_enable_pin = ES_ENABLE_PIN; +Pin external_dir_pin = ES_DIR_PIN; +Pin external_step_pin = ES_STEP_PIN; + +uint32_t last_extruder_rpm_micros; +bool last_extruder_direction; +uint16_t extruder_steps_per_rev = 16 * 200; /* / 5 for MakerGear 1:5 geared stepper */ + +volatile uint16_t ext_stepper_ticks_per_step = 0; +volatile int16_t ext_stepper_counter = 0; + + // TIMER0 is used to PWM motor driver A enable on OC0B. void initExtruderMotor() { last_extruder_speed = 0; - TCCR0A = 0b00000011; // Leave pin off by default - TCCR0B = 0b00000011; - OCR0B = 0; - TIMSK0 = 0; // no interrupts needed. HB1_ENABLE_PIN.setDirection(true); HB1_ENABLE_PIN.setValue(false); HB1_DIR_PIN.setDirection(true); @@ -60,16 +70,51 @@ void initExtruderMotor() { } } -void setStepperMode(bool mode) { - stepper_motor_mode = mode; - setExtruderMotor(last_extruder_speed); +void setStepperMode(bool mode, bool external/* = false*/) { + stepper_motor_mode = mode && !external; + external_stepper_motor_mode = mode && external; + + if (stepper_motor_mode) { + TCCR0A = 0b00000000; + TCCR0B = 0b00000011; + TIMSK0 = 0b00000001; + } else if (external_stepper_motor_mode) { + // external stepper uses setExtruderMotorRPM, but setStepperMode() calls this once, so setup here + + // Setup pins + external_enable_pin.setDirection(true); + external_enable_pin.setValue(true); // true = disabled + + external_dir_pin.setDirection(true); + external_dir_pin.setValue(true); // true = forward + + external_step_pin.setDirection(true); + external_step_pin.setValue(false); + + // CTC Mode, + TCCR0A = _BV(WGM01); + // 8x prescaler, with CTC mode that 1/16th of clock, or 1MHz + TCCR0B = _BV(CS01); + // Timer/Counter 0 Output Compare A Match Interrupt On + TIMSK0 = _BV(OCIE1A); + + OCR0A = ES_TICK_LENGTH-1; // 1/(16,000,000 / (2*8)*(1+OCR0A)) = ES_TICK_LENGTH micros/tick + + DEBUG_LED.setValue(true); + } else { + TCCR0A = 0b00000011; // Leave pin off by default + TCCR0B = 0b00000011; + OCR0B = 0; + TIMSK0 = 0; // no interrupts needed. + setExtruderMotor(last_extruder_speed); + } } void setExtruderMotor(int16_t speed) { if (speed == last_extruder_speed) return; last_extruder_speed = speed; ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - if (!stepper_motor_mode) { + if (!stepper_motor_mode && !external_stepper_motor_mode) { TIMSK0 = 0; if (speed == 0) { TCCR0A = 0b00000011; @@ -94,14 +139,39 @@ void setExtruderMotor(int16_t speed) { } else { OCR0B = speed; } + } + } +} + + +// set the motor's RPM -- in microseconds for one full revolution +void setExtruderMotorRPM(uint32_t micros, bool direction) { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + if (micros > 0.0) { + // 60,000,000 is one RPM + // 1,000,000 is one RPS + ext_stepper_ticks_per_step = (micros / ES_TICK_LENGTH) / extruder_steps_per_rev; + //ext_stepper_counter = 0; + + // Timer/Counter 0 Output Compare A Match Interrupt On + TIMSK0 = _BV(OCF0A); + + external_dir_pin.setValue(direction); // true = firward + external_enable_pin.setValue(false); // true = disabled + external_step_pin.setValue(false); + // DEBUG_LED.setValue(true); } else { - TCCR0A = 0b00000000; - TCCR0B = 0b00000011; - TIMSK0 = 0b00000001; + // Timer/Counter 0 Output Compare A Match Interrupt Off + TIMSK0 = 0; + external_enable_pin.setValue(true); // true = disabled + // DEBUG_LED.setValue(false); } } + } +// ## H-Bridge Stepper Driving using Timer0 Overflow ## + const uint8_t hb1_en_pattern = 0xdd; const uint8_t hb1_dir_pattern = 0xc3; const uint8_t hb2_en_pattern = 0x77; @@ -110,7 +180,6 @@ const uint8_t hb2_dir_pattern = 0xf0; // at speed 255, ~80Hz full-stepping const int16_t acc_rollover = (6375/2); - volatile uint8_t stepper_pwm = 0; inline void setStep() { @@ -133,3 +202,18 @@ ISR(TIMER0_OVF_vect) { } setStep(); } + +// ## External Stepper Driving using Timer 0 Compare A ## + +ISR(TIMER0_COMPA_vect) { + if (ext_stepper_ticks_per_step > 0) { + ++ext_stepper_counter; + if (ext_stepper_counter >= ext_stepper_ticks_per_step) { + external_step_pin.setValue(true); + _delay_loop_1(10); + external_step_pin.setValue(false); + + ext_stepper_counter = 0; + } + } +} diff --git a/v2/src/Extruder/boards/ecv22/ExtruderMotor.hh b/v2/src/Extruder/boards/ecv22/ExtruderMotor.hh index c1ef64e..f1a326a 100644 --- a/v2/src/Extruder/boards/ecv22/ExtruderMotor.hh +++ b/v2/src/Extruder/boards/ecv22/ExtruderMotor.hh @@ -22,12 +22,13 @@ void initExtruderMotor(); -void setStepperMode(bool mode); +void setStepperMode(bool mode, bool external = false); // 0 = stop // + = forward direction // - = negative direction // Valid range: -255 through 255 void setExtruderMotor(int16_t speed); +void setExtruderMotorRPM(uint32_t micros, bool direction); #endif // BOARDS_ECV22_EXTRUDER_MOTOR_HH_