Skip to content

Commit 9537b1d

Browse files
committed
Improve neopixel on ESP
Greedily grab as much RMT memory as we can. It blocks other RMT transmit channels but we only use it temporarily anyway. The more we can grab, the fewer interrupts are needed to keep the transmit going. Flickers may still happen due to file system writes but most of the time the animation just pauses. On ESP32, move CircuitPython to the second core. This helps NeoPixel by moving the RMT interrupt to the second core as well. When testing ESP32 I noticed that settings.toml writes won't apply until after hard reset. This removes that constraint but still requires the password to enable the web workflow. Fixes #3835
1 parent 2e29772 commit 9537b1d

File tree

6 files changed

+25
-12
lines changed

6 files changed

+25
-12
lines changed

docs/workflows.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,7 @@ Read-only characteristic that returns the UTF-8 encoded version string.
7171
If the keys `CIRCUITPY_WIFI_SSID` and `CIRCUITPY_WIFI_PASSWORD` are set in `settings.toml`,
7272
CircuitPython will automatically connect to the given Wi-Fi network on boot and upon reload.
7373

74-
If `CIRCUITPY_WEB_API_PASSWORD` is also set, the web workflow will also start.
75-
The web workflow will only be enabled if the Wi-Fi connection succeeds upon boot.
74+
If `CIRCUITPY_WEB_API_PASSWORD` is set, MDNS and the http server for the web workflow will also start.
7675

7776
The webserver is on port 80 unless overridden by `CIRCUITPY_WEB_API_PORT`. It also enables MDNS.
7877
The name of the board as advertised to the network can be overridden by `CIRCUITPY_WEB_INSTANCE_NAME`.
@@ -84,7 +83,7 @@ Here is an example `/settings.toml`:
8483
CIRCUITPY_WIFI_SSID="scottswifi"
8584
CIRCUITPY_WIFI_PASSWORD="secretpassword"
8685

87-
# To enable the the webserver. Change this too!
86+
# To enable the web workflow. Change this too!
8887
# Leave the User field blank in the browser.
8988
CIRCUITPY_WEB_API_PASSWORD="passw0rd"
9089

ports/espressif/common-hal/neopixel_write/__init__.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,19 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout,
6666
.clk_src = RMT_CLK_SRC_DEFAULT,
6767
.resolution_hz = 40000000,
6868
.trans_queue_depth = 1,
69-
.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
7069
};
70+
71+
// Greedily try and grab as much RMT memory as we can. The more we get, the
72+
// smoother the output will be because we'll trigger fewer interrupts. We'll
73+
// give it all back once we're done.
7174
rmt_channel_handle_t channel;
72-
CHECK_ESP_RESULT(rmt_new_tx_channel(&config, &channel));
75+
esp_err_t result = ESP_ERR_NOT_FOUND;
76+
config.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL * SOC_RMT_TX_CANDIDATES_PER_GROUP;
77+
while (result == ESP_ERR_NOT_FOUND && config.mem_block_symbols > 0) {
78+
result = rmt_new_tx_channel(&config, &channel);
79+
config.mem_block_symbols -= SOC_RMT_MEM_WORDS_PER_CHANNEL;
80+
}
81+
CHECK_ESP_RESULT(result);
7382

7483
size_t ns_per_tick = 1e9 / 40000000;
7584
uint16_t ws2812_t0h_ticks = WS2812_T0H_NS / ns_per_tick;
@@ -97,7 +106,11 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout,
97106
}
98107
};
99108
rmt_encoder_handle_t encoder;
100-
CHECK_ESP_RESULT(rmt_new_bytes_encoder(&encoder_config, &encoder));
109+
result = rmt_new_bytes_encoder(&encoder_config, &encoder);
110+
if (result != ESP_OK) {
111+
rmt_del_channel(channel);
112+
return;
113+
}
101114

102115
// Wait to make sure we don't append onto the last transmission. This should only be a tick or
103116
// two.
@@ -111,7 +124,7 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout,
111124
.loop_count = 0,
112125
.flags.eot_level = 0
113126
};
114-
esp_err_t result = rmt_transmit(channel, encoder, pixels, (size_t)numBytes, &transmit_config);
127+
result = rmt_transmit(channel, encoder, pixels, (size_t)numBytes, &transmit_config);
115128
if (result != ESP_OK) {
116129
rmt_del_encoder(encoder);
117130
rmt_disable(channel);

ports/espressif/esp-idf-config/sdkconfig-esp32.defaults

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ CONFIG_PCNT_CTRL_FUNC_IN_IRAM=y
2828
# ESP System Settings
2929
#
3030
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
31+
CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1=y
3132
# end of ESP System Settings
3233

3334
#

supervisor/shared/web_workflow/web_workflow.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ void supervisor_web_workflow_status(void) {
258258
}
259259
#endif
260260

261-
bool supervisor_start_web_workflow(bool reload) {
261+
bool supervisor_start_web_workflow(void) {
262262
#if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_OS_GETENV
263263

264264
char ssid[33];
@@ -310,7 +310,7 @@ bool supervisor_start_web_workflow(bool reload) {
310310

311311
bool initialized = pool.base.type == &socketpool_socketpool_type;
312312

313-
if (!initialized && !reload) {
313+
if (!initialized) {
314314
result = common_hal_os_getenv_str("CIRCUITPY_WEB_INSTANCE_NAME", web_instance_name, sizeof(web_instance_name));
315315
if (result != GETENV_OK || web_instance_name[0] == '\0') {
316316
strcpy(web_instance_name, MICROPY_HW_BOARD_NAME);

supervisor/shared/web_workflow/web_workflow.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
void supervisor_web_workflow_background(void *data);
3737
bool supervisor_web_workflow_status_dirty(void);
3838
void supervisor_web_workflow_status(void);
39-
bool supervisor_start_web_workflow(bool);
39+
bool supervisor_start_web_workflow(void);
4040
void supervisor_stop_web_workflow(void);
4141

4242
// Share the MDNS object with user code.

supervisor/shared/workflow.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ void supervisor_workflow_reset(void) {
5858
#endif
5959

6060
#if CIRCUITPY_WEB_WORKFLOW
61-
bool result = supervisor_start_web_workflow(true);
61+
bool result = supervisor_start_web_workflow();
6262
if (workflow_background_cb.fun) {
6363
if (result) {
6464
supervisor_workflow_request_background();
@@ -108,7 +108,7 @@ void supervisor_workflow_start(void) {
108108
#endif
109109

110110
#if CIRCUITPY_WEB_WORKFLOW
111-
if (supervisor_start_web_workflow(false)) {
111+
if (supervisor_start_web_workflow()) {
112112
// Enable background callbacks if web_workflow startup successful
113113
memset(&workflow_background_cb, 0, sizeof(workflow_background_cb));
114114
workflow_background_cb.fun = supervisor_web_workflow_background;

0 commit comments

Comments
 (0)