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,19 +42,27 @@
|
||||
*/
|
||||
#include "Config.h"
|
||||
|
||||
# include <FreeRTOS.h>
|
||||
# include <driver/periph_ctrl.h>
|
||||
# include <rom/lldesc.h>
|
||||
# include <soc/i2s_struct.h>
|
||||
# include <freertos/queue.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 <stdatomic.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <driver/periph_ctrl.h>
|
||||
#include <rom/lldesc.h>
|
||||
#include <soc/i2s_struct.h>
|
||||
#include <freertos/queue.h>
|
||||
|
||||
# include "Pins.h"
|
||||
# include "I2SOut.h"
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "Pins.h"
|
||||
#include "I2SOut.h"
|
||||
|
||||
// Always enable I2S streaming logic
|
||||
# define USE_I2S_OUT_STREAM_IMPL
|
||||
#define USE_I2S_OUT_STREAM_IMPL
|
||||
|
||||
//
|
||||
// Configrations for DMA connected I2S
|
||||
@@ -76,7 +84,7 @@ const int I2S_SAMPLE_SIZE = 4; /* 4 bytes,
|
||||
const int DMA_SAMPLE_COUNT = I2S_OUT_DMABUF_LEN / I2S_SAMPLE_SIZE; /* number of samples per buffer */
|
||||
const int SAMPLE_SAFE_COUNT = (20 / I2S_OUT_USEC_PER_PULSE); /* prevent buffer overrun (GRBL's $0 should be less than or equal 20) */
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
typedef struct {
|
||||
uint32_t** buffers;
|
||||
uint32_t* current;
|
||||
@@ -87,39 +95,39 @@ typedef struct {
|
||||
|
||||
static i2s_out_dma_t o_dma;
|
||||
static intr_handle_t i2s_out_isr_handle;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// output value
|
||||
static atomic_uint_least32_t i2s_out_port_data = ATOMIC_VAR_INIT(0);
|
||||
|
||||
// inner lock
|
||||
static portMUX_TYPE i2s_out_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
# define I2S_OUT_ENTER_CRITICAL() \
|
||||
do { \
|
||||
if (xPortInIsrContext()) { \
|
||||
portENTER_CRITICAL_ISR(&i2s_out_spinlock); \
|
||||
} else { \
|
||||
portENTER_CRITICAL(&i2s_out_spinlock); \
|
||||
} \
|
||||
} while (0)
|
||||
# define I2S_OUT_EXIT_CRITICAL() \
|
||||
do { \
|
||||
if (xPortInIsrContext()) { \
|
||||
portEXIT_CRITICAL_ISR(&i2s_out_spinlock); \
|
||||
} else { \
|
||||
portEXIT_CRITICAL(&i2s_out_spinlock); \
|
||||
} \
|
||||
} while (0)
|
||||
# define I2S_OUT_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_out_spinlock)
|
||||
# define I2S_OUT_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_out_spinlock)
|
||||
#define I2S_OUT_ENTER_CRITICAL() \
|
||||
do { \
|
||||
if (xPortInIsrContext()) { \
|
||||
portENTER_CRITICAL_ISR(&i2s_out_spinlock); \
|
||||
} else { \
|
||||
portENTER_CRITICAL(&i2s_out_spinlock); \
|
||||
} \
|
||||
} while (0)
|
||||
#define I2S_OUT_EXIT_CRITICAL() \
|
||||
do { \
|
||||
if (xPortInIsrContext()) { \
|
||||
portEXIT_CRITICAL_ISR(&i2s_out_spinlock); \
|
||||
} else { \
|
||||
portEXIT_CRITICAL(&i2s_out_spinlock); \
|
||||
} \
|
||||
} while (0)
|
||||
#define I2S_OUT_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_out_spinlock)
|
||||
#define I2S_OUT_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_out_spinlock)
|
||||
|
||||
static int i2s_out_initialized = 0;
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
static volatile uint32_t i2s_out_pulse_period;
|
||||
static uint32_t i2s_out_remain_time_until_next_pulse; // Time remaining until the next pulse (μsec)
|
||||
static volatile i2s_out_pulse_func_t i2s_out_pulse_func;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static uint8_t i2s_out_ws_pin = 255;
|
||||
static uint8_t i2s_out_bck_pin = 255;
|
||||
@@ -129,24 +137,24 @@ static volatile i2s_out_pulser_status_t i2s_out_pulser_status = PASSTHROUGH;
|
||||
|
||||
// outer lock
|
||||
static portMUX_TYPE i2s_out_pulser_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
# define I2S_OUT_PULSER_ENTER_CRITICAL() \
|
||||
do { \
|
||||
if (xPortInIsrContext()) { \
|
||||
portENTER_CRITICAL_ISR(&i2s_out_pulser_spinlock); \
|
||||
} else { \
|
||||
portENTER_CRITICAL(&i2s_out_pulser_spinlock); \
|
||||
} \
|
||||
} while (0)
|
||||
# define I2S_OUT_PULSER_EXIT_CRITICAL() \
|
||||
do { \
|
||||
if (xPortInIsrContext()) { \
|
||||
portEXIT_CRITICAL_ISR(&i2s_out_pulser_spinlock); \
|
||||
} else { \
|
||||
portEXIT_CRITICAL(&i2s_out_pulser_spinlock); \
|
||||
} \
|
||||
} while (0)
|
||||
# define I2S_OUT_PULSER_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_out_pulser_spinlock)
|
||||
# define I2S_OUT_PULSER_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_out_pulser_spinlock)
|
||||
#define I2S_OUT_PULSER_ENTER_CRITICAL() \
|
||||
do { \
|
||||
if (xPortInIsrContext()) { \
|
||||
portENTER_CRITICAL_ISR(&i2s_out_pulser_spinlock); \
|
||||
} else { \
|
||||
portENTER_CRITICAL(&i2s_out_pulser_spinlock); \
|
||||
} \
|
||||
} while (0)
|
||||
#define I2S_OUT_PULSER_EXIT_CRITICAL() \
|
||||
do { \
|
||||
if (xPortInIsrContext()) { \
|
||||
portEXIT_CRITICAL_ISR(&i2s_out_pulser_spinlock); \
|
||||
} else { \
|
||||
portEXIT_CRITICAL(&i2s_out_pulser_spinlock); \
|
||||
} \
|
||||
} while (0)
|
||||
#define I2S_OUT_PULSER_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_out_pulser_spinlock)
|
||||
#define I2S_OUT_PULSER_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_out_pulser_spinlock)
|
||||
|
||||
//
|
||||
// Internal functions
|
||||
@@ -161,13 +169,13 @@ static inline void gpio_matrix_out_check(uint8_t gpio, uint32_t signal_idx, bool
|
||||
}
|
||||
|
||||
static inline void i2s_out_single_data() {
|
||||
# if I2S_OUT_NUM_BITS == 16
|
||||
#if I2S_OUT_NUM_BITS == 16
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data);
|
||||
port_data <<= 16; // Shift needed. This specification is not spelled out in the manual.
|
||||
I2S0.conf_single_data = port_data; // Apply port data in real-time (static I2S)
|
||||
# else
|
||||
#else
|
||||
I2S0.conf_single_data = atomic_load(&i2s_out_port_data); // Apply port data in real-time (static I2S)
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void i2s_out_reset_fifo_without_lock() {
|
||||
@@ -183,7 +191,7 @@ static void IRAM_ATTR i2s_out_reset_fifo() {
|
||||
I2S_OUT_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
static int IRAM_ATTR i2s_clear_dma_buffer(lldesc_t* dma_desc, uint32_t port_data) {
|
||||
uint32_t* buf = (uint32_t*)dma_desc->buf;
|
||||
for (int i = 0; i < DMA_SAMPLE_COUNT; i++) {
|
||||
@@ -210,7 +218,7 @@ static int IRAM_ATTR i2s_clear_o_dma_buffers(uint32_t port_data) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static int IRAM_ATTR i2s_out_gpio_attach(uint8_t ws, uint8_t bck, uint8_t data) {
|
||||
// Route the i2s pins to the appropriate GPIO
|
||||
@@ -243,13 +251,13 @@ static int IRAM_ATTR i2s_out_gpio_shiftout(uint32_t port_data) {
|
||||
|
||||
static int IRAM_ATTR i2s_out_stop() {
|
||||
I2S_OUT_ENTER_CRITICAL();
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
// Stop FIFO DMA
|
||||
I2S0.out_link.stop = 1;
|
||||
|
||||
// Disconnect DMA from FIFO
|
||||
I2S0.fifo_conf.dscr_en = 0; //Unset this bit to disable I2S DMA mode. (R/W)
|
||||
# endif
|
||||
#endif
|
||||
// stop TX module
|
||||
I2S0.conf.tx_start = 0;
|
||||
|
||||
@@ -269,10 +277,10 @@ static int IRAM_ATTR i2s_out_stop() {
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data); // current expanded port value
|
||||
i2s_out_gpio_shiftout(port_data);
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
//clear pending interrupt
|
||||
I2S0.int_clr.val = I2S0.int_st.val;
|
||||
# endif
|
||||
#endif
|
||||
I2S_OUT_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
@@ -296,7 +304,7 @@ static int IRAM_ATTR i2s_out_start() {
|
||||
I2S0.conf.rx_reset = 1;
|
||||
I2S0.conf.rx_reset = 0;
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
// reset DMA
|
||||
I2S0.lc_conf.in_rst = 1;
|
||||
I2S0.lc_conf.in_rst = 0;
|
||||
@@ -304,13 +312,13 @@ static int IRAM_ATTR i2s_out_start() {
|
||||
I2S0.lc_conf.out_rst = 0;
|
||||
|
||||
I2S0.out_link.addr = (uint32_t)o_dma.desc[0];
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// reset FIFO
|
||||
i2s_out_reset_fifo_without_lock();
|
||||
|
||||
// start DMA link
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
if (i2s_out_pulser_status == PASSTHROUGH) {
|
||||
I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
I2S0.conf_single_data = port_data;
|
||||
@@ -318,17 +326,17 @@ static int IRAM_ATTR i2s_out_start() {
|
||||
I2S0.conf_chan.tx_chan_mod = 4; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
I2S0.conf_single_data = 0;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
I2S0.conf1.tx_stop_en = 1; // BCK and WCK are suppressed while FIFO is empty
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
// Connect DMA to FIFO
|
||||
I2S0.fifo_conf.dscr_en = 1; // Set this bit to enable I2S DMA mode. (R/W)
|
||||
|
||||
I2S0.int_clr.val = 0xFFFFFFFF;
|
||||
I2S0.out_link.start = 1;
|
||||
# endif
|
||||
#endif
|
||||
I2S0.conf.tx_start = 1;
|
||||
// Wait for the first FIFO data to prevent the unintentional generation of 0 data
|
||||
ets_delay_us(20);
|
||||
@@ -339,7 +347,7 @@ static int IRAM_ATTR i2s_out_start() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
// Fill out one DMA buffer
|
||||
// Call with the I2S_OUT_PULSER lock acquired.
|
||||
// Note that the lock is temporarily released while calling the callback function.
|
||||
@@ -516,15 +524,18 @@ 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
|
||||
}
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL(); // Unlock pulser status
|
||||
|
||||
static UBaseType_t uxHighWaterMark = 0;
|
||||
reportTaskStackSize(uxHighWaterMark);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//
|
||||
// External funtions
|
||||
//
|
||||
void IRAM_ATTR i2s_out_delay() {
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL();
|
||||
if (i2s_out_pulser_status == PASSTHROUGH) {
|
||||
// Depending on the timing, it may not be reflected immediately,
|
||||
@@ -536,9 +547,9 @@ void IRAM_ATTR i2s_out_delay() {
|
||||
delay(I2S_OUT_DELAY_MS);
|
||||
}
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
# else
|
||||
#else
|
||||
ets_delay_us(I2S_OUT_USEC_PER_PULSE * 2);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void IRAM_ATTR i2s_out_write(uint8_t pin, uint8_t val) {
|
||||
@@ -548,15 +559,15 @@ void IRAM_ATTR i2s_out_write(uint8_t pin, uint8_t val) {
|
||||
} else {
|
||||
atomic_fetch_and(&i2s_out_port_data, ~bit);
|
||||
}
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
// It needs a lock for access, but I've given up because I need speed.
|
||||
// This is not a problem as long as there is no overlap between the status change and digitalWrite().
|
||||
if (i2s_out_pulser_status == PASSTHROUGH) {
|
||||
i2s_out_single_data();
|
||||
}
|
||||
# else
|
||||
#else
|
||||
i2s_out_single_data();
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t IRAM_ATTR i2s_out_read(uint8_t pin) {
|
||||
@@ -565,9 +576,9 @@ uint8_t IRAM_ATTR i2s_out_read(uint8_t pin) {
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR i2s_out_push_sample(uint32_t usec) {
|
||||
uint32_t num = usec/I2S_OUT_USEC_PER_PULSE;
|
||||
uint32_t num = usec / I2S_OUT_USEC_PER_PULSE;
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
if (num > SAMPLE_SAFE_COUNT) {
|
||||
return 0;
|
||||
}
|
||||
@@ -579,9 +590,9 @@ uint32_t IRAM_ATTR i2s_out_push_sample(uint32_t usec) {
|
||||
n++;
|
||||
} while (n < num);
|
||||
return n;
|
||||
# else
|
||||
#else
|
||||
return 0;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
i2s_out_pulser_status_t IRAM_ATTR i2s_out_get_pulser_status() {
|
||||
@@ -593,7 +604,7 @@ i2s_out_pulser_status_t IRAM_ATTR i2s_out_get_pulser_status() {
|
||||
|
||||
int IRAM_ATTR i2s_out_set_passthrough() {
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL();
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
// Triggers a change of mode if it is compiled to use I2S stream.
|
||||
// The mode is not changed directly by this function.
|
||||
// Pull the trigger
|
||||
@@ -604,17 +615,17 @@ int IRAM_ATTR i2s_out_set_passthrough() {
|
||||
// (i2sOutTask() -> stepper_pulse_func() -> st_go_idle() -> Stepper_Timer_Stop() -> this function)
|
||||
// And only i2sOutTask() can change the state to PASSTHROUGH.
|
||||
// So, to change the state, you need to return to i2sOutTask() as soon as possible.
|
||||
# else
|
||||
#else
|
||||
// If it is compiled to not use I2S streams, change the mode directly.
|
||||
i2s_out_pulser_status = PASSTHROUGH;
|
||||
# endif
|
||||
#endif
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IRAM_ATTR i2s_out_set_stepping() {
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL();
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
// Re-entered (fail safe)
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
@@ -650,31 +661,31 @@ int IRAM_ATTR i2s_out_set_stepping() {
|
||||
// because the process in i2s_out_start() is different depending on the status.
|
||||
i2s_out_pulser_status = STEPPING;
|
||||
i2s_out_start();
|
||||
# else
|
||||
#else
|
||||
i2s_out_pulser_status = STEPPING;
|
||||
# endif
|
||||
#endif
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IRAM_ATTR i2s_out_set_pulse_period(uint32_t period) {
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
i2s_out_pulse_period = period;
|
||||
# endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IRAM_ATTR i2s_out_set_pulse_callback(i2s_out_pulse_func_t func) {
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
i2s_out_pulse_func = func;
|
||||
# endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IRAM_ATTR i2s_out_reset() {
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL();
|
||||
i2s_out_stop();
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data);
|
||||
i2s_clear_o_dma_buffers(port_data);
|
||||
@@ -682,7 +693,7 @@ int IRAM_ATTR i2s_out_reset() {
|
||||
i2s_clear_o_dma_buffers(0);
|
||||
i2s_out_pulser_status = PASSTHROUGH;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
// You need to set the status before calling i2s_out_start()
|
||||
// because the process in i2s_out_start() is different depending on the status.
|
||||
i2s_out_start();
|
||||
@@ -733,7 +744,7 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
|
||||
* M = 2
|
||||
*/
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
// Allocate the array of pointers to the buffers
|
||||
o_dma.buffers = (uint32_t**)malloc(sizeof(uint32_t*) * I2S_OUT_DMABUF_COUNT);
|
||||
if (o_dma.buffers == nullptr) {
|
||||
@@ -770,7 +781,7 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
|
||||
|
||||
// Set the first DMA descriptor
|
||||
I2S0.out_link.addr = (uint32_t)o_dma.desc[0];
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// stop i2s
|
||||
I2S0.out_link.stop = 1;
|
||||
@@ -806,9 +817,9 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
|
||||
I2S0.lc_conf.outdscr_burst_en = 0;
|
||||
I2S0.lc_conf.out_no_restart_clr = 0;
|
||||
I2S0.lc_conf.indscr_burst_en = 0;
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
I2S0.lc_conf.out_eof_mode = 1; // I2S_OUT_EOF_INT generated when DMA has popped all data from the FIFO;
|
||||
# endif
|
||||
#endif
|
||||
I2S0.conf2.lcd_en = 0;
|
||||
I2S0.conf2.camera_en = 0;
|
||||
I2S0.pdm_conf.pcm2pdm_conv_en = 0;
|
||||
@@ -816,7 +827,7 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
|
||||
|
||||
I2S0.fifo_conf.dscr_en = 0;
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
// Stream output mode
|
||||
I2S0.conf_chan.tx_chan_mod = 4; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
@@ -826,31 +837,31 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
|
||||
I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
I2S0.conf_single_data = init_param.init_val;
|
||||
}
|
||||
# else
|
||||
#else
|
||||
// For the static output mode
|
||||
I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
I2S0.conf_single_data = init_param.init_val; // initial constant value
|
||||
# endif
|
||||
# if I2S_OUT_NUM_BITS == 16
|
||||
#endif
|
||||
#if I2S_OUT_NUM_BITS == 16
|
||||
I2S0.fifo_conf.tx_fifo_mod = 0; // 0: 16-bit dual channel data, 3: 32-bit single channel data
|
||||
I2S0.fifo_conf.rx_fifo_mod = 0; // 0: 16-bit dual channel data, 3: 32-bit single channel data
|
||||
I2S0.sample_rate_conf.tx_bits_mod = 16; // default is 16-bits
|
||||
I2S0.sample_rate_conf.rx_bits_mod = 16; // default is 16-bits
|
||||
# else
|
||||
#else
|
||||
I2S0.fifo_conf.tx_fifo_mod = 3; // 0: 16-bit dual channel data, 3: 32-bit single channel data
|
||||
I2S0.fifo_conf.rx_fifo_mod = 3; // 0: 16-bit dual channel data, 3: 32-bit single channel data
|
||||
// Data width is 32-bit. Forgetting this setting will result in a 16-bit transfer.
|
||||
I2S0.sample_rate_conf.tx_bits_mod = 32;
|
||||
I2S0.sample_rate_conf.rx_bits_mod = 32;
|
||||
# endif
|
||||
#endif
|
||||
I2S0.conf.tx_mono = 0; // Set this bit to enable transmitter’s mono mode in PCM standard mode.
|
||||
|
||||
I2S0.conf_chan.rx_chan_mod = 1; // 1: right+right
|
||||
I2S0.conf.rx_mono = 0;
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
I2S0.fifo_conf.dscr_en = 1; //connect DMA to fifo
|
||||
# endif
|
||||
#endif
|
||||
I2S0.conf.tx_start = 0;
|
||||
I2S0.conf.rx_start = 0;
|
||||
|
||||
@@ -858,9 +869,9 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
|
||||
I2S0.conf.tx_right_first = 0; // Setting this bit allows the right-channel data to be sent first.
|
||||
|
||||
I2S0.conf.tx_slave_mod = 0; // Master
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
I2S0.fifo_conf.tx_fifo_mod_force_en = 1; //The bit should always be set to 1.
|
||||
# endif
|
||||
#endif
|
||||
I2S0.pdm_conf.rx_pdm_en = 0; // Set this bit to enable receiver’s PDM mode.
|
||||
I2S0.pdm_conf.tx_pdm_en = 0; // Set this bit to enable transmitter’s PDM mode.
|
||||
|
||||
@@ -877,13 +888,13 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
|
||||
// set clock (fi2s) 160MHz / 5
|
||||
I2S0.clkm_conf.clka_en = 0; // Use 160 MHz PLL_D2_CLK as reference
|
||||
// N + b/a = 0
|
||||
# if I2S_OUT_NUM_BITS == 16
|
||||
#if I2S_OUT_NUM_BITS == 16
|
||||
// N = 10
|
||||
I2S0.clkm_conf.clkm_div_num = 10; // minimum value of 2, reset value of 4, max 256 (I²S clock divider’s integral value)
|
||||
# else
|
||||
#else
|
||||
// N = 5
|
||||
I2S0.clkm_conf.clkm_div_num = 5; // minimum value of 2, reset value of 4, max 256 (I²S clock divider’s integral value)
|
||||
# endif
|
||||
#endif
|
||||
// b/a = 0
|
||||
I2S0.clkm_conf.clkm_div_b = 0; // 0 at reset
|
||||
I2S0.clkm_conf.clkm_div_a = 0; // 0 at reset, what about divide by 0? (not an issue)
|
||||
@@ -893,7 +904,7 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
|
||||
I2S0.sample_rate_conf.tx_bck_div_num = 2; // minimum value of 2 defaults to 6
|
||||
I2S0.sample_rate_conf.rx_bck_div_num = 2;
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
#ifdef USE_I2S_OUT_STREAM_IMPL
|
||||
// Enable TX interrupts (DMA Interrupts)
|
||||
I2S0.int_ena.out_eof = 1; // Triggered when rxlink has finished sending a packet.
|
||||
I2S0.int_ena.out_dscr_err = 0; // Triggered when invalid rxlink descriptors are encountered.
|
||||
@@ -907,7 +918,7 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
|
||||
// Create the task that will feed the buffer
|
||||
xTaskCreatePinnedToCore(i2sOutTask,
|
||||
"I2SOutTask",
|
||||
1024 * 10,
|
||||
4096,
|
||||
NULL,
|
||||
1,
|
||||
nullptr,
|
||||
@@ -917,7 +928,7 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
|
||||
// Allocate and Enable the I2S interrupt
|
||||
esp_intr_alloc(ETS_I2S0_INTR_SOURCE, 0, i2s_out_intr_handler, nullptr, &i2s_out_isr_handle);
|
||||
esp_intr_enable(i2s_out_isr_handle);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Remember GPIO pin numbers
|
||||
i2s_out_ws_pin = init_param.ws_pin;
|
||||
@@ -931,18 +942,18 @@ int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
# ifndef I2S_OUT_WS
|
||||
# define I2S_OUT_WS GPIO_NUM_17
|
||||
# endif
|
||||
# ifndef I2S_OUT_BCK
|
||||
# define I2S_OUT_BCK GPIO_NUM_22
|
||||
# endif
|
||||
# ifndef I2S_OUT_DATA
|
||||
# define I2S_OUT_DATA GPIO_NUM_21
|
||||
# endif
|
||||
# ifndef I2S_OUT_INIT_VAL
|
||||
# define I2S_OUT_INIT_VAL 0
|
||||
# endif
|
||||
#ifndef I2S_OUT_WS
|
||||
# define I2S_OUT_WS GPIO_NUM_17
|
||||
#endif
|
||||
#ifndef I2S_OUT_BCK
|
||||
# define I2S_OUT_BCK GPIO_NUM_22
|
||||
#endif
|
||||
#ifndef I2S_OUT_DATA
|
||||
# define I2S_OUT_DATA GPIO_NUM_21
|
||||
#endif
|
||||
#ifndef I2S_OUT_INIT_VAL
|
||||
# define I2S_OUT_INIT_VAL 0
|
||||
#endif
|
||||
/*
|
||||
Initialize I2S out by default parameters.
|
||||
|
||||
|
@@ -330,11 +330,8 @@ void limits_init() {
|
||||
}
|
||||
|
||||
if (limit_sw_queue == NULL) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MsgLevel::Info,
|
||||
"%s limit switch on pin %s",
|
||||
reportAxisNameMsg(axis, gang_index),
|
||||
pinName(pin).c_str());
|
||||
grbl_msg_sendf(
|
||||
CLIENT_SERIAL, MsgLevel::Info, "%s limit switch on pin %s", reportAxisNameMsg(axis, gang_index), pinName(pin).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -427,17 +424,19 @@ void limitCheckTask(void* pvParameters) {
|
||||
mc_reset(); // Initiate system kill.
|
||||
sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event
|
||||
}
|
||||
static UBaseType_t uxHighWaterMark = 0;
|
||||
reportTaskStackSize(uxHighWaterMark);
|
||||
}
|
||||
}
|
||||
|
||||
float limitsMaxPosition(uint8_t axis) {
|
||||
float mpos = axis_settings[axis]->home_mpos->get();
|
||||
float mpos = axis_settings[axis]->home_mpos->get();
|
||||
|
||||
return bitnum_istrue(homing_dir_mask->get(), axis) ? mpos + axis_settings[axis]->max_travel->get() : mpos;
|
||||
}
|
||||
|
||||
float limitsMinPosition(uint8_t axis) {
|
||||
float mpos = axis_settings[axis]->home_mpos->get();
|
||||
float mpos = axis_settings[axis]->home_mpos->get();
|
||||
|
||||
return bitnum_istrue(homing_dir_mask->get(), axis) ? mpos : mpos - axis_settings[axis]->max_travel->get();
|
||||
}
|
||||
|
@@ -60,18 +60,14 @@ namespace Motors {
|
||||
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
||||
vTaskDelay(2000); // initial delay
|
||||
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) {
|
||||
p->update();
|
||||
}
|
||||
|
||||
vTaskDelayUntil(&xLastWakeTime, xUpdate);
|
||||
|
||||
static UBaseType_t uxHighWaterMark = 0;
|
||||
reportTaskStackSize(uxHighWaterMark);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -360,13 +360,10 @@ namespace Motors {
|
||||
} // sys.state
|
||||
} // 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);
|
||||
|
||||
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));
|
||||
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* reportAxisNameMsg(uint8_t 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_current_line_number = 0;
|
||||
myFile.close();
|
||||
SD.end();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -147,7 +148,7 @@ uint8_t get_sd_state(bool refresh) {
|
||||
sd_state = SDCARD_NOT_PRESENT;
|
||||
//using default value for speed ? should be parameter
|
||||
//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) {
|
||||
sd_state = SDCARD_IDLE;
|
||||
}
|
||||
|
@@ -68,7 +68,27 @@ uint8_t serial_get_rx_buffer_available(uint8_t client) {
|
||||
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() {
|
||||
#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.setRxBufferSize(256);
|
||||
// reset all buffers
|
||||
@@ -76,9 +96,11 @@ void serial_init() {
|
||||
grbl_send(CLIENT_SERIAL, "\r\n"); // create some white space after ESP32 boot info
|
||||
serialCheckTaskHandle = 0;
|
||||
// create a task to check for incoming data
|
||||
// For a 4096-word stack, uxTaskGetStackHighWaterMark reports 244 words available
|
||||
// after WebUI attaches.
|
||||
xTaskCreatePinnedToCore(serialCheckTask, // task
|
||||
"serialCheckTask", // name for task
|
||||
8192, // size of task stack
|
||||
4096, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
&serialCheckTaskHandle,
|
||||
@@ -89,9 +111,10 @@ void serial_init() {
|
||||
// this task runs and checks for data on all interfaces
|
||||
// REaltime stuff is acted upon, then characters are added to the appropriate buffer
|
||||
void serialCheckTask(void* pvParameters) {
|
||||
uint8_t data = 0;
|
||||
uint8_t client = CLIENT_ALL; // who sent the data
|
||||
while (true) { // run continuously
|
||||
uint8_t data = 0;
|
||||
uint8_t client = CLIENT_ALL; // who sent the data
|
||||
static UBaseType_t uxHighWaterMark = 0;
|
||||
while (true) { // run continuously
|
||||
while (any_client_has_data()) {
|
||||
if (Serial.available()) {
|
||||
client = CLIENT_SERIAL;
|
||||
@@ -149,7 +172,10 @@ void serialCheckTask(void* pvParameters) {
|
||||
WebUI::Serial2Socket.handle_flush();
|
||||
#endif
|
||||
vTaskDelay(1 / portTICK_RATE_MS); // Yield to other tasks
|
||||
} // while(true)
|
||||
|
||||
static UBaseType_t uxHighWaterMark = 0;
|
||||
reportTaskStackSize(uxHighWaterMark);
|
||||
} // while(true)
|
||||
}
|
||||
|
||||
void serial_reset_read_buffer(uint8_t client) {
|
||||
|
@@ -185,6 +185,9 @@ namespace Spindles {
|
||||
// Wait a bit before we retry. Set the delay to poll-rate. Not sure
|
||||
// if we should use a different value...
|
||||
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);
|
||||
}
|
||||
debouncing = false;
|
||||
|
||||
static UBaseType_t uxHighWaterMark = 0;
|
||||
reportTaskStackSize(uxHighWaterMark);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@@ -20,8 +20,6 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Grbl.h"
|
||||
|
||||
// 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
|
||||
// critical events.
|
||||
|
@@ -600,9 +600,9 @@ namespace WebUI {
|
||||
|
||||
#ifdef ENABLE_WIFI
|
||||
static Error listAPs(char* parameter, AuthenticationLevel auth_level) { // ESP410
|
||||
JSONencoder* j = new JSONencoder(espresponse->client() != CLIENT_WEBUI);
|
||||
j->begin();
|
||||
j->begin_array("AP_LIST");
|
||||
JSONencoder j(espresponse->client() != CLIENT_WEBUI);
|
||||
j.begin();
|
||||
j.begin_array("AP_LIST");
|
||||
// An initial async scanNetworks was issued at startup, so there
|
||||
// is a good chance that scan information is already available.
|
||||
int n = WiFi.scanComplete();
|
||||
@@ -614,12 +614,12 @@ namespace WebUI {
|
||||
break;
|
||||
default:
|
||||
for (int i = 0; i < n; ++i) {
|
||||
j->begin_object();
|
||||
j->member("SSID", WiFi.SSID(i));
|
||||
j->member("SIGNAL", wifi_config.getSignal(WiFi.RSSI(i)));
|
||||
j->member("IS_PROTECTED", WiFi.encryptionType(i) != WIFI_AUTH_OPEN);
|
||||
j.begin_object();
|
||||
j.member("SSID", WiFi.SSID(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 ? "0" : "1");
|
||||
j->end_object();
|
||||
j.end_object();
|
||||
}
|
||||
WiFi.scanDelete();
|
||||
// Restart the scan in async mode so new data will be available
|
||||
@@ -630,9 +630,8 @@ namespace WebUI {
|
||||
}
|
||||
break;
|
||||
}
|
||||
j->end_array();
|
||||
webPrint(j->end());
|
||||
delete j;
|
||||
j.end_array();
|
||||
webPrint(j.end());
|
||||
if (espresponse->client() != CLIENT_WEBUI) {
|
||||
espresponse->println("");
|
||||
}
|
||||
@@ -657,17 +656,16 @@ namespace WebUI {
|
||||
}
|
||||
|
||||
static Error listSettings(char* parameter, AuthenticationLevel auth_level) { // ESP400
|
||||
JSONencoder* j = new JSONencoder(espresponse->client() != CLIENT_WEBUI);
|
||||
j->begin();
|
||||
j->begin_array("EEPROM");
|
||||
JSONencoder j(espresponse->client() != CLIENT_WEBUI);
|
||||
j.begin();
|
||||
j.begin_array("EEPROM");
|
||||
for (Setting* js = Setting::List; js; js = js->next()) {
|
||||
if (js->getType() == WEBSET) {
|
||||
js->addWebui(j);
|
||||
js->addWebui(&j);
|
||||
}
|
||||
}
|
||||
j->end_array();
|
||||
webPrint(j->end());
|
||||
delete j;
|
||||
j.end_array();
|
||||
webPrint(j.end());
|
||||
return Error::Ok;
|
||||
}
|
||||
|
||||
@@ -833,15 +831,15 @@ namespace WebUI {
|
||||
}
|
||||
|
||||
static Error listLocalFilesJSON(char* parameter, AuthenticationLevel auth_level) { // No ESP command
|
||||
JSONencoder* j = new JSONencoder(espresponse->client() != CLIENT_WEBUI);
|
||||
j->begin();
|
||||
j->begin_array("files");
|
||||
listDirJSON(SPIFFS, "/", 4, j);
|
||||
j->end_array();
|
||||
j->member("total", SPIFFS.totalBytes());
|
||||
j->member("used", SPIFFS.usedBytes());
|
||||
j->member("occupation", String(100 * SPIFFS.usedBytes() / SPIFFS.totalBytes()));
|
||||
webPrint(j->end());
|
||||
JSONencoder j(espresponse->client() != CLIENT_WEBUI);
|
||||
j.begin();
|
||||
j.begin_array("files");
|
||||
listDirJSON(SPIFFS, "/", 4, &j);
|
||||
j.end_array();
|
||||
j.member("total", SPIFFS.totalBytes());
|
||||
j.member("used", SPIFFS.usedBytes());
|
||||
j.member("occupation", String(100 * SPIFFS.usedBytes() / SPIFFS.totalBytes()));
|
||||
webPrint(j.end());
|
||||
if (espresponse->client() != CLIENT_WEBUI) {
|
||||
webPrintln("");
|
||||
}
|
||||
|
@@ -28,6 +28,8 @@ build_flags =
|
||||
-DCORE_DEBUG_LEVEL=0
|
||||
-Wno-unused-variable
|
||||
-Wno-unused-function
|
||||
;-DDEBUG_REPORT_HEAP_SIZE
|
||||
;-DDEBUG_REPORT_STACK_FREE
|
||||
|
||||
[env]
|
||||
lib_deps =
|
||||
|
Reference in New Issue
Block a user