Merge pull request #697 from paulfertser/poc-limit-power
Limit maximum power more efficiently using dual speed PWM
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include "BSP_Flash.h"
|
#include "BSP_Flash.h"
|
||||||
#include "BSP_Power.h"
|
#include "BSP_Power.h"
|
||||||
#include "BSP_QC.h"
|
#include "BSP_QC.h"
|
||||||
#include "Defines.h"
|
#include "Defines.h"
|
||||||
#include "Model_Config.h"
|
#include "Model_Config.h"
|
||||||
#include "stdint.h"
|
|
||||||
/*
|
/*
|
||||||
* BSP.h -- Board Support
|
* BSP.h -- Board Support
|
||||||
*
|
*
|
||||||
@@ -16,11 +17,19 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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
|
// Called first thing in main() to init the hardware
|
||||||
void preRToSInit();
|
void preRToSInit();
|
||||||
// Called once the RToS has started for any extra work
|
// Called once the RToS has started for any extra work
|
||||||
void postRToSInit();
|
void postRToSInit();
|
||||||
|
|
||||||
|
// Called once from preRToSInit()
|
||||||
|
void BSPInit(void);
|
||||||
|
|
||||||
// Called to reset the hardware watchdog unit
|
// Called to reset the hardware watchdog unit
|
||||||
void resetWatchdog();
|
void resetWatchdog();
|
||||||
// Accepts a output level of 0.. to use to control the tip output PWM
|
// 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);
|
uint16_t getTipRawTemp(uint8_t refresh);
|
||||||
// Returns the main DC input voltage, using the adjustable divisor + sample flag
|
// Returns the main DC input voltage, using the adjustable divisor + sample flag
|
||||||
uint16_t getInputVoltageX10(uint16_t divisor, uint8_t sample);
|
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
|
// Readers for the two buttons
|
||||||
// !! Returns 1 if held down, 0 if released
|
// !! Returns 1 if held down, 0 if released
|
||||||
|
|||||||
@@ -12,6 +12,14 @@
|
|||||||
volatile uint16_t PWMSafetyTimer = 0;
|
volatile uint16_t PWMSafetyTimer = 0;
|
||||||
volatile uint8_t pendingPWM = 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)
|
//2 second filter (ADC is PID_TIM_HZ Hz)
|
||||||
history<uint16_t, PID_TIM_HZ> rawTempFilter = { { 0 }, 0, 0 };
|
history<uint16_t, PID_TIM_HZ> rawTempFilter = { { 0 }, 0, 0 };
|
||||||
void resetWatchdog() {
|
void resetWatchdog() {
|
||||||
@@ -190,6 +198,41 @@ void setTipPWM(uint8_t pulse) {
|
|||||||
pendingPWM = 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
|
// These are called by the HAL after the corresponding events from the system
|
||||||
// timers.
|
// timers.
|
||||||
|
|
||||||
@@ -299,6 +342,10 @@ uint8_t getButtonB() {
|
|||||||
1 : 0;
|
1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BSPInit(void) {
|
||||||
|
switchToFastPWM();
|
||||||
|
}
|
||||||
|
|
||||||
void reboot() {
|
void reboot() {
|
||||||
|
|
||||||
NVIC_SystemReset();
|
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
|
// Timer 2 is fairly slow as its being used to run the PWM and trigger the ADC
|
||||||
// in the PWM off time.
|
// in the PWM off time.
|
||||||
htim2.Instance = TIM2;
|
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
|
// 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.CounterMode = TIM_COUNTERMODE_UP;
|
||||||
htim2.Init.Period = 255 + 17;
|
// dummy value, will be reconfigured by BSPInit()
|
||||||
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4; // 4mhz before divide
|
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.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||||
htim2.Init.RepetitionCounter = 0;
|
htim2.Init.RepetitionCounter = 0;
|
||||||
HAL_TIM_Base_Init(&htim2);
|
HAL_TIM_Base_Init(&htim2);
|
||||||
@@ -337,7 +339,8 @@ static void MX_TIM2_Init(void) {
|
|||||||
HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
|
HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
|
||||||
|
|
||||||
sConfigOC.OCMode = TIM_OCMODE_PWM1;
|
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
|
//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.
|
* It takes 4 milliseconds for output to be stable after PWM turns off.
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ void preRToSInit() {
|
|||||||
*/
|
*/
|
||||||
HAL_Init();
|
HAL_Init();
|
||||||
Setup_HAL(); // Setup all the HAL objects
|
Setup_HAL(); // Setup all the HAL objects
|
||||||
|
BSPInit();
|
||||||
#ifdef I2C_SOFT
|
#ifdef I2C_SOFT
|
||||||
I2CBB::init();
|
I2CBB::init();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,6 +25,4 @@ extern expMovingAverage<uint32_t, wattHistoryFilter> x10WattHistory;
|
|||||||
int32_t tempToX10Watts(int32_t rawTemp);
|
int32_t tempToX10Watts(int32_t rawTemp);
|
||||||
void setTipX10Watts(int32_t mw);
|
void setTipX10Watts(int32_t mw);
|
||||||
uint8_t X10WattsToPWM(int32_t milliWatts, uint8_t sample = 0);
|
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_ */
|
#endif /* POWER_HPP_ */
|
||||||
|
|||||||
@@ -9,8 +9,7 @@
|
|||||||
#include <Settings.h>
|
#include <Settings.h>
|
||||||
#include <BSP.h>
|
#include <BSP.h>
|
||||||
|
|
||||||
const uint16_t powerPWM = 255;
|
static int32_t PWMToX10Watts(uint8_t pwm, uint8_t sample);
|
||||||
const uint16_t totalPWM = 255 + 17; //htim2.Init.Period, the full PWM cycle
|
|
||||||
|
|
||||||
expMovingAverage<uint32_t, wattHistoryFilter> x10WattHistory = { 0 };
|
expMovingAverage<uint32_t, wattHistoryFilter> x10WattHistory = { 0 };
|
||||||
|
|
||||||
@@ -30,7 +29,7 @@ void setTipX10Watts(int32_t mw) {
|
|||||||
x10WattHistory.update(actualMilliWatts);
|
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
|
//P = V^2 / R, v*v = v^2 * 100
|
||||||
// R = R*10
|
// R = R*10
|
||||||
// P therefore is in V^2*100/R*10 = W*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))
|
// if (milliWatts > (int(systemSettings.pidPowerLimit) * 10))
|
||||||
// milliWatts = (int(systemSettings.pidPowerLimit) * 10);
|
// milliWatts = (int(systemSettings.pidPowerLimit) * 10);
|
||||||
|
|
||||||
//Calculate desired milliwatts as a percentage of availableW10
|
//Calculate desired milliwatts as a percentage of availableW10
|
||||||
uint32_t pwm = (powerPWM * milliWatts) / availableW10(sample);
|
uint32_t pwm;
|
||||||
|
do {
|
||||||
|
pwm = (powerPWM * milliWatts) / availableW10(sample);
|
||||||
if (pwm > powerPWM) {
|
if (pwm > powerPWM) {
|
||||||
pwm = powerPWM; //constrain to max PWM counter, shouldnt be possible, but small cost for safety to avoid wraps
|
// constrain to max PWM counter, shouldn't be possible,
|
||||||
|
// but small cost for safety to avoid wraps
|
||||||
|
pwm = powerPWM;
|
||||||
}
|
}
|
||||||
|
} while (tryBetterPWM(pwm));
|
||||||
|
|
||||||
return 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
|
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
|
//Then convert pwm into percentage of powerPWM to get the percentage of the max mw
|
||||||
return (((uint32_t) pwm) * maxMW) / powerPWM;
|
return (((uint32_t) pwm) * maxMW) / powerPWM;
|
||||||
|
|||||||
@@ -131,7 +131,7 @@
|
|||||||
|
|
||||||
#ifdef MODEL_TS100
|
#ifdef MODEL_TS100
|
||||||
const int32_t tipMass = 45; // X10 watts to raise 1 deg C in 1 second
|
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
|
#endif
|
||||||
|
|
||||||
#ifdef MODEL_TS80
|
#ifdef MODEL_TS80
|
||||||
|
|||||||
Reference in New Issue
Block a user