1
0
forked from me/IronOS

Work in progress

Working, but has temp offset issue slightly.

Could have slightly wrong gain values
This commit is contained in:
Ben V. Brown
2019-10-07 21:11:31 +11:00
parent 3e1abc451c
commit 6a39e4bcc8
9 changed files with 67 additions and 83 deletions

View File

@@ -44,9 +44,7 @@ typedef struct {
uint8_t customTipGain; // Tip gain value if custom tuned, or 0 if using a
// tipType param
#ifdef MODEL_TS80
uint8_t pidPowerLimit;
#endif
uint8_t version; // Used to track if a reset is needed on firmware upgrade
uint32_t padding; // This is here for in case we are not an even divisor so
// that nothing gets cut off

View File

@@ -18,22 +18,21 @@
// Once we have feed-forward temp estimation we should be able to better tune this.
#ifdef MODEL_TS100
const uint16_t tipMass = 450; // divide here so division is compile-time.
const int32_t tipMass = 3500; // divide here so division is compile-time.
const uint8_t tipResistance = 85; //x10 ohms, 8.5 typical for ts100, 4.5 typical for ts80
#endif
#ifdef MODEL_TS80
const uint16_t tipMass = 450;
const uint32_t tipMass = 4500;
const uint8_t tipResistance = 45; //x10 ohms, 8.5 typical for ts100, 4.5 typical for ts80
#endif
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);
void setTipMilliWatts(int32_t mw);
uint8_t milliWattsToPWM(int32_t milliWatts, uint8_t divisor,
uint8_t sample = 0);
int32_t PWMToMilliWatts(uint8_t pwm, uint8_t divisor, uint8_t sample = 0);
const uint8_t oscillationPeriod = 8*PID_TIM_HZ; // I term look back value
extern history<uint32_t, oscillationPeriod> x10WattHistory;
int32_t tempToX10Watts(int32_t rawTemp);
void setTipX10Watts(int32_t mw);
uint8_t X10WattsToPWM(int32_t milliWatts, uint8_t sample = 0);
int32_t PWMToX10Watts(uint8_t pwm, uint8_t sample = 0);
uint32_t availableW10(uint8_t sample) ;
#endif /* POWER_HPP_ */

View File

@@ -502,9 +502,9 @@ static void gui_solderingMode(uint8_t jumpToSleep) {
if (systemSettings.detailedSoldering) {
OLED::setFont(1);
OLED::print(SolderingAdvancedPowerPrompt); // Power:
OLED::printNumber(milliWattHistory[0] / 1000, 2);
OLED::printNumber(x10WattHistory[0] / 10, 2);
OLED::print(SymbolDot);
OLED::printNumber(milliWattHistory[0] / 100 % 10, 1);
OLED::printNumber(x10WattHistory[0] % 10, 1);
OLED::print(SymbolWatts);
if (systemSettings.sensitivity && systemSettings.SleepTime) {
@@ -514,6 +514,9 @@ static void gui_solderingMode(uint8_t jumpToSleep) {
OLED::setCursor(0, 8);
OLED::print(SleepingTipAdvancedString);
//OLED::printNumber(
// TipThermoModel::convertTipRawADCTouV(getTipRawTemp(0)), 5); // Draw the tip temp out finally
gui_drawTipTemp(true);
OLED::print(SymbolSpace);
printVoltage();
@@ -535,14 +538,10 @@ static void gui_solderingMode(uint8_t jumpToSleep) {
OLED::print(SymbolSpace);
// Draw heating/cooling symbols
OLED::drawHeatSymbol(
milliWattsToPWM(milliWattHistory[0],
systemSettings.voltageDiv));
OLED::drawHeatSymbol(X10WattsToPWM(x10WattHistory[0]));
} else {
// Draw heating/cooling symbols
OLED::drawHeatSymbol(
milliWattsToPWM(milliWattHistory[0],
systemSettings.voltageDiv));
OLED::drawHeatSymbol(X10WattsToPWM(x10WattHistory[0]));
// We draw boost arrow if boosting, or else gap temp <-> heat
// indicator
if (boostModeOn)
@@ -645,13 +644,17 @@ void showDebugMenu(void) {
break;
case 6:
//Raw Tip
OLED::printNumber(TipThermoModel::convertTipRawADCTouV(getTipRawTemp(0)), 6);
{
uint32_t temp = systemSettings.CalibrationOffset;
systemSettings.CalibrationOffset = 0;
OLED::printNumber(
TipThermoModel::convertTipRawADCTouV(getTipRawTemp(1)), 6);
systemSettings.CalibrationOffset = temp;
}
break;
case 7:
//Temp in C
OLED::printNumber(
TipThermoModel::convertTipRawADCToDegC(getTipRawTemp(0)),
5);
OLED::printNumber(TipThermoModel::getTipInC(1), 5);
break;
case 8:
//Handle Temp

View File

@@ -106,13 +106,14 @@ void resetSettings() {
systemSettings.descriptionScrollSpeed = 0; // default to slow
#ifdef MODEL_TS100
systemSettings.CalibrationOffset = 650; // the adc offset in uV
systemSettings.CalibrationOffset = 300; // the adc offset in uV
systemSettings.pidPowerLimit=70; // Sets the max pwm power limit
#endif
#ifdef MODEL_TS80
systemSettings.pidPowerLimit=24; // Sets the max pwm power limit
systemSettings.CalibrationOffset = 650; // the adc offset in uV
systemSettings.CalibrationOffset = 300; // the adc offset in uV
#endif
saveSettings(); // Save defaults
}

View File

@@ -256,6 +256,6 @@ uint32_t TipThermoModel::getTipInC(bool sampleNow) {
uint32_t TipThermoModel::getTipInF(bool sampleNow) {
uint32_t currentTipTempInF = TipThermoModel::convertTipRawADCToDegF(
getTipRawTemp(sampleNow));
currentTipTempInF += convertCtoF(getHandleTemperature() / 10); //Add handle offset
return currentTipTempInF;
currentTipTempInF += convertCtoF(getHandleTemperature() / 10); //Add handle offset
return currentTipTempInF;
}

View File

@@ -581,8 +581,9 @@ static void setTipOffset() {
OLED::clearScreen();
OLED::setCursor(0, 0);
OLED::drawCheckbox(true);
OLED::printNumber(systemSettings.CalibrationOffset,4);
OLED::refresh();
osDelay(1000);
osDelay(1200);
}
//Provide the user the option to tune their own tip if custom is selected

View File

@@ -27,7 +27,6 @@ uint16_t getHandleTemperature() {
return result;
}
uint16_t getTipInstantTemperature() {
uint16_t sum = 0; // 12 bit readings * 8 -> 15 bits
uint16_t readings[8];
@@ -42,23 +41,15 @@ uint16_t getTipInstantTemperature() {
readings[5] = hadc2.Instance->JDR2;
readings[6] = hadc2.Instance->JDR3;
readings[7] = hadc2.Instance->JDR4;
uint8_t minID = 0, maxID = 0;
for (int i = 0; i < 8; i++) {
if (readings[i] < readings[minID])
minID = i;
else if (readings[i] > readings[maxID])
maxID = i;
sum += readings[i];
}
for (int i = 0; i < 8; i++) {
if (i != maxID)
sum += readings[i];
}
sum += readings[minID]; //Duplicate the min to make up for the missing max value
return sum; // 8x over sample
}
//2 second filter (ADC is PID_TIM_HZ Hz)
history<uint16_t, PID_TIM_HZ*4> rawTempFilter = { { 0 }, 0, 0 };
history<uint16_t, PID_TIM_HZ > rawTempFilter = { { 0 }, 0, 0 };
uint16_t getTipRawTemp(uint8_t refresh) {
if (refresh) {
@@ -354,7 +345,6 @@ void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) {
}
}
void vApplicationIdleHook(void) {
HAL_IWDG_Refresh(&hiwdg);
}

View File

@@ -47,7 +47,7 @@ int main(void) {
HAL_Init();
Setup_HAL(); // Setup all the HAL objects
HAL_IWDG_Refresh(&hiwdg);
setTipMilliWatts(0); // force tip off
setTipX10Watts(0); // force tip off
FRToSI2C::init(&hi2c1);
OLED::initialize(); // start up the LCD
OLED::setFont(0); // default to bigger font
@@ -106,7 +106,7 @@ void startPIDTask(void const *argument __unused) {
* We take the current tip temperature & evaluate the next step for the tip
* control PWM.
*/
setTipMilliWatts(0); // disable the output driver if the output is set to be off
setTipX10Watts(0); // disable the output driver if the output is set to be off
#ifdef MODEL_TS80
idealQCVoltage = calculateMaxVoltage(systemSettings.cutoutSetting);
#endif
@@ -118,7 +118,7 @@ void startPIDTask(void const *argument __unused) {
#else
#endif
history<int32_t, 16> tempError = { { 0 }, 0, 0 };
history<int32_t, PID_TIM_HZ > tempError = { { 0 }, 0, 0 };
currentTempTargetDegC = 0; // Force start with no output (off). If in sleep / soldering this will
// be over-ridden rapidly
pidTaskNotification = xTaskGetCurrentTaskHandle();
@@ -145,7 +145,7 @@ void startPIDTask(void const *argument __unused) {
tempError.update(tError);
// Now for the PID!
int32_t milliWattsOut = 0;
int32_t x10WattsOut = 0;
// P term - total power needed to hit target temp next cycle.
// thermal mass = 1690 milliJ/*C for my tip.
@@ -154,17 +154,17 @@ 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.
int32_t milliWattsNeeded = tempToMilliWatts(
tempError.average());
int32_t x10WattsNeeded = tempToX10Watts(tError);
// tempError.average());
// note that milliWattsNeeded is sometimes negative, this counters overshoot
// from I term's inertia.
milliWattsOut += milliWattsNeeded;
x10WattsOut += x10WattsNeeded;
// I term - energy needed to compensate for heat loss.
// We track energy put into the system over some window.
// Assuming the temp is stable, energy in = energy transfered.
// (If it isn't, P will dominate).
milliWattsOut += milliWattHistory.average();
x10WattsOut += x10WattHistory.average();
// D term - use sudden temp change to counter fast cooling/heating.
// In practice, this provides an early boost if temp is dropping
@@ -172,7 +172,7 @@ void startPIDTask(void const *argument __unused) {
// basically: temp - lastTemp
// Unfortunately, our temp signal is too noisy to really help.
setTipMilliWatts(milliWattsOut);
setTipX10Watts(x10WattsOut);
} else {
#ifdef MODEL_TS80
@@ -180,15 +180,15 @@ 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(2500); // typically its around 5W to hold the current temp, so this wont raise temp much
setTipX10Watts(25); // typically its around 5W to hold the current temp, so this wont raise temp much
} else
setTipMilliWatts(0);
setTipX10Watts(0);
//Then wait until the next 0.5 seconds
if (xTaskGetTickCount() - lastPowerPulse > 50) {
lastPowerPulse = xTaskGetTickCount();
}
#else
setTipMilliWatts(0);
setTipX10Watts(0);
#endif
}
@@ -197,7 +197,6 @@ void startPIDTask(void const *argument __unused) {
asm("bkpt");
//ADC interrupt timeout
setTipMilliWatts(0);
setTipPWM(0);
}
}

View File

@@ -12,33 +12,30 @@
const uint16_t powerPWM = 255;
const uint16_t totalPWM = 255 + 17; //htim2.Init.Period, the full PWM cycle
history<uint32_t, oscillationPeriod> milliWattHistory = { { 0 }, 0, 0 };
history<uint32_t, oscillationPeriod> x10WattHistory = { { 0 }, 0, 0 };
int32_t tempToMilliWatts(int32_t rawTemp) {
int32_t tempToX10Watts(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;
int32_t milliJoules = tipMass * rawTemp;
return milliJoules;
}
void setTipMilliWatts(int32_t mw) {
//Enforce Max Watts Limiter # TODO
int32_t output = milliWattsToPWM(mw, systemSettings.voltageDiv , 1);
void setTipX10Watts(int32_t mw) {
int32_t output = X10WattsToPWM(mw, 1);
setTipPWM(output);
uint32_t actualMilliWatts = PWMToMilliWatts(output,
systemSettings.voltageDiv , 0);
uint32_t actualMilliWatts = PWMToX10Watts(output, 0);
milliWattHistory.update(actualMilliWatts);
x10WattHistory.update(actualMilliWatts);
}
int32_t availableW10(uint8_t divisor, uint8_t sample) {
uint32_t availableW10(uint8_t sample) {
//P = V^2 / R, v*v = v^2 * 100
// R = R*10
// P therefore is in V^2*100/R*10 = W*10.
int32_t v = getInputVoltageX10(divisor, sample); // 100 = 10v
int32_t availableWattsX10 = (v * v) / tipResistance;
uint32_t v = getInputVoltageX10(systemSettings.voltageDiv, sample); // 100 = 10v
uint32_t availableWattsX10 = (v * v) / tipResistance;
//However, 100% duty cycle is not possible as there is a dead time while the ADC takes a reading
//Therefore need to scale available milliwats by this
@@ -50,27 +47,23 @@ int32_t availableW10(uint8_t divisor, uint8_t sample) {
return availableWattsX10;
}
uint8_t milliWattsToPWM(int32_t milliWatts, uint8_t divisor, uint8_t sample) {
// Scale input milliWatts to the pwm rate
if (milliWatts < 10) // no pint driving tip
uint8_t X10WattsToPWM(int32_t milliWatts, uint8_t sample) {
// Scale input milliWatts to the pwm range available
if (milliWatts < 1)
return 0;
// if (milliWatts > (int(systemSettings.pidPowerLimit) * 10))
// milliWatts = (int(systemSettings.pidPowerLimit) * 10);
//Calculate desired milliwatts as a percentage of availableW10
int32_t pwm = (powerPWM * milliWatts) / availableW10(divisor, sample);
uint32_t pwm = (powerPWM * milliWatts) / availableW10(sample);
if (pwm > powerPWM) {
pwm = powerPWM; //constrain to max PWM counter, shouldnt be possible, but small cost for safety to avoid wraps
} else if (pwm < 0) { //cannot go negative
pwm = 0;
}
return pwm;
}
int32_t PWMToMilliWatts(uint8_t pwm, uint8_t divisor, uint8_t sample) {
int32_t maxMW = availableW10(divisor, sample); //Get the milliwatts for the max pwm period
int32_t PWMToX10Watts(uint8_t pwm, uint8_t sample) {
uint32_t maxMW = availableW10(sample); //Get the milliwatts for the max pwm period
//Then convert pwm into percentage of powerPWM to get the percentage of the max mw
int32_t res = (pwm * maxMW) / powerPWM;
if (res < 0)
res = 0;
return res;
return (((uint32_t) pwm) * maxMW) / powerPWM;
}