mirror of
https://github.com/bdring/Grbl_Esp32.git
synced 2025-08-29 17:19:50 +02:00
Use less memory (#644)
a) closeFile() now does SD.end() to release memory after running a file from SD. b) Several task stacks are smaller c) All tasks now check their free space if DEBUG_REPORT_STACK_FREE is defined. platformio.ini has a commented-out line that can be uncommented to turn that on. d) Similarly, platformio.ini can turn on DEBUG_REPORT_HEAP_SIZE e) Fixed a small leak that occurred when listing local files. With these changes, the heap size tends to hover around 53K, dropping to about 37K when running a file from SD.
This commit is contained in:
@@ -42,6 +42,14 @@
|
|||||||
*/
|
*/
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
// This block of #includes is necessary for Report.h
|
||||||
|
#include "Error.h"
|
||||||
|
#include "WebUI/Authentication.h"
|
||||||
|
#include "WebUI/ESPResponse.h"
|
||||||
|
#include "Probe.h"
|
||||||
|
#include "System.h"
|
||||||
|
#include "Report.h"
|
||||||
|
|
||||||
#include <FreeRTOS.h>
|
#include <FreeRTOS.h>
|
||||||
#include <driver/periph_ctrl.h>
|
#include <driver/periph_ctrl.h>
|
||||||
#include <rom/lldesc.h>
|
#include <rom/lldesc.h>
|
||||||
@@ -516,6 +524,9 @@ static void IRAM_ATTR i2sOutTask(void* parameter) {
|
|||||||
o_dma.rw_pos = 0; // If someone calls i2s_out_push_sample, make sure there is no buffer overflow
|
o_dma.rw_pos = 0; // If someone calls i2s_out_push_sample, make sure there is no buffer overflow
|
||||||
}
|
}
|
||||||
I2S_OUT_PULSER_EXIT_CRITICAL(); // Unlock pulser status
|
I2S_OUT_PULSER_EXIT_CRITICAL(); // Unlock pulser status
|
||||||
|
|
||||||
|
static UBaseType_t uxHighWaterMark = 0;
|
||||||
|
reportTaskStackSize(uxHighWaterMark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -907,7 +918,7 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
|
|||||||
// Create the task that will feed the buffer
|
// Create the task that will feed the buffer
|
||||||
xTaskCreatePinnedToCore(i2sOutTask,
|
xTaskCreatePinnedToCore(i2sOutTask,
|
||||||
"I2SOutTask",
|
"I2SOutTask",
|
||||||
1024 * 10,
|
4096,
|
||||||
NULL,
|
NULL,
|
||||||
1,
|
1,
|
||||||
nullptr,
|
nullptr,
|
||||||
|
@@ -330,11 +330,8 @@ void limits_init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (limit_sw_queue == NULL) {
|
if (limit_sw_queue == NULL) {
|
||||||
grbl_msg_sendf(CLIENT_SERIAL,
|
grbl_msg_sendf(
|
||||||
MsgLevel::Info,
|
CLIENT_SERIAL, MsgLevel::Info, "%s limit switch on pin %s", reportAxisNameMsg(axis, gang_index), pinName(pin).c_str());
|
||||||
"%s limit switch on pin %s",
|
|
||||||
reportAxisNameMsg(axis, gang_index),
|
|
||||||
pinName(pin).c_str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -427,6 +424,8 @@ void limitCheckTask(void* pvParameters) {
|
|||||||
mc_reset(); // Initiate system kill.
|
mc_reset(); // Initiate system kill.
|
||||||
sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event
|
sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event
|
||||||
}
|
}
|
||||||
|
static UBaseType_t uxHighWaterMark = 0;
|
||||||
|
reportTaskStackSize(uxHighWaterMark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -60,18 +60,14 @@ namespace Motors {
|
|||||||
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
||||||
vTaskDelay(2000); // initial delay
|
vTaskDelay(2000); // initial delay
|
||||||
while (true) { // don't ever return from this or the task dies
|
while (true) { // don't ever return from this or the task dies
|
||||||
|
|
||||||
// static UBaseType_t uxHighWaterMark = 0;
|
|
||||||
// if (uxHighWaterMark != uxTaskGetStackHighWaterMark(NULL)) {
|
|
||||||
// uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL);
|
|
||||||
// grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Servo Task Min Stack Space: %d", uxHighWaterMark);
|
|
||||||
// }
|
|
||||||
|
|
||||||
for (Servo* p = List; p; p = p->link) {
|
for (Servo* p = List; p; p = p->link) {
|
||||||
p->update();
|
p->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
vTaskDelayUntil(&xLastWakeTime, xUpdate);
|
vTaskDelayUntil(&xLastWakeTime, xUpdate);
|
||||||
|
|
||||||
|
static UBaseType_t uxHighWaterMark = 0;
|
||||||
|
reportTaskStackSize(uxHighWaterMark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -360,13 +360,10 @@ namespace Motors {
|
|||||||
} // sys.state
|
} // sys.state
|
||||||
} // if mask
|
} // if mask
|
||||||
|
|
||||||
// static UBaseType_t uxHighWaterMark = 0;
|
|
||||||
// if (uxHighWaterMark != uxTaskGetStackHighWaterMark(NULL)) {
|
|
||||||
// uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL);
|
|
||||||
// grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "SG Task Stack Space: %d", uxHighWaterMark);
|
|
||||||
// }
|
|
||||||
|
|
||||||
vTaskDelayUntil(&xLastWakeTime, xreadSg);
|
vTaskDelayUntil(&xLastWakeTime, xreadSg);
|
||||||
|
|
||||||
|
static UBaseType_t uxHighWaterMark = 0;
|
||||||
|
reportTaskStackSize(uxHighWaterMark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -938,3 +938,13 @@ char* reportAxisNameMsg(uint8_t axis) {
|
|||||||
sprintf(name, "%c Axis", report_get_axis_letter(axis));
|
sprintf(name, "%c Axis", report_get_axis_letter(axis));
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reportTaskStackSize(UBaseType_t& saved) {
|
||||||
|
#ifdef DEBUG_REPORT_STACK_FREE
|
||||||
|
UBaseType_t newHighWater = uxTaskGetStackHighWaterMark(NULL);
|
||||||
|
if (newHighWater != saved) {
|
||||||
|
saved = newHighWater;
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "%s Min Stack Space: %d", pcTaskGetTaskName(NULL), saved);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@@ -127,3 +127,5 @@ char report_get_axis_letter(uint8_t axis);
|
|||||||
char* reportAxisLimitsMsg(uint8_t axis);
|
char* reportAxisLimitsMsg(uint8_t axis);
|
||||||
char* reportAxisNameMsg(uint8_t axis);
|
char* reportAxisNameMsg(uint8_t axis);
|
||||||
char* reportAxisNameMsg(uint8_t axis, uint8_t dual_axis);
|
char* reportAxisNameMsg(uint8_t axis, uint8_t dual_axis);
|
||||||
|
|
||||||
|
void reportTaskStackSize(UBaseType_t& saved);
|
||||||
|
@@ -81,6 +81,7 @@ boolean closeFile() {
|
|||||||
SD_ready_next = false;
|
SD_ready_next = false;
|
||||||
sd_current_line_number = 0;
|
sd_current_line_number = 0;
|
||||||
myFile.close();
|
myFile.close();
|
||||||
|
SD.end();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +148,7 @@ uint8_t get_sd_state(bool refresh) {
|
|||||||
sd_state = SDCARD_NOT_PRESENT;
|
sd_state = SDCARD_NOT_PRESENT;
|
||||||
//using default value for speed ? should be parameter
|
//using default value for speed ? should be parameter
|
||||||
//refresh content if card was removed
|
//refresh content if card was removed
|
||||||
if (SD.begin((GRBL_SPI_SS == -1) ? SS : GRBL_SPI_SS, SPI, GRBL_SPI_FREQ)) {
|
if (SD.begin((GRBL_SPI_SS == -1) ? SS : GRBL_SPI_SS, SPI, GRBL_SPI_FREQ, "/sd", 2)) {
|
||||||
if (SD.cardSize() > 0) {
|
if (SD.cardSize() > 0) {
|
||||||
sd_state = SDCARD_IDLE;
|
sd_state = SDCARD_IDLE;
|
||||||
}
|
}
|
||||||
|
@@ -68,7 +68,27 @@ uint8_t serial_get_rx_buffer_available(uint8_t client) {
|
|||||||
return client_buffer[client].availableforwrite();
|
return client_buffer[client].availableforwrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void heapCheckTask(void* pvParameters) {
|
||||||
|
static uint32_t heapSize = 0;
|
||||||
|
while (true) {
|
||||||
|
uint32_t newHeapSize = xPortGetFreeHeapSize();
|
||||||
|
if (newHeapSize != heapSize) {
|
||||||
|
heapSize = newHeapSize;
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "heap %d", heapSize);
|
||||||
|
}
|
||||||
|
vTaskDelay(3000 / portTICK_RATE_MS); // Yield to other tasks
|
||||||
|
|
||||||
|
static UBaseType_t uxHighWaterMark = 0;
|
||||||
|
reportTaskStackSize(uxHighWaterMark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void serial_init() {
|
void serial_init() {
|
||||||
|
#ifdef DEBUG_REPORT_HEAP_SIZE
|
||||||
|
// For a 2000-word stack, uxTaskGetStackHighWaterMark reports 288 words available
|
||||||
|
xTaskCreatePinnedToCore(heapCheckTask, "heapTask", 2000, NULL, 1, NULL, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
Serial.begin(BAUD_RATE);
|
Serial.begin(BAUD_RATE);
|
||||||
Serial.setRxBufferSize(256);
|
Serial.setRxBufferSize(256);
|
||||||
// reset all buffers
|
// reset all buffers
|
||||||
@@ -76,9 +96,11 @@ void serial_init() {
|
|||||||
grbl_send(CLIENT_SERIAL, "\r\n"); // create some white space after ESP32 boot info
|
grbl_send(CLIENT_SERIAL, "\r\n"); // create some white space after ESP32 boot info
|
||||||
serialCheckTaskHandle = 0;
|
serialCheckTaskHandle = 0;
|
||||||
// create a task to check for incoming data
|
// create a task to check for incoming data
|
||||||
|
// For a 4096-word stack, uxTaskGetStackHighWaterMark reports 244 words available
|
||||||
|
// after WebUI attaches.
|
||||||
xTaskCreatePinnedToCore(serialCheckTask, // task
|
xTaskCreatePinnedToCore(serialCheckTask, // task
|
||||||
"serialCheckTask", // name for task
|
"serialCheckTask", // name for task
|
||||||
8192, // size of task stack
|
4096, // size of task stack
|
||||||
NULL, // parameters
|
NULL, // parameters
|
||||||
1, // priority
|
1, // priority
|
||||||
&serialCheckTaskHandle,
|
&serialCheckTaskHandle,
|
||||||
@@ -91,6 +113,7 @@ void serial_init() {
|
|||||||
void serialCheckTask(void* pvParameters) {
|
void serialCheckTask(void* pvParameters) {
|
||||||
uint8_t data = 0;
|
uint8_t data = 0;
|
||||||
uint8_t client = CLIENT_ALL; // who sent the data
|
uint8_t client = CLIENT_ALL; // who sent the data
|
||||||
|
static UBaseType_t uxHighWaterMark = 0;
|
||||||
while (true) { // run continuously
|
while (true) { // run continuously
|
||||||
while (any_client_has_data()) {
|
while (any_client_has_data()) {
|
||||||
if (Serial.available()) {
|
if (Serial.available()) {
|
||||||
@@ -149,6 +172,9 @@ void serialCheckTask(void* pvParameters) {
|
|||||||
WebUI::Serial2Socket.handle_flush();
|
WebUI::Serial2Socket.handle_flush();
|
||||||
#endif
|
#endif
|
||||||
vTaskDelay(1 / portTICK_RATE_MS); // Yield to other tasks
|
vTaskDelay(1 / portTICK_RATE_MS); // Yield to other tasks
|
||||||
|
|
||||||
|
static UBaseType_t uxHighWaterMark = 0;
|
||||||
|
reportTaskStackSize(uxHighWaterMark);
|
||||||
} // while(true)
|
} // while(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -185,6 +185,9 @@ namespace Spindles {
|
|||||||
// Wait a bit before we retry. Set the delay to poll-rate. Not sure
|
// Wait a bit before we retry. Set the delay to poll-rate. Not sure
|
||||||
// if we should use a different value...
|
// if we should use a different value...
|
||||||
vTaskDelay(VFD_RS485_POLL_RATE);
|
vTaskDelay(VFD_RS485_POLL_RATE);
|
||||||
|
|
||||||
|
static UBaseType_t uxHighWaterMark = 0;
|
||||||
|
reportTaskStackSize(uxHighWaterMark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -123,6 +123,9 @@ void controlCheckTask(void* pvParameters) {
|
|||||||
system_exec_control_pin(pins);
|
system_exec_control_pin(pins);
|
||||||
}
|
}
|
||||||
debouncing = false;
|
debouncing = false;
|
||||||
|
|
||||||
|
static UBaseType_t uxHighWaterMark = 0;
|
||||||
|
reportTaskStackSize(uxHighWaterMark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -20,8 +20,6 @@
|
|||||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Grbl.h"
|
|
||||||
|
|
||||||
// System states. The state variable primarily tracks the individual functions
|
// System states. The state variable primarily tracks the individual functions
|
||||||
// of Grbl to manage each without overlapping. It is also used as a messaging flag for
|
// of Grbl to manage each without overlapping. It is also used as a messaging flag for
|
||||||
// critical events.
|
// critical events.
|
||||||
|
@@ -600,9 +600,9 @@ namespace WebUI {
|
|||||||
|
|
||||||
#ifdef ENABLE_WIFI
|
#ifdef ENABLE_WIFI
|
||||||
static Error listAPs(char* parameter, AuthenticationLevel auth_level) { // ESP410
|
static Error listAPs(char* parameter, AuthenticationLevel auth_level) { // ESP410
|
||||||
JSONencoder* j = new JSONencoder(espresponse->client() != CLIENT_WEBUI);
|
JSONencoder j(espresponse->client() != CLIENT_WEBUI);
|
||||||
j->begin();
|
j.begin();
|
||||||
j->begin_array("AP_LIST");
|
j.begin_array("AP_LIST");
|
||||||
// An initial async scanNetworks was issued at startup, so there
|
// An initial async scanNetworks was issued at startup, so there
|
||||||
// is a good chance that scan information is already available.
|
// is a good chance that scan information is already available.
|
||||||
int n = WiFi.scanComplete();
|
int n = WiFi.scanComplete();
|
||||||
@@ -614,12 +614,12 @@ namespace WebUI {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
for (int i = 0; i < n; ++i) {
|
for (int i = 0; i < n; ++i) {
|
||||||
j->begin_object();
|
j.begin_object();
|
||||||
j->member("SSID", WiFi.SSID(i));
|
j.member("SSID", WiFi.SSID(i));
|
||||||
j->member("SIGNAL", wifi_config.getSignal(WiFi.RSSI(i)));
|
j.member("SIGNAL", wifi_config.getSignal(WiFi.RSSI(i)));
|
||||||
j->member("IS_PROTECTED", WiFi.encryptionType(i) != WIFI_AUTH_OPEN);
|
j.member("IS_PROTECTED", WiFi.encryptionType(i) != WIFI_AUTH_OPEN);
|
||||||
// j->member("IS_PROTECTED", WiFi.encryptionType(i) == WIFI_AUTH_OPEN ? "0" : "1");
|
// j->member("IS_PROTECTED", WiFi.encryptionType(i) == WIFI_AUTH_OPEN ? "0" : "1");
|
||||||
j->end_object();
|
j.end_object();
|
||||||
}
|
}
|
||||||
WiFi.scanDelete();
|
WiFi.scanDelete();
|
||||||
// Restart the scan in async mode so new data will be available
|
// Restart the scan in async mode so new data will be available
|
||||||
@@ -630,9 +630,8 @@ namespace WebUI {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
j->end_array();
|
j.end_array();
|
||||||
webPrint(j->end());
|
webPrint(j.end());
|
||||||
delete j;
|
|
||||||
if (espresponse->client() != CLIENT_WEBUI) {
|
if (espresponse->client() != CLIENT_WEBUI) {
|
||||||
espresponse->println("");
|
espresponse->println("");
|
||||||
}
|
}
|
||||||
@@ -657,17 +656,16 @@ namespace WebUI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Error listSettings(char* parameter, AuthenticationLevel auth_level) { // ESP400
|
static Error listSettings(char* parameter, AuthenticationLevel auth_level) { // ESP400
|
||||||
JSONencoder* j = new JSONencoder(espresponse->client() != CLIENT_WEBUI);
|
JSONencoder j(espresponse->client() != CLIENT_WEBUI);
|
||||||
j->begin();
|
j.begin();
|
||||||
j->begin_array("EEPROM");
|
j.begin_array("EEPROM");
|
||||||
for (Setting* js = Setting::List; js; js = js->next()) {
|
for (Setting* js = Setting::List; js; js = js->next()) {
|
||||||
if (js->getType() == WEBSET) {
|
if (js->getType() == WEBSET) {
|
||||||
js->addWebui(j);
|
js->addWebui(&j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
j->end_array();
|
j.end_array();
|
||||||
webPrint(j->end());
|
webPrint(j.end());
|
||||||
delete j;
|
|
||||||
return Error::Ok;
|
return Error::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -833,15 +831,15 @@ namespace WebUI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Error listLocalFilesJSON(char* parameter, AuthenticationLevel auth_level) { // No ESP command
|
static Error listLocalFilesJSON(char* parameter, AuthenticationLevel auth_level) { // No ESP command
|
||||||
JSONencoder* j = new JSONencoder(espresponse->client() != CLIENT_WEBUI);
|
JSONencoder j(espresponse->client() != CLIENT_WEBUI);
|
||||||
j->begin();
|
j.begin();
|
||||||
j->begin_array("files");
|
j.begin_array("files");
|
||||||
listDirJSON(SPIFFS, "/", 4, j);
|
listDirJSON(SPIFFS, "/", 4, &j);
|
||||||
j->end_array();
|
j.end_array();
|
||||||
j->member("total", SPIFFS.totalBytes());
|
j.member("total", SPIFFS.totalBytes());
|
||||||
j->member("used", SPIFFS.usedBytes());
|
j.member("used", SPIFFS.usedBytes());
|
||||||
j->member("occupation", String(100 * SPIFFS.usedBytes() / SPIFFS.totalBytes()));
|
j.member("occupation", String(100 * SPIFFS.usedBytes() / SPIFFS.totalBytes()));
|
||||||
webPrint(j->end());
|
webPrint(j.end());
|
||||||
if (espresponse->client() != CLIENT_WEBUI) {
|
if (espresponse->client() != CLIENT_WEBUI) {
|
||||||
webPrintln("");
|
webPrintln("");
|
||||||
}
|
}
|
||||||
|
@@ -28,6 +28,8 @@ build_flags =
|
|||||||
-DCORE_DEBUG_LEVEL=0
|
-DCORE_DEBUG_LEVEL=0
|
||||||
-Wno-unused-variable
|
-Wno-unused-variable
|
||||||
-Wno-unused-function
|
-Wno-unused-function
|
||||||
|
;-DDEBUG_REPORT_HEAP_SIZE
|
||||||
|
;-DDEBUG_REPORT_STACK_FREE
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
|
Reference in New Issue
Block a user