From 0bd3dfdcf7b439c2cb6c88918b558444b40f81c2 Mon Sep 17 00:00:00 2001 From: "D.R.racer" Date: Wed, 25 May 2022 20:37:14 +0200 Subject: [PATCH] This starts to print ;) Temporarily disabled filament runout as this breaks ToolChange operation yet for unknown reason. --- Firmware/Filament_sensor.cpp | 486 +++++++++++++++++++++++++++++++- Firmware/Filament_sensor.h | 527 ++++------------------------------- Firmware/Tcodes.cpp | 21 +- Firmware/mmu2.cpp | 8 +- Firmware/ultralcd.cpp | 4 +- 5 files changed, 554 insertions(+), 492 deletions(-) diff --git a/Firmware/Filament_sensor.cpp b/Firmware/Filament_sensor.cpp index ec8045eb0..431196e6f 100644 --- a/Firmware/Filament_sensor.cpp +++ b/Firmware/Filament_sensor.cpp @@ -1,4 +1,15 @@ +#include +#include +#include + #include "Filament_sensor.h" +#include "Timer.h" +#include "cardreader.h" +#include "eeprom.h" +#include "menu.h" +#include "pat9125.h" +#include "temperature.h" +#include "ultralcd.h" #ifdef FILAMENT_SENSOR #if FILAMENT_SENSOR_TYPE == FSENSOR_IR @@ -8,4 +19,477 @@ IR_sensor_analog fsensor; #elif FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125 PAT9125_sensor fsensor; #endif -#endif //FILAMENT_SENSOR +#endif // FILAMENT_SENSOR + +void Filament_sensor::setEnabled(bool enabled) { + eeprom_update_byte((uint8_t *)EEPROM_FSENSOR, enabled); + if (enabled) { + init(); + } else { + deinit(); + } +} + +void Filament_sensor::setAutoLoadEnabled(bool state, bool updateEEPROM) { + autoLoadEnabled = state; + if (updateEEPROM) { + eeprom_update_byte((uint8_t *)EEPROM_FSENS_AUTOLOAD_ENABLED, state); + } +} + +void Filament_sensor::setRunoutEnabled(bool state, bool updateEEPROM) { + runoutEnabled = state; + if (updateEEPROM) { + eeprom_update_byte((uint8_t *)EEPROM_FSENS_RUNOUT_ENABLED, state); + } +} + +void Filament_sensor::setActionOnError(SensorActionOnError state, bool updateEEPROM) { + sensorActionOnError = state; + if (updateEEPROM) { + eeprom_update_byte((uint8_t *)EEPROM_FSENSOR_ACTION_NA, (uint8_t)state); + } +} + +void Filament_sensor::settings_init_common() { + bool enabled = eeprom_read_byte((uint8_t *)EEPROM_FSENSOR); + if ((state != State::disabled) != enabled) { + state = enabled ? State::initializing : State::disabled; + } + + autoLoadEnabled = eeprom_read_byte((uint8_t *)EEPROM_FSENS_AUTOLOAD_ENABLED); + runoutEnabled = eeprom_read_byte((uint8_t *)EEPROM_FSENS_RUNOUT_ENABLED); + sensorActionOnError = (SensorActionOnError)eeprom_read_byte((uint8_t *)EEPROM_FSENSOR_ACTION_NA); + if (sensorActionOnError == SensorActionOnError::_Undef) { + sensorActionOnError = SensorActionOnError::_Continue; + } +} + +bool Filament_sensor::checkFilamentEvents() { + if (state != State::ready) + return false; + if (eventBlankingTimer.running() && !eventBlankingTimer.expired(100)) { // event blanking for 100ms + return false; + } + + bool newFilamentPresent = getFilamentPresent(); + if (oldFilamentPresent != newFilamentPresent) { + oldFilamentPresent = newFilamentPresent; + eventBlankingTimer.start(); + if (newFilamentPresent) { // filament insertion + puts_P(PSTR("filament inserted")); + triggerFilamentInserted(); + postponedLoadEvent = true; + } else { // filament removal + puts_P(PSTR("filament removed")); + triggerFilamentRemoved(); + } + return true; + } + return false; +} + +void Filament_sensor::triggerFilamentInserted() { + if (autoLoadEnabled && (eFilamentAction == FilamentAction::None) && + !(moves_planned() || IS_SD_PRINTING || usb_timer.running() || (lcd_commands_type == LcdCommands::Layer1Cal) || + eeprom_read_byte((uint8_t *)EEPROM_WIZARD_ACTIVE))) { + filAutoLoad(); + } +} + +void Filament_sensor::triggerFilamentRemoved() { + if (runoutEnabled + && (eFilamentAction == FilamentAction::None) + && !saved_printing + && ( + moves_planned() + || IS_SD_PRINTING + || usb_timer.running() + || (lcd_commands_type == LcdCommands::Layer1Cal) + || eeprom_read_byte((uint8_t *)EEPROM_WIZARD_ACTIVE) + ) + ){ +// filRunout(); + } +} + +void Filament_sensor::filAutoLoad() { + eFilamentAction = FilamentAction::AutoLoad; + if (target_temperature[0] >= EXTRUDE_MINTEMP) { + bFilamentPreheatState = true; + menu_submenu(mFilamentItemForce); + } else { + menu_submenu(lcd_generic_preheat_menu); + lcd_timeoutToStatus.start(); + } +} + +void Filament_sensor::filRunout() { + runoutEnabled = false; + autoLoadEnabled = false; + stop_and_save_print_to_ram(0, 0); + restore_print_from_ram_and_continue(0); + eeprom_update_byte((uint8_t *)EEPROM_FERROR_COUNT, eeprom_read_byte((uint8_t *)EEPROM_FERROR_COUNT) + 1); + eeprom_update_word((uint16_t *)EEPROM_FERROR_COUNT_TOT, eeprom_read_word((uint16_t *)EEPROM_FERROR_COUNT_TOT) + 1); + enquecommand_front_P((PSTR("M600"))); +} + +void Filament_sensor::triggerError() { + state = State::error; + + /// some message, idk + ; // +} + +#if (FILAMENT_SENSOR_TYPE == FSENSOR_IR) || (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG) +void IR_sensor::init() { + if (state == State::error) { + deinit(); // deinit first if there was an error. + } + puts_P(PSTR("fsensor::init()")); + SET_INPUT(IR_SENSOR_PIN); // input mode + WRITE(IR_SENSOR_PIN, 1); // pullup + settings_init(); // also sets the state to State::initializing +} + +void IR_sensor::deinit() { + puts_P(PSTR("fsensor::deinit()")); + SET_INPUT(IR_SENSOR_PIN); // input mode + WRITE(IR_SENSOR_PIN, 0); // no pullup + state = State::disabled; +} + +bool IR_sensor::update() { + switch (state) { + case State::initializing: + state = State::ready; // the IR sensor gets ready instantly as it's just a gpio read operation. + oldFilamentPresent = + getFilamentPresent(); // initialize the current filament state so that we don't create a switching event right after the sensor is ready. + // fallthru + case State::ready: { + postponedLoadEvent = false; + bool event = checkFilamentEvents(); + + ; // + + return event; + } break; + case State::disabled: + case State::error: + default: + return false; + } + return false; +} + +bool IR_sensor::getFilamentPresent() { return !READ(IR_SENSOR_PIN); } + +bool IR_sensor::probeOtherType() { return pat9125_probe(); } + +void IR_sensor::settings_init() { Filament_sensor::settings_init_common(); } + +#if (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG) +void IR_sensor_analog::init() { + IR_sensor::init(); + settings_init(); +} + +void IR_sensor_analog::deinit() { IR_sensor::deinit(); } + +bool IR_sensor_analog::update() { + bool event = IR_sensor::update(); + if (state == State::ready) { + if (voltReady) { + voltReady = false; + uint16_t volt = getVoltRaw(); + printf_P(PSTR("newVoltRaw:%u\n"), volt / OVERSAMPLENR); + + // detect min-max, some long term sliding window for filtration may be added + // avoiding floating point operations, thus computing in raw + if (volt > maxVolt) { + maxVolt = volt; + } else if (volt < minVolt) { + minVolt = volt; + } + //! The trouble is, I can hold the filament in the hole in such a way, that it creates the exact voltage + //! to be detected as the new fsensor + //! We can either fake it by extending the detection window to a looooong time + //! or do some other countermeasures + + //! what we want to detect: + //! if minvolt gets below ~0.3V, it means there is an old fsensor + //! if maxvolt gets above 4.6V, it means we either have an old fsensor or broken cables/fsensor + //! So I'm waiting for a situation, when minVolt gets to range <0, 1.5> and maxVolt gets into range <3.0, 5> + //! If and only if minVolt is in range <0.3, 1.5> and maxVolt is in range <3.0, 4.6>, I'm considering a situation with the new fsensor + if (minVolt >= IRsensor_Ldiode_TRESHOLD && minVolt <= IRsensor_Lmax_TRESHOLD && maxVolt >= IRsensor_Hmin_TRESHOLD && + maxVolt <= IRsensor_Hopen_TRESHOLD) { + IR_ANALOG_Check(SensorRevision::_Old, SensorRevision::_Rev04); + } + //! If and only if minVolt is in range <0.0, 0.3> and maxVolt is in range <4.6, 5.0V>, I'm considering a situation with the old fsensor + //! Note, we are not relying on one voltage here - getting just +5V can mean an old fsensor or a broken new sensor - that's why + //! we need to have both voltages detected correctly to allow switching back to the old fsensor. + else if (minVolt < IRsensor_Ldiode_TRESHOLD && maxVolt > IRsensor_Hopen_TRESHOLD && maxVolt <= IRsensor_VMax_TRESHOLD) { + IR_ANALOG_Check(SensorRevision::_Rev04, SensorRevision::_Old); + } + + if (!checkVoltage(volt)) { + triggerError(); + } + } + } + + ; // + + return event; +} + +void IR_sensor_analog::voltUpdate(uint16_t raw) { // to be called from the ADC ISR when a cycle is finished + voltRaw = raw; + voltReady = true; +} + +uint16_t IR_sensor_analog::getVoltRaw() { + uint16_t newVoltRaw; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { newVoltRaw = voltRaw; } + return newVoltRaw; +} + +void IR_sensor_analog::settings_init() { + IR_sensor::settings_init(); + sensorRevision = (SensorRevision)eeprom_read_byte((uint8_t *)EEPROM_FSENSOR_PCB); +} + +const char *IR_sensor_analog::getIRVersionText() { + switch (sensorRevision) { + case SensorRevision::_Old: + return _T(MSG_IR_03_OR_OLDER); + case SensorRevision::_Rev04: + return _T(MSG_IR_04_OR_NEWER); + default: + return _T(MSG_IR_UNKNOWN); + } +} + +void IR_sensor_analog::setSensorRevision(SensorRevision rev, bool updateEEPROM) { + sensorRevision = rev; + if (updateEEPROM) { + eeprom_update_byte((uint8_t *)EEPROM_FSENSOR_PCB, (uint8_t)rev); + } +} + +bool IR_sensor_analog::checkVoltage(uint16_t raw) { + if (IRsensor_Lmax_TRESHOLD <= raw && raw <= IRsensor_Hmin_TRESHOLD) { + /// If the voltage is in forbidden range, the fsensor is ok, but the lever is mounted improperly. + /// Or the user is so creative so that he can hold a piece of fillament in the hole in such a genius way, + /// that the IR fsensor reading is within 1.5 and 3V ... this would have been highly unusual + /// and would have been considered more like a sabotage than normal printer operation + if (voltageErrorCnt++ > 4) { + puts_P(PSTR("fsensor in forbidden range 1.5-3V - check sensor")); + return false; + } + } else { + voltageErrorCnt = 0; + } + if (sensorRevision == SensorRevision::_Rev04) { + /// newer IR sensor cannot normally produce 4.6-5V, this is considered a failure/bad mount + if (IRsensor_Hopen_TRESHOLD <= raw && raw <= IRsensor_VMax_TRESHOLD) { + puts_P(PSTR("fsensor v0.4 in fault range 4.6-5V - unconnected")); + return false; + } + /// newer IR sensor cannot normally produce 0-0.3V, this is considered a failure +#if 0 // Disabled as it has to be decided if we gonna use this or not. + if(IRsensor_Hopen_TRESHOLD <= raw && raw <= IRsensor_VMax_TRESHOLD) { + puts_P(PSTR("fsensor v0.4 in fault range 0.0-0.3V - wrong IR sensor")); + return false; + } +#endif + } + /// If IR sensor is "uknown state" and filament is not loaded > 1.5V return false +#if 0 +#error "I really think this code can't be enabled anymore because we are constantly checking this voltage." + if((sensorRevision == SensorRevision::_Undef) && (raw > IRsensor_Lmax_TRESHOLD)) { + puts_P(PSTR("Unknown IR sensor version and no filament loaded detected.")); + return false; + } +#endif + // otherwise the IR fsensor is considered working correctly + return true; +} + +void IR_sensor_analog::IR_ANALOG_Check(SensorRevision isVersion, SensorRevision switchTo) { + bool bTemp = (!CHECK_ALL_HEATERS); + bTemp = bTemp && (menu_menu == lcd_status_screen); + bTemp = bTemp && ((sensorRevision == isVersion) || (sensorRevision == SensorRevision::_Undef)); + bTemp = bTemp && (state == State::ready); + if (bTemp) { + nFSCheckCount++; + if (nFSCheckCount > FS_CHECK_COUNT) { + nFSCheckCount = 0; // not necessary + setSensorRevision(switchTo, true); + printf_IRSensorAnalogBoardChange(); + switch (switchTo) { + case SensorRevision::_Old: + lcd_setstatuspgm(_T(MSG_FS_V_03_OR_OLDER)); ////MSG_FS_V_03_OR_OLDER c=18 + break; + case SensorRevision::_Rev04: + lcd_setstatuspgm(_T(MSG_FS_V_04_OR_NEWER)); ////MSG_FS_V_04_OR_NEWER c=18 + break; + default: + break; + } + } + } else { + nFSCheckCount = 0; + } +} +#endif //(FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG) +#endif //(FILAMENT_SENSOR_TYPE == FSENSOR_IR) || (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG) + +#if (FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125) +void PAT9125_sensor::init() { + if (state == State::error) { + deinit(); // deinit first if there was an error. + } + puts_P(PSTR("fsensor::init()")); + + settings_init(); // also sets the state to State::initializing + + calcChunkSteps(cs.axis_steps_per_unit[E_AXIS]); // for jam detection + + if (!pat9125_init()) { + deinit(); + triggerError(); + ; // + } +#ifdef IR_SENSOR_PIN + else if (!READ(IR_SENSOR_PIN)) { + ; // MK3 fw on MK3S printer + } +#endif // IR_SENSOR_PIN +} + +void PAT9125_sensor::deinit() { + puts_P(PSTR("fsensor::deinit()")); + ; // + state = State::disabled; + filter = 0; +} + +bool PAT9125_sensor::update() { + switch (state) { + case State::initializing: + if (!updatePAT9125()) { + break; // still not stable. Stay in the initialization state. + } + oldFilamentPresent = + getFilamentPresent(); // initialize the current filament state so that we don't create a switching event right after the sensor is ready. + oldPos = pat9125_y; + state = State::ready; + break; + case State::ready: { + updatePAT9125(); + postponedLoadEvent = false; + bool event = checkFilamentEvents(); + + ; // + + return event; + } break; + case State::disabled: + case State::error: + default: + return false; + } + return false; +} + +bool PAT9125_sensor::probeOtherType() { + SET_INPUT(IR_SENSOR_PIN); // input mode + WRITE(IR_SENSOR_PIN, 1); // pullup + _delay_us(100); // wait for the pullup to pull the line high (might be needed, not really sure. The internal pullups are quite weak and there might be a + // long wire attached). + bool fsensorDetected = !READ(IR_SENSOR_PIN); + WRITE(IR_SENSOR_PIN, 0); // no pullup + return fsensorDetected; +} + +void PAT9125_sensor::setJamDetectionEnabled(bool state, bool updateEEPROM) { + jamDetection = state; + oldPos = pat9125_y; + resetStepCount(); + jamErrCnt = 0; + if (updateEEPROM) { + eeprom_update_byte((uint8_t *)EEPROM_FSENSOR_JAM_DETECTION, state); + } +} + +void PAT9125_sensor::settings_init() { + puts_P(PSTR("settings_init")); + Filament_sensor::settings_init_common(); + setJamDetectionEnabled(eeprom_read_byte((uint8_t *)EEPROM_FSENSOR_JAM_DETECTION)); +} + +int16_t PAT9125_sensor::getStepCount() { + int16_t st_cnt; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { st_cnt = stepCount; } + return st_cnt; +} + +void PAT9125_sensor::resetStepCount() { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { stepCount = 0; } +} + +void PAT9125_sensor::filJam() { + runoutEnabled = false; + autoLoadEnabled = false; + jamDetection = false; + stop_and_save_print_to_ram(0, 0); + restore_print_from_ram_and_continue(0); + eeprom_update_byte((uint8_t *)EEPROM_FERROR_COUNT, eeprom_read_byte((uint8_t *)EEPROM_FERROR_COUNT) + 1); + eeprom_update_word((uint16_t *)EEPROM_FERROR_COUNT_TOT, eeprom_read_word((uint16_t *)EEPROM_FERROR_COUNT_TOT) + 1); + enquecommand_front_P((PSTR("M600"))); +} + +bool PAT9125_sensor::updatePAT9125() { + if (jamDetection) { + int16_t _stepCount = getStepCount(); + if (abs(_stepCount) >= chunkSteps) { // end of chunk. Check distance + resetStepCount(); + if (!pat9125_update()) { // get up to date data. reinit on error. + init(); // try to reinit. + } + bool fsDir = (pat9125_y - oldPos) > 0; + bool stDir = _stepCount > 0; + if (fsDir != stDir) { + jamErrCnt++; + } else if (jamErrCnt) { + jamErrCnt--; + } + oldPos = pat9125_y; + } + if (jamErrCnt > 10) { + jamErrCnt = 0; + filJam(); + } + } + + if (!pollingTimer.running() || pollingTimer.expired(pollingPeriod)) { + pollingTimer.start(); + if (!pat9125_update()) { + init(); // try to reinit. + } + + bool present = (pat9125_s < 17) || (pat9125_s >= 17 && pat9125_b >= 50); + if (present != filterFilPresent) { + filter++; + } else if (filter) { + filter--; + } + if (filter >= filterCnt) { + filter = 0; + filterFilPresent = present; + } + } + return (filter == 0); // return stability +} +#endif // #if (FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125) diff --git a/Firmware/Filament_sensor.h b/Firmware/Filament_sensor.h index cc664d746..bc7694a07 100644 --- a/Firmware/Filament_sensor.h +++ b/Firmware/Filament_sensor.h @@ -1,22 +1,10 @@ #pragma once - #include -#include -#include -#include -#include "Marlin.h" -#include "ultralcd.h" -#include "menu.h" -#include "cardreader.h" -#include "temperature.h" #include "cmdqueue.h" -#include "eeprom.h" #include "pins.h" #include "fastio.h" #include "adc.h" -#include "Timer.h" -#include "pat9125.h" #define FSENSOR_IR 1 #define FSENSOR_IR_ANALOG 2 @@ -46,44 +34,21 @@ public: _Undef = EEPROM_EMPTY_VALUE }; - void setEnabled(bool enabled) { - eeprom_update_byte((uint8_t *)EEPROM_FSENSOR, enabled); - if (enabled) { - init(); - } - else { - deinit(); - } - } + void setEnabled(bool enabled); - void setAutoLoadEnabled(bool state, bool updateEEPROM = false) { - autoLoadEnabled = state; - if (updateEEPROM) { - eeprom_update_byte((uint8_t *)EEPROM_FSENS_AUTOLOAD_ENABLED, state); - } - } + void setAutoLoadEnabled(bool state, bool updateEEPROM = false); bool getAutoLoadEnabled() { return autoLoadEnabled; } - void setRunoutEnabled(bool state, bool updateEEPROM = false) { - runoutEnabled = state; - if (updateEEPROM) { - eeprom_update_byte((uint8_t *)EEPROM_FSENS_RUNOUT_ENABLED, state); - } - } + void setRunoutEnabled(bool state, bool updateEEPROM = false); bool getRunoutEnabled() { return runoutEnabled; } - void setActionOnError(SensorActionOnError state, bool updateEEPROM = false) { - sensorActionOnError = state; - if (updateEEPROM) { - eeprom_update_byte((uint8_t *)EEPROM_FSENSOR_ACTION_NA, (uint8_t)state); - } - } + void setActionOnError(SensorActionOnError state, bool updateEEPROM = false); SensorActionOnError getActionOnError() { return sensorActionOnError; @@ -106,85 +71,19 @@ public: } protected: - void settings_init() { - bool enabled = eeprom_read_byte((uint8_t*)EEPROM_FSENSOR); - if ((state != State::disabled) != enabled) { - state = enabled ? State::initializing : State::disabled; - } - - autoLoadEnabled = eeprom_read_byte((uint8_t*)EEPROM_FSENS_AUTOLOAD_ENABLED); - runoutEnabled = eeprom_read_byte((uint8_t*)EEPROM_FSENS_RUNOUT_ENABLED); - sensorActionOnError = (SensorActionOnError)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_ACTION_NA); - if (sensorActionOnError == SensorActionOnError::_Undef) { - sensorActionOnError = SensorActionOnError::_Continue; - } - } + void settings_init_common(); - bool checkFilamentEvents() { - if (state != State::ready) - return false; - if (eventBlankingTimer.running() && !eventBlankingTimer.expired(100)) {// event blanking for 100ms - return false; - } - - bool newFilamentPresent = getFilamentPresent(); - if (oldFilamentPresent != newFilamentPresent) { - oldFilamentPresent = newFilamentPresent; - eventBlankingTimer.start(); - if (newFilamentPresent) { //filament insertion - puts_P(PSTR("filament inserted")); - triggerFilamentInserted(); - postponedLoadEvent = true; - } - else { //filament removal - puts_P(PSTR("filament removed")); - triggerFilamentRemoved(); - } - return true; - } - return false; - }; + bool checkFilamentEvents(); - void triggerFilamentInserted() { - if (autoLoadEnabled && (eFilamentAction == FilamentAction::None) && !(moves_planned() || IS_SD_PRINTING || usb_timer.running() || (lcd_commands_type == LcdCommands::Layer1Cal) || eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE))) { - filAutoLoad(); - } - } + void triggerFilamentInserted(); - void triggerFilamentRemoved() { - if (runoutEnabled && (eFilamentAction == FilamentAction::None) && !saved_printing && (moves_planned() || IS_SD_PRINTING || usb_timer.running() || (lcd_commands_type == LcdCommands::Layer1Cal) || eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE))) { - filRunout(); - } - } + void triggerFilamentRemoved(); - void filAutoLoad() { - eFilamentAction = FilamentAction::AutoLoad; - if(target_temperature[0] >= EXTRUDE_MINTEMP){ - bFilamentPreheatState = true; - menu_submenu(mFilamentItemForce); - } - else { - menu_submenu(lcd_generic_preheat_menu); - lcd_timeoutToStatus.start(); - } - } + void filAutoLoad(); - void filRunout() { - runoutEnabled = false; - autoLoadEnabled = false; - stop_and_save_print_to_ram(0, 0); - restore_print_from_ram_and_continue(0); - eeprom_update_byte((uint8_t*)EEPROM_FERROR_COUNT, eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT) + 1); - eeprom_update_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT) + 1); - enquecommand_front_P((PSTR("M600"))); - } + void filRunout(); - void triggerError() { - state = State::error; - - /// some message, idk - ;// - } + void triggerError(); State state; bool autoLoadEnabled; @@ -198,137 +97,34 @@ protected: #if (FILAMENT_SENSOR_TYPE == FSENSOR_IR) || (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG) class IR_sensor: public Filament_sensor { public: - void init() { - if (state == State::error) { - deinit(); //deinit first if there was an error. - } - puts_P(PSTR("fsensor::init()")); - SET_INPUT(IR_SENSOR_PIN); //input mode - WRITE(IR_SENSOR_PIN, 1); //pullup - settings_init(); //also sets the state to State::initializing - } - - void deinit() { - puts_P(PSTR("fsensor::deinit()")); - SET_INPUT(IR_SENSOR_PIN); //input mode - WRITE(IR_SENSOR_PIN, 0); //no pullup - state = State::disabled; - } - - bool update() { - switch (state) { - case State::initializing: - state = State::ready; //the IR sensor gets ready instantly as it's just a gpio read operation. - oldFilamentPresent = getFilamentPresent(); //initialize the current filament state so that we don't create a switching event right after the sensor is ready. - // fallthru - case State::ready: { - postponedLoadEvent = false; - bool event = checkFilamentEvents(); - - ;// - - return event; - } break; - case State::disabled: - case State::error: - default: - return false; - } - return false; - } - - bool getFilamentPresent() { - return !READ(IR_SENSOR_PIN); - } - + void init() override; + void deinit() override; + bool update()override ; + bool getFilamentPresent()override; #ifdef FSENSOR_PROBING - bool probeOtherType() { - return pat9125_probe(); - } + bool probeOtherType()override; #endif - - void settings_init() { - Filament_sensor::settings_init(); - } -protected: + void settings_init(); }; #if (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG) +constexpr static uint16_t Voltage2Raw(float V) { + return (V * 1023 * OVERSAMPLENR / VOLT_DIV_REF ) + 0.5F; +} +constexpr static float Raw2Voltage(uint16_t raw) { + return VOLT_DIV_REF * (raw / (1023.F * OVERSAMPLENR)); +} + class IR_sensor_analog: public IR_sensor { public: - void init() { - IR_sensor::init(); - settings_init(); - } + void init()override; + void deinit()override; + bool update()override; + void voltUpdate(uint16_t raw); - void deinit() { - IR_sensor::deinit(); - } + uint16_t getVoltRaw(); - bool update() { - bool event = IR_sensor::update(); - if (state == State::ready) { - if (voltReady) { - voltReady = false; - uint16_t volt = getVoltRaw(); - printf_P(PSTR("newVoltRaw:%u\n"), volt / OVERSAMPLENR); - - // detect min-max, some long term sliding window for filtration may be added - // avoiding floating point operations, thus computing in raw - if(volt > maxVolt) { - maxVolt = volt; - } - else if(volt < minVolt) { - minVolt = volt; - } - //! The trouble is, I can hold the filament in the hole in such a way, that it creates the exact voltage - //! to be detected as the new fsensor - //! We can either fake it by extending the detection window to a looooong time - //! or do some other countermeasures - - //! what we want to detect: - //! if minvolt gets below ~0.3V, it means there is an old fsensor - //! if maxvolt gets above 4.6V, it means we either have an old fsensor or broken cables/fsensor - //! So I'm waiting for a situation, when minVolt gets to range <0, 1.5> and maxVolt gets into range <3.0, 5> - //! If and only if minVolt is in range <0.3, 1.5> and maxVolt is in range <3.0, 4.6>, I'm considering a situation with the new fsensor - if(minVolt >= IRsensor_Ldiode_TRESHOLD && minVolt <= IRsensor_Lmax_TRESHOLD && maxVolt >= IRsensor_Hmin_TRESHOLD && maxVolt <= IRsensor_Hopen_TRESHOLD) { - IR_ANALOG_Check(SensorRevision::_Old, SensorRevision::_Rev04); - } - //! If and only if minVolt is in range <0.0, 0.3> and maxVolt is in range <4.6, 5.0V>, I'm considering a situation with the old fsensor - //! Note, we are not relying on one voltage here - getting just +5V can mean an old fsensor or a broken new sensor - that's why - //! we need to have both voltages detected correctly to allow switching back to the old fsensor. - else if( minVolt < IRsensor_Ldiode_TRESHOLD && maxVolt > IRsensor_Hopen_TRESHOLD && maxVolt <= IRsensor_VMax_TRESHOLD) { - IR_ANALOG_Check(SensorRevision::_Rev04, SensorRevision::_Old); - } - - if (!checkVoltage(volt)) { - triggerError(); - } - } - } - - ;// - - return event; - } - - void voltUpdate(uint16_t raw) { //to be called from the ADC ISR when a cycle is finished - voltRaw = raw; - voltReady = true; - } - - uint16_t getVoltRaw() { - uint16_t newVoltRaw; - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - newVoltRaw = voltRaw; - } - return newVoltRaw; - } - - void settings_init() { - IR_sensor::settings_init(); - sensorRevision = (SensorRevision)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_PCB); - } + void settings_init(); enum class SensorRevision : uint8_t { _Old = 0, @@ -340,83 +136,24 @@ public: return sensorRevision; } - const char* getIRVersionText() { - switch(sensorRevision) { - case SensorRevision::_Old: - return _T(MSG_IR_03_OR_OLDER); - case SensorRevision::_Rev04: - return _T(MSG_IR_04_OR_NEWER); - default: - return _T(MSG_IR_UNKNOWN); - } - } + const char* getIRVersionText(); - void setSensorRevision(SensorRevision rev, bool updateEEPROM = false) { - sensorRevision = rev; - if (updateEEPROM) { - eeprom_update_byte((uint8_t *)EEPROM_FSENSOR_PCB, (uint8_t)rev); - } - } + void setSensorRevision(SensorRevision rev, bool updateEEPROM = false); - uint16_t Voltage2Raw(float V) { - return (V * 1023 * OVERSAMPLENR / VOLT_DIV_REF ) + 0.5F; - } - float Raw2Voltage(uint16_t raw) { - return VOLT_DIV_REF * (raw / (1023.F * OVERSAMPLENR)); - } - - bool checkVoltage(uint16_t raw) { - if(IRsensor_Lmax_TRESHOLD <= raw && raw <= IRsensor_Hmin_TRESHOLD) { - /// If the voltage is in forbidden range, the fsensor is ok, but the lever is mounted improperly. - /// Or the user is so creative so that he can hold a piece of fillament in the hole in such a genius way, - /// that the IR fsensor reading is within 1.5 and 3V ... this would have been highly unusual - /// and would have been considered more like a sabotage than normal printer operation - if (voltageErrorCnt++ > 4) { - puts_P(PSTR("fsensor in forbidden range 1.5-3V - check sensor")); - return false; - } - } - else { - voltageErrorCnt = 0; - } - if(sensorRevision == SensorRevision::_Rev04) { - /// newer IR sensor cannot normally produce 4.6-5V, this is considered a failure/bad mount - if(IRsensor_Hopen_TRESHOLD <= raw && raw <= IRsensor_VMax_TRESHOLD) { - puts_P(PSTR("fsensor v0.4 in fault range 4.6-5V - unconnected")); - return false; - } - /// newer IR sensor cannot normally produce 0-0.3V, this is considered a failure - #if 0 //Disabled as it has to be decided if we gonna use this or not. - if(IRsensor_Hopen_TRESHOLD <= raw && raw <= IRsensor_VMax_TRESHOLD) { - puts_P(PSTR("fsensor v0.4 in fault range 0.0-0.3V - wrong IR sensor")); - return false; - } - #endif - } - /// If IR sensor is "uknown state" and filament is not loaded > 1.5V return false - #if 0 - #error "I really think this code can't be enabled anymore because we are constantly checking this voltage." - if((sensorRevision == SensorRevision::_Undef) && (raw > IRsensor_Lmax_TRESHOLD)) { - puts_P(PSTR("Unknown IR sensor version and no filament loaded detected.")); - return false; - } - #endif - // otherwise the IR fsensor is considered working correctly - return true; - } + bool checkVoltage(uint16_t raw); // Voltage2Raw is not constexpr :/ - const uint16_t IRsensor_Ldiode_TRESHOLD = Voltage2Raw(0.3f); // ~0.3V, raw value=982 - const uint16_t IRsensor_Lmax_TRESHOLD = Voltage2Raw(1.5f); // ~1.5V (0.3*Vcc), raw value=4910 - const uint16_t IRsensor_Hmin_TRESHOLD = Voltage2Raw(3.0f); // ~3.0V (0.6*Vcc), raw value=9821 - const uint16_t IRsensor_Hopen_TRESHOLD = Voltage2Raw(4.6f); // ~4.6V (N.C. @ Ru~20-50k, Rd'=56k, Ru'=10k), raw value=15059 - const uint16_t IRsensor_VMax_TRESHOLD = Voltage2Raw(5.f); // ~5V, raw value=16368 + constexpr static uint16_t IRsensor_Ldiode_TRESHOLD = Voltage2Raw(0.3F); // ~0.3V, raw value=982 + constexpr static uint16_t IRsensor_Lmax_TRESHOLD = Voltage2Raw(1.5F); // ~1.5V (0.3*Vcc), raw value=4910 + constexpr static uint16_t IRsensor_Hmin_TRESHOLD = Voltage2Raw(3.0F); // ~3.0V (0.6*Vcc), raw value=9821 + constexpr static uint16_t IRsensor_Hopen_TRESHOLD = Voltage2Raw(4.6F); // ~4.6V (N.C. @ Ru~20-50k, Rd'=56k, Ru'=10k), raw value=15059 + constexpr static uint16_t IRsensor_VMax_TRESHOLD = Voltage2Raw(5.F); // ~5V, raw value=16368 private: SensorRevision sensorRevision; volatile bool voltReady; //this gets set by the adc ISR volatile uint16_t voltRaw; - uint16_t minVolt = Voltage2Raw(6.f); + uint16_t minVolt = Voltage2Raw(6.F); uint16_t maxVolt = 0; uint16_t nFSCheckCount; uint8_t voltageErrorCnt; @@ -426,33 +163,7 @@ private: /// Called from 2 spots which have a very similar behavior /// 1: SensorRevision::_Old -> SensorRevision::_Rev04 and print _i("FS v0.4 or newer") /// 2: SensorRevision::_Rev04 -> sensorRevision=SensorRevision::_Old and print _i("FS v0.3 or older") - void IR_ANALOG_Check(SensorRevision isVersion, SensorRevision switchTo) { - bool bTemp = (!CHECK_ALL_HEATERS); - bTemp = bTemp && (menu_menu == lcd_status_screen); - bTemp = bTemp && ((sensorRevision == isVersion) || (sensorRevision == SensorRevision::_Undef)); - bTemp = bTemp && (state == State::ready); - if (bTemp) { - nFSCheckCount++; - if (nFSCheckCount > FS_CHECK_COUNT) { - nFSCheckCount = 0; // not necessary - setSensorRevision(switchTo, true); - printf_IRSensorAnalogBoardChange(); - switch (switchTo) { - case SensorRevision::_Old: - lcd_setstatuspgm(_T(MSG_FS_V_03_OR_OLDER)); ////MSG_FS_V_03_OR_OLDER c=18 - break; - case SensorRevision::_Rev04: - lcd_setstatuspgm(_T(MSG_FS_V_04_OR_NEWER)); ////MSG_FS_V_04_OR_NEWER c=18 - break; - default: - break; - } - } - } - else { - nFSCheckCount = 0; - } - } + void IR_ANALOG_Check(SensorRevision isVersion, SensorRevision switchTo); }; #endif //(FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG) #endif //(FILAMENT_SENSOR_TYPE == FSENSOR_IR) || (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG) @@ -460,86 +171,18 @@ private: #if (FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125) class PAT9125_sensor: public Filament_sensor { public: - void init() { - if (state == State::error) { - deinit(); //deinit first if there was an error. - } - puts_P(PSTR("fsensor::init()")); - - settings_init(); //also sets the state to State::initializing - - calcChunkSteps(cs.axis_steps_per_unit[E_AXIS]); //for jam detection - - if (!pat9125_init()) { - deinit(); - triggerError(); - ;// - } -#ifdef IR_SENSOR_PIN - else if (!READ(IR_SENSOR_PIN)) { - ;// MK3 fw on MK3S printer - } -#endif //IR_SENSOR_PIN - } - - void deinit() { - puts_P(PSTR("fsensor::deinit()")); - ;// - state = State::disabled; - filter = 0; - } - - bool update() { - switch (state) { - case State::initializing: - if (!updatePAT9125()) { - break; // still not stable. Stay in the initialization state. - } - oldFilamentPresent = getFilamentPresent(); //initialize the current filament state so that we don't create a switching event right after the sensor is ready. - oldPos = pat9125_y; - state = State::ready; - break; - case State::ready: { - updatePAT9125(); - postponedLoadEvent = false; - bool event = checkFilamentEvents(); - - ;// - - return event; - } break; - case State::disabled: - case State::error: - default: - return false; - } - return false; - } - - bool getFilamentPresent() { + void init()override; + void deinit()override; + bool update()override; + bool getFilamentPresent() override{ return filterFilPresent; } #ifdef FSENSOR_PROBING - bool probeOtherType() { - SET_INPUT(IR_SENSOR_PIN); //input mode - WRITE(IR_SENSOR_PIN, 1); //pullup - _delay_us(100); //wait for the pullup to pull the line high (might be needed, not really sure. The internal pullups are quite weak and there might be a long wire attached). - bool fsensorDetected = !READ(IR_SENSOR_PIN); - WRITE(IR_SENSOR_PIN, 0); //no pullup - return fsensorDetected; - } + bool probeOtherType() override; #endif - void setJamDetectionEnabled(bool state, bool updateEEPROM = false) { - jamDetection = state; - oldPos = pat9125_y; - resetStepCount(); - jamErrCnt = 0; - if (updateEEPROM) { - eeprom_update_byte((uint8_t *)EEPROM_FSENSOR_JAM_DETECTION, state); - } - } + void setJamDetectionEnabled(bool state, bool updateEEPROM = false); bool getJamDetectionEnabled() { return jamDetection; @@ -549,11 +192,7 @@ public: stepCount += rev ? -1 : 1; } - void settings_init() { - puts_P(PSTR("settings_init")); - Filament_sensor::settings_init(); - setJamDetectionEnabled(eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_JAM_DETECTION)); - } + void settings_init(); private: static constexpr uint16_t pollingPeriod = 10; //[ms] static constexpr uint8_t filterCnt = 5; //how many checks need to be done in order to determine the filament presence precisely. @@ -567,79 +206,17 @@ private: int16_t chunkSteps; uint8_t jamErrCnt; - void calcChunkSteps(float u) { + constexpr void calcChunkSteps(float u) { chunkSteps = (int16_t)(1.25 * u); //[mm] } - int16_t getStepCount() { - int16_t st_cnt; - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - st_cnt = stepCount; - } - return st_cnt; - } + int16_t getStepCount(); - void resetStepCount() { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - stepCount = 0; - } - } + void resetStepCount(); - void filJam() { - runoutEnabled = false; - autoLoadEnabled = false; - jamDetection = false; - stop_and_save_print_to_ram(0, 0); - restore_print_from_ram_and_continue(0); - eeprom_update_byte((uint8_t*)EEPROM_FERROR_COUNT, eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT) + 1); - eeprom_update_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT) + 1); - enquecommand_front_P((PSTR("M600"))); - } + void filJam(); - bool updatePAT9125() { - if (jamDetection) { - int16_t _stepCount = getStepCount(); - if (abs(_stepCount) >= chunkSteps) { //end of chunk. Check distance - resetStepCount(); - if (!pat9125_update()) { //get up to date data. reinit on error. - init(); //try to reinit. - } - bool fsDir = (pat9125_y - oldPos) > 0; - bool stDir = _stepCount > 0; - if (fsDir != stDir) { - jamErrCnt++; - } - else if (jamErrCnt) { - jamErrCnt--; - } - oldPos = pat9125_y; - } - if (jamErrCnt > 10) { - jamErrCnt = 0; - filJam(); - } - } - - if (!pollingTimer.running() || pollingTimer.expired(pollingPeriod)) { - pollingTimer.start(); - if (!pat9125_update()) { - init(); //try to reinit. - } - - bool present = (pat9125_s < 17) || (pat9125_s >= 17 && pat9125_b >= 50); - if (present != filterFilPresent) { - filter++; - } - else if (filter) { - filter--; - } - if (filter >= filterCnt) { - filter = 0; - filterFilPresent = present; - } - } - return (filter == 0); //return stability - } + bool updatePAT9125(); }; #endif //(FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125) diff --git a/Firmware/Tcodes.cpp b/Firmware/Tcodes.cpp index e61584f52..52141ddf9 100644 --- a/Firmware/Tcodes.cpp +++ b/Firmware/Tcodes.cpp @@ -45,7 +45,7 @@ void TCodes(char *const strchr_pointer, uint8_t codeValue) { if (IsInvalidTCode(strchr_pointer, index)){ TCodeInvalid(); - } else if (strchr_pointer[index] == 'x'){ + } /*else if (strchr_pointer[index] == 'x'){ // load to bondtech gears; if mmu is not present do nothing if (MMU2::mmu2.Enabled()) { MMU2::mmu2.tool_change(strchr_pointer[index], choose_menu_P(_T(MSG_CHOOSE_EXTRUDER), _T(MSG_EXTRUDER))); @@ -55,16 +55,16 @@ void TCodes(char *const strchr_pointer, uint8_t codeValue) { if (MMU2::mmu2.Enabled()) { MMU2::mmu2.tool_change(strchr_pointer[index], 0); } - } else { + }*/ else { SChooseFromMenu selectedSlot; - if (strchr_pointer[index] == '?') - selectedSlot = TCodeChooseFromMenu(); - else { +// if (strchr_pointer[index] == '?') +// selectedSlot = TCodeChooseFromMenu(); +// else { selectedSlot.slot = codeValue; - if (MMU2::mmu2.Enabled() && lcd_autoDepleteEnabled()) { - selectedSlot.slot = ad_getAlternative(selectedSlot.slot); - } - } +// if (MMU2::mmu2.Enabled() && lcd_autoDepleteEnabled()) { +// selectedSlot.slot = ad_getAlternative(selectedSlot.slot); +// } +// } st_synchronize(); if (MMU2::mmu2.Enabled()) { @@ -78,9 +78,10 @@ void TCodes(char *const strchr_pointer, uint8_t codeValue) { manage_response(true, true, MMU_UNLOAD_MOVE); } #endif // defined(MMU_HAS_CUTTER) && defined(MMU_ALWAYS_CUT) - MMU2::mmu2.tool_change(selectedSlot.slot); if (selectedSlot.loadToNozzle){ // for single material usage with mmu MMU2::mmu2.load_filament_to_nozzle(selectedSlot.slot); + } else { + MMU2::mmu2.tool_change(selectedSlot.slot); } } } else { diff --git a/Firmware/mmu2.cpp b/Firmware/mmu2.cpp index a2474e2a4..7f4ab5b05 100644 --- a/Firmware/mmu2.cpp +++ b/Firmware/mmu2.cpp @@ -59,8 +59,8 @@ static constexpr E_Step ramming_sequence[] PROGMEM = { }; static constexpr E_Step load_to_nozzle_sequence[] PROGMEM = { - { 36.0F, 810.0F / 60.F}, // feed rate = 13.5mm/s - Load fast until filament reach end of nozzle - { 30.0F, 198.0F / 60.F}, // feed rate = 3.3mm/s - Load slower once filament is out of the nozzle + { 10.0F, 810.0F / 60.F}, // feed rate = 13.5mm/s - Load fast until filament reach end of nozzle + { 25.0F, 198.0F / 60.F}, // feed rate = 3.3mm/s - Load slower once filament is out of the nozzle }; namespace MMU2 { @@ -663,14 +663,14 @@ void MMU2::OnMMUProgressMsg(ProgressCode pc){ // After the MMU knows the FSENSOR is triggered it will: // 1. Push the filament by additional 30mm (see fsensorToNozzle) // 2. Disengage the idler and push another 5mm. - current_position[E_AXIS] += 30.0f + 5.0f; + current_position[E_AXIS] += 30.0f + 2.0f; plan_buffer_line_curposXYZE(MMU2_LOAD_TO_NOZZLE_FEED_RATE); break; case FilamentState::NOT_PRESENT: // fsensor not triggered, continue moving extruder if(!blocks_queued()) { // Only plan a move if there is no move ongoing - current_position[E_AXIS] += 5.0f; + current_position[E_AXIS] += 2.0f; plan_buffer_line_curposXYZE(MMU2_LOAD_TO_NOZZLE_FEED_RATE); } break; diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 7f1c9f69e..f3e635678 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -6217,7 +6217,7 @@ static bool lcd_selftest_IRsensor(bool bStandalone) uint16_t volt_IR_int = fsensor.getVoltRaw(); newSensorRevision = (volt_IR_int < fsensor.IRsensor_Hopen_TRESHOLD) ? IR_sensor_analog::SensorRevision::_Rev04 : IR_sensor_analog::SensorRevision::_Old; - printf_P(PSTR("Measured filament sensor high level: %4.2fV\n"), fsensor.Raw2Voltage(volt_IR_int) ); + printf_P(PSTR("Measured filament sensor high level: %4.2fV\n"), Raw2Voltage(volt_IR_int) ); if(volt_IR_int < fsensor.IRsensor_Hmin_TRESHOLD){ if(!bStandalone) lcd_selftest_error(TestError::FsensorLevel,"HIGH",""); @@ -6225,7 +6225,7 @@ static bool lcd_selftest_IRsensor(bool bStandalone) } lcd_show_fullscreen_message_and_wait_P(_i("Insert the filament (do not load it) into the extruder and then press the knob."));////MSG_INSERT_FIL c=20 r=6 volt_IR_int = fsensor.getVoltRaw(); - printf_P(PSTR("Measured filament sensor low level: %4.2fV\n"), fsensor.Raw2Voltage(volt_IR_int)); + printf_P(PSTR("Measured filament sensor low level: %4.2fV\n"), Raw2Voltage(volt_IR_int)); if(volt_IR_int > (fsensor.IRsensor_Lmax_TRESHOLD)){ if(!bStandalone) lcd_selftest_error(TestError::FsensorLevel,"LOW","");