diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 31fe24bf32..d146ddc7d0 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -9679,27 +9679,83 @@ static void handleSafetyTimer() #endif //SAFETYTIMER #ifdef IR_SENSOR_ANALOG -#define FS_CHECK_COUNT 16 -/// Switching mechanism of the fsensor type. -/// Called from 2 spots which have a very similar behavior -/// 1: ClFsensorPCB::_Old -> ClFsensorPCB::_Rev04 and print _i("FS v0.4 or newer") -/// 2: ClFsensorPCB::_Rev04 -> oFsensorPCB=ClFsensorPCB::_Old and print _i("FS v0.3 or older") -void manage_inactivity_IR_ANALOG_Check(uint16_t &nFSCheckCount, ClFsensorPCB isVersion, ClFsensorPCB switchTo, const char *statusLineTxt_P) { - bool bTemp = (!CHECK_ALL_HEATERS); - bTemp = bTemp && (menu_menu == lcd_status_screen); - bTemp = bTemp && ((oFsensorPCB == isVersion) || (oFsensorPCB == ClFsensorPCB::_Undef)); - bTemp = bTemp && fsensor_enabled; - if (bTemp) { - nFSCheckCount++; - if (nFSCheckCount > FS_CHECK_COUNT) { - nFSCheckCount = 0; // not necessary - oFsensorPCB = switchTo; +void manage_inactivity_IR_ANALOG_CheckPCB() +{ + static uint16_t minVolt = Voltage2Raw(6.F), maxVolt = 0; + static ClFsensorPCB nFsensorPCB = oFsensorPCB; + static uint16_t nFSCheckCount = FS_CHECK_COUNT; + + // only attempt detection when cold and idling in the status screen + if (!fsensor_enabled || CHECK_ALL_HEATERS || menu_menu != lcd_status_screen) + return; + + // detect min-max, some long term sliding window for filtration may be added + // avoiding floating point operations, thus computing in raw + if( current_voltage_raw_IR > maxVolt )maxVolt = current_voltage_raw_IR; + if( current_voltage_raw_IR < minVolt )minVolt = current_voltage_raw_IR; + +#if 0 // Start: IR Sensor debug info + { // debug print + static uint16_t lastVolt = ~0U; + if( current_voltage_raw_IR != lastVolt ){ + printf_P(PSTR("fs volt=%4.2fV (min=%4.2f max=%4.2f)\n"), Raw2Voltage(current_voltage_raw_IR), Raw2Voltage(minVolt), Raw2Voltage(maxVolt) ); + lastVolt = current_voltage_raw_IR; + } + } +#endif // End: IR Sensor debug info + + //! 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 + ClFsensorPCB tempFsensorPCB; + const char *statusLineTxt_P; + + //! 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 + ){ + tempFsensorPCB = ClFsensorPCB::_Rev04; + statusLineTxt_P = _i("FS v0.4 or newer"); ////MSG_FS_V_04_OR_NEWER c=18 + } + //! 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 + ){ + tempFsensorPCB = ClFsensorPCB::_Old; + statusLineTxt_P = _i("FS v0.3 or older"); ////MSG_FS_V_03_OR_OLDER c=18 + } + //! Ambiguous range + else + { + tempFsensorPCB = ClFsensorPCB::_Undef; + } + + if (tempFsensorPCB != ClFsensorPCB::_Undef) + { + --oFSCheckCount; + + if (tempFsensorPCB != nFsensorPCB) + { + // latest detection changed, reset internal counters + nFsensorPCB = tempFsensorPCB; + nFSCheckCount = FS_CHECK_COUNT; + } + else if(!--nFSCheckCount) + { + // consistent PCB match, set detected sensor type and stop attempts + oFSCheckCount = 0; + oFsensorPCB = tempFsensorPCB; eeprom_update_byte((uint8_t *)EEPROM_FSENSOR_PCB, (uint8_t)oFsensorPCB); printf_IRSensorAnalogBoardChange(); lcd_setstatuspgm(statusLineTxt_P); } - } else { - nFSCheckCount = 0; } } #endif @@ -9707,14 +9763,10 @@ void manage_inactivity_IR_ANALOG_Check(uint16_t &nFSCheckCount, ClFsensorPCB isV void manage_inactivity(bool ignore_stepper_queue/*=false*/) //default argument set in Marlin.h { #ifdef FILAMENT_SENSOR -bool bInhibitFlag = false; -#ifdef IR_SENSOR_ANALOG -static uint16_t nFSCheckCount=0; -#endif // IR_SENSOR_ANALOG + bool bInhibitFlag = false; if (mmu_enabled == false) { -//-// if (mcode_in_progress != 600) //M600 not in progress if (!PRINTER_ACTIVE) bInhibitFlag=(menu_menu==lcd_menu_show_sensors_state); //Block Filament sensor actions if PRINTER is not active and Support::SensorInfo menu active #ifdef IR_SENSOR_ANALOG bInhibitFlag=bInhibitFlag||bMenuFSDetect; // Block Filament sensor actions if Settings::HWsetup::FSdetect menu active @@ -9723,80 +9775,33 @@ static uint16_t nFSCheckCount=0; { if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LcdCommands::Layer1Cal) && ! eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE)) { + // idling: housekeeping and autoload checks #ifdef IR_SENSOR_ANALOG - static uint16_t minVolt = Voltage2Raw(6.F), maxVolt = 0; - // detect min-max, some long term sliding window for filtration may be added - // avoiding floating point operations, thus computing in raw - if( current_voltage_raw_IR > maxVolt )maxVolt = current_voltage_raw_IR; - if( current_voltage_raw_IR < minVolt )minVolt = current_voltage_raw_IR; - -#if 0 // Start: IR Sensor debug info - { // debug print - static uint16_t lastVolt = ~0U; - if( current_voltage_raw_IR != lastVolt ){ - printf_P(PSTR("fs volt=%4.2fV (min=%4.2f max=%4.2f)\n"), Raw2Voltage(current_voltage_raw_IR), Raw2Voltage(minVolt), Raw2Voltage(maxVolt) ); - lastVolt = current_voltage_raw_IR; - } - } -#endif // End: IR Sensor debug info - //! 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 - ){ - manage_inactivity_IR_ANALOG_Check(nFSCheckCount, ClFsensorPCB::_Old, ClFsensorPCB::_Rev04, _i("FS v0.4 or newer") ); ////MSG_FS_V_04_OR_NEWER c=18 - } - //! 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 - ){ - manage_inactivity_IR_ANALOG_Check(nFSCheckCount, ClFsensorPCB::_Rev04, oFsensorPCB=ClFsensorPCB::_Old, _i("FS v0.3 or older")); ////MSG_FS_V_03_OR_OLDER c=18 - } + if (oFSCheckCount) + { + // Attempt to detect an upgrade of the filament sensor PCB + manage_inactivity_IR_ANALOG_CheckPCB(); + } #endif // IR_SENSOR_ANALOG if (fsensor_check_autoload()) { #ifdef PAT9125 fsensor_autoload_check_stop(); #endif //PAT9125 -//-// if (degHotend0() > EXTRUDE_MINTEMP) -if(0) - { - Sound_MakeCustom(50,1000,false); - loading_flag = true; - enquecommand_front_P((PSTR("M701"))); - } - else - { -/* - lcd_update_enable(false); - show_preheat_nozzle_warning(); - lcd_update_enable(true); -*/ - eFilamentAction=FilamentAction::AutoLoad; - bFilamentFirstRun=false; - if(target_temperature[0]>=EXTRUDE_MINTEMP){ - bFilamentPreheatState=true; -// mFilamentItem(target_temperature[0],target_temperature_bed); - menu_submenu(mFilamentItemForce); - } else { - menu_submenu(lcd_generic_preheat_menu); - lcd_timeoutToStatus.start(); - } - } + eFilamentAction=FilamentAction::AutoLoad; + bFilamentFirstRun=false; + if(target_temperature[0]>=EXTRUDE_MINTEMP){ + bFilamentPreheatState=true; + menu_submenu(mFilamentItemForce); + } else { + menu_submenu(lcd_generic_preheat_menu); + lcd_timeoutToStatus.start(); + } } } else { + // printing: runout detection #ifdef PAT9125 fsensor_autoload_check_stop(); #endif //PAT9125 diff --git a/Firmware/fsensor.cpp b/Firmware/fsensor.cpp index 4eac7bd08d..ec231c6543 100755 --- a/Firmware/fsensor.cpp +++ b/Firmware/fsensor.cpp @@ -123,6 +123,7 @@ uint16_t fsensor_oq_sh_sum; #ifdef IR_SENSOR_ANALOG ClFsensorPCB oFsensorPCB; ClFsensorActionNA oFsensorActionNA; +uint16_t oFSCheckCount = FS_CHECK_COUNT * 3; bool bIRsensorStateFlag=false; unsigned long nIRsensorLastTime; #endif //IR_SENSOR_ANALOG @@ -208,6 +209,10 @@ void fsensor_init(void) oFsensorPCB = (ClFsensorPCB)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_PCB); oFsensorActionNA = (ClFsensorActionNA)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_ACTION_NA); + // disable checking for PCB updates if already at the newest version + if(oFsensorPCB == ClFsensorPCB::_Newest) + oFSCheckCount = 0; + // If the fsensor is not responding even at the start of the printer, // set this flag accordingly to show N/A in Settings->Filament sensor. // This is even valid for both fsensor board revisions (0.3 or older and 0.4). diff --git a/Firmware/fsensor.h b/Firmware/fsensor.h index 7eb09ab8b5..8df75fea08 100755 --- a/Firmware/fsensor.h +++ b/Firmware/fsensor.h @@ -83,15 +83,18 @@ extern uint8_t fsensor_log; //! @} #endif //PAT9125 -#define VOLT_DIV_REF 5 - #ifdef IR_SENSOR_ANALOG #define IR_SENSOR_STEADY 10 // [ms] +// number of required consistent consecutive filament sensor check attempts +#define FS_CHECK_COUNT 16 +// number of remaining filament sensor checks to be done +extern uint16_t oFSCheckCount; + enum class ClFsensorPCB:uint_least8_t { _Old=0, - _Rev04=1, + _Rev04=1, _Newest=1, _Undef=EEPROM_EMPTY_VALUE }; @@ -107,12 +110,8 @@ extern ClFsensorActionNA oFsensorActionNA; extern const char* FsensorIRVersionText(); extern bool fsensor_IR_check(); -constexpr uint16_t Voltage2Raw(float V){ - return ( V * 1023 * OVERSAMPLENR / VOLT_DIV_REF ) + 0.5F; -} -constexpr float Raw2Voltage(uint16_t raw){ - return VOLT_DIV_REF*(raw / (1023.F * OVERSAMPLENR) ); -} + +#include "temperature.h" constexpr uint16_t IRsensor_Ldiode_TRESHOLD = Voltage2Raw(0.3F); // ~0.3V, raw value=982 constexpr uint16_t IRsensor_Lmax_TRESHOLD = Voltage2Raw(1.5F); // ~1.5V (0.3*Vcc), raw value=4910 constexpr uint16_t IRsensor_Hmin_TRESHOLD = Voltage2Raw(3.0F); // ~3.0V (0.6*Vcc), raw value=9821 diff --git a/Firmware/temperature.h b/Firmware/temperature.h index 0bf9447244..9e805b4ea3 100755 --- a/Firmware/temperature.h +++ b/Firmware/temperature.h @@ -42,6 +42,15 @@ #endif //SYSTEM_TIMER_2 +// voltage conversion functions +#define VOLT_DIV_REF 5 + +constexpr uint16_t Voltage2Raw(float V){ + return ( V * 1023 * OVERSAMPLENR / VOLT_DIV_REF ) + 0.5F; +} +constexpr float Raw2Voltage(uint16_t raw){ + return VOLT_DIV_REF*(raw / (1023.F * OVERSAMPLENR) ); +} // public functions void tp_init(); //initialize the heating diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 02b9d30807..60ca57a36e 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -7301,7 +7301,7 @@ void lcd_belttest() #ifdef IR_SENSOR_ANALOG // called also from marlin_main.cpp void printf_IRSensorAnalogBoardChange(){ - printf_P(PSTR("Filament sensor board change detected: revision%S\n"), FsensorIRVersionText()); + printf_P(PSTR("Filament sensor board change detected: revision %S\n"), FsensorIRVersionText()); } static bool lcd_selftest_IRsensor(bool bStandalone) @@ -7327,6 +7327,7 @@ static bool lcd_selftest_IRsensor(bool bStandalone) } if((bPCBrev04 ? 1 : 0) != (uint8_t)oFsensorPCB){ // safer then "(uint8_t)bPCBrev04" oFsensorPCB=bPCBrev04 ? ClFsensorPCB::_Rev04 : ClFsensorPCB::_Old; + oFSCheckCount = 0; printf_IRSensorAnalogBoardChange(); eeprom_update_byte((uint8_t*)EEPROM_FSENSOR_PCB,(uint8_t)oFsensorPCB); }