From c308fe8cc2bd8e1e93e9441d7e8fc537a79a2259 Mon Sep 17 00:00:00 2001 From: "Ben V. Brown" <5425387+Ralim@users.noreply.github.com> Date: Sat, 21 Oct 2023 08:21:08 +1100 Subject: Pinecil v2 tune via PID (#1827) * Start PWM after adc irq fully done * Filter len 4 * Use comparitor 2 on timer for wrap around * Update IRQ.cpp * Tip measurements are uint16_t Update BSP.cpp Update BSP.cpp * WiP PID move pid tuning to config Update PIDThread.cpp * Handle PWM Timer gitchy comparitor * Tuning * Dampen with Kd * Cleaning up * Use TemperatureType_t for getTipTemp() * Add small rolling average to user GUI temp to reduce flicker * Trigger PID when adc is skipped (will use old values) --- source/Core/BSP/BSP_Power.h | 5 +- source/Core/BSP/MHP30/BSP.cpp | 4 +- source/Core/BSP/Miniware/BSP.cpp | 4 +- source/Core/BSP/Pinecil/BSP.cpp | 4 +- source/Core/BSP/Pinecilv2/BSP.cpp | 16 +- source/Core/BSP/Pinecilv2/IRQ.cpp | 71 ++++++--- source/Core/BSP/Pinecilv2/Setup.cpp | 27 ++-- .../drivers/bl702_driver/std_drv/inc/bl702_pwm.h | 168 ++++++++++----------- .../drivers/bl702_driver/std_drv/src/bl702_pwm.c | 11 ++ source/Core/BSP/Pinecilv2/configuration.h | 14 +- source/Core/BSP/Sequre_S60/BSP.cpp | 4 +- .../Core/Threads/OperatingModes/OperatingModes.h | 17 ++- source/Core/Threads/OperatingModes/Sleep.cpp | 2 +- .../OperatingModes/utils/DrawTipTemperature.cpp | 2 +- .../OperatingModes/utils/SolderingCommon.cpp | 14 +- source/Core/Threads/PIDThread.cpp | 86 +++++++++-- 16 files changed, 271 insertions(+), 178 deletions(-) diff --git a/source/Core/BSP/BSP_Power.h b/source/Core/BSP/BSP_Power.h index 46c4ae2e..348dc7a7 100644 --- a/source/Core/BSP/BSP_Power.h +++ b/source/Core/BSP/BSP_Power.h @@ -19,9 +19,8 @@ void power_check(); // Returns the tip resistance in x10 ohms, so 7.5 = 75; 14=140 etc uint8_t getTipResistanceX10(); -uint8_t getTipThermalMass(); -uint8_t getTipInertia(); - +uint16_t getTipThermalMass(); +uint16_t getTipInertia(); #ifdef __cplusplus } diff --git a/source/Core/BSP/MHP30/BSP.cpp b/source/Core/BSP/MHP30/BSP.cpp index 7d42019f..70149f4f 100644 --- a/source/Core/BSP/MHP30/BSP.cpp +++ b/source/Core/BSP/MHP30/BSP.cpp @@ -472,7 +472,7 @@ uint64_t getDeviceID() { uint8_t preStartChecksDone() { return 1; } -uint8_t getTipThermalMass() { return TIP_THERMAL_MASS; } -uint8_t getTipInertia() { return TIP_THERMAL_MASS; } +uint16_t getTipThermalMass() { return TIP_THERMAL_MASS; } +uint16_t getTipInertia() { return TIP_THERMAL_MASS; } void showBootLogo(void) { BootLogo::handleShowingLogo((uint8_t *)FLASH_LOGOADDR); } diff --git a/source/Core/BSP/Miniware/BSP.cpp b/source/Core/BSP/Miniware/BSP.cpp index f7e2053b..e930f682 100644 --- a/source/Core/BSP/Miniware/BSP.cpp +++ b/source/Core/BSP/Miniware/BSP.cpp @@ -396,7 +396,7 @@ bool isTipShorted() { return tipShorted; } #else bool isTipShorted() { return false; } #endif -uint8_t getTipThermalMass() { +uint16_t getTipThermalMass() { #ifdef TIP_RESISTANCE_SENSE_Pin if (lastTipResistance >= 80) { return TIP_THERMAL_MASS; @@ -406,7 +406,7 @@ uint8_t getTipThermalMass() { return TIP_THERMAL_MASS; #endif } -uint8_t getTipInertia() { +uint16_t getTipInertia() { #ifdef TIP_RESISTANCE_SENSE_Pin if (lastTipResistance >= 80) { return TIP_THERMAL_MASS; diff --git a/source/Core/BSP/Pinecil/BSP.cpp b/source/Core/BSP/Pinecil/BSP.cpp index 1c7a3888..56e96810 100644 --- a/source/Core/BSP/Pinecil/BSP.cpp +++ b/source/Core/BSP/Pinecil/BSP.cpp @@ -97,7 +97,7 @@ uint8_t getTipResistanceX10() { return TIP_RESISTANCE; } bool isTipShorted() { return false; } uint8_t preStartChecksDone() { return 1; } -uint8_t getTipThermalMass() { return TIP_THERMAL_MASS; } -uint8_t getTipInertia() { return TIP_THERMAL_MASS; } +uint16_t getTipThermalMass() { return TIP_THERMAL_MASS; } +uint16_t getTipInertia() { return TIP_THERMAL_MASS; } void showBootLogo(void) { BootLogo::handleShowingLogo((uint8_t *)FLASH_LOGOADDR); } diff --git a/source/Core/BSP/Pinecilv2/BSP.cpp b/source/Core/BSP/Pinecilv2/BSP.cpp index 7c711a61..c511be2e 100644 --- a/source/Core/BSP/Pinecilv2/BSP.cpp +++ b/source/Core/BSP/Pinecilv2/BSP.cpp @@ -160,18 +160,8 @@ uint8_t getTipResistanceX10() { return lastTipResistance; } -uint8_t getTipThermalMass() { - if (lastTipResistance >= 80) { - return 65; - } - return 45; -} -uint8_t getTipInertia() { - if (lastTipResistance >= 80) { - return 90; - } - return 10; -} +uint16_t getTipThermalMass() { return 120; } +uint16_t getTipInertia() { return 750; } // We want to calculate lastTipResistance // 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 @@ -180,7 +170,7 @@ uint8_t getTipInertia() { // Which is around 0.54mA this will induce: // 6 ohm tip -> 3.24mV (Real world ~= 3320) // 8 ohm tip -> 4.32mV (Real world ~= 4500) -// Which is definitely measureable +// Which is definitely measurable // 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 void performTipResistanceSampleReading() { diff --git a/source/Core/BSP/Pinecilv2/IRQ.cpp b/source/Core/BSP/Pinecilv2/IRQ.cpp index bd64a96e..7a857b18 100644 --- a/source/Core/BSP/Pinecilv2/IRQ.cpp +++ b/source/Core/BSP/Pinecilv2/IRQ.cpp @@ -19,17 +19,17 @@ extern "C" { } void start_PWM_output(void); -#define ADC_Filter_Smooth 1 +#define ADC_Filter_Smooth 4 /* This basically smooths over one PWM cycle / set of readings */ history ADC_Vin; history ADC_Temp; history ADC_Tip; -volatile uint8_t ADCBurstCounter = 0; -void adc_fifo_irq(void) { + +// 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) { if (ADC_GetIntStatus(ADC_INT_FIFO_READY) == SET) { // Read out all entries in the fifo while (ADC_Get_FIFO_Count()) { - ADCBurstCounter++; - volatile uint32_t reading = ADC_Read_FIFO(); + uint32_t reading = ADC_Read_FIFO(); // As per manual, 26 bit reading; lowest 16 are the ADC uint16_t sample = reading & 0xFFFF; uint8_t source = (reading >> 21) & 0b11111; @@ -43,23 +43,16 @@ void adc_fifo_irq(void) { case VIN_ADC_CHANNEL: ADC_Vin.update(sample); break; - default: break; } } - - if (ADCBurstCounter >= 8) { - ADCBurstCounter = 0; - start_PWM_output(); - - // unblock the PID controller thread - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - if (pidTaskNotification) { - vTaskNotifyGiveFromISR(pidTaskNotification, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); - } + // unblock the PID controller thread + if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + if (pidTaskNotification) { + vTaskNotifyGiveFromISR(pidTaskNotification, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } } @@ -100,16 +93,43 @@ void start_PWM_output(void) { PWM_Channel_Disable(PWM_Channel); switchToFastPWM(); } - TIMER_Enable(TIMER_CH0); } // Timer 0 is used to co-ordinate the ADC and the output PWM void timer0_comp0_callback(void) { - TIMER_Disable(TIMER_CH0); - ADC_Start(); + if (PWM_Channel_Is_Enabled(PWM_Channel)) { + // 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 + // + 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(); + } + TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_0); +} +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_comp1_callback(void) { PWM_Channel_Disable(PWM_Channel); } // Trigged at end of output cycle; turn off the tip PWM +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) { inFastPWMMode = true; holdoffTicks = 10; @@ -119,8 +139,8 @@ void switchToFastPWM(void) { // ~10Hz 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); tmpVal = BL_SET_REG_BITS_VAL(tmpVal, TIMER_TCDR2, 10); @@ -139,7 +159,7 @@ void switchToSlowPWM(void) { // Adjust ADC TIMER_SetCompValue(TIMER_CH0, TIMER_COMP_ID_0, powerPWM + holdoffTicks); - // Set divider to 22 + // Set divider for ~ 5Hz uint32_t tmpVal = BL_RD_REG(TIMER_BASE, TIMER_TCDR); @@ -193,5 +213,6 @@ uint16_t getADCHandleTemp(uint8_t sample) { return ADC_Temp.average(); } uint16_t getADCVin(uint8_t sample) { return ADC_Vin.average(); } -// 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 +// Returns the current raw tip reading after any cleanup filtering +// 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; } diff --git a/source/Core/BSP/Pinecilv2/Setup.cpp b/source/Core/BSP/Pinecilv2/Setup.cpp index 96d9a5d0..120ba237 100644 --- a/source/Core/BSP/Pinecilv2/Setup.cpp +++ b/source/Core/BSP/Pinecilv2/Setup.cpp @@ -102,7 +102,7 @@ void setup_adc(void) { adc_cfg.clkDiv = ADC_CLK_DIV_4; adc_cfg.vref = ADC_VREF_3P2V; - adc_cfg.resWidth = ADC_DATA_WIDTH_14_WITH_64_AVERAGE; + adc_cfg.resWidth = ADC_DATA_WIDTH_14_WITH_16_AVERAGE; adc_cfg.inputMode = ADC_INPUT_SINGLE_END; adc_cfg.v18Sel = ADC_V18_SEL_1P72V; 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.biasSel = ADC_BIAS_SEL_MAIN_BANDGAP; adc_cfg.vcm = ADC_PGA_VCM_1P6V; - adc_cfg.offsetCalibEn = ENABLE; + adc_cfg.offsetCalibEn = DISABLE; adc_cfg.offsetCalibVal = 0; ADC_Disable(); @@ -120,7 +120,7 @@ void setup_adc(void) { ADC_Init(&adc_cfg); adc_fifo_cfg.dmaEn = DISABLE; - adc_fifo_cfg.fifoThreshold = ADC_FIFO_THRESHOLD_8; + adc_fifo_cfg.fifoThreshold = ADC_FIFO_THRESHOLD_8; // Triger FIFO when all 8 measurements are done ADC_FIFO_Cfg(&adc_fifo_cfg); ADC_MIC_Bias_Disable(); ADC_Tsen_Disable(); @@ -138,26 +138,29 @@ void setup_timer_scheduler() { TIMER_Disable(TIMER_CH0); TIMER_CFG_Type cfg = { - TIMER_CH0, // Channel - TIMER_CLKSRC_32K, // Clock source - TIMER_PRELOAD_TRIG_COMP0, // Trigger; reset after trigger 0 - TIMER_COUNT_PRELOAD, // Counter mode - 22, // Clock div - (uint16_t)(powerPWM + holdoffTicks), // CH0 compare (adc) - 0, // CH1 compare (pwm out) - 0, // CH2 compare not used - 0, // Preload + TIMER_CH0, // Channel + TIMER_CLKSRC_32K, // Clock source + TIMER_PRELOAD_TRIG_COMP2, // Trigger; reset after trigger 0 + TIMER_COUNT_PRELOAD, // Counter mode + 22, // Clock div + (uint16_t)(powerPWM + holdoffTicks), // CH0 compare (adc) + (uint16_t)(powerPWM), // CH1 compare (pwm out) + (uint16_t)(powerPWM + holdoffTicks + tempMeasureTicks), // CH2 compare end of cycle + 0, // Preload }; 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_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_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_1, UNMASK); + TIMER_IntMask(TIMER_CH0, TIMER_INT_COMP_2, UNMASK); CPU_Interrupt_Enable(TIMER_CH0_IRQn); TIMER_Enable(TIMER_CH0); } diff --git a/source/Core/BSP/Pinecilv2/bl_mcu_sdk/drivers/bl702_driver/std_drv/inc/bl702_pwm.h b/source/Core/BSP/Pinecilv2/bl_mcu_sdk/drivers/bl702_driver/std_drv/inc/bl702_pwm.h index a158885f..44e5db58 100644 --- a/source/Core/BSP/Pinecilv2/bl_mcu_sdk/drivers/bl702_driver/std_drv/inc/bl702_pwm.h +++ b/source/Core/BSP/Pinecilv2/bl_mcu_sdk/drivers/bl702_driver/std_drv/inc/bl702_pwm.h @@ -1,43 +1,44 @@ /** - ****************************************************************************** - * @file bl702_pwm.h - * @version V1.0 - * @date - * @brief This file is the standard driver header file - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2020 Bouffalo Lab

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of Bouffalo Lab nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ + ****************************************************************************** + * @file bl702_pwm.h + * @version V1.0 + * @date + * @brief This file is the standard driver header file + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2020 Bouffalo Lab

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of Bouffalo Lab nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ #ifndef __BL702_PWM_H__ #define __BL702_PWM_H__ -#include "pwm_reg.h" #include "bl702_common.h" +#include "pwm_reg.h" + /** @addtogroup BL702_Peripheral_Driver * @{ @@ -55,61 +56,60 @@ * @brief PWM No. type definition */ typedef enum { - PWM_CH0 = 0, /*!< PWM Channel 0 define */ - PWM_CH1, /*!< PWM Channel 1 define */ - PWM_CH2, /*!< PWM Channel 2 define */ - PWM_CH3, /*!< PWM Channel 3 define */ - PWM_CH4, /*!< PWM Channel 4 define */ - PWM_CH_MAX, /*!< */ + PWM_CH0 = 0, /*!< PWM Channel 0 define */ + PWM_CH1, /*!< PWM Channel 1 define */ + PWM_CH2, /*!< PWM Channel 2 define */ + PWM_CH3, /*!< PWM Channel 3 define */ + PWM_CH4, /*!< PWM Channel 4 define */ + PWM_CH_MAX, /*!< */ } PWM_CH_ID_Type; /** * @brief PWM Clock definition */ typedef enum { - PWM_CLK_XCLK = 0, /*!< PWM Clock source :XTAL CLK */ - PWM_CLK_BCLK, /*!< PWM Clock source :Bus CLK */ - PWM_CLK_32K, /*!< PWM Clock source :32K CLK */ + PWM_CLK_XCLK = 0, /*!< PWM Clock source :XTAL CLK */ + PWM_CLK_BCLK, /*!< PWM Clock source :Bus CLK */ + PWM_CLK_32K, /*!< PWM Clock source :32K CLK */ } PWM_Clk_Type; /** * @brief PWM Stop Mode definition */ typedef enum { - PWM_STOP_ABRUPT = 0, /*!< PWM stop abrupt select define */ - PWM_STOP_GRACEFUL, /*!< PWM stop graceful select define */ + PWM_STOP_ABRUPT = 0, /*!< PWM stop abrupt select define */ + PWM_STOP_GRACEFUL, /*!< PWM stop graceful select define */ } PWM_Stop_Mode_Type; /** * @brief PWM mode type def */ typedef enum { - PWM_POL_NORMAL = 0, /*!< PWM normal polarity mode define */ - PWM_POL_INVERT, /*!< PWM invert polarity mode define */ + PWM_POL_NORMAL = 0, /*!< PWM normal polarity mode define */ + PWM_POL_INVERT, /*!< PWM invert polarity mode define */ } PWM_Polarity_Type; /** * @brief PWM interrupt type def */ typedef enum { - PWM_INT_PULSE_CNT = 0, /*!< PWM Pulse count interrupt define */ - PWM_INT_ALL, /*!< */ + PWM_INT_PULSE_CNT = 0, /*!< PWM Pulse count interrupt define */ + PWM_INT_ALL, /*!< */ } PWM_INT_Type; /** * @brief PWM configuration structure type definition */ -typedef struct -{ - PWM_CH_ID_Type ch; /*!< PWM channel */ - PWM_Clk_Type clk; /*!< PWM Clock */ - PWM_Stop_Mode_Type stopMode; /*!< PWM Stop Mode */ - PWM_Polarity_Type pol; /*!< PWM mode type */ - uint16_t clkDiv; /*!< PWM clkDiv num */ - uint16_t period; /*!< PWM period set */ - uint16_t threshold1; /*!< PWM threshold1 num */ - uint16_t threshold2; /*!< PWM threshold2 num */ - uint16_t intPulseCnt; /*!< PWM interrupt pulse count */ +typedef struct { + PWM_CH_ID_Type ch; /*!< PWM channel */ + PWM_Clk_Type clk; /*!< PWM Clock */ + PWM_Stop_Mode_Type stopMode; /*!< PWM Stop Mode */ + PWM_Polarity_Type pol; /*!< PWM mode type */ + uint16_t clkDiv; /*!< PWM clkDiv num */ + uint16_t period; /*!< PWM period set */ + uint16_t threshold1; /*!< PWM threshold1 num */ + uint16_t threshold2; /*!< PWM threshold2 num */ + uint16_t intPulseCnt; /*!< PWM interrupt pulse count */ } PWM_CH_CFG_Type; /*@} end of group PWM_Public_Types */ @@ -121,37 +121,27 @@ typedef struct /** @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 * @{ */ -#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 * @{ */ -#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 * @{ */ -#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 * @{ */ -#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 */ @@ -173,21 +163,21 @@ typedef struct void PWM_IRQHandler(void); #endif BL_Err_Type PWM_Channel_Init(PWM_CH_CFG_Type *chCfg); -void PWM_Channel_Update(PWM_CH_ID_Type ch, uint16_t period, uint16_t threshold1, uint16_t threshold2); -void PWM_Channel_Set_Div(PWM_CH_ID_Type ch, uint16_t div); -void PWM_Channel_Set_Threshold1(PWM_CH_ID_Type ch, uint16_t threshold1); -void PWM_Channel_Set_Threshold2(PWM_CH_ID_Type ch, uint16_t threshold2); -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_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_Disable(PWM_CH_ID_Type ch); -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_Int_Callback_Install(PWM_CH_ID_Type ch, uint32_t intType, intCallback_Type *cbFun); +void PWM_Channel_Update(PWM_CH_ID_Type ch, uint16_t period, uint16_t threshold1, uint16_t threshold2); +void PWM_Channel_Set_Div(PWM_CH_ID_Type ch, uint16_t div); +void PWM_Channel_Set_Threshold1(PWM_CH_ID_Type ch, uint16_t threshold1); +void PWM_Channel_Set_Threshold2(PWM_CH_ID_Type ch, uint16_t threshold2); +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_IntMask(PWM_CH_ID_Type ch, PWM_INT_Type intType, BL_Mask_Type intMask); +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_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_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); - /*@} end of group PWM_Public_Functions */ /*@} end of group PWM */ diff --git a/source/Core/BSP/Pinecilv2/bl_mcu_sdk/drivers/bl702_driver/std_drv/src/bl702_pwm.c b/source/Core/BSP/Pinecilv2/bl_mcu_sdk/drivers/bl702_driver/std_drv/src/bl702_pwm.c index 535ef94e..b6315801 100644 --- a/source/Core/BSP/Pinecilv2/bl_mcu_sdk/drivers/bl702_driver/std_drv/src/bl702_pwm.c +++ b/source/Core/BSP/Pinecilv2/bl_mcu_sdk/drivers/bl702_driver/std_drv/src/bl702_pwm.c @@ -354,7 +354,18 @@ void PWM_Channel_Enable(PWM_CH_ID_Type ch) { tmpVal = BL_RD_REG(PWMx, PWM_CONFIG); 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 * diff --git a/source/Core/BSP/Pinecilv2/configuration.h b/source/Core/BSP/Pinecilv2/configuration.h index 3683b085..5297f3a4 100644 --- a/source/Core/BSP/Pinecilv2/configuration.h +++ b/source/Core/BSP/Pinecilv2/configuration.h @@ -160,10 +160,16 @@ #define HALL_SI7210 #define DEBUG_UART_OUTPUT #define HAS_POWER_DEBUG_MENU -#define HARDWARE_MAX_WATTAGE_X10 750 -#define BLE_ENABLED -#define NEEDS_VBUS_PROBE 0 -#define CANT_DIRECT_READ_SETTINGS +#define HARDWARE_MAX_WATTAGE_X10 750 +#define BLE_ENABLED // We have a BLE stack +#define NEEDS_VBUS_PROBE 0 // No vbus probe, its not connected in pcb +#define CANT_DIRECT_READ_SETTINGS // We cant memcpy settings due to flash cache +#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 */ #define FLASH_PAGE_SIZE (1024) // Read pages diff --git a/source/Core/BSP/Sequre_S60/BSP.cpp b/source/Core/BSP/Sequre_S60/BSP.cpp index 25ad176e..f960cd0d 100644 --- a/source/Core/BSP/Sequre_S60/BSP.cpp +++ b/source/Core/BSP/Sequre_S60/BSP.cpp @@ -234,8 +234,8 @@ uint8_t getTipResistanceX10() { return TIP_RESISTANCE; } bool isTipShorted() { return false; } uint8_t preStartChecksDone() { return 1; } -uint8_t getTipThermalMass() { return TIP_THERMAL_MASS; } -uint8_t getTipInertia() { return TIP_THERMAL_INERTIA; } +uint16_t getTipThermalMass() { return TIP_THERMAL_MASS; } +uint16_t getTipInertia() { return TIP_THERMAL_INERTIA; } void setBuzzer(bool on) {} diff --git a/source/Core/Threads/OperatingModes/OperatingModes.h b/source/Core/Threads/OperatingModes/OperatingModes.h index 8ab84391..c552e327 100644 --- a/source/Core/Threads/OperatingModes/OperatingModes.h +++ b/source/Core/Threads/OperatingModes/OperatingModes.h @@ -10,6 +10,7 @@ extern "C" { #include "Settings.h" #include "TipThermoModel.h" #include "Translation.h" +#include "Types.h" #include "cmsis_os.h" #include "configuration.h" #include "history.hpp" @@ -25,12 +26,12 @@ extern "C" { // Exposed modes enum OperatingMode { - idle = 0, - soldering = 1, - boost = 2, - sleeping = 3, - settings = 4, - debug = 5 + idle = 0, + soldering = 1, + boost = 2, + sleeping = 3, + settings = 4, + debug = 5 }; // Main functions @@ -46,6 +47,6 @@ void drawHomeScreen(bool buttonLockout) __attribute__((noreturn)); // IDLE / Hom void renderHomeScreenAssets(void); // Called to act as start delay and used to render out flipped images for home screen graphics // Common helpers -int8_t getPowerSourceNumber(void); // Returns number ID of power source -uint16_t getTipTemp(void); // Returns temperature of the tip in *C/*F (based on user settings) +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) #endif diff --git a/source/Core/Threads/OperatingModes/Sleep.cpp b/source/Core/Threads/OperatingModes/Sleep.cpp index 9839a25d..5c3c47e7 100644 --- a/source/Core/Threads/OperatingModes/Sleep.cpp +++ b/source/Core/Threads/OperatingModes/Sleep.cpp @@ -25,7 +25,7 @@ int gui_SolderingSleepingMode(bool stayOff, bool autoStarted) { } // draw the lcd - uint16_t tipTemp = getTipTemp(); + TemperatureType_t tipTemp = getTipTemp(); OLED::clearScreen(); OLED::setCursor(0, 0); diff --git a/source/Core/Threads/OperatingModes/utils/DrawTipTemperature.cpp b/source/Core/Threads/OperatingModes/utils/DrawTipTemperature.cpp index b14cf64f..7e5cff17 100644 --- a/source/Core/Threads/OperatingModes/utils/DrawTipTemperature.cpp +++ b/source/Core/Threads/OperatingModes/utils/DrawTipTemperature.cpp @@ -4,7 +4,7 @@ void gui_drawTipTemp(bool symbol, const FontStyle font) { // Draw tip temp handling unit conversion & tolerance near setpoint - uint16_t Temp = getTipTemp(); + TemperatureType_t Temp = getTipTemp(); OLED::printNumber(Temp, 3, font); // Draw the tip temp out if (symbol) { diff --git a/source/Core/Threads/OperatingModes/utils/SolderingCommon.cpp b/source/Core/Threads/OperatingModes/utils/SolderingCommon.cpp index e8e457fa..0f1bbd2a 100644 --- a/source/Core/Threads/OperatingModes/utils/SolderingCommon.cpp +++ b/source/Core/Threads/OperatingModes/utils/SolderingCommon.cpp @@ -4,6 +4,8 @@ #include "SolderingCommon.h" #include "OperatingModes.h" +#include "configuration.h" +#include "history.hpp" extern bool heaterThermalRunaway; @@ -166,4 +168,14 @@ int8_t getPowerSourceNumber(void) { } // Returns temperature of the tip in *C/*F (based on user settings) -uint16_t getTipTemp(void) { return getSettingValue(SettingsOptions::TemperatureInF) ? TipThermoModel::getTipInF() : TipThermoModel::getTipInC(); } +TemperatureType_t getTipTemp(void) { +#ifdef FILTER_DISPLAYED_TIP_TEMP + static history 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 +} diff --git a/source/Core/Threads/PIDThread.cpp b/source/Core/Threads/PIDThread.cpp index 7118273b..615a966d 100644 --- a/source/Core/Threads/PIDThread.cpp +++ b/source/Core/Threads/PIDThread.cpp @@ -10,6 +10,7 @@ #include "Settings.h" #include "TipThermoModel.h" #include "cmsis_os.h" +#include "configuration.h" #include "history.hpp" #include "main.hpp" #include "power.hpp" @@ -22,7 +23,7 @@ volatile TemperatureType_t currentTempTargetDegC = 0; // Current temperature t int32_t powerSupplyWattageLimit = 0; bool heaterThermalRunaway = false; -static int32_t getPIDResultX10Watts(TemperatureType_t tError); +static int32_t getPIDResultX10Watts(TemperatureType_t set_point, TemperatureType_t current_value); static void detectThermalRunaway(const TemperatureType_t currentTipTempInC, const TemperatureType_t tError); static void setOutputx10WattsViaFilters(int32_t x10Watts); static int32_t getX10WattageLimits(); @@ -71,10 +72,9 @@ void startPIDTask(void const *argument __unused) { if (PIDTempTarget > TipThermoModel::getTipMaxInC()) { PIDTempTarget = TipThermoModel::getTipMaxInC(); } - TemperatureType_t tError = PIDTempTarget - currentTipTempInC; - detectThermalRunaway(currentTipTempInC, tError); - x10WattsOut = getPIDResultX10Watts(tError); + detectThermalRunaway(currentTipTempInC, PIDTempTarget - currentTipTempInC); + x10WattsOut = getPIDResultX10Watts(PIDTempTarget, currentTipTempInC); } else { detectThermalRunaway(currentTipTempInC, 0); } @@ -89,6 +89,53 @@ void startPIDTask(void const *argument __unused) { } } +#ifdef TIP_CONTROL_PID +template 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 struct Integrator { T sum; @@ -114,12 +161,20 @@ template struct Integrator { T get(bool positiveOnly = true) const { return (positiveOnly) ? ((sum > 0) ? sum : 0) : sum; } }; -int32_t getPIDResultX10Watts(TemperatureType_t setpointDelta) { - static TickType_t lastCall = 0; - static Integrator powerStore = {0}; +#endif +int32_t getPIDResultX10Watts(TemperatureType_t set_point, TemperatureType_t current_reading) { + static TickType_t lastCall = 0; + +#ifdef TIP_CONTROL_PID + static PID pid = {0, 0}; - const TickType_t rate = TICKS_SECOND / (xTaskGetTickCount() - lastCall); - lastCall = xTaskGetTickCount(); + const TickType_t interval = (xTaskGetTickCount() - lastCall); + +#else + static Integrator powerStore = {0}; + const TickType_t rate = TICKS_SECOND / (xTaskGetTickCount() - lastCall); +#endif + 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 set point temperature. In the same time we have 'imprecise' @@ -141,11 +196,16 @@ int32_t getPIDResultX10Watts(TemperatureType_t setpointDelta) { // 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. - return powerStore.update(((TemperatureType_t)getTipThermalMass()) * setpointDelta, // the required power - getTipInertia(), // Inertia, smaller numbers increase dominance of the previous value - 2, // gain - rate, // PID cycle frequency + +#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 + 2, // gain + rate, // PID cycle frequency getX10WattageLimits()); +#endif } void detectThermalRunaway(const TemperatureType_t currentTipTempInC, const TemperatureType_t tError) { -- cgit v1.2.3