diff --git a/workspace/TS100/Core/Inc/Settings.h b/workspace/TS100/Core/Inc/Settings.h index 5e883651..dfaeb501 100644 --- a/workspace/TS100/Core/Inc/Settings.h +++ b/workspace/TS100/Core/Inc/Settings.h @@ -11,7 +11,7 @@ #define SETTINGS_H_ #include #include "stm32f1xx_hal.h" -#define SETTINGSVERSION ( 0x19 ) +#define SETTINGSVERSION ( 0x1A ) /*Change this if you change the struct below to prevent people getting \ out of sync*/ @@ -39,7 +39,7 @@ typedef struct { uint8_t descriptionScrollSpeed :1; // Description scroll speed uint16_t voltageDiv; // Voltage divisor factor uint16_t BoostTemp; // Boost mode set point for the iron - int16_t CalibrationOffset; // This stores the temperature offset for this tip + uint16_t CalibrationOffset; // This stores the temperature offset for this tip // in the iron. uint8_t PID_P; // PID P Term uint8_t PID_I; // PID I Term @@ -47,7 +47,6 @@ typedef struct { uint8_t version; // Used to track if a reset is needed on firmware upgrade uint8_t customTipGain; // Tip gain value if custom tuned, or 0 if using a // tipType param - uint8_t tipType; #ifdef MODEL_TS80 uint8_t pidPowerLimit; #endif diff --git a/workspace/TS100/Core/Inc/main.hpp b/workspace/TS100/Core/Inc/main.hpp index 2474fe60..78b6cc70 100644 --- a/workspace/TS100/Core/Inc/main.hpp +++ b/workspace/TS100/Core/Inc/main.hpp @@ -5,7 +5,7 @@ #include "OLED.hpp" #include "Setup.h" extern uint8_t PCBVersion; -extern uint32_t currentlyActiveTemperatureTarget; +extern uint32_t currentTempTargetDegC; enum ButtonState { BUTTON_NONE = 0, /* No buttons pressed / < filter time*/ BUTTON_F_SHORT = 1, /* User has pressed the front button*/ diff --git a/workspace/TS100/Core/Inc/power.hpp b/workspace/TS100/Core/Inc/power.hpp index 1850cd14..10e327f2 100644 --- a/workspace/TS100/Core/Inc/power.hpp +++ b/workspace/TS100/Core/Inc/power.hpp @@ -30,7 +30,7 @@ const uint8_t tipResistance = 45; //x10 ohms, 8.5 typical for ts100, 4.5 typical const uint8_t oscillationPeriod = 6 * PID_TIM_HZ; // I term look back value extern history milliWattHistory; -int32_t tempToMilliWatts(int32_t rawTemp, uint8_t rawC); +int32_t tempToMilliWatts(int32_t rawTemp); void setTipMilliWatts(int32_t mw); uint8_t milliWattsToPWM(int32_t milliWatts, uint8_t divisor, uint8_t sample = 0); diff --git a/workspace/TS100/Core/Src/GUIThread.cpp b/workspace/TS100/Core/Src/GUIThread.cpp index 2cee6943..51a24cc1 100644 --- a/workspace/TS100/Core/Src/GUIThread.cpp +++ b/workspace/TS100/Core/Src/GUIThread.cpp @@ -19,7 +19,7 @@ #include "TipThermoModel.h" extern uint8_t PCBVersion; // File local variables -extern uint32_t currentlyActiveTemperatureTarget; +extern uint32_t currentTempTargetDegC; extern uint32_t lastMovementTime; extern int16_t idealQCVoltage; uint32_t lastButtonTime = 0; @@ -57,9 +57,9 @@ void gui_drawTipTemp(bool symbol) { uint16_t Temp = getTipRawTemp(0); if (systemSettings.temperatureInF) - Temp = tipMeasurementToF(Temp); + Temp = TipThermoModel::convertTipRawADCToDegF(Temp); else - Temp = tipMeasurementToC(Temp); + Temp = TipThermoModel::convertTipRawADCToDegC(Temp); OLED::printNumber(Temp, 3); // Draw the tip temp out finally if (symbol) { @@ -201,7 +201,7 @@ static bool checkVoltageForExit() { } OLED::refresh(); - currentlyActiveTemperatureTarget = 0; + currentTempTargetDegC = 0; waitForButtonPress(); return true; } @@ -216,17 +216,17 @@ static void gui_drawBatteryIcon() { // we need to calculate which of the 10 levels they are on uint8_t cellCount = systemSettings.cutoutSetting + 2; uint32_t cellV = getInputVoltageX10(systemSettings.voltageDiv, 0) - / cellCount; + / cellCount; // Should give us approx cell voltage X10 // Range is 42 -> 33 = 9 steps therefore we will use battery 1-10 if (cellV < 33) - cellV = 33; - cellV -= 33;// Should leave us a number of 0-9 + cellV = 33; + cellV -= 33; // Should leave us a number of 0-9 if (cellV > 9) - cellV = 9; + cellV = 9; OLED::drawBattery(cellV + 1); } else - OLED::drawSymbol(15); // Draw the DC Logo + OLED::drawSymbol(15); // Draw the DC Logo #else // On TS80 we replace this symbol with the voltage we are operating on // If <9V then show single digit, if not show duals @@ -250,7 +250,7 @@ static void gui_drawBatteryIcon() { } static void gui_solderingTempAdjust() { uint32_t lastChange = xTaskGetTickCount(); - currentlyActiveTemperatureTarget = 0; + currentTempTargetDegC = 0; uint32_t autoRepeatTimer = 0; uint8_t autoRepeatAcceleration = 0; for (;;) { @@ -317,7 +317,7 @@ static void gui_solderingTempAdjust() { #ifdef MODEL_TS80 if (!OLED::getRotation()) #else - if (OLED::getRotation()) + if (OLED::getRotation()) #endif OLED::print(SymbolMinus); else @@ -333,7 +333,7 @@ static void gui_solderingTempAdjust() { #ifdef MODEL_TS80 if (!OLED::getRotation()) #else - if (OLED::getRotation()) + if (OLED::getRotation()) #endif OLED::print(SymbolPlus); else @@ -354,24 +354,23 @@ static int gui_SolderingSleepingMode() { || (xTaskGetTickCount() - lastButtonTime < 100)) return 0; // user moved or pressed a button, go back to soldering #ifdef MODEL_TS100 - if (checkVoltageForExit()) + if (checkVoltageForExit()) return 1; // return non-zero on error #endif if (systemSettings.temperatureInF) { - currentlyActiveTemperatureTarget = ftoTipMeasurement( + currentTempTargetDegC = TipThermoModel::convertFtoC( min(systemSettings.SleepTemp, systemSettings.SolderingTemp)); } else { - currentlyActiveTemperatureTarget = ctoTipMeasurement( - min(systemSettings.SleepTemp, - systemSettings.SolderingTemp)); + currentTempTargetDegC = (min(systemSettings.SleepTemp, + systemSettings.SolderingTemp)); } // draw the lcd uint16_t tipTemp; if (systemSettings.temperatureInF) - tipTemp = tipMeasurementToF(getTipRawTemp(0)); + tipTemp = TipThermoModel::convertTipRawADCToDegF(getTipRawTemp(0)); else - tipTemp = tipMeasurementToC(getTipRawTemp(0)); + tipTemp = TipThermoModel::convertTipRawADCToDegC(getTipRawTemp(0)); OLED::clearScreen(); OLED::setCursor(0, 0); @@ -403,7 +402,7 @@ static int gui_SolderingSleepingMode() { if (((uint32_t) (xTaskGetTickCount() - lastMovementTime)) > (uint32_t) (systemSettings.ShutdownTime * 60 * 100)) { // shutdown - currentlyActiveTemperatureTarget = 0; + currentTempTargetDegC = 0; return 1; // we want to exit soldering mode } OLED::refresh(); @@ -561,9 +560,9 @@ static void gui_solderingMode(uint8_t jumpToSleep) { if (badTipCounter > 128) { OLED::print(BadTipString); OLED::refresh(); - currentlyActiveTemperatureTarget = 0; + currentTempTargetDegC = 0; waitForButtonPress(); - currentlyActiveTemperatureTarget = 0; + currentTempTargetDegC = 0; return; } OLED::refresh(); @@ -571,19 +570,17 @@ static void gui_solderingMode(uint8_t jumpToSleep) { // Update the setpoints for the temperature if (boostModeOn) { if (systemSettings.temperatureInF) - currentlyActiveTemperatureTarget = ftoTipMeasurement( + currentTempTargetDegC = TipThermoModel::convertFtoC( systemSettings.BoostTemp); else - currentlyActiveTemperatureTarget = ctoTipMeasurement( - systemSettings.BoostTemp); + currentTempTargetDegC = (systemSettings.BoostTemp); } else { if (systemSettings.temperatureInF) - currentlyActiveTemperatureTarget = ftoTipMeasurement( + currentTempTargetDegC = TipThermoModel::convertFtoC( systemSettings.SolderingTemp); else - currentlyActiveTemperatureTarget = ctoTipMeasurement( - systemSettings.SolderingTemp); + currentTempTargetDegC = (systemSettings.SolderingTemp); } #ifdef MODEL_TS100 @@ -648,11 +645,13 @@ void showDebugMenu(void) { break; case 6: //Raw Tip - OLED::printNumber(TipThermoModel::convertTipRawADCToDegC(getTipRawTemp(0)), 6); + OLED::printNumber(TipThermoModel::convertTipRawADCTouV(getTipRawTemp(0)), 6); break; case 7: //Temp in C - OLED::printNumber(tipMeasurementToC(getTipRawTemp(0)), 5); + OLED::printNumber( + TipThermoModel::convertTipRawADCToDegC(getTipRawTemp(0)), + 5); break; case 8: //Handle Temp @@ -756,15 +755,14 @@ void startGUITask(void const *argument __unused) { enterSettingsMenu(); // enter the settings menu saveSettings(); buttonLockout = true; - setCalibrationOffset(systemSettings.CalibrationOffset); // ensure cal offset is applied break; default: break; } - currentlyActiveTemperatureTarget = 0; // ensure tip is off + currentTempTargetDegC = 0; // ensure tip is off getInputVoltageX10(systemSettings.voltageDiv, 0); - uint16_t tipTemp = tipMeasurementToC(getTipRawTemp(0)); + uint16_t tipTemp = TipThermoModel::convertTipRawADCToDegC(getTipRawTemp(0)); // Preemptively turn the display on. Turn it off if and only if // the tip temperature is below 50 degrees C *and* motion sleep @@ -772,9 +770,11 @@ void startGUITask(void const *argument __unused) { // button presses) in a while. OLED::setDisplayState(OLED::DisplayState::ON); - if ((tipTemp < 50) && systemSettings.sensitivity && - (((xTaskGetTickCount() - lastMovementTime) > MOVEMENT_INACTIVITY_TIME) && - ((xTaskGetTickCount() - lastButtonTime) > BUTTON_INACTIVITY_TIME))) { + if ((tipTemp < 50) && systemSettings.sensitivity + && (((xTaskGetTickCount() - lastMovementTime) + > MOVEMENT_INACTIVITY_TIME) + && ((xTaskGetTickCount() - lastButtonTime) + > BUTTON_INACTIVITY_TIME))) { OLED::setDisplayState(OLED::DisplayState::OFF); } @@ -801,7 +801,7 @@ void startGUITask(void const *argument __unused) { #ifdef MODEL_TS80 if (!OLED::getRotation()) { #else - if (OLED::getRotation()) { + if (OLED::getRotation()) { #endif OLED::drawArea(12, 0, 84, 16, idleScreenBG); OLED::setCursor(0, 0); @@ -822,7 +822,7 @@ void startGUITask(void const *argument __unused) { #ifdef MODEL_TS80 if (!OLED::getRotation()) { #else - if (OLED::getRotation()) { + if (OLED::getRotation()) { #endif // in right handed mode we want to draw over the first part OLED::fillArea(55, 0, 41, 16, 0); // clear the area for the temp diff --git a/workspace/TS100/Core/Src/Settings.cpp b/workspace/TS100/Core/Src/Settings.cpp index bd355b47..3e3a5db5 100644 --- a/workspace/TS100/Core/Src/Settings.cpp +++ b/workspace/TS100/Core/Src/Settings.cpp @@ -97,7 +97,7 @@ void resetSettings() { systemSettings.ShutdownTime = 10; // How many minutes until the unit turns itself off systemSettings.boostModeEnabled = - 1; // Default to having boost mode on as most people prefer itF + 1; // Default to having boost mode on as most people prefer it systemSettings.BoostTemp = 420; // default to 400C systemSettings.autoStartMode = 0; // Auto start off for safety systemSettings.coolingTempBlink = @@ -107,15 +107,15 @@ void resetSettings() { systemSettings.PID_P = 42; // PID tuning constants systemSettings.PID_I = 50; systemSettings.PID_D = 15; - systemSettings.CalibrationOffset = 1400; // the adc offset - systemSettings.customTipGain = - 0; // The tip type is either default or a custom gain + #ifdef MODEL_TS100 - systemSettings.tipType = TS_B2; // Default to the B2 Tip + + systemSettings.CalibrationOffset = 700; // the adc offset in uV + #endif #ifdef MODEL_TS80 systemSettings.pidPowerLimit=24; // Sets the max pwm power limit - systemSettings.tipType = TS_B02; // Default to the B2 Tip + systemSettings.CalibrationOffset = 700; // the adc offset in uV #endif saveSettings(); // Save defaults } diff --git a/workspace/TS100/Core/Src/TipThermoModel.cpp b/workspace/TS100/Core/Src/TipThermoModel.cpp index bb18602c..af3dcd06 100644 --- a/workspace/TS100/Core/Src/TipThermoModel.cpp +++ b/workspace/TS100/Core/Src/TipThermoModel.cpp @@ -6,6 +6,7 @@ */ #include "TipThermoModel.h" +#include "Settings.h" /* * The hardware is laid out as a non-inverting op-amp @@ -48,6 +49,10 @@ uint32_t TipThermoModel::convertTipRawADCTouV(uint16_t rawADC) { //Now to divide this down by the gain valueuV = (valueuV) / op_amp_gain_stage; //Remove uV tipOffset + if (valueuV > systemSettings.CalibrationOffset) + valueuV -= systemSettings.CalibrationOffset; + else + valueuV = 0; //TODO return valueuV; } @@ -55,6 +60,9 @@ uint32_t TipThermoModel::convertTipRawADCTouV(uint16_t rawADC) { uint32_t TipThermoModel::convertTipRawADCToDegC(uint16_t rawADC) { return convertuVToDegC(convertTipRawADCTouV(rawADC)); } +uint32_t TipThermoModel::convertTipRawADCToDegF(uint16_t rawADC) { + return convertuVToDegF(convertTipRawADCTouV(rawADC)); +} //Table that is designed to be walked to find the best sample for the lookup @@ -66,110 +74,112 @@ struct HakkoThermocoupleLookup { values() { values[0][0] = 0; values[0][1] = 0; - values[1][0] = 175; - values[1][1] = 100; - values[2][0] = 381; - values[2][1] = 200; - values[3][0] = 587; - values[3][1] = 300; - values[4][0] = 804; - values[4][1] = 400; - values[5][0] = 1005; - values[5][1] = 500; - values[6][0] = 1007; - values[6][1] = 600; - values[7][0] = 1107; - values[7][1] = 700; - values[8][0] = 1310; - values[8][1] = 800; - values[9][0] = 1522; - values[9][1] = 900; - values[10][0] = 1731; - values[10][1] = 1000; - values[11][0] = 1939; - values[11][1] = 1100; - values[12][0] = 2079; - values[12][1] = 1200; - values[13][0] = 2265; - values[13][1] = 1300; - values[14][0] = 2470; - values[14][1] = 1400; - values[15][0] = 2676; - values[15][1] = 1500; - values[16][0] = 2899; - values[16][1] = 1600; - values[17][0] = 3081; - values[17][1] = 1700; - values[18][0] = 3186; - values[18][1] = 1800; - values[19][0] = 3422; - values[19][1] = 1900; - values[20][0] = 3622; - values[20][1] = 2000; - values[21][0] = 3830; - values[21][1] = 2100; - values[22][0] = 4044; - values[22][1] = 2200; - values[23][0] = 4400; - values[23][1] = 2300; - values[24][0] = 4691; - values[24][1] = 2400; - values[25][0] = 4989; - values[25][1] = 2500; - values[26][0] = 5289; - values[26][1] = 2600; - values[27][0] = 5583; - values[27][1] = 2700; - values[28][0] = 5879; - values[28][1] = 2800; - values[29][0] = 6075; - values[29][1] = 2900; - values[30][0] = 6332; - values[30][1] = 3000; - values[31][0] = 6521; - values[31][1] = 3100; - values[32][0] = 6724; - values[32][1] = 3200; - values[33][0] = 6929; - values[33][1] = 3300; - values[34][0] = 7132; - values[34][1] = 3400; - values[35][0] = 7356; - values[35][1] = 3500; - values[36][0] = 7561; - values[36][1] = 3600; - values[37][0] = 7774; - values[37][1] = 3700; - values[38][0] = 7992; - values[38][1] = 3800; - values[39][0] = 8200; - values[39][1] = 3900; - values[40][0] = 8410; - values[40][1] = 4000; - values[41][0] = 8626; - values[41][1] = 4100; - values[42][0] = 8849; - values[42][1] = 4200; - values[43][0] = 9060; - values[43][1] = 4300; - values[44][0] = 9271; - values[44][1] = 4400; - values[45][0] = 9531; - values[45][1] = 4500; - values[46][0] = 9748; - values[46][1] = 4600; - values[47][0] = 10210; - values[47][1] = 4700; - values[48][0] = 10219; - values[48][1] = 4800; - values[49][0] = 10429; - values[49][1] = 4900; - values[50][0] = 10649; - values[50][1] = 5000; + values[1][0] = 0; + values[1][1] = 0; + values[2][0] = 175; + values[2][1] = 100; + values[3][0] = 381; + values[3][1] = 200; + values[4][0] = 587; + values[4][1] = 300; + values[5][0] = 804; + values[5][1] = 400; + values[6][0] = 1005; + values[6][1] = 500; + values[7][0] = 1007; + values[7][1] = 600; + values[8][0] = 1107; + values[8][1] = 700; + values[9][0] = 1310; + values[9][1] = 800; + values[10][0] = 1522; + values[10][1] = 900; + values[11][0] = 1731; + values[11][1] = 1000; + values[12][0] = 1939; + values[12][1] = 1100; + values[13][0] = 2079; + values[13][1] = 1200; + values[14][0] = 2265; + values[14][1] = 1300; + values[15][0] = 2470; + values[15][1] = 1400; + values[16][0] = 2676; + values[16][1] = 1500; + values[17][0] = 2899; + values[17][1] = 1600; + values[18][0] = 3081; + values[18][1] = 1700; + values[19][0] = 3186; + values[19][1] = 1800; + values[20][0] = 3422; + values[20][1] = 1900; + values[21][0] = 3622; + values[21][1] = 2000; + values[22][0] = 3830; + values[22][1] = 2100; + values[23][0] = 4044; + values[23][1] = 2200; + values[24][0] = 4400; + values[24][1] = 2300; + values[25][0] = 4691; + values[25][1] = 2400; + values[26][0] = 4989; + values[26][1] = 2500; + values[27][0] = 5289; + values[27][1] = 2600; + values[28][0] = 5583; + values[28][1] = 2700; + values[29][0] = 5879; + values[29][1] = 2800; + values[30][0] = 6075; + values[30][1] = 2900; + values[31][0] = 6332; + values[31][1] = 3000; + values[32][0] = 6521; + values[32][1] = 3100; + values[33][0] = 6724; + values[33][1] = 3200; + values[34][0] = 6929; + values[34][1] = 3300; + values[35][0] = 7132; + values[35][1] = 3400; + values[36][0] = 7356; + values[36][1] = 3500; + values[37][0] = 7561; + values[37][1] = 3600; + values[38][0] = 7774; + values[38][1] = 3700; + values[39][0] = 7992; + values[39][1] = 3800; + values[40][0] = 8200; + values[40][1] = 3900; + values[41][0] = 8410; + values[41][1] = 4000; + values[42][0] = 8626; + values[42][1] = 4100; + values[43][0] = 8849; + values[43][1] = 4200; + values[44][0] = 9060; + values[44][1] = 4300; + values[45][0] = 9271; + values[45][1] = 4400; + values[46][0] = 9531; + values[46][1] = 4500; + values[47][0] = 9748; + values[47][1] = 4600; + values[48][0] = 10210; + values[48][1] = 4700; + values[49][0] = 10219; + values[49][1] = 4800; + values[50][0] = 10429; + values[50][1] = 4900; + values[51][0] = 10649; + values[51][1] = 5000; } - uint32_t count = 51; - uint32_t values[51][2]; + uint32_t count = 52; + uint32_t values[52][2]; }; constexpr auto ThermalTable = HakkoThermocoupleLookup(); @@ -189,7 +199,7 @@ uint32_t TipThermoModel::convertuVToDegC(uint32_t tipuVDelta) { //This assumes results in the table are increasing order // TODO -> Should this be made into a binary search? Is it much faster?? for (uint32_t i = 1; i < ThermalTable.count; i++) { - if (((uint32_t) ThermalTable.values[i][0]) < tipuVDelta) { + if (((uint32_t) ThermalTable.values[i][0]) > tipuVDelta) { //Then extrapolate //Where i= the lower raw sample, i-1 is the higher raw sample return LinearInterpolate( // @@ -197,9 +207,41 @@ uint32_t TipThermoModel::convertuVToDegC(uint32_t tipuVDelta) { ThermalTable.values[i][1], // y1 ThermalTable.values[i - 1][0], // x2 ThermalTable.values[i - 1][1], // y2 - tipuVDelta); // raw sample to be interpolated + tipuVDelta) / 10; // raw sample to be interpolated } } - return 5000; + return 500; // fail high -> will turn off heater } + +uint32_t TipThermoModel::convertuVToDegF(uint32_t tipuVDelta) { + //(Y °C × 9/5) + 32 =Y°F + for (uint32_t i = 1; i < ThermalTable.count; i++) { + if (((uint32_t) ThermalTable.values[i][0]) < tipuVDelta) { + //Then extrapolate + //Where i= the lower raw sample, i-1 is the higher raw sample + return ((LinearInterpolate( // + ThermalTable.values[i][0], // x1 + ThermalTable.values[i][1], // y1 + ThermalTable.values[i - 1][0], // x2 + ThermalTable.values[i - 1][1], // y2 + tipuVDelta) // raw sample to be interpolated + * 9) / 50) + 32; // Convert C ->> F for 'mericans + + } + } + return 932; // fail high -> will turn off heater +} + +uint32_t TipThermoModel::convertCtoF(uint32_t degC) { + //(Y °C × 9/5) + 32 =Y°F + return 32 + ((degC * 9) / 5); +} + +uint32_t TipThermoModel::convertFtoC(uint32_t degF) { + //(Y°F − 32) × 5/9 = Y°C + if (degF < 32) + return 0; + return ((degF - 32) * 5) / 9; +} + diff --git a/workspace/TS100/Core/Src/TipThermoModel.h b/workspace/TS100/Core/Src/TipThermoModel.h index 8e57d55b..5641cf96 100644 --- a/workspace/TS100/Core/Src/TipThermoModel.h +++ b/workspace/TS100/Core/Src/TipThermoModel.h @@ -11,10 +11,17 @@ #include "hardware.h" class TipThermoModel { public: + //These are the main two functions + static uint32_t convertTipRawADCToDegC(uint16_t rawADC); + static uint32_t convertTipRawADCToDegF(uint16_t rawADC); //Returns the uV of the tip reading before the op-amp compensating for pullups static uint32_t convertTipRawADCTouV(uint16_t rawADC); - static uint32_t convertTipRawADCToDegC(uint16_t rawADC); + static uint32_t convertCtoF(uint32_t degC); + static uint32_t convertFtoC(uint32_t degF); + +private: static uint32_t convertuVToDegC(uint32_t tipuVDelta); + static uint32_t convertuVToDegF(uint32_t tipuVDelta); }; #endif /* SRC_TIPTHERMOMODEL_H_ */ diff --git a/workspace/TS100/Core/Src/gui.cpp b/workspace/TS100/Core/Src/gui.cpp index abb0dadd..42ce89b6 100644 --- a/workspace/TS100/Core/Src/gui.cpp +++ b/workspace/TS100/Core/Src/gui.cpp @@ -9,7 +9,7 @@ #include "Translation.h" #include "cmsis_os.h" #include "main.hpp" - +#include "TipThermoModel.h" #include "string.h" extern uint32_t lastButtonTime; void gui_Menu(const menuitem* menu); @@ -50,19 +50,11 @@ static void settings_setCoolingBlinkEnabled(void); static void settings_displayCoolingBlinkEnabled(void); static void settings_setResetSettings(void); static void settings_displayResetSettings(void); -static void settings_setTipModel(void); -static void settings_displayTipModel(void); static void settings_setCalibrate(void); static void settings_displayCalibrate(void); static void settings_setCalibrateVIN(void); static void settings_displayCalibrateVIN(void); -// Calibration Menu -static void calibration_displaySimpleCal(void); // Hot water cal -static void calibration_enterSimpleCal(void); -static void calibration_displayAdvancedCal(void); // two point cal -static void calibration_enterAdvancedCal(void); - // Menu functions static void settings_displaySolderingMenu(void); static void settings_enterSolderingMenu(void); @@ -197,8 +189,6 @@ const menuitem advancedMenu[] = { settings_displayAdvancedSolderingScreens } }, /* Advanced soldering screen*/ { (const char*) SettingsDescriptions[13], { settings_setResetSettings }, { settings_displayResetSettings } }, /*Resets settings*/ -{ (const char*) SettingsDescriptions[17], { settings_setTipModel }, { - settings_displayTipModel } }, /*Select tip Model */ { (const char*) SettingsDescriptions[12], { settings_setCalibrate }, { settings_displayCalibrate } }, /*Calibrate tip*/ { (const char*) SettingsDescriptions[14], { settings_setCalibrateVIN }, { @@ -206,13 +196,6 @@ const menuitem advancedMenu[] = { { NULL, { NULL }, { NULL } } // end of menu marker. DO NOT REMOVE }; -const menuitem calibrationMenu[] { { (const char*) SettingsDescriptions[6], { - calibration_enterSimpleCal }, { calibration_displaySimpleCal } }, -/* Simple Cal*/ -{ (const char*) SettingsDescriptions[6], { calibration_enterAdvancedCal }, { - calibration_displayAdvancedCal } }, /* Advanced Cal */ -{ NULL, { NULL }, { NULL } } }; - static void printShortDescriptionSingleLine(uint32_t shortDescIndex) { OLED::setFont(0); OLED::setCharCursor(0, 0); @@ -305,7 +288,7 @@ static void settings_displayInputVRange(void) { printShortDescription(0, 6); if (systemSettings.cutoutSetting) { - OLED::printNumber(2 + systemSettings.cutoutSetting,1); + OLED::printNumber(2 + systemSettings.cutoutSetting, 1); OLED::print(SymbolCellCount); } else { OLED::print(SymbolDC); @@ -574,47 +557,11 @@ static void settings_displayResetSettings(void) { printShortDescription(13, 7); } -static void settings_setTipModel(void) { - systemSettings.tipType++; - if(systemSettings.tipType==Tip_MiniWare) - systemSettings.tipType++; -#ifdef MODEL_TS100 - if(systemSettings.tipType==Tip_Hakko) - systemSettings.tipType++; -#endif - systemSettings.tipType %= (Tip_Custom + 1); // Wrap after custom -} -static void settings_displayTipModel(void) { - printShortDescription(17, 4); - // Print in small text the tip model - OLED::setFont(1); - // set the cursor - // Print the mfg - OLED::setCursor(55, 0); - if (systemSettings.tipType == Tip_Custom) { - OLED::print(TipModelStrings[Tip_Custom]); - } else if (systemSettings.tipType < Tip_MiniWare) { - OLED::print(TipModelStrings[Tip_MiniWare]); - } -#ifdef MODEL_TS100 - else if (systemSettings.tipType < Tip_Hakko) { - OLED::print(TipModelStrings[Tip_Hakko]); - } -#endif - - OLED::setCursor(55, 8); - if (systemSettings.tipType != Tip_Custom) - OLED::print(TipModelStrings[systemSettings.tipType]); - -} -static void calibration_displaySimpleCal(void) { - printShortDescription(18, 5); -} static void setTipOffset() { - setCalibrationOffset(0); // turn off the current offset + systemSettings.CalibrationOffset = 0; - // If the thermocouple at the end of the tip, and the handle are at - // equalibrium, then the output should be zero, as there is no temperature + // If the thermo-couple at the end of the tip, and the handle are at + // equilibrium, then the output should be zero, as there is no temperature // differential. uint32_t offset = 0; @@ -629,147 +576,20 @@ static void setTipOffset() { OLED::refresh(); osDelay(100); } - systemSettings.CalibrationOffset = offset / 15; - // Need to remove from this the ambient temperature offset - uint32_t ambientoffset = getHandleTemperature(); // Handle temp in C x10 - ambientoffset *= 100; - ambientoffset /= tipGainCalValue; - systemSettings.CalibrationOffset -= ambientoffset; - setCalibrationOffset(systemSettings.CalibrationOffset); // store the error + systemSettings.CalibrationOffset = TipThermoModel::convertTipRawADCTouV( + offset / 15); OLED::clearScreen(); OLED::setCursor(0, 0); OLED::drawCheckbox(true); OLED::refresh(); osDelay(1000); } -static void calibration_enterSimpleCal(void) { - // User has entered into the simple cal routine - if (userConfirmation(SettingsCalibrationWarning)) { - // User has confirmed their handle is at ambient - // So take the offset measurement - setTipOffset(); - // Next we want the user to put the tip into 100C water so we can calculate - // their tip's gain Gain is the m term from rise/run plot of raw readings vs - // (tip-handle) Thus we want to calculate - // ([TipRawHot-TipRawCold])/(ActualHot-HandleHot)-(ActualCold-HandleCold) - // Thus we first need to store -> - // TiprawCold,HandleCold,ActualCold==HandleCold -> RawTipCold - uint32_t RawTipCold = getTipRawTemp(0) * 10; - OLED::clearScreen(); - OLED::setCursor(0, 0); - OLED::setFont(1); - OLED::print("Please Insert Tip\nInto Boiling Water"); - OLED::refresh(); - osDelay(200); - waitForButtonPress(); - // Now take the three hot measurements - // Assume water is boiling at 100C - uint32_t RawTipHot = getTipRawTemp(0) * 10; - uint32_t HandleTempHot = getHandleTemperature() / 10; - - uint32_t gain = (RawTipHot - RawTipCold) / (100 - HandleTempHot); - - // Show this to the user - OLED::clearScreen(); - OLED::setCursor(0, 0); - OLED::print(YourGainMessage); - OLED::printNumber(gain, 6); - OLED::refresh(); - osDelay(2000); - waitForButtonPress(); - OLED::clearScreen(); - OLED::setCursor(0, 0); - OLED::print(SymbolPlus); - OLED::printNumber(RawTipHot, 8); - OLED::setCursor(0, 8); - OLED::print(SymbolMinus); - OLED::printNumber(RawTipCold, 8); - OLED::refresh(); - osDelay(2000); - waitForButtonPress(); - } -} -static void calibration_displayAdvancedCal(void) { - printShortDescription(19, 5); -} -static void calibration_enterAdvancedCal(void) { - //Advanced cal - if (userConfirmation(SettingsCalibrationWarning)) { - //User has confirmed their handle is at ambient - //So take the offset measurement - setTipOffset(); - //The tip now has a known ADC offset - //Head up until it is at 350C - //Then let the user adjust the gain value until it converges - systemSettings.customTipGain = 160; // start safe and high - bool exit = false; - - while (exit == false) { - //Set tip to 350C - setTipType(Tip_Custom, systemSettings.customTipGain); - currentlyActiveTemperatureTarget = ctoTipMeasurement(350); - //Check if user has pressed button to change the gain - ButtonState buttons = getButtonState(); - switch (buttons) { - case BUTTON_NONE: - break; - case BUTTON_BOTH: - case BUTTON_B_LONG: - case BUTTON_F_LONG: - exit = true; - break; - case BUTTON_F_SHORT: - systemSettings.customTipGain++; - break; - case BUTTON_B_SHORT: { - systemSettings.customTipGain--; - } - break; - default: - break; - } - if (systemSettings.customTipGain > 200) - systemSettings.customTipGain = 200; - else if (systemSettings.customTipGain <= 100) - systemSettings.customTipGain = 100; - OLED::setCursor(0, 0); - OLED::clearScreen(); - OLED::setFont(0); - if (OLED::getRotation()) - OLED::print(SymbolMinus); - else - OLED::print(SymbolPlus); - - OLED::print(SymbolSpace); - OLED::printNumber(systemSettings.customTipGain, 4); - OLED::print(SymbolSpace); - if (OLED::getRotation()) - OLED::print(SymbolPlus); - else - OLED::print(SymbolMinus); - OLED::refresh(); - GUIDelay(); - } - // Wait for the user to confirm the exit message that the calibration is done - userConfirmation(SettingsCalibrationDone); - } -} //Provide the user the option to tune their own tip if custom is selected //If not only do single point tuning as per usual static void settings_setCalibrate(void) { - if (systemSettings.tipType == Tip_Custom) { - // Two types of calibration - // 1. Basic, idle temp + hot water (100C) - // 2. Advanced, 100C + 350C, we keep PID tracking to a temperature target - return gui_Menu(calibrationMenu); - } - // Else - // Ask user if handle is at the tip temperature - // Any error between handle and the tip will be a direct offset in the control - // loop - else if (userConfirmation(SettingsCalibrationWarning)) { + if (userConfirmation(SettingsCalibrationWarning)) { // User confirmed // So we now perform the actual calculation setTipOffset(); diff --git a/workspace/TS100/Core/Src/hardware.cpp b/workspace/TS100/Core/Src/hardware.cpp index 2fd574a1..fa10da38 100644 --- a/workspace/TS100/Core/Src/hardware.cpp +++ b/workspace/TS100/Core/Src/hardware.cpp @@ -9,17 +9,7 @@ #include "hardware.h" #include "history.hpp" volatile uint16_t PWMSafetyTimer = 0; -volatile int16_t CalibrationTempOffset = 0; -uint16_t tipGainCalValue = 0; -void setTipType(enum TipType tipType, uint8_t manualCalGain) { - if (manualCalGain) - tipGainCalValue = manualCalGain; - else - tipGainCalValue = lookupTipDefaultCalValue(tipType); -} -void setCalibrationOffset(int16_t offSet) { - CalibrationTempOffset = offSet; -} + uint16_t getHandleTemperature() { // We return the current handle temperature in X10 C // TMP36 in handle, 0.5V offset and then 10mV per deg C (0.75V @ 25C for @@ -36,34 +26,7 @@ uint16_t getHandleTemperature() { result /= 993; return result; } -uint16_t tipMeasurementToC(uint16_t raw) { - //((Raw Tip-RawOffset) * calibrationgain) / 1000 = tip delta in CX10 - // tip delta in CX10 + handleTemp in CX10 = tip absolute temp in CX10 - // Div answer by 10 to get final result - uint32_t tipDelta = ((raw - CalibrationTempOffset) * tipGainCalValue) - / 1000; - tipDelta += getHandleTemperature(); - - return tipDelta / 10; -} -uint16_t ctoTipMeasurement(uint16_t temp) { - //[ (temp-handle/10) * 10000 ]/calibrationgain = tip raw delta - // tip raw delta + tip offset = tip ADC reading - int32_t TipRaw = ((temp - (getHandleTemperature() / 10)) * 10000) - / tipGainCalValue; - TipRaw += CalibrationTempOffset; - return TipRaw; -} - -uint16_t tipMeasurementToF(uint16_t raw) { - // Convert result from C to F - return (tipMeasurementToC(raw) * 9) / 5 + 32; -} -uint16_t ftoTipMeasurement(uint16_t temp) { - // Convert the temp back to C from F - return ctoTipMeasurement(((temp - 32) * 5) / 9); -} uint16_t getTipInstantTemperature() { uint16_t sum = 0; // 12 bit readings * 8 -> 15 bits @@ -93,44 +56,7 @@ uint16_t getTipInstantTemperature() { sum += readings[minID]; //Duplicate the min to make up for the missing max value return sum; // 8x over sample } -/* - * Loopup table for the tip calibration values for - * the gain of the tip's - * This can be found by line of best fit of TipRaw on X, and TipTemp-handle on - * Y. Then take the m term * 10000 - * */ -uint16_t lookupTipDefaultCalValue(enum TipType tipID) { -#ifdef MODEL_TS100 - switch (tipID) { - case TS_D24: - return 141; - break; - case TS_BC2: - return (133 + 129) / 2; - break; - case TS_C1: - return 133; - break; - case TS_B2: - return 133; - default: - return 132; // make this the average of all - break; - } -#else - switch (tipID) { - case TS_D25: - return 154; - break; - case TS_B02: - return 154; - break; - default: - return 154; // make this the average of all - break; - } -#endif -} + //2 second filter (ADC is PID_TIM_HZ Hz) history rawTempFilter = { { 0 }, 0, 0 }; @@ -333,54 +259,7 @@ void startQC(uint16_t divisor) { if (QCTries > 10) QCMode = 0; } -// Get tip resistance in milliohms -uint32_t calculateTipR() { - static uint32_t lastRes = 0; - if (lastRes) - return lastRes; - // We inject a small current into the front end of the iron, - // By measuring the Vdrop over the tip we can calculate the resistance - // Turn PA0 into an output and drive high to inject (3.3V-0.6)/(6K8+Rtip) - // current PA0->Diode -> 6K8 -> Tip -> GND So the op-amp will amplify the - // small signal across the tip and convert this into an easily read voltage - GPIO_InitTypeDef GPIO_InitStruct; - GPIO_InitStruct.Pin = GPIO_PIN_0; - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // Set low first - setTipPWM(0); - vTaskDelay(1); - uint32_t offReading = getTipRawTemp(1); - for (uint8_t i = 0; i < 49; i++) { - vTaskDelay(1); // delay to allow it to stabilize - HAL_IWDG_Refresh(&hiwdg); - offReading += getTipRawTemp(1); - } - // Turn on - HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // Set hgih - vTaskDelay(1); // delay to allow it too stabilize - uint32_t onReading = getTipInstantTemperature(); - for (uint8_t i = 0; i < 49; i++) { - vTaskDelay(1); // delay to allow it to stabilize - HAL_IWDG_Refresh(&hiwdg); - onReading += getTipRawTemp(1); - } - - HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // Turn the output off finally - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - uint32_t difference = onReading - offReading; - // V = IR, therefore I = V/R - // We can divide this reading by a known "gain" to get the resulting - // resistance This was determined emperically This tip is 4.688444162 ohms, - // 4688 milliohms (Measured using 4 terminal measurement) 25x oversampling - // reads this as around 47490 Almost perfectly 10x the milliohms value This - // will drift massively with tip temp However we really only need 10x ohms - lastRes = (difference / 21) + 1; // ceil - return lastRes; -} static unsigned int sqrt32(unsigned long n) { unsigned int c = 0x8000; unsigned int g = 0x8000; @@ -398,7 +277,7 @@ int16_t calculateMaxVoltage(uint8_t useHP) { // This measures the tip resistance, then it calculates the appropriate // voltage To stay under ~18W. Mosfet is "9A", so no issues there // QC3.0 supports up to 18W, which is 2A @9V and 1.5A @12V - uint32_t milliOhms = calculateTipR(); + uint32_t milliOhms = 4500; // Check no tip if (milliOhms > 10000) return -1; diff --git a/workspace/TS100/Core/Src/main.cpp b/workspace/TS100/Core/Src/main.cpp index 488f511a..ff715501 100644 --- a/workspace/TS100/Core/Src/main.cpp +++ b/workspace/TS100/Core/Src/main.cpp @@ -11,10 +11,10 @@ #include "stdlib.h" #include "stm32f1xx_hal.h" #include "string.h" - +#include "TipThermoModel.h" uint8_t PCBVersion = 0; // File local variables -uint32_t currentlyActiveTemperatureTarget = 0; +uint32_t currentTempTargetDegC = 0; // Current temperature target in C uint32_t lastMovementTime = 0; int16_t idealQCVoltage = 0; // FreeRTOS variables @@ -71,9 +71,7 @@ int main(void) { } HAL_IWDG_Refresh(&hiwdg); restoreSettings(); // load the settings from flash - setCalibrationOffset(systemSettings.CalibrationOffset); - setTipType((enum TipType) systemSettings.tipType, - systemSettings.customTipGain); // apply tip type selection + HAL_IWDG_Refresh(&hiwdg); /* Create the thread(s) */ @@ -112,7 +110,6 @@ void startPIDTask(void const *argument __unused) { #ifdef MODEL_TS80 idealQCVoltage = calculateMaxVoltage(systemSettings.cutoutSetting); #endif - uint8_t rawC = ctoTipMeasurement(101) - ctoTipMeasurement(100); // 1*C change in raw. #ifdef MODEL_TS80 //Set power management code to the tip resistance in ohms * 10 @@ -122,30 +119,30 @@ void startPIDTask(void const *argument __unused) { #endif history tempError = { { 0 }, 0, 0 }; - currentlyActiveTemperatureTarget = 0; // Force start with no output (off). If in sleep / soldering this will - // be over-ridden rapidly + currentTempTargetDegC = 0; // Force start with no output (off). If in sleep / soldering this will + // be over-ridden rapidly pidTaskNotification = xTaskGetCurrentTaskHandle(); for (;;) { if (ulTaskNotifyTake(pdTRUE, 2000)) { // This is a call to block this thread until the ADC does its samples uint16_t rawTemp = getTipRawTemp(1); // get instantaneous reading - if (currentlyActiveTemperatureTarget) { + if (currentTempTargetDegC) { // Cap the max set point to 450C - if (currentlyActiveTemperatureTarget > ctoTipMeasurement(450)) { + if (currentTempTargetDegC > (450)) { //Maximum allowed output - currentlyActiveTemperatureTarget = ctoTipMeasurement(450); - } else if (currentlyActiveTemperatureTarget > 32400) { - //Cap to max adc reading - currentlyActiveTemperatureTarget = 32400; + currentTempTargetDegC = (450); } + // Convert the current tip to degree's C + uint32_t currentTipTempInC = + TipThermoModel::convertTipRawADCToDegC(rawTemp); + currentTipTempInC += getHandleTemperature() / 10; //Add handle offset // As we get close to our target, temp noise causes the system // to be unstable. Use a rolling average to dampen it. - // We overshoot by roughly 1/2 of 1 degree Fahrenheit. + // We overshoot by roughly 1 degree C. // This helps stabilize the display. - int32_t tError = currentlyActiveTemperatureTarget - rawTemp - + (rawC / 4); + int32_t tError = currentTempTargetDegC - currentTipTempInC + 1; tError = tError > INT16_MAX ? INT16_MAX : tError; tError = tError < INT16_MIN ? INT16_MIN : tError; tempError.update(tError); @@ -160,15 +157,8 @@ void startPIDTask(void const *argument __unused) { // This is necessary because of the temp noise and thermal lag in the system. // Once we have feed-forward temp estimation we should be able to better tune this. -#ifdef MODEL_TS100 - const uint16_t mass = 2020 / 20; // divide here so division is compile-time. -#endif -#ifdef MODEL_TS80 - const uint16_t mass = 2020 / 50; -#endif - - int32_t milliWattsNeeded = tempToMilliWatts(tempError.average(), - mass); + int32_t milliWattsNeeded = tempToMilliWatts( + tempError.average()); // note that milliWattsNeeded is sometimes negative, this counters overshoot // from I term's inertia. milliWattsOut += milliWattsNeeded; @@ -193,7 +183,7 @@ void startPIDTask(void const *argument __unused) { // This is purely guesswork :'( as everyone implements stuff differently if (xTaskGetTickCount() - lastPowerPulse < 10) { // for the first 100mS turn on for a bit - setTipMilliWatts(5000); // typically its around 5W to hold the current temp, so this wont raise temp much + setTipMilliWatts(2500); // typically its around 5W to hold the current temp, so this wont raise temp much } else setTipMilliWatts(0); //Then wait until the next 0.5 seconds diff --git a/workspace/TS100/Core/Src/power.cpp b/workspace/TS100/Core/Src/power.cpp index 967a72e9..b5f7490a 100644 --- a/workspace/TS100/Core/Src/power.cpp +++ b/workspace/TS100/Core/Src/power.cpp @@ -14,11 +14,11 @@ const uint16_t totalPWM = 255 + 17; //htim2.Init.Period, the full PWM cycle history milliWattHistory = { { 0 }, 0, 0 }; -int32_t tempToMilliWatts(int32_t rawTemp, uint8_t rawC) { +int32_t tempToMilliWatts(int32_t rawTemp) { // mass is in milliJ/*C, rawC is raw per degree C // returns milliWatts needed to raise/lower a mass by rawTemp // degrees in one cycle. - int32_t milliJoules = tipMass*10 * (rawTemp / rawC); + int32_t milliJoules = tipMass*10 * rawTemp; return milliJoules; }