From cdf1f43e60ce4513a6cfc478652e68f9d6d11e3a Mon Sep 17 00:00:00 2001 From: Jochen Vothknecht <jochen3120@gmail.com> Date: Sun, 27 Aug 2023 05:33:03 +0200 Subject: [PATCH] Much dev. Much wow. --- .../SiliconTorch/Service/SpiderFurnace.cpp | 93 ++++++++++++++++--- .../SiliconTorch/Service/SpiderFurnace.hpp | 32 +++++-- 2 files changed, 105 insertions(+), 20 deletions(-) diff --git a/CLC-qthing/SiliconTorch/Service/SpiderFurnace.cpp b/CLC-qthing/SiliconTorch/Service/SpiderFurnace.cpp index 5cd06d6..387b3c8 100644 --- a/CLC-qthing/SiliconTorch/Service/SpiderFurnace.cpp +++ b/CLC-qthing/SiliconTorch/Service/SpiderFurnace.cpp @@ -7,6 +7,7 @@ // ESP32 specific #include "esp_log.h" #include "driver/gpio.h" +#include "driver/ledc.h" // project specific #include <Types.hpp> @@ -39,15 +40,10 @@ namespace SiliconTorch { setNameSpace("SpiderFurnace"); } - void SpiderFurnace::start() { - // TODO: Make configurable" - const u8 MISO = 17; - const u8 MOSI = 16; - const u8 SCLK = 27; - const u8 CS = 26; + void SpiderFurnace::start() { - tc0 = new MAX31856::MAX31856(MISO, MOSI, SCLK, CS); + tc0 = new MAX31856::MAX31856(IO_MISO, IO_MOSI, IO_SCLK, IO_CS); // TODO: Configure tc0!! tc0->setConversionMode(false); // disable automatic conversions @@ -59,14 +55,58 @@ namespace SiliconTorch { tc0->setConversionMode(true); // re-enable automatic conversions + // Set-up Heater IO + gpio_config_t conf; + + conf.intr_type = GPIO_INTR_DISABLE; + conf.mode = GPIO_MODE_OUTPUT; + conf.pin_bit_mask = 1ULL << IO_HEATER; + conf.pull_up_en = GPIO_PULLUP_DISABLE; + conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + + gpio_config(&conf); + gpio_set_level((gpio_num_t)IO_HEATER, 0); + + + // Set-up Heater PWM + ledc_timer_config_t timer_cfg; + timer_cfg.duty_resolution = (ledc_timer_bit_t)PWM_BITS; + timer_cfg.freq_hz = PWM_FREQ; + timer_cfg.speed_mode = LEDC_HIGH_SPEED_MODE; + timer_cfg.timer_num = LEDC_TIMER_1; // FxCyanF uses ch0 + timer_cfg.clk_cfg = LEDC_AUTO_CLK; + + ledc_channel_config_t ledc_channel; + ledc_channel.channel = pwmCh; + ledc_channel.duty = 0; + ledc_channel.gpio_num = (gpio_num_t)IO_HEATER; + ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE; + ledc_channel.hpoint = 0; + ledc_channel.timer_sel = LEDC_TIMER_1; + ledc_channel.intr_type = LEDC_INTR_DISABLE; + + ledc_fade_func_install(0); + ledc_timer_config(&timer_cfg); + ledc_channel_config(&ledc_channel); + + + // pre-seed sliding window f32 t = tc0->getTemperature(); - for (u8 n = 0; n < 10; n++) + for (u8 n = 0; n < SlidingWindowLength; n++) tc0dat->insert(t); + // Set-up PID controller pidTask = new SpiderLib::Util::LambdaTask([&](){ + TickType_t lastWakeTime = xTaskGetTickCount(); tc0age = Time::ms(); + + f32 error = 0.0f; + f32 sum_error = 0.0f; + f32 diff_error = 0.0f; + f32 last_error = 0.0f; + while (true) { faultReg.value = tc0->readU8(MAX31856::SR::addr); @@ -86,23 +126,38 @@ namespace SiliconTorch { } } - ESP_LOGI(TAG, "T: %.2f °C Fault: %s", temperature(), hasFault() ? "true" : "false"); + f32 t = temperature(); - if (!hasFault()) { + if (!hasFault() && t <= MAX_TEMP) { + + error = targetTemperature - t; + sum_error += error; // TODO: "I festhalten" + diff_error = last_error - error; + last_error = error; - // Do actual PID stuff… + f32 out = kP * error; + out += kI * sum_error; + out += kD * diff_error; + + // if (out > MAX_PWM) + // TODO: "I festhalten" ?? + + setPWM(out); } else { - // PWM = 0 + setPWM(0.0f); } + ESP_LOGI(TAG, "T: %.2f °C Fault: %s _i: %.2f PWM: %.2f", t, hasFault() ? "true" : "false", sum_error, pwmOut); + vTaskDelayUntil(&lastWakeTime, 1000 / TICK_FREQ / portTICK_PERIOD_MS); } }); - - } + void SpiderFurnace::setTargetTemperature(f32 t) { + if (t >= 0.0f && t <= MAX_TEMP) targetTemperature = t; + } json SpiderFurnace::getConfigJSON() const { @@ -113,6 +168,16 @@ namespace SiliconTorch { return out; } + void SpiderFurnace::setPWM(f32 value) { + if (value < 0.0f) value = 0.0f; + if (value > MAX_PWM) value = MAX_PWM; + + u32 maxVal = (1 << PWM_BITS) - 1; + u32 pwmVal = value * maxVal; + + ledc_set_duty(LEDC_HIGH_SPEED_MODE, pwmCh, pwmVal); + ledc_update_duty(LEDC_HIGH_SPEED_MODE, pwmCh); + } f32 SpiderFurnace::temperature() const { return tc0dat->average(); diff --git a/CLC-qthing/SiliconTorch/Service/SpiderFurnace.hpp b/CLC-qthing/SiliconTorch/Service/SpiderFurnace.hpp index 230f383..6dde523 100644 --- a/CLC-qthing/SiliconTorch/Service/SpiderFurnace.hpp +++ b/CLC-qthing/SiliconTorch/Service/SpiderFurnace.hpp @@ -8,6 +8,7 @@ // ESP32 specific #include "esp_log.h" +#include "driver/ledc.h" // project specific #include <SpiderLib.hpp> @@ -28,9 +29,20 @@ namespace SiliconTorch { namespace SpiderFurnace { + constexpr u8 PWM_BITS = 12; + constexpr u32 PWM_FREQ = 10000; // Hz + constexpr u8 TICK_FREQ = 10; // Hz + constexpr u8 SlidingWindowLength = 8; + constexpr f32 MaxTempChangePerSecond = 1000; // K // TODO: formally set to 100 but triggers too often?! + constexpr f32 MAX_TEMP = 1320.0f; // °C + constexpr f32 MAX_PWM = 0.5f; // p% - constexpr u8 TICK_FREQ = 10; // Hz - constexpr f32 MaxTempChangePerSecond = 100; // K + // TODO: Make configurable" + constexpr u8 IO_CS = 26; + constexpr u8 IO_MISO = 17; + constexpr u8 IO_MOSI = 16; + constexpr u8 IO_SCLK = 27; + constexpr u8 IO_HEATER = 25; enum FurnaceState { @@ -57,7 +69,7 @@ namespace SiliconTorch { f32 temperature() const; - + void setTargetTemperature(f32 t); @@ -68,17 +80,25 @@ namespace SiliconTorch { private: - FurnaceState state = RUNNING; + f32 kP = 0.0f; + f32 kI = 0.0f; + f32 kD = 0.0f; + + f32 targetTemperature = 0.0f; + + // FurnaceState state = RUNNING; + + ledc_channel_t pwmCh; MAX31856::SR faultReg; u64 tc0age = 0; // ms MAX31856::MAX31856* tc0; - SlidingWindow<f32>* tc0dat = new SlidingWindow<f32>(8); // TODO: Make configurable! - + SlidingWindow<f32>* tc0dat = new SlidingWindow<f32>(SlidingWindowLength); SpiderLib::Util::LambdaTask* pidTask = NULL; + void setPWM(f32 value); }; -- GitLab