mirror of
https://github.com/Ralim/IronOS.git
synced 2025-02-26 07:53:55 +00:00
Introduce PWM freq switching so that power could be averaged on shorter intervals
With this a TS-I tip is usable with a small netbook 19 V / 30 W PSU with power limit set to 40 W (38.9 W is reported during the heating up stage). Without this the device just reboots on attempt to turn on the heater (unless the power limit is set to 10 or even 5 W). This code doesn't affect maximum power available and allows up to 73 W when a beefy 24 V / 96 W PSU is used. Should be useful for all models, not just TS100. The fixed comments are based on calculations, not measurements! Fixes #693.
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "BSP_Flash.h"
|
||||
#include "BSP_Power.h"
|
||||
#include "BSP_QC.h"
|
||||
#include "Defines.h"
|
||||
#include "Model_Config.h"
|
||||
#include "stdint.h"
|
||||
/*
|
||||
* BSP.h -- Board Support
|
||||
*
|
||||
@@ -16,11 +17,19 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// maximum htim2 PWM value
|
||||
extern const uint16_t powerPWM;
|
||||
// htim2.Init.Period, the full PWM cycle
|
||||
extern uint16_t totalPWM;
|
||||
|
||||
// Called first thing in main() to init the hardware
|
||||
void preRToSInit();
|
||||
// Called once the RToS has started for any extra work
|
||||
void postRToSInit();
|
||||
|
||||
// Called once from preRToSInit()
|
||||
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
|
||||
@@ -31,6 +40,9 @@ uint16_t getHandleTemperature();
|
||||
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
|
||||
|
||||
@@ -12,6 +12,14 @@
|
||||
volatile uint16_t PWMSafetyTimer = 0;
|
||||
volatile uint8_t pendingPWM = 0;
|
||||
|
||||
const uint16_t powerPWM = 255;
|
||||
static const uint8_t holdoffTicks = 13; // delay of 7 ms
|
||||
static const uint8_t tempMeasureTicks = 17;
|
||||
|
||||
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() {
|
||||
@@ -190,6 +198,41 @@ void setTipPWM(uint8_t pulse) {
|
||||
pendingPWM = pulse;
|
||||
}
|
||||
|
||||
static void switchToFastPWM(void) {
|
||||
fastPWM = true;
|
||||
totalPWM = powerPWM + tempMeasureTicks * 2;
|
||||
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;
|
||||
}
|
||||
|
||||
static void switchToSlowPWM(void) {
|
||||
fastPWM = false;
|
||||
totalPWM = powerPWM + tempMeasureTicks;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// These are called by the HAL after the corresponding events from the system
|
||||
// timers.
|
||||
|
||||
@@ -299,6 +342,10 @@ uint8_t getButtonB() {
|
||||
1 : 0;
|
||||
}
|
||||
|
||||
void BSPInit(void) {
|
||||
switchToFastPWM();
|
||||
}
|
||||
|
||||
void reboot() {
|
||||
|
||||
NVIC_SystemReset();
|
||||
|
||||
@@ -315,13 +315,15 @@ static void MX_TIM2_Init(void) {
|
||||
// Timer 2 is fairly slow as its being used to run the PWM and trigger the ADC
|
||||
// in the PWM off time.
|
||||
htim2.Instance = TIM2;
|
||||
htim2.Init.Prescaler = 4000; //1mhz tick rate/800 = 1.25 KHz tick rate
|
||||
// dummy value, will be reconfigured by BSPInit()
|
||||
htim2.Init.Prescaler = 2000; // 2 MHz timer clock/2000 = 1 kHz tick rate
|
||||
|
||||
// pwm out is 10k from tim3, we want to run our PWM at around 10hz or slower on the output stage
|
||||
// These values give a rate of around 8Hz
|
||||
// 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;
|
||||
htim2.Init.Period = 255 + 17;
|
||||
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4; // 4mhz before divide
|
||||
// dummy value, will be reconfigured by BSPInit()
|
||||
htim2.Init.Period = 255 + 17 * 2;
|
||||
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4; // 8 MHz (x2 APB1) before divide
|
||||
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||
htim2.Init.RepetitionCounter = 0;
|
||||
HAL_TIM_Base_Init(&htim2);
|
||||
@@ -337,7 +339,8 @@ static void MX_TIM2_Init(void) {
|
||||
HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
|
||||
|
||||
sConfigOC.OCMode = TIM_OCMODE_PWM1;
|
||||
sConfigOC.Pulse = 255 + 13; //13 -> Delay of 5ms
|
||||
// dummy value, will be reconfigured by BSPInit()
|
||||
sConfigOC.Pulse = 255 + 13 * 2; // 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.
|
||||
|
||||
@@ -17,6 +17,7 @@ void preRToSInit() {
|
||||
*/
|
||||
HAL_Init();
|
||||
Setup_HAL(); // Setup all the HAL objects
|
||||
BSPInit();
|
||||
#ifdef I2C_SOFT
|
||||
I2CBB::init();
|
||||
#endif
|
||||
|
||||
@@ -25,6 +25,4 @@ 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);
|
||||
int32_t PWMToX10Watts(uint8_t pwm, uint8_t sample = 0);
|
||||
uint32_t availableW10(uint8_t sample) ;
|
||||
#endif /* POWER_HPP_ */
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
#include <Settings.h>
|
||||
#include <BSP.h>
|
||||
|
||||
const uint16_t powerPWM = 255;
|
||||
const uint16_t totalPWM = 255 + 17; //htim2.Init.Period, the full PWM cycle
|
||||
static int32_t PWMToX10Watts(uint8_t pwm, uint8_t sample);
|
||||
|
||||
expMovingAverage<uint32_t, wattHistoryFilter> x10WattHistory = { 0 };
|
||||
|
||||
@@ -30,7 +29,7 @@ void setTipX10Watts(int32_t mw) {
|
||||
x10WattHistory.update(actualMilliWatts);
|
||||
}
|
||||
|
||||
uint32_t availableW10(uint8_t sample) {
|
||||
static 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.
|
||||
@@ -56,15 +55,22 @@ uint8_t X10WattsToPWM(int32_t milliWatts, uint8_t sample) {
|
||||
}
|
||||
// if (milliWatts > (int(systemSettings.pidPowerLimit) * 10))
|
||||
// milliWatts = (int(systemSettings.pidPowerLimit) * 10);
|
||||
|
||||
//Calculate desired milliwatts as a percentage of availableW10
|
||||
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
|
||||
}
|
||||
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));
|
||||
|
||||
return pwm;
|
||||
}
|
||||
|
||||
int32_t PWMToX10Watts(uint8_t pwm, uint8_t sample) {
|
||||
static 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
|
||||
return (((uint32_t) pwm) * maxMW) / powerPWM;
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
|
||||
#ifdef MODEL_TS100
|
||||
const int32_t tipMass = 45; // X10 watts to raise 1 deg C in 1 second
|
||||
const uint8_t tipResistance = 85; //x10 ohms, 8.5 typical for ts100, 4.5 typical for ts80
|
||||
const uint8_t tipResistance = 75; //x10 ohms, 7.5 typical for ts100 tips
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_TS80
|
||||
|
||||
Reference in New Issue
Block a user