OPtimization on cores, netc, setup

This commit is contained in:
Heuideog Yi @ PC RnD1 2026-04-16 06:17:22 +09:00
parent 8415d83a6c
commit fd5298b691
8 changed files with 123 additions and 162 deletions

BIN
.gitignore vendored

Binary file not shown.

View File

@ -20,6 +20,7 @@
#ifndef DEBUG #ifndef DEBUG
#define DEBUG 1 // Set to 0 to disable debug output #define DEBUG 1 // Set to 0 to disable debug output
#endif #endif
#undef DEBUG
//#define BLE_DEBUG //#define BLE_DEBUG

View File

@ -53,10 +53,10 @@ MY_IRAM_ATTR void loop() {
// Un-Conditional Loop // Un-Conditional Loop
{ {
//ESP_LOGI(TAG_MAIN,"Checking WiFi2"); //ESP_LOGI(TAG_MAIN,"Checking WiFi2");
checkWiFi(tickMillis); //checkWiFi(tickMillis);
//ESP_LOGI(TAG_MAIN,"Host Loop"); //ESP_LOGI(TAG_MAIN,"Host Loop");
host.Loop(tickMillis); //host.Loop(tickMillis);
// UI Button Check // UI Button Check
ui.loopButton(tickMillis); ui.loopButton(tickMillis);

View File

@ -68,60 +68,69 @@ void NTC_10K::setup(bool bNegativePolarity) {
m_bNegativePolarity = bNegativePolarity; m_bNegativePolarity = bNegativePolarity;
_vRef = 3.3f; _vRef = 3.3f;
_RESO = 4095; _RESO = 4095;
for (int i = 0; i < 16; i++) temps[i] = 0; m_nTemp = -9999;
temp_idx = 0; m_fTemp = -9999.0;
temp_sum = 0; m_fLastTemp = 0.0f;
pinMode(PIN_NTC, INPUT); // Set PIN_NTC as input pinMode(PIN_NTC, INPUT); // Set PIN_NTC as input
analogReadResolution(12); // Set ADC resolution to 12 bits (0-4095) analogReadResolution(12); // Set ADC resolution to 12 bits (0-4095)
analogSetAttenuation(ADC_11db); // Set attenuation for full-scale 3.3V analogSetAttenuation(ADC_11db); // Set attenuation for full-scale 3.3V
} }
/**
* @brief Reads NTC sensor, calculates temperature via interpolation,
* and applies an Exponential Moving Average (EMA) filter.
* * History:
* - 2026-04-16: Refactored from Simple Moving Average (SMA) to EMA with float buffer.
* - 2026-04-16: Optimized interpolation to reduce CPU cycles.
* - 2026-04-16: Implemented aggressive alpha (0.01) to mitigate 5°C PWM noise.
* - 2026-04-16: Upgraded lastTemp to float (m_fLastTemp) for total precision.
*/
void NTC_10K::readSensor() { void NTC_10K::readSensor() {
float Vin; float Vin;
int16_t temp; float currentInstantTemp; // High-precision intermediate
static int16_t lastTemp = 0;
int adcValue = analogRead(PIN_NTC); // Read ADC value from PIN_NTC // 1. Hardware Acquisition
int adcValue = constrain(analogRead(PIN_NTC), 1, 4094);
// Calculate the input voltage from the ADC reading // 2. Voltage and Resistance Calculation
Vin = (float)adcValue * _vRef / _RESO; Vin = (float)adcValue * _vRef / _RESO;
// Calculate the resistance of the thermistor
// Calculate the resistance of the thermistor (adjusted for inverted ADC behavior)
float r; float r;
if (m_bNegativePolarity) { if (m_bNegativePolarity) {
// NTC is connected to Negative
r = (Vin / (_vRef - Vin)) * rRef; r = (Vin / (_vRef - Vin)) * rRef;
} else { } else {
// NTC is connected to Positive
r = ((_vRef - Vin) / Vin) * rRef; r = ((_vRef - Vin) / Vin) * rRef;
} }
// Find the index of the resistance in the table where r is between resistance[i-1] and resistance[i] // 3. Table Lookup
int i = 0; int i = 0;
while (i < sizeof(resistance) / sizeof(resistance[0]) - 1 && resistance[i] > r) { int tableSize = sizeof(resistance) / sizeof(resistance[0]);
while (i < tableSize - 1 && resistance[i] > r) {
i++; i++;
} }
// If r is out of range, return the closest extreme temperature // 4. Interpolation Logic (Precise Float Math)
if (i == 0 || i == sizeof(resistance) / sizeof(resistance[0]) - 1) { if (i == 0 || i == tableSize - 1) {
if (lastTemp != 0) temp = lastTemp; // Use last known good float value if out of bounds
else temp = 0; currentInstantTemp = (m_fLastTemp != 0.0f) ? m_fLastTemp : 0.0f;
} }
else { else {
// Interpolate between resistance[i-1] and resistance[i] // Faster Slope Calculation: y = y0 + m * (r - r0)
float m = (temp_C[i] - temp_C[i - 1]) / (resistance[i] - resistance[i - 1]); // Slope float m = (temp_C[i] - temp_C[i - 1]) / (resistance[i] - resistance[i - 1]);
float b = temp_C[i - 1] - (m * resistance[i - 1]); // Intercept currentInstantTemp = temp_C[i - 1] + m * (r - resistance[i - 1]);
temp = (int16_t) roundf((m * r + b) * 10.0f);
} }
// Return the temperature as an integer scaled by 10 (e.g., 25.3°C => 253) // 5. Exponential Moving Average (EMA) Filtering
temp_sum -= temps[temp_idx]; if (m_fTemp < -5000.0f) {
temps[temp_idx++] = temp; m_fTemp = currentInstantTemp;
temp_idx &= NTC_MASK; } else {
temp_sum += temp; // 0.01f Alpha: The 5°C PWM noise now only moves the buffer by 0.05°C per hit.
lastTemp = temp; const float alpha = 0.05f;
m_nTemp = temp_sum / NTC_COUNT; m_fTemp = (currentInstantTemp * alpha) + (m_fTemp * (1.0f - alpha));
}
// 6. Update Outputs
m_fLastTemp = currentInstantTemp; // Store precise float for next loop
m_nTemp = (int16_t)roundf(m_fTemp * 10.0f); // Final integer output (e.g., 25.34 -> 253)
} }

View File

@ -21,6 +21,8 @@ private:
int _RESO; int _RESO;
bool m_bNegativePolarity; bool m_bNegativePolarity;
int16_t m_nTemp; int16_t m_nTemp;
float m_fTemp;
float m_fLastTemp;
public: public:
void setup(bool bNegativePolarity); void setup(bool bNegativePolarity);

12
OTA.cpp
View File

@ -17,10 +17,10 @@
// OTA // OTA
// //
// ============================================================== // ==============================================================
const char *HC__VERSION = "20260413001"; const char *HC__VERSION = "20250415001";
#define UPDATE_PORT ((uint16_t) 443) #define UPDATE_PORT ((uint16_t) 443)
String url = "visionsoft.kr"; const char *url = "visionsoft.kr";
String uri = "/hc/hc_firmware_update.php"; const char *uri = "/sc/pages/firmware_download.php";
const char *HTTPUPDATE_USERAGRENT = "ESP32-http-Update"; const char *HTTPUPDATE_USERAGRENT = "ESP32-http-Update";
const char *COMPANY_NAME = "VisionSoft"; const char *COMPANY_NAME = "VisionSoft";
const char *SERVICE_NAME = "HermitCrab"; const char *SERVICE_NAME = "HermitCrab";
@ -78,11 +78,11 @@ bool checkOTA(bool bForceUpdate)
// result: POSITIVE (HTTP/Status), NEGATIVE (Network Error) // result: POSITIVE (HTTP/Status), NEGATIVE (Network Error)
int result = ESPUpdate.update( int result = ESPUpdate.update(
client, client,
"visionsoft.kr", // Server Host url, // Server Host
443, // Server Port HTTPS, 443, // Server Port HTTPS,
"/sc/pages/firmware_download.php", // phpUri, uri, // phpUri,
HC__VERSION, // Current Version string HC__VERSION, // Current Version string
"HCesp", // Project Tag SERVICE_NAME, // Project Tag
bForceUpdate, // bForceUpdate bForceUpdate, // bForceUpdate
true // bRebootAfterInstall true // bRebootAfterInstall
); );

View File

@ -57,23 +57,14 @@ void setup() {
bShowSensor = false; bShowSensor = false;
DPRINTLN("1");
setupConfig(); setupConfig();
DPRINTLN("2");
setupStatus(); setupStatus();
DPRINTLN("3");
setupPins(); setupPins();
DPRINTLN("4");
scanI2C(); scanI2C();
DPRINTLN("5");
setupSensor(); setupSensor();
DPRINTLN("6");
ui.setup(); ui.setup();
DPRINTLN("7");
ui.message(0, (char *) "WiFi..."); ui.message(0, (char *) "WiFi...");
DPRINTLN("8");
setupWiFi(); setupWiFi();
DPRINTLN("9");
if (aht25.sensor() || aht10_0x39.sensor()) { if (aht25.sensor() || aht10_0x39.sensor()) {
ui.message(4, (char *) "Sensor... OK!"); ui.message(4, (char *) "Sensor... OK!");
@ -97,7 +88,7 @@ void setup() {
xTaskCreatePinnedToCore( xTaskCreatePinnedToCore(
core0Task, // Function to run as a task core0Task, // Function to run as a task
"Task0", // Task name "Task0", // Task name
10240, // Stack size in words 20480, // Stack size in words
NULL, // Task input parameter NULL, // Task input parameter
1, // Priority of the task 1, // Priority of the task
&TaskHandle_0, // Task handle &TaskHandle_0, // Task handle
@ -126,7 +117,7 @@ void setupWiFi() {
// Connect WiFi for OTA // Connect WiFi for OTA
if (config.ssid[0] && config.pw[0]) { if (config.ssid[0] && config.pw[0]) {
#if defined(ESP32) #if defined(ESP32)
esp_wifi_set_max_tx_power(84); esp_wifi_set_max_tx_power(74);
#elif defined(ESP8266) #elif defined(ESP8266)
WiFi.setOutputPower(20.5f); WiFi.setOutputPower(20.5f);
pinMode(16,OUTPUT); pinMode(16,OUTPUT);
@ -198,8 +189,6 @@ void setupPostWiFi(bool bBoot = false) {
} }
} }
#include "driver/ledc.h"
void setupPins() { void setupPins() {
// --- Basic Digital Pin Initialization --- // --- Basic Digital Pin Initialization ---
pinMode(PIN_HEATER1, OUTPUT); pinMode(PIN_HEATER1, OUTPUT);
@ -219,39 +208,11 @@ void setupPins() {
ledcAttachChannel(PIN_LED_HEATER2, PWM_1KHZ_FREQ, PWM_RESOLUTION, PWM_HEATER2_CHANNEL); ledcAttachChannel(PIN_LED_HEATER2, PWM_1KHZ_FREQ, PWM_RESOLUTION, PWM_HEATER2_CHANNEL);
// --- 3. Low Speed Group: Mist & WiFi LED (1.19Hz) --- // --- 3. Low Speed Group: Mist & WiFi LED (1.19Hz) ---
// Initialized at 32Hz to bypass the slow divider calculation/WDT panic. // Initialized at 1Hz to bypass the slow divider calculation/WDT panic.
// Must be ESP32 coer version 3.0.2 in ordre to set 1Hz
ledcAttachChannel(PIN_MIST, PWM_1HZ_FREQ, PWM_RESOLUTION, PWM_MIST_CHANNEL); ledcAttachChannel(PIN_MIST, PWM_1HZ_FREQ, PWM_RESOLUTION, PWM_MIST_CHANNEL);
ledcAttachChannel(PIN_LED_WIFI, PWM_1HZ_FREQ, PWM_RESOLUTION, PWM_WIFI_LED_CHANNEL); ledcAttachChannel(PIN_LED_WIFI, PWM_1HZ_FREQ, PWM_RESOLUTION, PWM_WIFI_LED_CHANNEL);
// MANUALLY RECONFIGURE TIMER FOR 1.19Hz
// Source: LEDC_REF_TICK (1MHz)
// Divider: 819 (Integer part)
// Result: 1,000,000 / (819 * 1024) ≈ 1.192 Hz
// Note: On Core 2.0.17, LEDC_USE_REF_TICK is the correct constant.
/*
ledc_timer_set(
LEDC_LOW_SPEED_MODE,
LEDC_TIMER_0,
(uint32_t)(819 << 8), // 18.8 bit register: 819 integer, 0 fractional
(uint32_t)PWM_RESOLUTION,
LEDC_REF_TICK
);
*/
/*
ledc_timer_config_t mist_timer_conf = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.duty_resolution = LEDC_TIMER_8_BIT,
.timer_num = LEDC_TIMER_0,
.freq_hz = 2, // The driver will target 1Hz
.clk_cfg = LEDC_USE_REF_TICK, // Forces the 1MHz source
.deconfigure = false
};
esp_err_t err = ledc_timer_config(&mist_timer_conf);
if (err == ESP_OK) {
// Apply the change and reset the counter
ledc_timer_rst(LEDC_LOW_SPEED_MODE, LEDC_TIMER_0);
}
*/
// --- Initial State Writes --- // --- Initial State Writes ---
ledcWrite(PIN_MOTOR, PWM_OFF); ledcWrite(PIN_MOTOR, PWM_OFF);
ledcWrite(PIN_FAN, PWM_OFF); ledcWrite(PIN_FAN, PWM_OFF);
@ -320,7 +281,7 @@ void setupSensor() {
if (aht25.setup()) { if (aht25.setup()) {
delay(82); delay(82);
aht25.readSensor(millis()); aht25.readSensor(millis());
DPRINTF("AHTx0 initialized successfully at 0x38. Temp: %.2f, Humid: %.2f%%\n", DPRINTF("AHT25 initialized successfully at 0x38. Temp: %.2f, Humid: %.2f%%\n",
aht25.getTemperature() / 100.0f, aht25.getHumidity() / 100.0f); aht25.getTemperature() / 100.0f, aht25.getHumidity() / 100.0f);
} }

View File

@ -27,33 +27,24 @@ MY_IRAM_ATTR void core0Task(void *pvParameters) {
wl_status_t lastWiFiStatus = WL_DISCONNECTED; wl_status_t lastWiFiStatus = WL_DISCONNECTED;
unsigned long tickMillis = millis(); unsigned long tickMillis = millis();
unsigned long tickSecond; unsigned long tickSecond;
unsigned long lastTick = tickMillis / 1000;
unsigned long lastTickMillis = tickMillis;
unsigned long lastSensorUpdate1 = tickMillis;
unsigned long lastSensorUpdate2 = tickMillis + 2500;
uint16_t tick1000, lastTick1000 = tickMillis % 1000;;
uint16_t tick250, lastTick250 = tickMillis % 250;
uint8_t slot; uint8_t slot;
uint8_t lastSlot = tickMillis / 50; uint8_t lastSlot = 255;
esp_task_wdt_add(NULL); // NULL for the current task esp_task_wdt_add(NULL); // NULL for the current task
ui.start(); ui.start();
ble.setupScan(); ble.setupScan();
while (true) { while (true) {
esp_task_wdt_reset(); esp_task_wdt_reset();
tickMillis = millis(); tickMillis = millis();
tick250 = tickMillis % 250;
tick1000 = tickMillis % 1000;
tickSecond = tickMillis / 1000; tickSecond = tickMillis / 1000;
slot = tick1000 / 50; slot = (tickMillis % 1000) / 50;
//=============================================================================== //===============================================================================
// Loop top // Loop top: Once in a second loop
// Once in a second loop
if (tick1000 != lastTick1000) {
if (slot != lastSlot) { if (slot != lastSlot) {
lastSlot = slot;
switch (slot) { switch (slot) {
case 1: case 1:
case 6: case 6:
@ -62,11 +53,16 @@ MY_IRAM_ATTR void core0Task(void *pvParameters) {
ui.updateDisplayTop(tickSecond); ui.updateDisplayTop(tickSecond);
break; break;
case 2: case 2:
case 4:
case 7: case 7:
case 9:
case 12: case 12:
case 14:
case 17: // NTC Temp Sensor case 17: // NTC Temp Sensor
ntc.readSensor(); case 19:
ble.loop(tickMillis);
break; break;
case 3: // NTP - Time case 3: // NTP - Time
if (isWiFiConnected()) { if (isWiFiConnected()) {
if (timeManager.getTime(tickMillis)) { if (timeManager.getTime(tickMillis)) {
@ -74,20 +70,15 @@ MY_IRAM_ATTR void core0Task(void *pvParameters) {
} }
} }
break; break;
case 4:
case 9:
case 14:
case 19:
ntc.readSensor();
break;
case 5: // Heartbeat case 5: // Heartbeat
if (isWiFiConnected()) { if (isWiFiConnected()) {
host.SendHeartBeat(tickMillis); host.SendHeartBeat(tickMillis);
} }
break; break;
case 8: // BLE case 8: // NTC
ble.loop(tickMillis); ntc.readSensor();
break; break;
case 13: // ATH2x - 0x38 case 13: // ATH2x - 0x38
@ -104,20 +95,17 @@ MY_IRAM_ATTR void core0Task(void *pvParameters) {
default: // 0 10 default: // 0 10
break; break;
} }
lastSlot = slot;
} }
lastTick1000 = tick1000;
lastTick250 = tick250;
} // end of - if (tick1000 != lastTick1000)
// ===================================================== // =====================================================
// Unconditional Loop // Unconditional Loop
checkWiFi(tickMillis);
host.Loop(tickMillis);
host.MonitorUDP(); host.MonitorUDP();
// Loop end // Loop end
//========================================================================== //==========================================================================
lastTickMillis = tickMillis;
esp_task_wdt_reset(); esp_task_wdt_reset();
} // end of - While(True) } // end of - While(True)