1
0
forked from me/IronOS

Rough refactor main control loop to C

This commit is contained in:
Ben V. Brown
2019-10-07 18:58:51 +11:00
parent c5f6f6d044
commit 1cf88b2cd6
11 changed files with 233 additions and 496 deletions

View File

@@ -11,7 +11,7 @@
#define SETTINGS_H_
#include <stdint.h>
#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

View File

@@ -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*/

View File

@@ -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<uint32_t, oscillationPeriod> 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);

View File

@@ -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

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -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_ */

View File

@@ -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();

View File

@@ -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<uint16_t, PID_TIM_HZ*4> 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;

View File

@@ -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<int32_t, 16> 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

View File

@@ -14,11 +14,11 @@ const uint16_t totalPWM = 255 + 17; //htim2.Init.Period, the full PWM cycle
history<uint32_t, oscillationPeriod> 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;
}