Compare commits

..

1 Commits

Author SHA1 Message Date
Ben V. Brown
07893daec7 Increase PWM rate 2023-09-23 13:06:44 +10:00
17 changed files with 199 additions and 292 deletions

View File

@@ -34,7 +34,7 @@
"message": "!Skrat hrotu!" "message": "!Skrat hrotu!"
}, },
"SettingsCalibrationWarning": { "SettingsCalibrationWarning": {
"message": "Pred reštartovaním sa uistite, že hrot a rúčka v izbovej teplote!" "message": "Pred reštartovaním sa uistite, že hrot a rúčka je v izbovej teplote!"
}, },
"CJCCalibrating": { "CJCCalibrating": {
"message": "kalibrovanie\n" "message": "kalibrovanie\n"
@@ -73,7 +73,7 @@
"message": "Vaše zariadenie je pravdepodobne falzifikát!" "message": "Vaše zariadenie je pravdepodobne falzifikát!"
}, },
"TooHotToStartProfileWarning": { "TooHotToStartProfileWarning": {
"message": "Teplota príliš vysoká pre štart profilu" "message": "Teplota príliž vysoká pre štart profilu"
} }
}, },
"characters": { "characters": {
@@ -168,43 +168,43 @@
"description": "Rýchlosť predhrievania (stupňe za sekundu)" "description": "Rýchlosť predhrievania (stupňe za sekundu)"
}, },
"ProfilePhase1Temp": { "ProfilePhase1Temp": {
"displayText": "Teplota\nFáza 1", "displayText": "Teplota\nFáze 1",
"description": "Cieľová teplota na konci tejto fázy" "description": "Cieľová teplota na konci tejto fáze"
}, },
"ProfilePhase1Duration": { "ProfilePhase1Duration": {
"displayText": "Trvanie\nFáza 1", "displayText": "Trvanie\nFáze 1",
"description": "Doba trvania tejto fázy (sekundy)" "description": "Doba trvania tejto fáze (sekundy)"
}, },
"ProfilePhase2Temp": { "ProfilePhase2Temp": {
"displayText": "Teplota\nFáza 2", "displayText": "Teplota\nFáze 2",
"description": "" "description": ""
}, },
"ProfilePhase2Duration": { "ProfilePhase2Duration": {
"displayText": "Trvanie\nFáza 2", "displayText": "Trvanie\nFáze 2",
"description": "" "description": ""
}, },
"ProfilePhase3Temp": { "ProfilePhase3Temp": {
"displayText": "Teplota\nFáza 3", "displayText": "Teplota\nFáze 3",
"description": "" "description": ""
}, },
"ProfilePhase3Duration": { "ProfilePhase3Duration": {
"displayText": "Trvanie\nFáza 3", "displayText": "Trvanie\nFáze 3",
"description": "" "description": ""
}, },
"ProfilePhase4Temp": { "ProfilePhase4Temp": {
"displayText": "Teplota\nFáza 4", "displayText": "Teplota\nFáze 4",
"description": "" "description": ""
}, },
"ProfilePhase4Duration": { "ProfilePhase4Duration": {
"displayText": "Trvanie\nFáza 4", "displayText": "Trvanie\nFáze 4",
"description": "" "description": ""
}, },
"ProfilePhase5Temp": { "ProfilePhase5Temp": {
"displayText": "Teplota\nFáza 5", "displayText": "Teplota\nFáze 5",
"description": "" "description": ""
}, },
"ProfilePhase5Duration": { "ProfilePhase5Duration": {
"displayText": "Trvanie\nFáza 4", "displayText": "Trvanie\nFáze 4",
"description": "" "description": ""
}, },
"ProfileCooldownSpeed": { "ProfileCooldownSpeed": {
@@ -288,7 +288,7 @@
"description": "Obmedzenie výkonu podľa použitého zdroja (watt)" "description": "Obmedzenie výkonu podľa použitého zdroja (watt)"
}, },
"CalibrateCJC": { "CalibrateCJC": {
"displayText": "Kalibrácia CJC\npri nasledujúcom štarte", "displayText": "Kalibrácia CJC\npri nasladujúcom štarte",
"description": "Pri nasledujúcom štarte bude kalibrovaná kompenzácia studeného spoja (nie je potrebné ak Delta T je < 5°C)" "description": "Pri nasledujúcom štarte bude kalibrovaná kompenzácia studeného spoja (nie je potrebné ak Delta T je < 5°C)"
}, },
"VoltageCalibration": { "VoltageCalibration": {

View File

@@ -19,8 +19,9 @@ void power_check();
// Returns the tip resistance in x10 ohms, so 7.5 = 75; 14=140 etc // Returns the tip resistance in x10 ohms, so 7.5 = 75; 14=140 etc
uint8_t getTipResistanceX10(); uint8_t getTipResistanceX10();
uint16_t getTipThermalMass(); uint8_t getTipThermalMass();
uint16_t getTipInertia(); uint8_t getTipInertia();
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -472,7 +472,7 @@ uint64_t getDeviceID() {
uint8_t preStartChecksDone() { return 1; } uint8_t preStartChecksDone() { return 1; }
uint16_t getTipThermalMass() { return TIP_THERMAL_MASS; } uint8_t getTipThermalMass() { return TIP_THERMAL_MASS; }
uint16_t getTipInertia() { return TIP_THERMAL_MASS; } uint8_t getTipInertia() { return TIP_THERMAL_MASS; }
void showBootLogo(void) { BootLogo::handleShowingLogo((uint8_t *)FLASH_LOGOADDR); } void showBootLogo(void) { BootLogo::handleShowingLogo((uint8_t *)FLASH_LOGOADDR); }

View File

@@ -396,7 +396,7 @@ bool isTipShorted() { return tipShorted; }
#else #else
bool isTipShorted() { return false; } bool isTipShorted() { return false; }
#endif #endif
uint16_t getTipThermalMass() { uint8_t getTipThermalMass() {
#ifdef TIP_RESISTANCE_SENSE_Pin #ifdef TIP_RESISTANCE_SENSE_Pin
if (lastTipResistance >= 80) { if (lastTipResistance >= 80) {
return TIP_THERMAL_MASS; return TIP_THERMAL_MASS;
@@ -406,7 +406,7 @@ uint16_t getTipThermalMass() {
return TIP_THERMAL_MASS; return TIP_THERMAL_MASS;
#endif #endif
} }
uint16_t getTipInertia() { uint8_t getTipInertia() {
#ifdef TIP_RESISTANCE_SENSE_Pin #ifdef TIP_RESISTANCE_SENSE_Pin
if (lastTipResistance >= 80) { if (lastTipResistance >= 80) {
return TIP_THERMAL_MASS; return TIP_THERMAL_MASS;

View File

@@ -97,7 +97,7 @@ uint8_t getTipResistanceX10() { return TIP_RESISTANCE; }
bool isTipShorted() { return false; } bool isTipShorted() { return false; }
uint8_t preStartChecksDone() { return 1; } uint8_t preStartChecksDone() { return 1; }
uint16_t getTipThermalMass() { return TIP_THERMAL_MASS; } uint8_t getTipThermalMass() { return TIP_THERMAL_MASS; }
uint16_t getTipInertia() { return TIP_THERMAL_MASS; } uint8_t getTipInertia() { return TIP_THERMAL_MASS; }
void showBootLogo(void) { BootLogo::handleShowingLogo((uint8_t *)FLASH_LOGOADDR); } void showBootLogo(void) { BootLogo::handleShowingLogo((uint8_t *)FLASH_LOGOADDR); }

View File

@@ -160,8 +160,18 @@ uint8_t getTipResistanceX10() {
return lastTipResistance; return lastTipResistance;
} }
uint16_t getTipThermalMass() { return 120; } uint8_t getTipThermalMass() {
uint16_t getTipInertia() { return 750; } if (lastTipResistance >= 80) {
return 65;
}
return 45;
}
uint8_t getTipInertia() {
if (lastTipResistance >= 80) {
return 90;
}
return 10;
}
// We want to calculate lastTipResistance // We want to calculate lastTipResistance
// If tip is connected, and the tip is cold and the tip is not being heated // If tip is connected, and the tip is cold and the tip is not being heated
// We can use the GPIO to inject a small current into the tip and measure this // We can use the GPIO to inject a small current into the tip and measure this
@@ -170,7 +180,7 @@ uint16_t getTipInertia() { return 750; }
// Which is around 0.54mA this will induce: // Which is around 0.54mA this will induce:
// 6 ohm tip -> 3.24mV (Real world ~= 3320) // 6 ohm tip -> 3.24mV (Real world ~= 3320)
// 8 ohm tip -> 4.32mV (Real world ~= 4500) // 8 ohm tip -> 4.32mV (Real world ~= 4500)
// Which is definitely measurable // Which is definitely measureable
// Taking shortcuts here as we know we only really have to pick apart 6 and 8 ohm tips // Taking shortcuts here as we know we only really have to pick apart 6 and 8 ohm tips
// These are reported as 60 and 75 respectively // These are reported as 60 and 75 respectively
void performTipResistanceSampleReading() { void performTipResistanceSampleReading() {

View File

@@ -19,17 +19,17 @@ extern "C" {
} }
void start_PWM_output(void); void start_PWM_output(void);
#define ADC_Filter_Smooth 4 /* This basically smooths over one PWM cycle / set of readings */ #define ADC_Filter_Smooth 1
history<uint16_t, ADC_Filter_Smooth> ADC_Vin; history<uint16_t, ADC_Filter_Smooth> ADC_Vin;
history<uint16_t, ADC_Filter_Smooth> ADC_Temp; history<uint16_t, ADC_Filter_Smooth> ADC_Temp;
history<uint16_t, ADC_Filter_Smooth> ADC_Tip; history<uint16_t, ADC_Filter_Smooth> ADC_Tip;
volatile uint8_t ADCBurstCounter = 0;
// IRQ is called at the end of the 8 set readings, pop these from the FIFO and send to filters
void adc_fifo_irq(void) { void adc_fifo_irq(void) {
if (ADC_GetIntStatus(ADC_INT_FIFO_READY) == SET) { if (ADC_GetIntStatus(ADC_INT_FIFO_READY) == SET) {
// Read out all entries in the fifo // Read out all entries in the fifo
while (ADC_Get_FIFO_Count()) { while (ADC_Get_FIFO_Count()) {
uint32_t reading = ADC_Read_FIFO(); ADCBurstCounter++;
volatile uint32_t reading = ADC_Read_FIFO();
// As per manual, 26 bit reading; lowest 16 are the ADC // As per manual, 26 bit reading; lowest 16 are the ADC
uint16_t sample = reading & 0xFFFF; uint16_t sample = reading & 0xFFFF;
uint8_t source = (reading >> 21) & 0b11111; uint8_t source = (reading >> 21) & 0b11111;
@@ -43,10 +43,16 @@ void adc_fifo_irq(void) {
case VIN_ADC_CHANNEL: case VIN_ADC_CHANNEL:
ADC_Vin.update(sample); ADC_Vin.update(sample);
break; break;
default: default:
break; break;
} }
} }
if (ADCBurstCounter >= 8) {
ADCBurstCounter = 0;
start_PWM_output();
// unblock the PID controller thread // unblock the PID controller thread
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
@@ -56,6 +62,7 @@ void adc_fifo_irq(void) {
} }
} }
} }
}
// Clear IRQ // Clear IRQ
ADC_IntClr(ADC_INT_ALL); ADC_IntClr(ADC_INT_ALL);
} }
@@ -93,57 +100,30 @@ void start_PWM_output(void) {
PWM_Channel_Disable(PWM_Channel); PWM_Channel_Disable(PWM_Channel);
switchToFastPWM(); switchToFastPWM();
} }
TIMER_Enable(TIMER_CH0);
} }
// Timer 0 is used to co-ordinate the ADC and the output PWM // Timer 0 is used to co-ordinate the ADC and the output PWM
void timer0_comp0_callback(void) { void timer0_comp0_callback(void) {
if (PWM_Channel_Is_Enabled(PWM_Channel)) { TIMER_Disable(TIMER_CH0);
// So there appears to be a bug _somewhere_ where sometimes the comparator doesn't fire
// Its not re-occurring with specific values, so suspect its a weird bug
// For now, we just skip the cycle and throw away the ADC readings. Its a waste but
// It stops stupid glitches in readings, i'd take slight instability from the time jump
// Over the readings we get that are borked as the header is left on
// <Ralim 2023/10/14>
PWM_Channel_Disable(PWM_Channel);
// MSG("ALERT PWM Glitch\r\n");
// Triger the PID now instead
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (pidTaskNotification) {
vTaskNotifyGiveFromISR(pidTaskNotification, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
} else {
ADC_Start(); ADC_Start();
} }
TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_0); void timer0_comp1_callback(void) { PWM_Channel_Disable(PWM_Channel); } // Trigged at end of output cycle; turn off the tip PWM
}
void timer0_comp1_callback(void) {
// Trigged at end of output cycle; turn off the tip PWM
PWM_Channel_Disable(PWM_Channel);
TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_1);
}
void timer0_comp2_callback(void) {
// Triggered at end of timer cycle; re-start the tip driver
start_PWM_output();
TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_2);
}
void switchToFastPWM(void) { void switchToFastPWM(void) {
inFastPWMMode = true; inFastPWMMode = true;
holdoffTicks = 10; holdoffTicks = 20;
tempMeasureTicks = 10; tempMeasureTicks = 20;
totalPWM = powerPWM + tempMeasureTicks + holdoffTicks; totalPWM = powerPWM + tempMeasureTicks + holdoffTicks;
TIMER_SetCompValue(TIMER_CH0, TIMER_COMP_ID_2, totalPWM); TIMER_SetCompValue(TIMER_CH0, TIMER_COMP_ID_2, totalPWM);
// ~10Hz // ~10Hz
TIMER_SetCompValue(TIMER_CH0, TIMER_COMP_ID_0, powerPWM + holdoffTicks); TIMER_SetCompValue(TIMER_CH0, TIMER_COMP_ID_0, powerPWM + holdoffTicks);
// Set divider to 10 ~= 10.5Hz // Set divider to 10 ~= 10.5Hz
uint32_t tmpVal = BL_RD_REG(TIMER_BASE, TIMER_TCDR); uint32_t tmpVal = BL_RD_REG(TIMER_BASE, TIMER_TCDR);
tmpVal = BL_SET_REG_BITS_VAL(tmpVal, TIMER_TCDR2, 10); tmpVal = BL_SET_REG_BITS_VAL(tmpVal, TIMER_TCDR2, 6);
BL_WR_REG(TIMER_BASE, TIMER_TCDR, tmpVal); BL_WR_REG(TIMER_BASE, TIMER_TCDR, tmpVal);
} }
@@ -151,19 +131,19 @@ void switchToFastPWM(void) {
void switchToSlowPWM(void) { void switchToSlowPWM(void) {
// 5Hz // 5Hz
inFastPWMMode = false; inFastPWMMode = false;
holdoffTicks = 5; holdoffTicks = 10;
tempMeasureTicks = 5; tempMeasureTicks = 10;
totalPWM = powerPWM + tempMeasureTicks + holdoffTicks; totalPWM = powerPWM + tempMeasureTicks + holdoffTicks;
TIMER_SetCompValue(TIMER_CH0, TIMER_COMP_ID_2, totalPWM); TIMER_SetCompValue(TIMER_CH0, TIMER_COMP_ID_2, totalPWM);
// Adjust ADC // Adjust ADC
TIMER_SetCompValue(TIMER_CH0, TIMER_COMP_ID_0, powerPWM + holdoffTicks); TIMER_SetCompValue(TIMER_CH0, TIMER_COMP_ID_0, powerPWM + holdoffTicks);
// Set divider for ~ 5Hz // Set divider to 22
uint32_t tmpVal = BL_RD_REG(TIMER_BASE, TIMER_TCDR); uint32_t tmpVal = BL_RD_REG(TIMER_BASE, TIMER_TCDR);
tmpVal = BL_SET_REG_BITS_VAL(tmpVal, TIMER_TCDR2, 20); tmpVal = BL_SET_REG_BITS_VAL(tmpVal, TIMER_TCDR2, 12);
BL_WR_REG(TIMER_BASE, TIMER_TCDR, tmpVal); BL_WR_REG(TIMER_BASE, TIMER_TCDR, tmpVal);
} }
@@ -213,6 +193,5 @@ uint16_t getADCHandleTemp(uint8_t sample) { return ADC_Temp.average(); }
uint16_t getADCVin(uint8_t sample) { return ADC_Vin.average(); } uint16_t getADCVin(uint8_t sample) { return ADC_Vin.average(); }
// Returns the current raw tip reading after any cleanup filtering // Returns either average or instant value. When sample is set the samples from the injected ADC are copied to the filter and then the raw reading is returned
// For Pinecil V2 we dont do any rolling filtering other than just averaging all 4 readings in the adc snapshot
uint16_t getTipRawTemp(uint8_t sample) { return ADC_Tip.average() >> 1; } uint16_t getTipRawTemp(uint8_t sample) { return ADC_Tip.average() >> 1; }

View File

@@ -102,7 +102,7 @@ void setup_adc(void) {
adc_cfg.clkDiv = ADC_CLK_DIV_4; adc_cfg.clkDiv = ADC_CLK_DIV_4;
adc_cfg.vref = ADC_VREF_3P2V; adc_cfg.vref = ADC_VREF_3P2V;
adc_cfg.resWidth = ADC_DATA_WIDTH_14_WITH_16_AVERAGE; adc_cfg.resWidth = ADC_DATA_WIDTH_14_WITH_64_AVERAGE;
adc_cfg.inputMode = ADC_INPUT_SINGLE_END; adc_cfg.inputMode = ADC_INPUT_SINGLE_END;
adc_cfg.v18Sel = ADC_V18_SEL_1P72V; adc_cfg.v18Sel = ADC_V18_SEL_1P72V;
adc_cfg.v11Sel = ADC_V11_SEL_1P1V; adc_cfg.v11Sel = ADC_V11_SEL_1P1V;
@@ -111,7 +111,7 @@ void setup_adc(void) {
adc_cfg.chopMode = ADC_CHOP_MOD_AZ_ON; adc_cfg.chopMode = ADC_CHOP_MOD_AZ_ON;
adc_cfg.biasSel = ADC_BIAS_SEL_MAIN_BANDGAP; adc_cfg.biasSel = ADC_BIAS_SEL_MAIN_BANDGAP;
adc_cfg.vcm = ADC_PGA_VCM_1P6V; adc_cfg.vcm = ADC_PGA_VCM_1P6V;
adc_cfg.offsetCalibEn = DISABLE; adc_cfg.offsetCalibEn = ENABLE;
adc_cfg.offsetCalibVal = 0; adc_cfg.offsetCalibVal = 0;
ADC_Disable(); ADC_Disable();
@@ -120,7 +120,7 @@ void setup_adc(void) {
ADC_Init(&adc_cfg); ADC_Init(&adc_cfg);
adc_fifo_cfg.dmaEn = DISABLE; adc_fifo_cfg.dmaEn = DISABLE;
adc_fifo_cfg.fifoThreshold = ADC_FIFO_THRESHOLD_8; // Triger FIFO when all 8 measurements are done adc_fifo_cfg.fifoThreshold = ADC_FIFO_THRESHOLD_8;
ADC_FIFO_Cfg(&adc_fifo_cfg); ADC_FIFO_Cfg(&adc_fifo_cfg);
ADC_MIC_Bias_Disable(); ADC_MIC_Bias_Disable();
ADC_Tsen_Disable(); ADC_Tsen_Disable();
@@ -140,27 +140,24 @@ void setup_timer_scheduler() {
TIMER_CFG_Type cfg = { TIMER_CFG_Type cfg = {
TIMER_CH0, // Channel TIMER_CH0, // Channel
TIMER_CLKSRC_32K, // Clock source TIMER_CLKSRC_32K, // Clock source
TIMER_PRELOAD_TRIG_COMP2, // Trigger; reset after trigger 0 TIMER_PRELOAD_TRIG_COMP0, // Trigger; reset after trigger 0
TIMER_COUNT_PRELOAD, // Counter mode TIMER_COUNT_PRELOAD, // Counter mode
22, // Clock div 22, // Clock div
(uint16_t)(powerPWM + holdoffTicks), // CH0 compare (adc) (uint16_t)(powerPWM + holdoffTicks), // CH0 compare (adc)
(uint16_t)(powerPWM), // CH1 compare (pwm out) 0, // CH1 compare (pwm out)
(uint16_t)(powerPWM + holdoffTicks + tempMeasureTicks), // CH2 compare end of cycle 0, // CH2 compare not used
0, // Preload 0, // Preload
}; };
TIMER_Init(&cfg); TIMER_Init(&cfg);
Timer_Int_Callback_Install(TIMER_CH0, TIMER_INT_COMP_0, timer0_comp0_callback); Timer_Int_Callback_Install(TIMER_CH0, TIMER_INT_COMP_0, timer0_comp0_callback);
Timer_Int_Callback_Install(TIMER_CH0, TIMER_INT_COMP_1, timer0_comp1_callback); Timer_Int_Callback_Install(TIMER_CH0, TIMER_INT_COMP_1, timer0_comp1_callback);
Timer_Int_Callback_Install(TIMER_CH0, TIMER_INT_COMP_2, timer0_comp2_callback);
TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_0); TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_0);
TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_1); TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_1);
TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_2);
TIMER_IntMask(TIMER_CH0, TIMER_INT_COMP_0, UNMASK); TIMER_IntMask(TIMER_CH0, TIMER_INT_COMP_0, UNMASK);
TIMER_IntMask(TIMER_CH0, TIMER_INT_COMP_1, UNMASK); TIMER_IntMask(TIMER_CH0, TIMER_INT_COMP_1, UNMASK);
TIMER_IntMask(TIMER_CH0, TIMER_INT_COMP_2, UNMASK);
CPU_Interrupt_Enable(TIMER_CH0_IRQn); CPU_Interrupt_Enable(TIMER_CH0_IRQn);
TIMER_Enable(TIMER_CH0); TIMER_Enable(TIMER_CH0);
} }

View File

@@ -36,9 +36,8 @@
#ifndef __BL702_PWM_H__ #ifndef __BL702_PWM_H__
#define __BL702_PWM_H__ #define __BL702_PWM_H__
#include "bl702_common.h"
#include "pwm_reg.h" #include "pwm_reg.h"
#include "bl702_common.h"
/** @addtogroup BL702_Peripheral_Driver /** @addtogroup BL702_Peripheral_Driver
* @{ * @{
@@ -100,7 +99,8 @@ typedef enum {
/** /**
* @brief PWM configuration structure type definition * @brief PWM configuration structure type definition
*/ */
typedef struct { typedef struct
{
PWM_CH_ID_Type ch; /*!< PWM channel */ PWM_CH_ID_Type ch; /*!< PWM channel */
PWM_Clk_Type clk; /*!< PWM Clock */ PWM_Clk_Type clk; /*!< PWM Clock */
PWM_Stop_Mode_Type stopMode; /*!< PWM Stop Mode */ PWM_Stop_Mode_Type stopMode; /*!< PWM Stop Mode */
@@ -121,27 +121,37 @@ typedef struct {
/** @defgroup PWM_CH_ID_TYPE /** @defgroup PWM_CH_ID_TYPE
* @{ * @{
*/ */
#define IS_PWM_CH_ID_TYPE(type) (((type) == PWM_CH0) || ((type) == PWM_CH1) || ((type) == PWM_CH2) || ((type) == PWM_CH3) || ((type) == PWM_CH4) || ((type) == PWM_CH_MAX)) #define IS_PWM_CH_ID_TYPE(type) (((type) == PWM_CH0) || \
((type) == PWM_CH1) || \
((type) == PWM_CH2) || \
((type) == PWM_CH3) || \
((type) == PWM_CH4) || \
((type) == PWM_CH_MAX))
/** @defgroup PWM_CLK_TYPE /** @defgroup PWM_CLK_TYPE
* @{ * @{
*/ */
#define IS_PWM_CLK_TYPE(type) (((type) == PWM_CLK_XCLK) || ((type) == PWM_CLK_BCLK) || ((type) == PWM_CLK_32K)) #define IS_PWM_CLK_TYPE(type) (((type) == PWM_CLK_XCLK) || \
((type) == PWM_CLK_BCLK) || \
((type) == PWM_CLK_32K))
/** @defgroup PWM_STOP_MODE_TYPE /** @defgroup PWM_STOP_MODE_TYPE
* @{ * @{
*/ */
#define IS_PWM_STOP_MODE_TYPE(type) (((type) == PWM_STOP_ABRUPT) || ((type) == PWM_STOP_GRACEFUL)) #define IS_PWM_STOP_MODE_TYPE(type) (((type) == PWM_STOP_ABRUPT) || \
((type) == PWM_STOP_GRACEFUL))
/** @defgroup PWM_POLARITY_TYPE /** @defgroup PWM_POLARITY_TYPE
* @{ * @{
*/ */
#define IS_PWM_POLARITY_TYPE(type) (((type) == PWM_POL_NORMAL) || ((type) == PWM_POL_INVERT)) #define IS_PWM_POLARITY_TYPE(type) (((type) == PWM_POL_NORMAL) || \
((type) == PWM_POL_INVERT))
/** @defgroup PWM_INT_TYPE /** @defgroup PWM_INT_TYPE
* @{ * @{
*/ */
#define IS_PWM_INT_TYPE(type) (((type) == PWM_INT_PULSE_CNT) || ((type) == PWM_INT_ALL)) #define IS_PWM_INT_TYPE(type) (((type) == PWM_INT_PULSE_CNT) || \
((type) == PWM_INT_ALL))
/*@} end of group PWM_Public_Constants */ /*@} end of group PWM_Public_Constants */
@@ -171,13 +181,13 @@ void PWM_Channel_Set_Period(PWM_CH_ID_Type ch, uint16_t period);
void PWM_Channel_Get(PWM_CH_ID_Type ch, uint16_t *period, uint16_t *threshold1, uint16_t *threshold2); void PWM_Channel_Get(PWM_CH_ID_Type ch, uint16_t *period, uint16_t *threshold1, uint16_t *threshold2);
void PWM_IntMask(PWM_CH_ID_Type ch, PWM_INT_Type intType, BL_Mask_Type intMask); void PWM_IntMask(PWM_CH_ID_Type ch, PWM_INT_Type intType, BL_Mask_Type intMask);
void PWM_Channel_Enable(PWM_CH_ID_Type ch); void PWM_Channel_Enable(PWM_CH_ID_Type ch);
uint8_t PWM_Channel_Is_Enabled(PWM_CH_ID_Type ch);
void PWM_Channel_Disable(PWM_CH_ID_Type ch); void PWM_Channel_Disable(PWM_CH_ID_Type ch);
void PWM_SW_Mode(PWM_CH_ID_Type ch, BL_Fun_Type enable); void PWM_SW_Mode(PWM_CH_ID_Type ch, BL_Fun_Type enable);
void PWM_SW_Force_Value(PWM_CH_ID_Type ch, uint8_t value); void PWM_SW_Force_Value(PWM_CH_ID_Type ch, uint8_t value);
void PWM_Int_Callback_Install(PWM_CH_ID_Type ch, uint32_t intType, intCallback_Type *cbFun); void PWM_Int_Callback_Install(PWM_CH_ID_Type ch, uint32_t intType, intCallback_Type *cbFun);
BL_Err_Type PWM_Smart_Configure(PWM_CH_ID_Type ch, uint32_t frequency, uint8_t dutyCycle); BL_Err_Type PWM_Smart_Configure(PWM_CH_ID_Type ch, uint32_t frequency, uint8_t dutyCycle);
/*@} end of group PWM_Public_Functions */ /*@} end of group PWM_Public_Functions */
/*@} end of group PWM */ /*@} end of group PWM */

View File

@@ -354,18 +354,7 @@ void PWM_Channel_Enable(PWM_CH_ID_Type ch) {
tmpVal = BL_RD_REG(PWMx, PWM_CONFIG); tmpVal = BL_RD_REG(PWMx, PWM_CONFIG);
BL_WR_REG(PWMx, PWM_CONFIG, BL_CLR_REG_BIT(tmpVal, PWM_STOP_EN)); BL_WR_REG(PWMx, PWM_CONFIG, BL_CLR_REG_BIT(tmpVal, PWM_STOP_EN));
} }
uint8_t PWM_Channel_Is_Enabled(PWM_CH_ID_Type ch) {
uint32_t tmpVal;
/* Get channel register */
uint32_t PWMx = PWM_Get_Channel_Reg(ch);
/* Check the parameters */
CHECK_PARAM(IS_PWM_CH_ID_TYPE(ch));
/* Config pwm clock to enable pwm */
tmpVal = BL_RD_REG(PWMx, PWM_CONFIG);
return BL_GET_REG_BITS_VAL(tmpVal, PWM_STOP_EN) == 0;
}
/**************************************************************************** /****************************************************************************
* @brief PWM disable * @brief PWM disable
* *

View File

@@ -161,15 +161,9 @@
#define DEBUG_UART_OUTPUT #define DEBUG_UART_OUTPUT
#define HAS_POWER_DEBUG_MENU #define HAS_POWER_DEBUG_MENU
#define HARDWARE_MAX_WATTAGE_X10 750 #define HARDWARE_MAX_WATTAGE_X10 750
#define BLE_ENABLED // We have a BLE stack #define BLE_ENABLED
#define NEEDS_VBUS_PROBE 0 // No vbus probe, its not connected in pcb #define NEEDS_VBUS_PROBE 0
#define CANT_DIRECT_READ_SETTINGS // We cant memcpy settings due to flash cache #define CANT_DIRECT_READ_SETTINGS
#define TIP_CONTROL_PID // We use PID rather than integrator
#define TIP_PID_KP 45 // Reasonable compromise for most tips so far
#define TIP_PID_KI 9 // About as high for stability across tips
#define TIP_PID_KD 200 // Helps dampen smaller tips; ~= nothing for larger tips
#define FILTER_DISPLAYED_TIP_TEMP 8 // Filtering for GUI display
#endif /* Pinecilv2 */ #endif /* Pinecilv2 */
#define FLASH_PAGE_SIZE (1024) // Read pages #define FLASH_PAGE_SIZE (1024) // Read pages

View File

@@ -234,8 +234,8 @@ uint8_t getTipResistanceX10() { return TIP_RESISTANCE; }
bool isTipShorted() { return false; } bool isTipShorted() { return false; }
uint8_t preStartChecksDone() { return 1; } uint8_t preStartChecksDone() { return 1; }
uint16_t getTipThermalMass() { return TIP_THERMAL_MASS; } uint8_t getTipThermalMass() { return TIP_THERMAL_MASS; }
uint16_t getTipInertia() { return TIP_THERMAL_INERTIA; } uint8_t getTipInertia() { return TIP_THERMAL_INERTIA; }
void setBuzzer(bool on) {} void setBuzzer(bool on) {}

View File

@@ -10,7 +10,6 @@ extern "C" {
#include "Settings.h" #include "Settings.h"
#include "TipThermoModel.h" #include "TipThermoModel.h"
#include "Translation.h" #include "Translation.h"
#include "Types.h"
#include "cmsis_os.h" #include "cmsis_os.h"
#include "configuration.h" #include "configuration.h"
#include "history.hpp" #include "history.hpp"
@@ -48,5 +47,5 @@ void renderHomeScreenAssets(void); // Called to
// Common helpers // Common helpers
int8_t getPowerSourceNumber(void); // Returns number ID of power source int8_t getPowerSourceNumber(void); // Returns number ID of power source
TemperatureType_t getTipTemp(void); // Returns temperature of the tip in *C/*F (based on user settings) uint16_t getTipTemp(void); // Returns temperature of the tip in *C/*F (based on user settings)
#endif #endif

View File

@@ -25,7 +25,7 @@ int gui_SolderingSleepingMode(bool stayOff, bool autoStarted) {
} }
// draw the lcd // draw the lcd
TemperatureType_t tipTemp = getTipTemp(); uint16_t tipTemp = getTipTemp();
OLED::clearScreen(); OLED::clearScreen();
OLED::setCursor(0, 0); OLED::setCursor(0, 0);

View File

@@ -4,7 +4,7 @@
void gui_drawTipTemp(bool symbol, const FontStyle font) { void gui_drawTipTemp(bool symbol, const FontStyle font) {
// Draw tip temp handling unit conversion & tolerance near setpoint // Draw tip temp handling unit conversion & tolerance near setpoint
TemperatureType_t Temp = getTipTemp(); uint16_t Temp = getTipTemp();
OLED::printNumber(Temp, 3, font); // Draw the tip temp out OLED::printNumber(Temp, 3, font); // Draw the tip temp out
if (symbol) { if (symbol) {

View File

@@ -4,8 +4,6 @@
#include "SolderingCommon.h" #include "SolderingCommon.h"
#include "OperatingModes.h" #include "OperatingModes.h"
#include "configuration.h"
#include "history.hpp"
extern bool heaterThermalRunaway; extern bool heaterThermalRunaway;
@@ -168,14 +166,4 @@ int8_t getPowerSourceNumber(void) {
} }
// Returns temperature of the tip in *C/*F (based on user settings) // Returns temperature of the tip in *C/*F (based on user settings)
TemperatureType_t getTipTemp(void) { uint16_t getTipTemp(void) { return getSettingValue(SettingsOptions::TemperatureInF) ? TipThermoModel::getTipInF() : TipThermoModel::getTipInC(); }
#ifdef FILTER_DISPLAYED_TIP_TEMP
static history<TemperatureType_t, FILTER_DISPLAYED_TIP_TEMP> Filter_Temp;
TemperatureType_t reading = getSettingValue(SettingsOptions::TemperatureInF) ? TipThermoModel::getTipInF() : TipThermoModel::getTipInC();
Filter_Temp.update(reading);
return Filter_Temp.average();
#else
return getSettingValue(SettingsOptions::TemperatureInF) ? TipThermoModel::getTipInF() : TipThermoModel::getTipInC();
#endif
}

View File

@@ -10,7 +10,6 @@
#include "Settings.h" #include "Settings.h"
#include "TipThermoModel.h" #include "TipThermoModel.h"
#include "cmsis_os.h" #include "cmsis_os.h"
#include "configuration.h"
#include "history.hpp" #include "history.hpp"
#include "main.hpp" #include "main.hpp"
#include "power.hpp" #include "power.hpp"
@@ -23,7 +22,7 @@ volatile TemperatureType_t currentTempTargetDegC = 0; // Current temperature t
int32_t powerSupplyWattageLimit = 0; int32_t powerSupplyWattageLimit = 0;
bool heaterThermalRunaway = false; bool heaterThermalRunaway = false;
static int32_t getPIDResultX10Watts(TemperatureType_t set_point, TemperatureType_t current_value); static int32_t getPIDResultX10Watts(TemperatureType_t tError);
static void detectThermalRunaway(const TemperatureType_t currentTipTempInC, const TemperatureType_t tError); static void detectThermalRunaway(const TemperatureType_t currentTipTempInC, const TemperatureType_t tError);
static void setOutputx10WattsViaFilters(int32_t x10Watts); static void setOutputx10WattsViaFilters(int32_t x10Watts);
static int32_t getX10WattageLimits(); static int32_t getX10WattageLimits();
@@ -72,9 +71,10 @@ void startPIDTask(void const *argument __unused) {
if (PIDTempTarget > TipThermoModel::getTipMaxInC()) { if (PIDTempTarget > TipThermoModel::getTipMaxInC()) {
PIDTempTarget = TipThermoModel::getTipMaxInC(); PIDTempTarget = TipThermoModel::getTipMaxInC();
} }
TemperatureType_t tError = PIDTempTarget - currentTipTempInC;
detectThermalRunaway(currentTipTempInC, PIDTempTarget - currentTipTempInC); detectThermalRunaway(currentTipTempInC, tError);
x10WattsOut = getPIDResultX10Watts(PIDTempTarget, currentTipTempInC); x10WattsOut = getPIDResultX10Watts(tError);
} else { } else {
detectThermalRunaway(currentTipTempInC, 0); detectThermalRunaway(currentTipTempInC, 0);
} }
@@ -89,53 +89,6 @@ void startPIDTask(void const *argument __unused) {
} }
} }
#ifdef TIP_CONTROL_PID
template <class T, T Kp, T Ki, T Kd, T integral_limit_scale> struct PID {
T previous_error_term;
T integration_running_sum;
T update(const T set_point, const T new_reading, const TickType_t interval_ms, const T max_output) {
const T target_delta = set_point - new_reading;
// Proportional term
const T kp_result = Kp * target_delta;
// Integral term as we use mixed sampling rates, we cant assume a constant sample interval
// Thus we multiply this out by the interval time to ~= dv/dt
// Then the shift by 1000 is ms -> Seconds
integration_running_sum += (target_delta * interval_ms * Ki) / 1000;
// We constrain integration_running_sum to limit windup
// This is not overly required for most use cases but can prevent large overshoot in constrained implementations
if (integration_running_sum > integral_limit_scale * max_output) {
integration_running_sum = integral_limit_scale * max_output;
} else if (integration_running_sum < -integral_limit_scale * max_output) {
integration_running_sum = -integral_limit_scale * max_output;
}
// Calculate the integral term, we use a shift 100 to get precision in integral as we often need small amounts
T ki_result = integration_running_sum / 100;
// Derivative term
T derivative = (target_delta - previous_error_term);
T kd_result = ((Kd * derivative) / (T)(interval_ms));
// Summation of the outputs
T output = kp_result + ki_result + kd_result;
// Restrict to max / 0
if (output > max_output)
output = max_output;
else if (output < 0)
output = 0;
// Save target_delta to previous target_delta
previous_error_term = target_delta;
return output;
}
};
#else
template <class T = TemperatureType_t> struct Integrator { template <class T = TemperatureType_t> struct Integrator {
T sum; T sum;
@@ -161,19 +114,11 @@ template <class T = TemperatureType_t> struct Integrator {
T get(bool positiveOnly = true) const { return (positiveOnly) ? ((sum > 0) ? sum : 0) : sum; } T get(bool positiveOnly = true) const { return (positiveOnly) ? ((sum > 0) ? sum : 0) : sum; }
}; };
#endif int32_t getPIDResultX10Watts(TemperatureType_t setpointDelta) {
int32_t getPIDResultX10Watts(TemperatureType_t set_point, TemperatureType_t current_reading) {
static TickType_t lastCall = 0; static TickType_t lastCall = 0;
#ifdef TIP_CONTROL_PID
static PID<TemperatureType_t, TIP_PID_KP, TIP_PID_KI, TIP_PID_KD, 5> pid = {0, 0};
const TickType_t interval = (xTaskGetTickCount() - lastCall);
#else
static Integrator<TemperatureType_t> powerStore = {0}; static Integrator<TemperatureType_t> powerStore = {0};
const TickType_t rate = TICKS_SECOND / (xTaskGetTickCount() - lastCall); const TickType_t rate = TICKS_SECOND / (xTaskGetTickCount() - lastCall);
#endif
lastCall = xTaskGetTickCount(); lastCall = xTaskGetTickCount();
// Sandman note: // Sandman note:
// PID Challenge - we have a small thermal mass that we to want heat up as fast as possible but we don't // PID Challenge - we have a small thermal mass that we to want heat up as fast as possible but we don't
@@ -196,16 +141,11 @@ int32_t getPIDResultX10Watts(TemperatureType_t set_point, TemperatureType_t curr
// tip temperature with (Delta Temperature ) °C in 1 second. // 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 // 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. // in X10 (J / °C) units as well.
return powerStore.update(((TemperatureType_t)getTipThermalMass()) * setpointDelta, // the required power
#ifdef TIP_CONTROL_PID
return pid.update(set_point, current_reading, interval, getX10WattageLimits());
#else
return powerStore.update(((TemperatureType_t)getTipThermalMass()) * (set_point - current_reading), // the required power
getTipInertia(), // Inertia, smaller numbers increase dominance of the previous value getTipInertia(), // Inertia, smaller numbers increase dominance of the previous value
2, // gain 2, // gain
rate, // PID cycle frequency rate, // PID cycle frequency
getX10WattageLimits()); getX10WattageLimits());
#endif
} }
void detectThermalRunaway(const TemperatureType_t currentTipTempInC, const TemperatureType_t tError) { void detectThermalRunaway(const TemperatureType_t currentTipTempInC, const TemperatureType_t tError) {