Merge pull request #1043 from Ralim/ralim/pid
PID complete rewrite with kudos to @sandmanRO and help from @discip
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
#include "BSP_Power.h"
|
||||
#include "BSP_QC.h"
|
||||
#include "Defines.h"
|
||||
#include "Model_Config.h"
|
||||
#include "configuration.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
/*
|
||||
@@ -33,16 +33,13 @@ void BSPInit(void);
|
||||
// Called to reset the hardware watchdog unit
|
||||
void resetWatchdog();
|
||||
// Accepts a output level of 0.. to use to control the tip output PWM
|
||||
void setTipPWM(uint8_t pulse);
|
||||
void setTipPWM(const uint8_t pulse, const bool shouldUseFastModePWM);
|
||||
// Returns the Handle temp in C, X10
|
||||
uint16_t getHandleTemperature(uint8_t sample);
|
||||
// Returns the Tip temperature ADC reading in raw units
|
||||
uint16_t getTipRawTemp(uint8_t refresh);
|
||||
// Returns the main DC input voltage, using the adjustable divisor + sample flag
|
||||
uint16_t getInputVoltageX10(uint16_t divisor, uint8_t sample);
|
||||
// Switch to the most suitable PWM freq given the desired period;
|
||||
// returns true if the switch was performed and totalPWM changed
|
||||
bool tryBetterPWM(uint8_t pwm);
|
||||
|
||||
// Readers for the two buttons
|
||||
// !! Returns 1 if held down, 0 if released
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include "BSP.h"
|
||||
#include "I2C_Wrapper.hpp"
|
||||
#include "Model_Config.h"
|
||||
#include "Pins.h"
|
||||
#include "Setup.h"
|
||||
#include "TipThermoModel.h"
|
||||
@@ -246,11 +245,7 @@ uint16_t getInputVoltageX10(uint16_t divisor, uint8_t sample) {
|
||||
}
|
||||
return sum * 4 / divisor;
|
||||
}
|
||||
bool tryBetterPWM(uint8_t pwm) {
|
||||
// We dont need this for the MHP30
|
||||
return false;
|
||||
}
|
||||
void setTipPWM(uint8_t pulse) {
|
||||
void setTipPWM(const uint8_t pulse, const bool shouldUseFastModePWM) {
|
||||
// We can just set the timer directly
|
||||
if (htim3.Instance->PSC > 20) {
|
||||
htim3.Instance->CCR1 = 0;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Model_Config.h
|
||||
*
|
||||
* Created on: 25 Jul 2020
|
||||
* Author: Ralim
|
||||
*/
|
||||
|
||||
#ifndef BSP_MINIWARE_MODEL_CONFIG_H_
|
||||
#define BSP_MINIWARE_MODEL_CONFIG_H_
|
||||
/*
|
||||
* Lookup for mapping features <-> Models
|
||||
*/
|
||||
|
||||
#ifndef MODEL_MHP30
|
||||
#error "No model defined!"
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_MHP30
|
||||
#define ACCEL_MSA
|
||||
#define POW_PD
|
||||
#define TEMP_NTC
|
||||
#define I2C_SOFT
|
||||
#define BATTFILTERDEPTH 8
|
||||
#define OLED_I2CBB
|
||||
#define ACCEL_EXITS_ON_MOVEMENT
|
||||
#endif
|
||||
#ifdef ACCEL_EXITS_ON_MOVEMENT
|
||||
#define NO_SLEEP_MODE
|
||||
#endif
|
||||
#endif /* BSP_MINIWARE_MODEL_CONFIG_H_ */
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#ifndef BSP_MINIWARE_PINS_H_
|
||||
#define BSP_MINIWARE_PINS_H_
|
||||
#include "Model_Config.h"
|
||||
#include "configuration.h"
|
||||
|
||||
// MHP30 pin map
|
||||
#define KEY_B_Pin GPIO_PIN_0
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "BSP.h"
|
||||
#include "BSP_Power.h"
|
||||
#include "Model_Config.h"
|
||||
#include "Pins.h"
|
||||
#include "QC3.h"
|
||||
#include "Settings.h"
|
||||
#include "configuration.h"
|
||||
#include "fusb_user.h"
|
||||
#include "fusbpd.h"
|
||||
#include "int_n.h"
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
* Author: Ralim
|
||||
*/
|
||||
#include "BSP.h"
|
||||
#include "Model_Config.h"
|
||||
#include "Pins.h"
|
||||
#include "QC3.h"
|
||||
#include "Settings.h"
|
||||
#include "configuration.h"
|
||||
#include "stm32f1xx_hal.h"
|
||||
|
||||
#ifdef POW_QC
|
||||
void QC_DPlusZero_Six() {
|
||||
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET); // pull down D+
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#ifndef BSP_MINIWARE_SOFTWARE_I2C_H_
|
||||
#define BSP_MINIWARE_SOFTWARE_I2C_H_
|
||||
#include "BSP.h"
|
||||
#include "Model_Config.h"
|
||||
#include "configuration.h"
|
||||
#include "stm32f1xx_hal.h"
|
||||
#ifdef I2C_SOFT
|
||||
|
||||
|
||||
156
source/Core/BSP/MHP30/configuration.h
Normal file
156
source/Core/BSP/MHP30/configuration.h
Normal file
@@ -0,0 +1,156 @@
|
||||
#ifndef CONFIGURATION_H_
|
||||
#define CONFIGURATION_H_
|
||||
#include "Settings.h"
|
||||
#include "configuration.h"
|
||||
#include <stdint.h>
|
||||
/**
|
||||
* Configuration.h
|
||||
* Define here your default pre settings for TS80 or TS100
|
||||
*
|
||||
*/
|
||||
|
||||
//===========================================================================
|
||||
//============================= Default Settings ============================
|
||||
//===========================================================================
|
||||
/**
|
||||
* Default soldering temp is 320.0 C
|
||||
* Temperature the iron sleeps at - default 150.0 C
|
||||
*/
|
||||
|
||||
#define SLEEP_TEMP 150 // Default sleep temperature
|
||||
#define BOOST_TEMP 420 // Default boost temp.
|
||||
#define BOOST_MODE_ENABLED 1 // 0: Disable 1: Enable
|
||||
|
||||
/**
|
||||
* Blink the temperature on the cooling screen when its > 50C
|
||||
*/
|
||||
#define COOLING_TEMP_BLINK 0 // 0: Disable 1: Enable
|
||||
|
||||
/**
|
||||
* How many seconds/minutes we wait until going to sleep/shutdown.
|
||||
* Values -> SLEEP_TIME * 10; i.e. 5*10 = 50 Seconds!
|
||||
*/
|
||||
#define SLEEP_TIME 5 // x10 Seconds
|
||||
#define SHUTDOWN_TIME 10 // Minutes
|
||||
|
||||
/**
|
||||
* Auto start off for safety.
|
||||
* Pissible values are:
|
||||
* 0 - none
|
||||
* 1 - Soldering Temperature
|
||||
* 2 - Sleep Temperature
|
||||
* 3 - Sleep Off Temperature
|
||||
*/
|
||||
#define AUTO_START_MODE 0 // Default to none
|
||||
|
||||
/**
|
||||
* Locking Mode
|
||||
* When in soldering mode a long press on both keys toggle the lock of the buttons
|
||||
* Possible values are:
|
||||
* 0 - Desactivated
|
||||
* 1 - Lock except boost
|
||||
* 2 - Full lock
|
||||
*/
|
||||
#define LOCKING_MODE 0 // Default to desactivated for safety
|
||||
|
||||
/**
|
||||
* OLED Orientation
|
||||
*
|
||||
*/
|
||||
#define ORIENTATION_MODE 0 // 0: Right 1:Left 2:Automatic - Default right
|
||||
#define REVERSE_BUTTON_TEMP_CHANGE 0 // 0:Default 1:Reverse - Reverse the plus and minus button assigment for temperature change
|
||||
|
||||
/**
|
||||
* Temp change settings
|
||||
*/
|
||||
#define TEMP_CHANGE_SHORT_STEP 1 // Default temp change short step +1
|
||||
#define TEMP_CHANGE_LONG_STEP 10 // Default temp change long step +10
|
||||
#define TEMP_CHANGE_SHORT_STEP_MAX 50 // Temp change short step MAX value
|
||||
#define TEMP_CHANGE_LONG_STEP_MAX 90 // Temp change long step MAX value
|
||||
|
||||
/* Power pulse for keeping power banks awake*/
|
||||
#define POWER_PULSE_INCREMENT 1
|
||||
#define POWER_PULSE_MAX 100 // x10 max watts
|
||||
#define POWER_PULSE_WAIT_MAX 9 // 9*2.5s = 22.5 seconds
|
||||
#define POWER_PULSE_DURATION_MAX 9 // 9*250ms = 2.25 seconds
|
||||
|
||||
#ifdef MODEL_TS100
|
||||
#define POWER_PULSE_DEFAULT 0
|
||||
#else
|
||||
#define POWER_PULSE_DEFAULT 5
|
||||
#endif
|
||||
#define POWER_PULSE_WAIT_DEFAULT 4 // Default rate of the power pulse: 4*2500 = 10000 ms = 10 s
|
||||
#define POWER_PULSE_DURATION_DEFAULT 1 // Default duration of the power pulse: 1*250 = 250 ms
|
||||
|
||||
/**
|
||||
* OLED Orientation Sensitivity on Automatic mode!
|
||||
* Motion Sensitivity <0=Off 1=Least Sensitive 9=Most Sensitive>
|
||||
*/
|
||||
#define SENSITIVITY 7 // Default 7
|
||||
|
||||
/**
|
||||
* Detailed soldering screen
|
||||
* Detailed idle screen (off for first time users)
|
||||
*/
|
||||
#define DETAILED_SOLDERING 0 // 0: Disable 1: Enable - Default 0
|
||||
#define DETAILED_IDLE 0 // 0: Disable 1: Enable - Default 0
|
||||
|
||||
#define THERMAL_RUNAWAY_TIME_SEC 20
|
||||
#define THERMAL_RUNAWAY_TEMP_C 20
|
||||
|
||||
#define CUT_OUT_SETTING 0 // default to no cut-off voltage
|
||||
#define RECOM_VOL_CELL 33 // Minimum voltage per cell (Recommended 3.3V (33))
|
||||
#define TEMPERATURE_INF 0 // default to 0
|
||||
#define DESCRIPTION_SCROLL_SPEED 0 // 0: Slow 1: Fast - default to slow
|
||||
#define ANIMATION_LOOP 1 // 0: off 1: on
|
||||
#define ANIMATION_SPEED settingOffSpeed_t::MEDIUM
|
||||
|
||||
#define OP_AMP_Rf_MHP30 268500 // 268.5 Kilo-ohms -> Measured
|
||||
#define OP_AMP_Rin_MHP30 1600 // 1.6 Kilo-ohms -> Measured
|
||||
|
||||
#define OP_AMP_GAIN_STAGE_MHP30 (1 + (OP_AMP_Rf_MHP30 / OP_AMP_Rin_MHP30))
|
||||
// Deriving the Voltage div:
|
||||
// Vin_max = (3.3*(r1+r2))/(r2)
|
||||
// vdiv = (32768*4)/(vin_max*10)
|
||||
|
||||
#ifndef MODEL_MHP30
|
||||
#error "No model defined!"
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_MHP30
|
||||
#define SOLDERING_TEMP 200 // Default soldering temp is 200.0 °C
|
||||
#define VOLTAGE_DIV 360 // Default for MHP30
|
||||
#define PID_POWER_LIMIT 65 // Sets the max pwm power limit
|
||||
#define CALIBRATION_OFFSET 0 // the adc offset in uV - MHP compensates automagically
|
||||
#define POWER_LIMIT 65 // 65 watts default power limit
|
||||
#define MAX_POWER_LIMIT 65 //
|
||||
#define POWER_LIMIT_STEPS 1 //
|
||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_MHP30 //
|
||||
#define USB_PD_VMAX 20 // Maximum voltage for PD to negotiate
|
||||
#define MODEL_HAS_DCDC // Has inductor to current filter
|
||||
#define PID_TIM_HZ (16) //
|
||||
#define MAX_TEMP_C 300 // Max soldering temp selectable °C
|
||||
#define MAX_TEMP_F 570 // Max soldering temp selectable °F
|
||||
#define MIN_TEMP_C 10 // Min soldering temp selectable °C
|
||||
#define MIN_TEMP_F 60 // Min soldering temp selectable °F
|
||||
#define MIN_BOOST_TEMP_C 150 // The min settable temp for boost mode °C
|
||||
#define MIN_BOOST_TEMP_F 300 // The min settable temp for boost mode °F
|
||||
#define NO_DISPLAY_ROTATE // Disable OLED rotation by accel
|
||||
#define SLEW_LIMIT 50 // Limit to 3.0 Watts per 64ms pid loop update rate slew rate
|
||||
#define ACCEL_MSA
|
||||
#define POW_PD
|
||||
#define TEMP_NTC
|
||||
#define I2C_SOFT
|
||||
#define BATTFILTERDEPTH 8
|
||||
#define OLED_I2CBB
|
||||
#define ACCEL_EXITS_ON_MOVEMENT
|
||||
|
||||
#define HARDWARE_MAX_WATTAGE_X10 650
|
||||
#define TIP_THERMAL_MASS 65 // TODO, needs refinement
|
||||
#define tipResistance 60 // x10 ohms, ~6 typical
|
||||
#endif
|
||||
|
||||
#ifdef ACCEL_EXITS_ON_MOVEMENT
|
||||
#define NO_SLEEP_MODE
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "Model_Config.h"
|
||||
#include "configuration.h"
|
||||
#ifdef POW_PD
|
||||
#include "BSP.h"
|
||||
#include "I2C_Wrapper.hpp"
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
|
||||
#include "BSP.h"
|
||||
#include "I2CBB.hpp"
|
||||
#include "Model_Config.h"
|
||||
#include "Pins.h"
|
||||
#include "Setup.h"
|
||||
#include "configuration.h"
|
||||
#include "fusbpd.h"
|
||||
#include <I2C_Wrapper.hpp>
|
||||
|
||||
void preRToSInit() {
|
||||
/* Reset of all peripherals, Initializes the Flash interface and the Systick.
|
||||
*/
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include "BSP.h"
|
||||
#include "I2C_Wrapper.hpp"
|
||||
#include "Model_Config.h"
|
||||
#include "Pins.h"
|
||||
#include "Setup.h"
|
||||
#include "TipThermoModel.h"
|
||||
@@ -10,6 +9,7 @@
|
||||
#include "history.hpp"
|
||||
#include "main.hpp"
|
||||
#include <IRQ.h>
|
||||
|
||||
volatile uint16_t PWMSafetyTimer = 0;
|
||||
volatile uint8_t pendingPWM = 0;
|
||||
|
||||
@@ -21,9 +21,7 @@ uint16_t totalPWM; // htim2.Init.Period, the full PWM cycle
|
||||
|
||||
static bool fastPWM;
|
||||
|
||||
// 2 second filter (ADC is PID_TIM_HZ Hz)
|
||||
history<uint16_t, PID_TIM_HZ> rawTempFilter = {{0}, 0, 0};
|
||||
void resetWatchdog() { HAL_IWDG_Refresh(&hiwdg); }
|
||||
void resetWatchdog() { HAL_IWDG_Refresh(&hiwdg); }
|
||||
#ifdef TEMP_NTC
|
||||
// Lookup table for the NTC
|
||||
// Stored as ADCReading,Temp in degC
|
||||
@@ -135,48 +133,36 @@ uint16_t getInputVoltageX10(uint16_t divisor, uint8_t sample) {
|
||||
return res;
|
||||
}
|
||||
|
||||
void setTipPWM(uint8_t pulse) {
|
||||
PWMSafetyTimer = 10; // This is decremented in the handler for PWM so that the tip pwm is
|
||||
// disabled if the PID task is not scheduled often enough.
|
||||
|
||||
pendingPWM = pulse;
|
||||
}
|
||||
|
||||
static void switchToFastPWM(void) {
|
||||
fastPWM = true;
|
||||
totalPWM = powerPWM + tempMeasureTicks * 2 + holdoffTicks;
|
||||
htim2.Instance->ARR = totalPWM;
|
||||
// ~3.5 Hz rate
|
||||
htim2.Instance->CCR1 = powerPWM + holdoffTicks * 2;
|
||||
// 2 MHz timer clock/2000 = 1 kHz tick rate
|
||||
htim2.Instance->PSC = 2000;
|
||||
// 10Hz
|
||||
fastPWM = true;
|
||||
totalPWM = powerPWM + tempMeasureTicks + holdoffTicks;
|
||||
htim2.Instance->ARR = totalPWM;
|
||||
htim2.Instance->CCR1 = powerPWM + holdoffTicks;
|
||||
htim2.Instance->PSC = 2690;
|
||||
}
|
||||
|
||||
static void switchToSlowPWM(void) {
|
||||
fastPWM = false;
|
||||
totalPWM = powerPWM + tempMeasureTicks + holdoffTicks;
|
||||
htim2.Instance->ARR = totalPWM;
|
||||
// ~1.84 Hz rate
|
||||
htim2.Instance->CCR1 = powerPWM + holdoffTicks;
|
||||
// 2 MHz timer clock/4000 = 500 Hz tick rate
|
||||
htim2.Instance->PSC = 4000;
|
||||
// 5Hz
|
||||
fastPWM = false;
|
||||
totalPWM = powerPWM + tempMeasureTicks / 2 + holdoffTicks / 2;
|
||||
htim2.Instance->ARR = totalPWM;
|
||||
htim2.Instance->CCR1 = powerPWM + holdoffTicks / 2;
|
||||
htim2.Instance->PSC = 2690 * 2;
|
||||
}
|
||||
|
||||
bool tryBetterPWM(uint8_t pwm) {
|
||||
if (fastPWM && pwm == powerPWM) {
|
||||
// maximum power for fast PWM reached, need to go slower to get more
|
||||
switchToSlowPWM();
|
||||
return true;
|
||||
} else if (!fastPWM && pwm < 230) {
|
||||
// 254 in fast PWM mode gives the same power as 239 in slow
|
||||
// allow for some reasonable hysteresis by switching only when it goes
|
||||
// below 230 (equivalent to 245 in fast mode)
|
||||
switchToFastPWM();
|
||||
return true;
|
||||
void setTipPWM(const uint8_t pulse, const bool shouldUseFastModePWM) {
|
||||
PWMSafetyTimer = 10; // This is decremented in the handler for PWM so that the tip pwm is
|
||||
// disabled if the PID task is not scheduled often enough.
|
||||
pendingPWM = pulse;
|
||||
if (fastPWM != shouldUseFastModePWM) {
|
||||
if (shouldUseFastModePWM) {
|
||||
switchToFastPWM();
|
||||
} else {
|
||||
switchToSlowPWM();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// These are called by the HAL after the corresponding events from the system
|
||||
// timers.
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Model_Config.h
|
||||
*
|
||||
* Created on: 25 Jul 2020
|
||||
* Author: Ralim
|
||||
*/
|
||||
|
||||
#ifndef BSP_MINIWARE_MODEL_CONFIG_H_
|
||||
#define BSP_MINIWARE_MODEL_CONFIG_H_
|
||||
/*
|
||||
* Lookup for mapping features <-> Models
|
||||
*/
|
||||
|
||||
#if defined(MODEL_TS100) + defined(MODEL_TS80) + defined(MODEL_TS80P) > 1
|
||||
#error "Multiple models defined!"
|
||||
#elif defined(MODEL_TS100) + defined(MODEL_TS80) + defined(MODEL_TS80P) == 0
|
||||
#error "No model defined!"
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_TS100
|
||||
#define POW_DC
|
||||
#define ACCEL_MMA
|
||||
#define ACCEL_LIS
|
||||
#define TEMP_TMP36
|
||||
#define BATTFILTERDEPTH 32
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_TS80
|
||||
#define ACCEL_LIS
|
||||
#define POW_QC
|
||||
#define TEMP_TMP36
|
||||
#define LIS_ORI_FLIP
|
||||
#define OLED_FLIP
|
||||
#define BATTFILTERDEPTH 8
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_TS80P
|
||||
#define ACCEL_LIS
|
||||
#define ACCEL_MSA
|
||||
#define POW_PD
|
||||
#define POW_QC
|
||||
#define TEMP_NTC
|
||||
#define I2C_SOFT
|
||||
#define LIS_ORI_FLIP
|
||||
#define OLED_FLIP
|
||||
#define BATTFILTERDEPTH 8
|
||||
#endif
|
||||
|
||||
#endif /* BSP_MINIWARE_MODEL_CONFIG_H_ */
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#ifndef BSP_MINIWARE_PINS_H_
|
||||
#define BSP_MINIWARE_PINS_H_
|
||||
#include "Model_Config.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef MODEL_TS100
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "BSP.h"
|
||||
#include "BSP_Power.h"
|
||||
#include "Model_Config.h"
|
||||
#include "Pins.h"
|
||||
#include "QC3.h"
|
||||
#include "Settings.h"
|
||||
#include "configuration.h"
|
||||
#include "fusb_user.h"
|
||||
#include "fusbpd.h"
|
||||
#include "int_n.h"
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
* Author: Ralim
|
||||
*/
|
||||
#include "BSP.h"
|
||||
#include "Model_Config.h"
|
||||
#include "Pins.h"
|
||||
#include "QC3.h"
|
||||
#include "Settings.h"
|
||||
#include "configuration.h"
|
||||
#include "stm32f1xx_hal.h"
|
||||
|
||||
#ifdef POW_QC
|
||||
void QC_DPlusZero_Six() {
|
||||
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET); // pull down D+
|
||||
|
||||
@@ -20,7 +20,7 @@ DMA_HandleTypeDef hdma_i2c1_tx;
|
||||
IWDG_HandleTypeDef hiwdg;
|
||||
TIM_HandleTypeDef htim2;
|
||||
TIM_HandleTypeDef htim3;
|
||||
#define ADC_FILTER_LEN 32
|
||||
#define ADC_FILTER_LEN 4
|
||||
#define ADC_SAMPLES 16
|
||||
uint16_t ADCReadings[ADC_SAMPLES]; // Used to store the adc readings for the handle cold junction temp
|
||||
|
||||
@@ -326,7 +326,8 @@ static void MX_TIM2_Init(void) {
|
||||
// These values give a rate of around 3.5 Hz for "fast" mode and 1.84 Hz for "slow"
|
||||
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
// dummy value, will be reconfigured by BSPInit()
|
||||
htim2.Init.Period = 255 + 17 * 2;
|
||||
htim2.Init.Period = powerPWM + 14 * 2;
|
||||
|
||||
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4; // 8 MHz (x2 APB1) before divide
|
||||
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||
htim2.Init.RepetitionCounter = 0;
|
||||
@@ -344,7 +345,7 @@ static void MX_TIM2_Init(void) {
|
||||
|
||||
sConfigOC.OCMode = TIM_OCMODE_PWM1;
|
||||
// dummy value, will be reconfigured by BSPInit() in the BSP.cpp
|
||||
sConfigOC.Pulse = 255 + 13 * 2; // 13 -> Delay of 7 ms
|
||||
sConfigOC.Pulse = powerPWM + 14; // 13 -> Delay of 7 ms
|
||||
// 255 is the largest time period of the drive signal, and then offset ADC sample to be a bit delayed after this
|
||||
/*
|
||||
* It takes 4 milliseconds for output to be stable after PWM turns off.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#ifndef BSP_MINIWARE_SOFTWARE_I2C_H_
|
||||
#define BSP_MINIWARE_SOFTWARE_I2C_H_
|
||||
#include "BSP.h"
|
||||
#include "Model_Config.h"
|
||||
#include "configuration.h"
|
||||
#include "stm32f1xx_hal.h"
|
||||
#ifdef I2C_SOFT
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
#include "Model_Config.h"
|
||||
#ifndef CONFIGURATION_H_
|
||||
#define CONFIGURATION_H_
|
||||
#include "Settings.h"
|
||||
#include <stdint.h>
|
||||
/**
|
||||
* Configuration.h
|
||||
* Define here your default pre settings for TS80 or TS100
|
||||
* Define here your default pre settings for TS80(P) or TS100
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
*
|
||||
*/
|
||||
#define ORIENTATION_MODE 0 // 0: Right 1:Left 2:Automatic - Default right
|
||||
#define REVERSE_BUTTON_TEMP_CHANGE 0 // 0:Default 1:Reverse - Reverse the plus and minus button assigment for temperatur change
|
||||
#define REVERSE_BUTTON_TEMP_CHANGE 0 // 0:Default 1:Reverse - Reverse the plus and minus button assigment for temperature change
|
||||
|
||||
/**
|
||||
* Temp change settings
|
||||
@@ -114,14 +114,16 @@
|
||||
|
||||
#define OP_AMP_GAIN_STAGE_TS80 (1 + (OP_AMP_Rf_TS80 / OP_AMP_Rin_TS80))
|
||||
|
||||
#define OP_AMP_Rf_MHP30 268500 // 268.5 Kilo-ohms -> Measured
|
||||
#define OP_AMP_Rin_MHP30 1600 // 1.6 Kilo-ohms -> Measured
|
||||
|
||||
#define OP_AMP_GAIN_STAGE_MHP30 (1 + (OP_AMP_Rf_MHP30 / OP_AMP_Rin_MHP30))
|
||||
// Deriving the Voltage div:
|
||||
// Vin_max = (3.3*(r1+r2))/(r2)
|
||||
// vdiv = (32768*4)/(vin_max*10)
|
||||
|
||||
#if defined(MODEL_TS100) + defined(MODEL_TS80) + defined(MODEL_TS80P) > 1
|
||||
#error "Multiple models defined!"
|
||||
#elif defined(MODEL_TS100) + defined(MODEL_TS80) + defined(MODEL_TS80P) == 0
|
||||
#error "No model defined!"
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_TS100
|
||||
#define SOLDERING_TEMP 320 // Default soldering temp is 320.0 °C
|
||||
#define VOLTAGE_DIV 467 // 467 - Default divider from schematic
|
||||
@@ -140,26 +142,10 @@
|
||||
#define MIN_TEMP_F 60 // Min soldering temp selectable °F
|
||||
#define MIN_BOOST_TEMP_C 250 // The min settable temp for boost mode °C
|
||||
#define MIN_BOOST_TEMP_F 480 // The min settable temp for boost mode °F
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_Pinecil
|
||||
#define SOLDERING_TEMP 320 // Default soldering temp is 320.0 °C
|
||||
#define VOLTAGE_DIV 467 // 467 - Default divider from schematic
|
||||
#define CALIBRATION_OFFSET 900 // 900 - Default adc offset in uV
|
||||
#define PID_POWER_LIMIT 70 // Sets the max pwm power limit
|
||||
#define POWER_LIMIT 0 // 0 watts default limit
|
||||
#define MAX_POWER_LIMIT 65 //
|
||||
#define POWER_LIMIT_STEPS 5 //
|
||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS100 // Uses TS100 resistors
|
||||
#define TEMP_uV_LOOKUP_HAKKO // Use Hakko lookup table
|
||||
#define USB_PD_VMAX 20 // Maximum voltage for PD to negotiate
|
||||
#define PID_TIM_HZ (8) // Tick rate of the PID loop
|
||||
#define MAX_TEMP_C 450 // Max soldering temp selectable °C
|
||||
#define MAX_TEMP_F 850 // Max soldering temp selectable °F
|
||||
#define MIN_TEMP_C 10 // Min soldering temp selectable °C
|
||||
#define MIN_TEMP_F 60 // Min soldering temp selectable °F
|
||||
#define MIN_BOOST_TEMP_C 250 // The min settable temp for boost mode °C
|
||||
#define MIN_BOOST_TEMP_F 480 // The min settable temp for boost mode °F
|
||||
#define POW_DC
|
||||
#define ACCEL_MMA
|
||||
#define ACCEL_LIS
|
||||
#define TEMP_TMP36
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_TS80
|
||||
@@ -180,6 +166,11 @@
|
||||
#define MIN_TEMP_F 60 // Min soldering temp selectable °F
|
||||
#define MIN_BOOST_TEMP_C 250 // The min settable temp for boost mode °C
|
||||
#define MIN_BOOST_TEMP_F 480 // The min settable temp for boost mode °F
|
||||
#define ACCEL_LIS
|
||||
#define POW_QC
|
||||
#define TEMP_TMP36
|
||||
#define LIS_ORI_FLIP
|
||||
#define OLED_FLIP
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_TS80P
|
||||
@@ -200,59 +191,31 @@
|
||||
#define MIN_TEMP_F 60 // Min soldering temp selectable °F
|
||||
#define MIN_BOOST_TEMP_C 250 // The min settable temp for boost mode °C
|
||||
#define MIN_BOOST_TEMP_F 480 // The min settable temp for boost mode °F
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_MHP30
|
||||
#define SOLDERING_TEMP 200 // Default soldering temp is 200.0 °C
|
||||
#define VOLTAGE_DIV 360 // Default for MHP30
|
||||
#define PID_POWER_LIMIT 65 // Sets the max pwm power limit
|
||||
#define CALIBRATION_OFFSET 0 // the adc offset in uV - MHP compensates automagically
|
||||
#define POWER_LIMIT 65 // 65 watts default power limit
|
||||
#define MAX_POWER_LIMIT 65 //
|
||||
#define POWER_LIMIT_STEPS 1 //
|
||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_MHP30 //
|
||||
#define USB_PD_VMAX 20 // Maximum voltage for PD to negotiate
|
||||
#define MODEL_HAS_DCDC // Has inductor to current filter
|
||||
#define PID_TIM_HZ (16) //
|
||||
#define THERMAL_MASS_OVERSHOOTS // We have overshoot so reverse direction of compensation
|
||||
#define MAX_TEMP_C 300 // Max soldering temp selectable °C
|
||||
#define MAX_TEMP_F 570 // Max soldering temp selectable °F
|
||||
#define MIN_TEMP_C 10 // Min soldering temp selectable °C
|
||||
#define MIN_TEMP_F 60 // Min soldering temp selectable °F
|
||||
#define MIN_BOOST_TEMP_C 150 // The min settable temp for boost mode °C
|
||||
#define MIN_BOOST_TEMP_F 300 // The min settable temp for boost mode °F
|
||||
#define NO_DISPLAY_ROTATE // Disable OLED rotation by accel
|
||||
#define SLEW_LIMIT 50 // Limit to 3.0 Watts per 64ms pid loop update rate slew rate
|
||||
#define ACCEL_LIS
|
||||
#define ACCEL_MSA
|
||||
#define POW_PD
|
||||
#define POW_QC
|
||||
#define TEMP_NTC
|
||||
#define I2C_SOFT
|
||||
#define LIS_ORI_FLIP
|
||||
#define OLED_FLIP
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_TS100
|
||||
const int32_t tipMass = 65; // X10 watts to raise 1 deg C in 1 second
|
||||
const uint8_t tipResistance = 75; // x10 ohms, 7.5 typical for ts100 tips
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_Pinecil
|
||||
const int32_t tipMass = 45; // X10 watts to raise 1 deg C in 1 second
|
||||
const uint8_t tipResistance = 75; // x10 ohms, 7.5 typical for ts100 tips
|
||||
#define HARDWARE_MAX_WATTAGE_X10 750
|
||||
#define TIP_THERMAL_MASS 65 // X10 watts to raise 1 deg C in 1 second
|
||||
#define tipResistance 75 // x10 ohms, 7.5 typical for ts100 tips
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_TS80
|
||||
const uint32_t tipMass = 40;
|
||||
const uint8_t tipResistance = 45; // x10 ohms, 4.5 typical for ts80 tips
|
||||
#define HARDWARE_MAX_WATTAGE_X10 180
|
||||
#define TIP_THERMAL_MASS 40
|
||||
#define tipResistance 45 // x10 ohms, 4.5 typical for ts80 tips
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_TS80P
|
||||
const uint32_t tipMass = 40;
|
||||
const uint8_t tipResistance = 45; // x10 ohms, 4.5 typical for ts80 tips
|
||||
#define HARDWARE_MAX_WATTAGE_X10 300
|
||||
#define TIP_THERMAL_MASS 40
|
||||
#define tipResistance 45 // x10 ohms, 4.5 typical for ts80 tips
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_MHP30
|
||||
const uint32_t tipMass = 45; // TODO
|
||||
const uint8_t tipResistance = 60; // x10 ohms, ~6 typical
|
||||
#endif
|
||||
|
||||
#ifdef POW_QC_20V
|
||||
#define QC_SETTINGS_MAX 3
|
||||
#else
|
||||
#define QC_SETTINGS_MAX 2
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "Model_Config.h"
|
||||
#include "configuration.h"
|
||||
#ifdef POW_PD
|
||||
#include "BSP.h"
|
||||
#include "I2CBB.hpp"
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
|
||||
#include "BSP.h"
|
||||
#include "I2CBB.hpp"
|
||||
#include "Model_Config.h"
|
||||
#include "Pins.h"
|
||||
#include "Setup.h"
|
||||
#include "configuration.h"
|
||||
#include "fusbpd.h"
|
||||
#include <I2C_Wrapper.hpp>
|
||||
|
||||
void preRToSInit() {
|
||||
/* Reset of all peripherals, Initializes the Flash interface and the Systick.
|
||||
*/
|
||||
|
||||
@@ -12,14 +12,12 @@
|
||||
#include "main.hpp"
|
||||
|
||||
const uint16_t powerPWM = 255;
|
||||
const uint8_t holdoffTicks = 25; // delay of 7 ms
|
||||
const uint8_t tempMeasureTicks = 25;
|
||||
const uint8_t holdoffTicks = 10;
|
||||
const uint8_t tempMeasureTicks = 14;
|
||||
|
||||
uint16_t totalPWM; // htim2.Init.Period, the full PWM cycle
|
||||
uint16_t totalPWM; // Total length of the cycle's ticks
|
||||
|
||||
// 2 second filter (ADC is PID_TIM_HZ Hz)
|
||||
history<uint16_t, PID_TIM_HZ> rawTempFilter = {{0}, 0, 0};
|
||||
void resetWatchdog() { fwdgt_counter_reload(); }
|
||||
void resetWatchdog() { fwdgt_counter_reload(); }
|
||||
|
||||
uint16_t getHandleTemperature(uint8_t sample) {
|
||||
#ifdef TEMP_TMP36
|
||||
|
||||
@@ -18,6 +18,9 @@ volatile uint16_t i2c_nbytes;
|
||||
volatile uint16_t i2c_write_dress;
|
||||
volatile uint16_t i2c_read_dress;
|
||||
volatile uint8_t i2c_process_flag = 0;
|
||||
static bool fastPWM;
|
||||
static void switchToSlowPWM(void);
|
||||
static void switchToFastPWM(void);
|
||||
void ADC0_1_IRQHandler(void) {
|
||||
|
||||
adc_interrupt_flag_clear(ADC0, ADC_INT_FLAG_EOIC);
|
||||
@@ -34,74 +37,58 @@ void ADC0_1_IRQHandler(void) {
|
||||
volatile uint16_t PWMSafetyTimer = 0;
|
||||
volatile uint8_t pendingPWM = 0;
|
||||
void TIMER1_IRQHandler(void) {
|
||||
static bool lastPeriodWasFast = false;
|
||||
|
||||
if (timer_interrupt_flag_get(TIMER1, TIMER_INT_UP) == SET) {
|
||||
timer_interrupt_flag_clear(TIMER1, TIMER_INT_UP);
|
||||
// rollover turn on output if required
|
||||
if (PWMSafetyTimer && pendingPWM) {
|
||||
timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_0, 50);
|
||||
}
|
||||
if (PWMSafetyTimer) {
|
||||
PWMSafetyTimer--;
|
||||
if (lastPeriodWasFast != fastPWM) {
|
||||
if (fastPWM) {
|
||||
switchToFastPWM();
|
||||
} else {
|
||||
switchToSlowPWM();
|
||||
}
|
||||
}
|
||||
if (pendingPWM) {
|
||||
timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_1, pendingPWM);
|
||||
timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_0, 50);
|
||||
} else {
|
||||
timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (timer_interrupt_flag_get(TIMER1, TIMER_INT_CH1) == SET) {
|
||||
timer_interrupt_flag_clear(TIMER1, TIMER_INT_CH1);
|
||||
// This is triggered on pwm setpoint trigger; we want to copy the pending
|
||||
// PWM value into the output control reg
|
||||
|
||||
timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_0, 0);
|
||||
if (pendingPWM) {
|
||||
timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_1, pendingPWM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setTipPWM(uint8_t pulse) {
|
||||
void switchToFastPWM(void) {
|
||||
fastPWM = true;
|
||||
totalPWM = powerPWM + tempMeasureTicks + holdoffTicks;
|
||||
TIMER_CAR(TIMER1) = (uint32_t)totalPWM;
|
||||
|
||||
// ~10Hz
|
||||
TIMER_CH0CV(TIMER1) = powerPWM + holdoffTicks;
|
||||
// 1 kHz tick rate
|
||||
TIMER_PSC(TIMER1) = 18000;
|
||||
}
|
||||
|
||||
void switchToSlowPWM(void) {
|
||||
// 5Hz
|
||||
fastPWM = false;
|
||||
totalPWM = powerPWM + tempMeasureTicks / 2 + holdoffTicks / 2;
|
||||
TIMER_CAR(TIMER1) = (uint32_t)totalPWM;
|
||||
TIMER_CH0CV(TIMER1) = powerPWM + holdoffTicks / 2;
|
||||
TIMER_PSC(TIMER1) = 36000;
|
||||
}
|
||||
void setTipPWM(const uint8_t pulse, const bool shouldUseFastModePWM) {
|
||||
PWMSafetyTimer = 10; // This is decremented in the handler for PWM so that the tip pwm is
|
||||
// disabled if the PID task is not scheduled often enough.
|
||||
pendingPWM = pulse;
|
||||
}
|
||||
|
||||
static bool fastPWM;
|
||||
static void switchToFastPWM(void) {
|
||||
fastPWM = true;
|
||||
totalPWM = powerPWM + tempMeasureTicks * 2;
|
||||
TIMER_CAR(TIMER1) = (uint32_t)totalPWM;
|
||||
|
||||
// ~3.5 Hz rate
|
||||
TIMER_CH0CV(TIMER1) = powerPWM + holdoffTicks * 2;
|
||||
// 1 kHz tick rate
|
||||
TIMER_PSC(TIMER1) = 12000;
|
||||
/* generate an update event */
|
||||
TIMER_SWEVG(TIMER1) |= (uint32_t)TIMER_SWEVG_UPG;
|
||||
}
|
||||
|
||||
static void switchToSlowPWM(void) {
|
||||
fastPWM = false;
|
||||
totalPWM = powerPWM + tempMeasureTicks;
|
||||
TIMER_CAR(TIMER1) = (uint32_t)totalPWM;
|
||||
// ~1.84 Hz rate
|
||||
TIMER_CH0CV(TIMER1) = powerPWM + holdoffTicks;
|
||||
// 500 Hz tick rate
|
||||
TIMER_PSC(TIMER1) = 24000;
|
||||
/* generate an update event */
|
||||
TIMER_SWEVG(TIMER1) |= (uint32_t)TIMER_SWEVG_UPG;
|
||||
}
|
||||
|
||||
bool tryBetterPWM(uint8_t pwm) {
|
||||
if (fastPWM && pwm == powerPWM) {
|
||||
// maximum power for fast PWM reached, need to go slower to get more
|
||||
switchToSlowPWM();
|
||||
return true;
|
||||
} else if (!fastPWM && pwm < 230) {
|
||||
// 254 in fast PWM mode gives the same power as 239 in slow
|
||||
// allow for some reasonable hysteresis by switching only when it goes
|
||||
// below 230 (equivalent to 245 in fast mode)
|
||||
switchToFastPWM();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
fastPWM = shouldUseFastModePWM;
|
||||
}
|
||||
|
||||
void EXTI5_9_IRQHandler(void) {
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Model_Config.h
|
||||
*
|
||||
* Created on: 25 Jul 2020
|
||||
* Author: Ralim
|
||||
*/
|
||||
|
||||
#ifndef BSP_PINE64_MODEL_CONFIG_H_
|
||||
#define BSP_PINE64_MODEL_CONFIG_H_
|
||||
/*
|
||||
* Lookup for mapping features <-> Models
|
||||
*/
|
||||
|
||||
#if defined(MODEL_Pinecil) == 0
|
||||
#error "No model defined!"
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_Pinecil
|
||||
#define POW_PD
|
||||
#define POW_QC
|
||||
#define POW_DC
|
||||
#define POW_QC_20V
|
||||
#define ENABLE_QC2
|
||||
#define TEMP_TMP36
|
||||
#define ACCEL_BMA
|
||||
#define ACCEL_SC7
|
||||
#define HALL_SENSOR
|
||||
#define HALL_SI7210
|
||||
#define BATTFILTERDEPTH 32
|
||||
#define DEBUG_UART_OUTPUT
|
||||
#endif
|
||||
|
||||
#endif /* BSP_PINE64_MODEL_CONFIG_H_ */
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "BSP.h"
|
||||
#include "BSP_Power.h"
|
||||
#include "Model_Config.h"
|
||||
#include "Pins.h"
|
||||
#include "QC3.h"
|
||||
#include "Settings.h"
|
||||
#include "configuration.h"
|
||||
#include "fusb_user.h"
|
||||
#include "fusbpd.h"
|
||||
#include "int_n.h"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "history.hpp"
|
||||
#include <string.h>
|
||||
#define ADC_NORM_SAMPLES 16
|
||||
#define ADC_FILTER_LEN 32
|
||||
#define ADC_FILTER_LEN 4
|
||||
uint16_t ADCReadings[ADC_NORM_SAMPLES]; // room for 32 lots of the pair of readings
|
||||
|
||||
// Functions
|
||||
@@ -264,17 +264,17 @@ void setup_timers() {
|
||||
/* initialize TIMER init parameter struct */
|
||||
timer_struct_para_init(&timer_initpara);
|
||||
/* TIMER1 configuration */
|
||||
timer_initpara.prescaler = 5000;
|
||||
timer_initpara.prescaler = 30000;
|
||||
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
|
||||
timer_initpara.counterdirection = TIMER_COUNTER_UP;
|
||||
timer_initpara.period = powerPWM + tempMeasureTicks;
|
||||
timer_initpara.period = powerPWM + tempMeasureTicks + holdoffTicks;
|
||||
timer_initpara.clockdivision = TIMER_CKDIV_DIV4;
|
||||
timer_initpara.repetitioncounter = 0;
|
||||
timer_init(TIMER1, &timer_initpara);
|
||||
|
||||
/* CH0 configured to implement the PWM irq's for the output control*/
|
||||
timer_channel_output_struct_para_init(&timer_ocintpara);
|
||||
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
|
||||
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_LOW;
|
||||
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
|
||||
timer_channel_output_config(TIMER1, TIMER_CH_0, &timer_ocintpara);
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ static void system_clock_108m_hxtal(void) {
|
||||
/* APB2 = AHB/1 */
|
||||
RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
|
||||
/* APB1 = AHB/2 */
|
||||
RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
|
||||
RCU_CFG0 |= RCU_APB1_CKAHB_DIV4;
|
||||
|
||||
/* CK_PLL = (CK_PREDIV0) * 27 = 108 MHz */
|
||||
RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
|
||||
|
||||
151
source/Core/BSP/Pine64/configuration.h
Normal file
151
source/Core/BSP/Pine64/configuration.h
Normal file
@@ -0,0 +1,151 @@
|
||||
#ifndef CONFIGURATION_H_
|
||||
#define CONFIGURATION_H_
|
||||
#include "Settings.h"
|
||||
#include <stdint.h>
|
||||
/**
|
||||
* Configuration.h
|
||||
* Define here your default pre settings for Pinecil
|
||||
*
|
||||
*/
|
||||
|
||||
//===========================================================================
|
||||
//============================= Default Settings ============================
|
||||
//===========================================================================
|
||||
/**
|
||||
* Default soldering temp is 320.0 C
|
||||
* Temperature the iron sleeps at - default 150.0 C
|
||||
*/
|
||||
|
||||
#define SLEEP_TEMP 150 // Default sleep temperature
|
||||
#define BOOST_TEMP 420 // Default boost temp.
|
||||
#define BOOST_MODE_ENABLED 1 // 0: Disable 1: Enable
|
||||
|
||||
/**
|
||||
* Blink the temperature on the cooling screen when its > 50C
|
||||
*/
|
||||
#define COOLING_TEMP_BLINK 0 // 0: Disable 1: Enable
|
||||
|
||||
/**
|
||||
* How many seconds/minutes we wait until going to sleep/shutdown.
|
||||
* Values -> SLEEP_TIME * 10; i.e. 5*10 = 50 Seconds!
|
||||
*/
|
||||
#define SLEEP_TIME 5 // x10 Seconds
|
||||
#define SHUTDOWN_TIME 10 // Minutes
|
||||
|
||||
/**
|
||||
* Auto start off for safety.
|
||||
* Pissible values are:
|
||||
* 0 - none
|
||||
* 1 - Soldering Temperature
|
||||
* 2 - Sleep Temperature
|
||||
* 3 - Sleep Off Temperature
|
||||
*/
|
||||
#define AUTO_START_MODE 0 // Default to none
|
||||
|
||||
/**
|
||||
* Locking Mode
|
||||
* When in soldering mode a long press on both keys toggle the lock of the buttons
|
||||
* Possible values are:
|
||||
* 0 - Desactivated
|
||||
* 1 - Lock except boost
|
||||
* 2 - Full lock
|
||||
*/
|
||||
#define LOCKING_MODE 0 // Default to desactivated for safety
|
||||
|
||||
/**
|
||||
* OLED Orientation
|
||||
*
|
||||
*/
|
||||
#define ORIENTATION_MODE 0 // 0: Right 1:Left 2:Automatic - Default right
|
||||
#define REVERSE_BUTTON_TEMP_CHANGE 0 // 0:Default 1:Reverse - Reverse the plus and minus button assigment for temperature change
|
||||
|
||||
/**
|
||||
* Temp change settings
|
||||
*/
|
||||
#define TEMP_CHANGE_SHORT_STEP 1 // Default temp change short step +1
|
||||
#define TEMP_CHANGE_LONG_STEP 10 // Default temp change long step +10
|
||||
#define TEMP_CHANGE_SHORT_STEP_MAX 50 // Temp change short step MAX value
|
||||
#define TEMP_CHANGE_LONG_STEP_MAX 90 // Temp change long step MAX value
|
||||
|
||||
/* Power pulse for keeping power banks awake*/
|
||||
#define POWER_PULSE_INCREMENT 1
|
||||
#define POWER_PULSE_MAX 100 // x10 max watts
|
||||
#define POWER_PULSE_WAIT_MAX 9 // 9*2.5s = 22.5 seconds
|
||||
#define POWER_PULSE_DURATION_MAX 9 // 9*250ms = 2.25 seconds
|
||||
|
||||
#ifdef MODEL_Pinecil
|
||||
#define POWER_PULSE_DEFAULT 0
|
||||
#else
|
||||
#define POWER_PULSE_DEFAULT 5
|
||||
#endif
|
||||
#define POWER_PULSE_WAIT_DEFAULT 4 // Default rate of the power pulse: 4*2500 = 10000 ms = 10 s
|
||||
#define POWER_PULSE_DURATION_DEFAULT 1 // Default duration of the power pulse: 1*250 = 250 ms
|
||||
|
||||
/**
|
||||
* OLED Orientation Sensitivity on Automatic mode!
|
||||
* Motion Sensitivity <0=Off 1=Least Sensitive 9=Most Sensitive>
|
||||
*/
|
||||
#define SENSITIVITY 7 // Default 7
|
||||
|
||||
/**
|
||||
* Detailed soldering screen
|
||||
* Detailed idle screen (off for first time users)
|
||||
*/
|
||||
#define DETAILED_SOLDERING 0 // 0: Disable 1: Enable - Default 0
|
||||
#define DETAILED_IDLE 0 // 0: Disable 1: Enable - Default 0
|
||||
|
||||
#define THERMAL_RUNAWAY_TIME_SEC 20
|
||||
#define THERMAL_RUNAWAY_TEMP_C 20
|
||||
|
||||
#define CUT_OUT_SETTING 0 // default to no cut-off voltage
|
||||
#define RECOM_VOL_CELL 33 // Minimum voltage per cell (Recommended 3.3V (33))
|
||||
#define TEMPERATURE_INF 0 // default to 0
|
||||
#define DESCRIPTION_SCROLL_SPEED 0 // 0: Slow 1: Fast - default to slow
|
||||
#define ANIMATION_LOOP 1 // 0: off 1: on
|
||||
#define ANIMATION_SPEED settingOffSpeed_t::MEDIUM
|
||||
|
||||
#define OP_AMP_Rf_Pinecil 750 * 1000 // 750 Kilo-ohms -> From schematic, R1
|
||||
#define OP_AMP_Rin_Pinecil 2370 // 2.37 Kilo-ohms -> From schematic, R2
|
||||
|
||||
#define OP_AMP_GAIN_STAGE_PINECIL (1 + (OP_AMP_Rf_Pinecil / OP_AMP_Rin_Pinecil))
|
||||
|
||||
#if defined(MODEL_Pinecil) == 0
|
||||
#error "No model defined!"
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_Pinecil
|
||||
#define SOLDERING_TEMP 320 // Default soldering temp is 320.0 °C
|
||||
#define VOLTAGE_DIV 467 // 467 - Default divider from schematic
|
||||
#define CALIBRATION_OFFSET 900 // 900 - Default adc offset in uV
|
||||
#define PID_POWER_LIMIT 70 // Sets the max pwm power limit
|
||||
#define POWER_LIMIT 0 // 0 watts default limit
|
||||
#define MAX_POWER_LIMIT 65 //
|
||||
#define POWER_LIMIT_STEPS 5 //
|
||||
#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_PINECIL // Uses Pinecil resistors
|
||||
#define TEMP_uV_LOOKUP_HAKKO // Use Hakko lookup table
|
||||
#define USB_PD_VMAX 20 // Maximum voltage for PD to negotiate
|
||||
#define PID_TIM_HZ (8) // Tick rate of the PID loop
|
||||
#define MAX_TEMP_C 450 // Max soldering temp selectable °C
|
||||
#define MAX_TEMP_F 850 // Max soldering temp selectable °F
|
||||
#define MIN_TEMP_C 10 // Min soldering temp selectable °C
|
||||
#define MIN_TEMP_F 60 // Min soldering temp selectable °F
|
||||
#define MIN_BOOST_TEMP_C 250 // The min settable temp for boost mode °C
|
||||
#define MIN_BOOST_TEMP_F 480 // The min settable temp for boost mode °F
|
||||
|
||||
#define POW_PD
|
||||
#define POW_QC
|
||||
#define POW_DC
|
||||
#define POW_QC_20V
|
||||
#define ENABLE_QC2
|
||||
#define TEMP_TMP36
|
||||
#define ACCEL_BMA
|
||||
#define ACCEL_SC7
|
||||
#define HALL_SENSOR
|
||||
#define HALL_SI7210
|
||||
#define DEBUG_UART_OUTPUT
|
||||
|
||||
#define HARDWARE_MAX_WATTAGE_X10 750
|
||||
#define TIP_THERMAL_MASS 65 // X10 watts to raise 1 deg C in 1 second
|
||||
#define tipResistance 75 // x10 ohms, 7.5 typical for Pinecil tips
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "Model_Config.h"
|
||||
#include "configuration.h"
|
||||
#ifdef POW_PD
|
||||
#include "BSP.h"
|
||||
#include "I2C_Wrapper.hpp"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Created on: 13 Jun 2020
|
||||
* Author: Ralim
|
||||
*/
|
||||
#include "Model_Config.h"
|
||||
#include "configuration.h"
|
||||
#ifdef POW_PD
|
||||
#include "BSP.h"
|
||||
#include "I2CBB.hpp"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Created on: 12 Jun 2020
|
||||
* Author: Ralim
|
||||
*/
|
||||
#include "Model_Config.h"
|
||||
#include "configuration.h"
|
||||
#ifdef I2C_SOFT
|
||||
#include "FreeRTOS.h"
|
||||
#include <I2CBB.hpp>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#ifndef BSP_MINIWARE_I2CBB_HPP_
|
||||
#define BSP_MINIWARE_I2CBB_HPP_
|
||||
#include "Model_Config.h"
|
||||
#include "configuration.h"
|
||||
#ifdef I2C_SOFT
|
||||
#include "BSP.h"
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef OLED_HPP_
|
||||
#define OLED_HPP_
|
||||
#include "Font.h"
|
||||
#include "Model_Config.h"
|
||||
#include "configuration.h"
|
||||
#include <BSP.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -72,14 +72,11 @@ uint32_t TipThermoModel::convertFtoC(uint32_t degF) {
|
||||
uint32_t TipThermoModel::getTipInC(bool sampleNow) {
|
||||
int32_t currentTipTempInC = TipThermoModel::convertTipRawADCToDegC(getTipRawTemp(sampleNow));
|
||||
currentTipTempInC += getHandleTemperature(sampleNow) / 10; // Add handle offset
|
||||
// Power usage indicates that our tip temp is lower than our thermocouple temp.
|
||||
// I found a number that doesn't unbalance the existing PID, causing overshoot.
|
||||
// This could be tuned in concert with PID parameters...
|
||||
#ifdef THERMAL_MASS_OVERSHOOTS
|
||||
currentTipTempInC += x10WattHistory.average() / 25;
|
||||
#else
|
||||
currentTipTempInC -= x10WattHistory.average() / 25;
|
||||
#endif
|
||||
|
||||
// Power usage indicates that our tip temp is lower than our thermocouple temp.
|
||||
// I found a number that doesn't unbalance the existing PID, causing overshoot.
|
||||
// This could be tuned in concert with PID parameters...
|
||||
|
||||
if (currentTipTempInC < 0)
|
||||
return 0;
|
||||
return currentTipTempInC;
|
||||
@@ -92,7 +89,7 @@ uint32_t TipThermoModel::getTipInF(bool sampleNow) {
|
||||
}
|
||||
|
||||
uint32_t TipThermoModel::getTipMaxInC() {
|
||||
uint32_t maximumTipTemp = TipThermoModel::convertTipRawADCToDegC(0x7FFF - (21 * 5)); // back off approx 5 deg c from ADC max
|
||||
uint32_t maximumTipTemp = TipThermoModel::convertTipRawADCToDegC(0x7FFF - (21 * 3)); // back off approx 5 deg c from ADC max
|
||||
maximumTipTemp += getHandleTemperature(0) / 10; // Add handle offset
|
||||
return maximumTipTemp - 1;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
const uint8_t wattHistoryFilter = 24; // I term look back weighting
|
||||
extern expMovingAverage<uint32_t, wattHistoryFilter> x10WattHistory;
|
||||
|
||||
int32_t tempToX10Watts(int32_t rawTemp);
|
||||
void setTipX10Watts(int32_t mw);
|
||||
uint8_t X10WattsToPWM(int32_t milliWatts, uint8_t sample = 0);
|
||||
uint32_t availableW10(uint8_t sample);
|
||||
int32_t tempToX10Watts(int32_t rawTemp);
|
||||
void setTipX10Watts(int32_t mw);
|
||||
uint8_t X10WattsToPWM(int32_t milliWatts, uint8_t sample = 0);
|
||||
#endif /* POWER_HPP_ */
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
// Quick charge 3.0 supporting functions
|
||||
#include "QC3.h"
|
||||
|
||||
#include "BSP.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "configuration.h"
|
||||
#include "stdint.h"
|
||||
enum QCState {
|
||||
NOT_STARTED = 0, // Have not checked
|
||||
@@ -70,7 +70,7 @@ void seekQC(int16_t Vx10, uint16_t divisor) {
|
||||
// try and step towards the wanted value
|
||||
|
||||
// 1. Measure current voltage
|
||||
int16_t vStart = getInputVoltageX10(divisor, 1);
|
||||
int16_t vStart = getInputVoltageX10(divisor, 0);
|
||||
int difference = Vx10 - vStart;
|
||||
|
||||
// 2. calculate ideal steps (0.2V changes)
|
||||
@@ -94,7 +94,7 @@ void seekQC(int16_t Vx10, uint16_t divisor) {
|
||||
#ifdef ENABLE_QC2
|
||||
// Re-measure
|
||||
/* Disabled due to nothing to test and code space of around 1k*/
|
||||
steps = vStart - getInputVoltageX10(divisor, 1);
|
||||
steps = vStart - getInputVoltageX10(divisor, 0);
|
||||
if (steps < 0)
|
||||
steps = -steps;
|
||||
if (steps > 4) {
|
||||
@@ -118,7 +118,7 @@ void seekQC(int16_t Vx10, uint16_t divisor) {
|
||||
void startQC(uint16_t divisor) {
|
||||
// Pre check that the input could be >5V already, and if so, dont both
|
||||
// negotiating as someone is feeding in hv
|
||||
if (getInputVoltageX10(divisor, 1) > 80) {
|
||||
if (getInputVoltageX10(divisor, 0) > 80) {
|
||||
QCTries = 11;
|
||||
QCMode = QCState::NO_QC;
|
||||
return;
|
||||
@@ -160,7 +160,7 @@ void startQC(uint16_t divisor) {
|
||||
// Wait for frontend ADC to stabilise
|
||||
QCMode = QCState::QC_2;
|
||||
for (uint8_t i = 0; i < 10; i++) {
|
||||
if (getInputVoltageX10(divisor, 1) > 80) {
|
||||
if (getInputVoltageX10(divisor, 0) > 80) {
|
||||
// yay we have at least QC2.0 or QC3.0
|
||||
QCMode = QCState::QC_3; // We have at least QC2, pray for 3
|
||||
return;
|
||||
|
||||
@@ -15,6 +15,12 @@
|
||||
#include <string.h> // for memset
|
||||
bool sanitiseSettings();
|
||||
|
||||
#ifdef POW_QC_20V
|
||||
#define QC_SETTINGS_MAX 3
|
||||
#else
|
||||
#define QC_SETTINGS_MAX 2
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This struct must be a multiple of 2 bytes as it is saved / restored from
|
||||
* flash in uint16_t chunks
|
||||
@@ -144,7 +150,7 @@ bool nextSettingValue(const enum SettingsOptions option) {
|
||||
} else {
|
||||
systemSettings.settingsValues[(int)option] += constants.increment;
|
||||
}
|
||||
return (constants.max - systemSettings.settingsValues[(int)option]) < constants.increment;
|
||||
return (constants.max - systemSettings.settingsValues[(int)option]) <= constants.increment;
|
||||
}
|
||||
|
||||
bool prevSettingValue(const enum SettingsOptions option) {
|
||||
|
||||
@@ -187,6 +187,8 @@ const menuitem UIMenu[] = {
|
||||
* Display orientation
|
||||
* Cooldown blink
|
||||
* Reverse Temp change buttons + -
|
||||
* Detailed IDLE
|
||||
* Detailed Soldering
|
||||
*/
|
||||
{SETTINGS_DESC(SettingsItemIndex::TemperatureUnit), settings_setTempF, settings_displayTempF,
|
||||
SettingsOptions::SettingsOptionsLength}, /* Temperature units, this has to be the first element in the array to work with the logic in settings_enterUIMenu() */
|
||||
@@ -196,12 +198,14 @@ const menuitem UIMenu[] = {
|
||||
{SETTINGS_DESC(SettingsItemIndex::CooldownBlink), nullptr, settings_displayCoolingBlinkEnabled, SettingsOptions::CoolingTempBlink}, /*Cooling blink warning*/
|
||||
{SETTINGS_DESC(SettingsItemIndex::ScrollingSpeed), nullptr, settings_displayScrollSpeed, SettingsOptions::DescriptionScrollSpeed}, /*Scroll Speed for descriptions*/
|
||||
{SETTINGS_DESC(SettingsItemIndex::ReverseButtonTempChange), nullptr, settings_displayReverseButtonTempChangeEnabled,
|
||||
SettingsOptions::ReverseButtonTempChangeEnabled}, /* Reverse Temp change buttons + - */
|
||||
{SETTINGS_DESC(SettingsItemIndex::AnimSpeed), nullptr, settings_displayAnimationSpeed, SettingsOptions::AnimationSpeed}, /*Animation Speed adjustment */
|
||||
{SETTINGS_DESC(SettingsItemIndex::AnimLoop), nullptr, settings_displayAnimationLoop, SettingsOptions::AnimationLoop}, /*Animation Loop switch */
|
||||
{SETTINGS_DESC(SettingsItemIndex::Brightness), nullptr, settings_displayBrightnessLevel, SettingsOptions::OLEDBrightness}, /*Brightness Level*/
|
||||
{SETTINGS_DESC(SettingsItemIndex::ColourInversion), nullptr, settings_displayInvertColor, SettingsOptions::OLEDInversion}, /*Invert screen colour*/
|
||||
{0, nullptr, nullptr, SettingsOptions::SettingsOptionsLength} // end of menu marker. DO NOT REMOVE
|
||||
SettingsOptions::ReverseButtonTempChangeEnabled}, /* Reverse Temp change buttons + - */
|
||||
{SETTINGS_DESC(SettingsItemIndex::AnimSpeed), nullptr, settings_displayAnimationSpeed, SettingsOptions::AnimationSpeed}, /*Animation Speed adjustment */
|
||||
{SETTINGS_DESC(SettingsItemIndex::AnimLoop), nullptr, settings_displayAnimationLoop, SettingsOptions::AnimationLoop}, /*Animation Loop switch */
|
||||
{SETTINGS_DESC(SettingsItemIndex::Brightness), nullptr, settings_displayBrightnessLevel, SettingsOptions::OLEDBrightness}, /*Brightness Level*/
|
||||
{SETTINGS_DESC(SettingsItemIndex::ColourInversion), nullptr, settings_displayInvertColor, SettingsOptions::OLEDInversion}, /*Invert screen colour*/
|
||||
{SETTINGS_DESC(SettingsItemIndex::AdvancedIdle), nullptr, settings_displayAdvancedIDLEScreens, SettingsOptions::DetailedIDLE}, /* Advanced idle screen*/
|
||||
{SETTINGS_DESC(SettingsItemIndex::AdvancedSoldering), nullptr, settings_displayAdvancedSolderingScreens, SettingsOptions::DetailedSoldering}, /* Advanced soldering screen*/
|
||||
{0, nullptr, nullptr, SettingsOptions::SettingsOptionsLength} // end of menu marker. DO NOT REMOVE
|
||||
};
|
||||
const menuitem PowerSavingMenu[] = {
|
||||
/*
|
||||
@@ -225,8 +229,6 @@ const menuitem advancedMenu[] = {
|
||||
|
||||
/*
|
||||
* Power limit
|
||||
* Detailed IDLE
|
||||
* Detailed Soldering
|
||||
* Calibrate Temperature
|
||||
* Calibrate Input V
|
||||
* Reset Settings
|
||||
@@ -237,8 +239,6 @@ const menuitem advancedMenu[] = {
|
||||
* Power Pulse Duration
|
||||
*/
|
||||
{SETTINGS_DESC(SettingsItemIndex::PowerLimit), nullptr, settings_displayPowerLimit, SettingsOptions::PowerLimit}, /*Power limit*/
|
||||
{SETTINGS_DESC(SettingsItemIndex::AdvancedIdle), nullptr, settings_displayAdvancedIDLEScreens, SettingsOptions::DetailedIDLE}, /* Advanced idle screen*/
|
||||
{SETTINGS_DESC(SettingsItemIndex::AdvancedSoldering), nullptr, settings_displayAdvancedSolderingScreens, SettingsOptions::DetailedSoldering}, /* Advanced soldering screen*/
|
||||
{SETTINGS_DESC(SettingsItemIndex::SettingsReset), settings_setResetSettings, settings_displayResetSettings, SettingsOptions::SettingsOptionsLength}, /*Resets settings*/
|
||||
{SETTINGS_DESC(SettingsItemIndex::TemperatureCalibration), settings_setCalibrate, settings_displayCalibrate, SettingsOptions::SettingsOptionsLength}, /*Calibrate tip*/
|
||||
{SETTINGS_DESC(SettingsItemIndex::VoltageCalibration), settings_setCalibrateVIN, settings_displayCalibrateVIN, SettingsOptions::SettingsOptionsLength}, /*Voltage input cal*/
|
||||
@@ -352,8 +352,12 @@ static bool settings_displayQCInputV(void) {
|
||||
|
||||
static bool settings_displayPDNegTimeout(void) {
|
||||
printShortDescription(SettingsItemIndex::PDNegTimeout, 5);
|
||||
OLED::printNumber(getSettingValue(SettingsOptions::PDNegTimeout), 2, FontStyle::LARGE);
|
||||
|
||||
auto value = getSettingValue(SettingsOptions::PDNegTimeout);
|
||||
if (value == 0) {
|
||||
OLED::print(translatedString(Tr->OffString), FontStyle::LARGE);
|
||||
} else {
|
||||
OLED::printNumber(value, 2, FontStyle::LARGE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@@ -409,7 +413,7 @@ static bool settings_displayShutdownTime(void) {
|
||||
return false;
|
||||
}
|
||||
static bool settings_setTempF(void) {
|
||||
nextSettingValue(SettingsOptions::TemperatureInF);
|
||||
bool res = nextSettingValue(SettingsOptions::TemperatureInF);
|
||||
uint16_t BoostTemp = getSettingValue(SettingsOptions::BoostTemp);
|
||||
uint16_t SolderingTemp = getSettingValue(SettingsOptions::SolderingTemp);
|
||||
uint16_t SleepTemp = getSettingValue(SettingsOptions::SleepTemp);
|
||||
@@ -438,7 +442,7 @@ static bool settings_setTempF(void) {
|
||||
setSettingValue(SettingsOptions::SolderingTemp, SolderingTemp);
|
||||
setSettingValue(SettingsOptions::SleepTemp, SleepTemp);
|
||||
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool settings_displayTempF(void) {
|
||||
@@ -641,7 +645,7 @@ static void setTipOffset() {
|
||||
OLED::refresh();
|
||||
osDelay(100);
|
||||
}
|
||||
setoffset = TipThermoModel::convertTipRawADCTouV(offset / 16);
|
||||
setoffset = TipThermoModel::convertTipRawADCTouV(offset / 16, true);
|
||||
}
|
||||
setSettingValue(SettingsOptions::CalibrationOffset, setoffset);
|
||||
OLED::clearScreen();
|
||||
|
||||
@@ -10,26 +10,41 @@
|
||||
#include <power.hpp>
|
||||
|
||||
static int32_t PWMToX10Watts(uint8_t pwm, uint8_t sample);
|
||||
const int fastPWMChangeoverPoint = 128;
|
||||
const int fastPWMChangeoverTolerance = 16;
|
||||
|
||||
expMovingAverage<uint32_t, wattHistoryFilter> x10WattHistory = {0};
|
||||
|
||||
bool shouldBeUsingFastPWMMode(const uint8_t pwmTicks) {
|
||||
// Determine if we should use slow or fast PWM mode
|
||||
// Crossover between modes set around the midpoint of the PWM control point
|
||||
static bool lastPWMWasFast = true;
|
||||
if (pwmTicks > (fastPWMChangeoverPoint + fastPWMChangeoverTolerance) && lastPWMWasFast) {
|
||||
lastPWMWasFast = false;
|
||||
} else if (pwmTicks < (fastPWMChangeoverPoint - fastPWMChangeoverTolerance) && !lastPWMWasFast) {
|
||||
lastPWMWasFast = true;
|
||||
}
|
||||
return lastPWMWasFast;
|
||||
}
|
||||
|
||||
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
|
||||
// mass is in x10J/*C, rawC is raw per degree C
|
||||
// returns x10Watts needed to raise/lower a mass by rawTemp
|
||||
// degrees in one cycle.
|
||||
int32_t milliJoules = tipMass * rawTemp;
|
||||
return milliJoules;
|
||||
int32_t x10Watts = TIP_THERMAL_MASS * rawTemp;
|
||||
return x10Watts;
|
||||
}
|
||||
|
||||
void setTipX10Watts(int32_t mw) {
|
||||
int32_t output = X10WattsToPWM(mw, 1);
|
||||
setTipPWM(output);
|
||||
uint32_t actualMilliWatts = PWMToX10Watts(output, 0);
|
||||
int32_t outputPWMLevel = X10WattsToPWM(mw, 1);
|
||||
const bool shouldUseFastPWM = shouldBeUsingFastPWMMode(outputPWMLevel);
|
||||
setTipPWM(outputPWMLevel, shouldUseFastPWM);
|
||||
uint32_t actualMilliWatts = PWMToX10Watts(outputPWMLevel, 0);
|
||||
|
||||
x10WattHistory.update(actualMilliWatts);
|
||||
}
|
||||
|
||||
static uint32_t availableW10(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.
|
||||
@@ -45,26 +60,21 @@ static uint32_t availableW10(uint8_t sample) {
|
||||
// availableMilliWattsX10 is now an accurate representation
|
||||
return availableWattsX10;
|
||||
}
|
||||
|
||||
uint8_t X10WattsToPWM(int32_t milliWatts, uint8_t sample) {
|
||||
// Scale input milliWatts to the pwm range available
|
||||
if (milliWatts < 1) {
|
||||
uint8_t X10WattsToPWM(int32_t x10Watts, uint8_t sample) {
|
||||
// Scale input x10Watts to the pwm range available
|
||||
if (x10Watts < 0) {
|
||||
// keep the battery voltage updating the filter
|
||||
getInputVoltageX10(getSettingValue(SettingsOptions::VoltageDiv), sample);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate desired milliwatts as a percentage of availableW10
|
||||
// Calculate desired x10Watts as a percentage of availableW10
|
||||
uint32_t pwm;
|
||||
do {
|
||||
pwm = (powerPWM * milliWatts) / availableW10(sample);
|
||||
if (pwm > powerPWM) {
|
||||
// constrain to max PWM counter, shouldn't be possible,
|
||||
// but small cost for safety to avoid wraps
|
||||
pwm = powerPWM;
|
||||
}
|
||||
} while (tryBetterPWM(pwm));
|
||||
|
||||
pwm = (powerPWM * x10Watts) / availableW10(sample);
|
||||
if (pwm > powerPWM) {
|
||||
// constrain to max PWM counter
|
||||
pwm = powerPWM;
|
||||
}
|
||||
return pwm;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,17 +12,18 @@
|
||||
#include "LIS2DH12.hpp"
|
||||
#include "MMA8652FC.hpp"
|
||||
#include "MSA301.h"
|
||||
#include "Model_Config.h"
|
||||
#include "QC3.h"
|
||||
#include "SC7A20.hpp"
|
||||
#include "Settings.h"
|
||||
#include "TipThermoModel.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "configuration.h"
|
||||
#include "history.hpp"
|
||||
#include "main.hpp"
|
||||
#include "power.hpp"
|
||||
#include "stdlib.h"
|
||||
#include "task.h"
|
||||
|
||||
#define MOVFilter 8
|
||||
uint8_t accelInit = 0;
|
||||
TickType_t lastMovementTime = 0;
|
||||
|
||||
@@ -20,36 +20,36 @@ TaskHandle_t pidTaskNotification = NULL;
|
||||
uint32_t currentTempTargetDegC = 0; // Current temperature target in C
|
||||
int32_t powerSupplyWattageLimit = 0;
|
||||
bool heaterThermalRunaway = false;
|
||||
|
||||
static int32_t getPIDResultX10Watts(int32_t tError);
|
||||
static void detectThermalRunaway(const int16_t currentTipTempInC, const int tError);
|
||||
static void setOutputx10WattsViaFilters(int32_t x10Watts);
|
||||
static int32_t getX10WattageLimits();
|
||||
|
||||
/* StartPIDTask function */
|
||||
void startPIDTask(void const *argument __unused) {
|
||||
/*
|
||||
* We take the current tip temperature & evaluate the next step for the tip
|
||||
* control PWM.
|
||||
*/
|
||||
setTipX10Watts(0); // disable the output driver if the output is set to be off
|
||||
TickType_t lastPowerPulseStart = 0;
|
||||
TickType_t lastPowerPulseEnd = 0;
|
||||
setTipX10Watts(0); // disable the output at startup
|
||||
|
||||
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();
|
||||
uint32_t PIDTempTarget = 0;
|
||||
uint16_t tipTempCRunawayTemp = 0;
|
||||
TickType_t runawaylastChangeTime = 0;
|
||||
currentTempTargetDegC = 0; // Force start with no output (off). If in sleep / soldering this will
|
||||
// be over-ridden rapidly
|
||||
pidTaskNotification = xTaskGetCurrentTaskHandle();
|
||||
uint32_t PIDTempTarget = 0;
|
||||
// Pre-seed the adc filters
|
||||
for (int i = 0; i < 64; i++) {
|
||||
vTaskDelay(2);
|
||||
for (int i = 0; i < 128; i++) {
|
||||
vTaskDelay(5);
|
||||
TipThermoModel::getTipInC(true);
|
||||
getInputVoltageX10(getSettingValue(SettingsOptions::VoltageDiv), 1);
|
||||
}
|
||||
#ifdef SLEW_LIMIT
|
||||
int32_t x10WattsOutLast = 0;
|
||||
#endif
|
||||
for (;;) {
|
||||
int32_t x10WattsOut = 0;
|
||||
|
||||
for (;;) {
|
||||
x10WattsOut = 0;
|
||||
// This is a call to block this thread until the ADC does its samples
|
||||
if (ulTaskNotifyTake(pdTRUE, 2000)) {
|
||||
// This is a call to block this thread until the ADC does its samples
|
||||
int32_t x10WattsOut = 0;
|
||||
// Do the reading here to keep the temp calculations churning along
|
||||
uint32_t currentTipTempInC = TipThermoModel::getTipInC(true);
|
||||
PIDTempTarget = currentTempTargetDegC;
|
||||
@@ -63,116 +63,163 @@ void startPIDTask(void const *argument __unused) {
|
||||
if (PIDTempTarget > TipThermoModel::getTipMaxInC()) {
|
||||
PIDTempTarget = TipThermoModel::getTipMaxInC();
|
||||
}
|
||||
// Convert the current tip to degree's C
|
||||
|
||||
// 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 degree C.
|
||||
// This helps stabilize the display.
|
||||
int32_t tError = PIDTempTarget - currentTipTempInC + 1;
|
||||
tError = tError > INT16_MAX ? INT16_MAX : tError;
|
||||
tError = tError < INT16_MIN ? INT16_MIN : tError;
|
||||
tempError.update(tError);
|
||||
|
||||
// Now for the PID!
|
||||
|
||||
// P term - total power needed to hit target temp next cycle.
|
||||
// thermal mass = 1690 milliJ/*C for my tip.
|
||||
// = Watts*Seconds to raise Temp from room temp to +100*C, divided by 100*C.
|
||||
// we divide milliWattsNeeded by 20 to let the I term dominate near the set point.
|
||||
// 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 x10WattsNeeded = tempToX10Watts(tError);
|
||||
// note that milliWattsNeeded is sometimes negative, this counters overshoot
|
||||
// from I term's inertia.
|
||||
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).
|
||||
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
|
||||
// and counters extra power if the iron is no longer losing temp.
|
||||
// basically: temp - lastTemp
|
||||
// Unfortunately, our temp signal is too noisy to really help.
|
||||
|
||||
// Check for thermal runaway, where it has been x seconds with negligible (y) temp rise
|
||||
// While trying to actively heat
|
||||
if ((tError > THERMAL_RUNAWAY_TEMP_C)) {
|
||||
// Temp error is high
|
||||
int16_t delta = (int16_t)currentTipTempInC - (int16_t)tipTempCRunawayTemp;
|
||||
if (delta < 0) {
|
||||
delta = -delta;
|
||||
}
|
||||
if (delta > THERMAL_RUNAWAY_TEMP_C) {
|
||||
// We have heated up more than the threshold, reset the timer
|
||||
tipTempCRunawayTemp = currentTipTempInC;
|
||||
runawaylastChangeTime = xTaskGetTickCount();
|
||||
} else {
|
||||
if ((xTaskGetTickCount() - runawaylastChangeTime) > (THERMAL_RUNAWAY_TIME_SEC * TICKS_SECOND)) {
|
||||
// It has taken too long to rise
|
||||
heaterThermalRunaway = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tipTempCRunawayTemp = currentTipTempInC;
|
||||
runawaylastChangeTime = xTaskGetTickCount();
|
||||
}
|
||||
int32_t tError = PIDTempTarget - currentTipTempInC;
|
||||
|
||||
detectThermalRunaway(currentTipTempInC, tError);
|
||||
x10WattsOut = getPIDResultX10Watts(tError);
|
||||
} else {
|
||||
tipTempCRunawayTemp = currentTipTempInC;
|
||||
runawaylastChangeTime = xTaskGetTickCount();
|
||||
detectThermalRunaway(currentTipTempInC, 0);
|
||||
}
|
||||
|
||||
// If the user turns on the option of using an occasional pulse to keep the power bank on
|
||||
if (getSettingValue(SettingsOptions::KeepAwakePulse)) {
|
||||
const TickType_t powerPulseWait = powerPulseWaitUnit * getSettingValue(SettingsOptions::KeepAwakePulseWait);
|
||||
if (xTaskGetTickCount() - lastPowerPulseStart > powerPulseWait) {
|
||||
const TickType_t powerPulseDuration = powerPulseDurationUnit * getSettingValue(SettingsOptions::KeepAwakePulseDuration);
|
||||
lastPowerPulseStart = xTaskGetTickCount();
|
||||
lastPowerPulseEnd = lastPowerPulseStart + powerPulseDuration;
|
||||
}
|
||||
|
||||
// If current PID is less than the pulse level, check if we want to constrain to the pulse as the floor
|
||||
if (x10WattsOut < getSettingValue(SettingsOptions::KeepAwakePulse) && xTaskGetTickCount() < lastPowerPulseEnd) {
|
||||
x10WattsOut = getSettingValue(SettingsOptions::KeepAwakePulse);
|
||||
}
|
||||
}
|
||||
|
||||
// Secondary safety check to forcefully disable header when within ADC noise of top of ADC
|
||||
if (getTipRawTemp(0) > (0x7FFF - 32)) {
|
||||
x10WattsOut = 0;
|
||||
}
|
||||
if (heaterThermalRunaway) {
|
||||
x10WattsOut = 0;
|
||||
}
|
||||
if (getSettingValue(SettingsOptions::PowerLimit) && x10WattsOut > (getSettingValue(SettingsOptions::PowerLimit) * 10)) {
|
||||
x10WattsOut = getSettingValue(SettingsOptions::PowerLimit) * 10;
|
||||
}
|
||||
if (powerSupplyWattageLimit && x10WattsOut > powerSupplyWattageLimit * 10) {
|
||||
x10WattsOut = powerSupplyWattageLimit * 10;
|
||||
}
|
||||
#ifdef SLEW_LIMIT
|
||||
if (x10WattsOut - x10WattsOutLast > SLEW_LIMIT) {
|
||||
x10WattsOut = x10WattsOutLast + SLEW_LIMIT;
|
||||
}
|
||||
if (x10WattsOut < 0) {
|
||||
x10WattsOut = 0;
|
||||
}
|
||||
x10WattsOutLast = x10WattsOut;
|
||||
#endif
|
||||
setTipX10Watts(x10WattsOut);
|
||||
#ifdef DEBUG_UART_OUTPUT
|
||||
log_system_state(x10WattsOut);
|
||||
#endif
|
||||
resetWatchdog();
|
||||
setOutputx10WattsViaFilters(x10WattsOut);
|
||||
} else {
|
||||
// ADC interrupt timeout
|
||||
setTipPWM(0);
|
||||
setTipPWM(0, false);
|
||||
}
|
||||
#ifdef DEBUG_UART_OUTPUT
|
||||
log_system_state(x10WattsOut);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template <class T = int32_t> struct Integrator {
|
||||
T sum;
|
||||
|
||||
T update(const T val, const int32_t inertia, const int32_t gain, const int32_t rate, const int32_t limit) {
|
||||
// Decay the old value. This is a simplified formula that still works with decent results
|
||||
// Ideally we would have used an exponential decay but the computational effort required
|
||||
// by exp function is just not justified here in respect to the outcome
|
||||
sum = (sum * (100 - (inertia / rate))) / 100;
|
||||
// Add the new value x integration interval ( 1 / rate)
|
||||
sum += (gain * val) / rate;
|
||||
|
||||
// limit the output
|
||||
if (sum > limit)
|
||||
sum = limit;
|
||||
else if (sum < -limit)
|
||||
sum = -limit;
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
void set(T const val) { sum = val; }
|
||||
|
||||
T get(bool positiveOnly = true) const { return (positiveOnly) ? ((sum > 0) ? sum : 0) : sum; }
|
||||
};
|
||||
int32_t getPIDResultX10Watts(int32_t setpointDelta) {
|
||||
static TickType_t lastCall = 0;
|
||||
static Integrator<int32_t> powerStore = {0};
|
||||
|
||||
const int rate = 1000 / (xTaskGetTickCount() - lastCall);
|
||||
lastCall = xTaskGetTickCount();
|
||||
// Sandman note:
|
||||
// PID Challenge - we have a small thermal mass that we to want heat up as fast as possible but we don't
|
||||
// want to overshot excessively (if at all) the setpoint temperature. In the same time we have 'imprecise'
|
||||
// instant temperature measurements. The nature of temperature reading imprecision is not necessarily
|
||||
// related to the sensor (thermocouple) or DAQ system, that otherwise are fairly decent. The real issue is
|
||||
// the thermal inertia. We basically read the temperature in the window between two heating sessions when
|
||||
// the output is off. However, the heater temperature does not dissipate instantly into the tip mass so
|
||||
// at any moment right after heating, the thermocouple would sense a temperature significantly higher than
|
||||
// moments later. We could use longer delays but that would slow the PID loop and that would lead to other
|
||||
// negative side effects. As a result, we can only rely on the I term but with a twist. Instead of a simple
|
||||
// integrator we are going to use a self decaying integrator that acts more like a dual I term / P term
|
||||
// rather than a plain I term. Depending on the circumstances, like when the delta temperature is large,
|
||||
// it acts more like a P term whereas on closing to setpoint it acts increasingly closer to a plain I term.
|
||||
// So in a sense, we have a bit of both.
|
||||
// So there we go...
|
||||
|
||||
// P = (Thermal Mass) x (Delta Temperature ) / 1sec, where thermal mass is in X10 J / °C and
|
||||
// delta temperature is in °C. The result is the power in X10 W needed to raise (or decrease!) the
|
||||
// tip temperature with (Delta Temperature ) °C in 1 second.
|
||||
// Note on powerStore. On update, if the value is provided in X10 (W) units then inertia shall be provided
|
||||
// in X10 (J / °C) units as well. Also, powerStore is updated with a gain of 2. Where this comes from: The actual
|
||||
// power CMOS is controlled by TIM3->CTR1 (that is software modulated - on/off - by TIM2-CTR4 interrupts). However,
|
||||
// TIM3->CTR1 is configured with a duty cycle of 50% so, in real, we get only 50% of the presumed power output
|
||||
// so we basically double the need (gain = 2) to get what we want.
|
||||
return powerStore.update(TIP_THERMAL_MASS * setpointDelta, // the required power
|
||||
TIP_THERMAL_MASS, // Inertia, smaller numbers increase dominance of the previous value
|
||||
2, // gain
|
||||
rate, // PID cycle frequency
|
||||
getX10WattageLimits());
|
||||
}
|
||||
|
||||
void detectThermalRunaway(const int16_t currentTipTempInC, const int tError) {
|
||||
static uint16_t tipTempCRunawayTemp = 0;
|
||||
static TickType_t runawaylastChangeTime = 0;
|
||||
|
||||
// Check for thermal runaway, where it has been x seconds with negligible (y) temp rise
|
||||
// While trying to actively heat
|
||||
if ((tError > THERMAL_RUNAWAY_TEMP_C)) {
|
||||
// Temp error is high
|
||||
int16_t delta = (int16_t)currentTipTempInC - (int16_t)tipTempCRunawayTemp;
|
||||
if (delta < 0) {
|
||||
delta = -delta;
|
||||
}
|
||||
if (delta > THERMAL_RUNAWAY_TEMP_C) {
|
||||
// We have heated up more than the threshold, reset the timer
|
||||
tipTempCRunawayTemp = currentTipTempInC;
|
||||
runawaylastChangeTime = xTaskGetTickCount();
|
||||
} else {
|
||||
if ((xTaskGetTickCount() - runawaylastChangeTime) > (THERMAL_RUNAWAY_TIME_SEC * TICKS_SECOND)) {
|
||||
// It has taken too long to rise
|
||||
heaterThermalRunaway = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tipTempCRunawayTemp = currentTipTempInC;
|
||||
runawaylastChangeTime = xTaskGetTickCount();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t getX10WattageLimits() {
|
||||
int32_t limit = availableW10(0);
|
||||
|
||||
if (getSettingValue(SettingsOptions::PowerLimit) && limit > (getSettingValue(SettingsOptions::PowerLimit) * 10)) {
|
||||
limit = getSettingValue(SettingsOptions::PowerLimit) * 10;
|
||||
}
|
||||
if (powerSupplyWattageLimit && limit > powerSupplyWattageLimit * 10) {
|
||||
limit = powerSupplyWattageLimit * 10;
|
||||
}
|
||||
return limit;
|
||||
}
|
||||
|
||||
void setOutputx10WattsViaFilters(int32_t x10WattsOut) {
|
||||
static TickType_t lastPowerPulseStart = 0;
|
||||
static TickType_t lastPowerPulseEnd = 0;
|
||||
#ifdef SLEW_LIMIT
|
||||
static int32_t x10WattsOutLast = 0;
|
||||
#endif
|
||||
|
||||
// If the user turns on the option of using an occasional pulse to keep the power bank on
|
||||
if (getSettingValue(SettingsOptions::KeepAwakePulse)) {
|
||||
const TickType_t powerPulseWait = powerPulseWaitUnit * getSettingValue(SettingsOptions::KeepAwakePulseWait);
|
||||
if (xTaskGetTickCount() - lastPowerPulseStart > powerPulseWait) {
|
||||
const TickType_t powerPulseDuration = powerPulseDurationUnit * getSettingValue(SettingsOptions::KeepAwakePulseDuration);
|
||||
lastPowerPulseStart = xTaskGetTickCount();
|
||||
lastPowerPulseEnd = lastPowerPulseStart + powerPulseDuration;
|
||||
}
|
||||
|
||||
// If current PID is less than the pulse level, check if we want to constrain to the pulse as the floor
|
||||
if (x10WattsOut < getSettingValue(SettingsOptions::KeepAwakePulse) && xTaskGetTickCount() < lastPowerPulseEnd) {
|
||||
x10WattsOut = getSettingValue(SettingsOptions::KeepAwakePulse);
|
||||
}
|
||||
}
|
||||
|
||||
// Secondary safety check to forcefully disable header when within ADC noise of top of ADC
|
||||
if (getTipRawTemp(0) > (0x7FFF - 32)) {
|
||||
x10WattsOut = 0;
|
||||
}
|
||||
if (heaterThermalRunaway) {
|
||||
x10WattsOut = 0;
|
||||
}
|
||||
#ifdef SLEW_LIMIT
|
||||
if (x10WattsOut - x10WattsOutLast > SLEW_LIMIT) {
|
||||
x10WattsOut = x10WattsOutLast + SLEW_LIMIT;
|
||||
}
|
||||
if (x10WattsOut < 0) {
|
||||
x10WattsOut = 0;
|
||||
}
|
||||
x10WattsOutLast = x10WattsOut;
|
||||
#endif
|
||||
setTipX10Watts(x10WattsOut);
|
||||
resetWatchdog();
|
||||
}
|
||||
Reference in New Issue
Block a user