Skip to content
Snippets Groups Projects
Commit 0377cc49 authored by q3k's avatar q3k
Browse files

main: move interrupts around, explain reasoning

parent 1a6b74e7
No related branches found
No related tags found
No related merge requests found
......@@ -15,27 +15,45 @@
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "nvs_flash.h"
// Called by micropython via MICROPY_BOARD_STARTUP.
void flow3r_startup(void) {
// Initialize display first as that gives us a nice splash screen.
st3m_gfx_init();
// Submit splash a couple of times to make sure we've fully flushed out the
// initial framebuffer (both on-ESP and in-screen) noise before we turn on
// the backlight.
for (int i = 0; i < 4; i++) {
st3m_gfx_splash("");
}
// Display should've flushed by now. Turn on backlight.
flow3r_bsp_display_set_backlight(100);
// Initialization is unfortunately quite complicated.
//
// In a perfect world, we'd just init everything in the main function in order.
// Unfortunately, the ESP32's interrupt routing is per-core, and the ESP-IDF has
// no API to configure interrupt handling to be performed by a core different
// than the one which performed the interrupt setup.
//
// Since calls to flow3r_bsp_*/st3m_* perform calls to initialize various ESP32
// peripherals via the ESP-IDF, it means these calls set up interrupts to be
// handled by whatever core is executing the initialization code.
//
// Thus, we must perform a complicated dance in which we set up parts of
// st3m/flow3r_bsp from one core, and part from another. Since flow3r_startup is
// called on core0, we set up another task whose only job is to initialize
// interrupts from core1.
//
// In the future we might refactor the codebase to use core pinning for all
// tasks, and then initiazlize interrupts from within tasks, effectively keeping
// interrupts local to handler tasks. But for now, we employ the strategy of
// generally trusting the scheduler and instead selecting which interrupts is
// handled by which core by performing initialization here.
//
// And we have to actually distribute these interrupts because each Xtensa core
// simply doesn't have enough interrupt slots to easily handle all of our
// external peripherals. Especially with the way the ESP-IDF interrupt
// allocation algorithm works. Core0 is already quite polluted by micropython
// doing its own initialization there, so we effectively push most interrupts to
// core1.
//
// TODO(q3k): revisit this mess.
st3m_mode_init();
st3m_mode_set(st3m_mode_kind_starting, "st3m");
st3m_mode_update_display(NULL);
// Populated by the core1 init task whenever core1 init is done.
static QueueHandle_t _core1_init_done_q;
// Initialize USB and console so that we get logging as early as possible.
void _init_core1(void *unused) {
st3m_usb_init();
st3m_console_init();
st3m_usb_app_conf_t app = {
......@@ -59,21 +77,12 @@ void flow3r_startup(void) {
vTaskDelay(100 / portTICK_PERIOD_MS);
flow3r_bsp_i2c_init();
st3m_mode_set(st3m_mode_kind_starting, "fs");
st3m_mode_update_display(NULL);
flow3r_fs_init();
st3m_mode_set(st3m_mode_kind_starting, "audio");
st3m_mode_update_display(NULL);
st3m_scope_init();
st3m_audio_init();
st3m_audio_set_player_function(bl00mbox_player_function);
st3m_mode_set(st3m_mode_kind_starting, "io");
st3m_mode_update_display(NULL);
st3m_leds_init();
st3m_io_init();
st3m_captouch_init();
st3m_imu_init();
st3m_mode_set(st3m_mode_kind_starting, "nvs");
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
......@@ -81,6 +90,47 @@ void flow3r_startup(void) {
nvs_flash_init();
}
// Let the main startup code know that core1 init is done. Then sleep
// forever. What a waste of stack space.
bool done = true;
xQueueSend(_core1_init_done_q, &done, portMAX_DELAY);
for (;;) {
vTaskDelay(10000 / portTICK_PERIOD_MS);
}
}
// Called by micropython via MICROPY_BOARD_STARTUP.
void flow3r_startup(void) {
_core1_init_done_q = xQueueCreate(1, sizeof(bool));
// Initialize display first as that gives us a nice splash screen.
st3m_gfx_init();
// Submit splash a couple of times to make sure we've fully flushed out the
// initial framebuffer (both on-ESP and in-screen) noise before we turn on
// the backlight.
for (int i = 0; i < 4; i++) {
st3m_gfx_splash("");
}
// Display should've flushed by now. Turn on backlight.
flow3r_bsp_display_set_backlight(100);
st3m_mode_init();
st3m_mode_set(st3m_mode_kind_starting, "core1");
st3m_mode_update_display(NULL);
xTaskCreatePinnedToCore(_init_core1, "core1-init", 4096, NULL,
configMAX_PRIORITIES - 1, NULL, 1);
bool done;
xQueueReceive(_core1_init_done_q, &done, portMAX_DELAY);
st3m_mode_set(st3m_mode_kind_starting, "core0");
st3m_mode_update_display(NULL);
st3m_scope_init();
st3m_audio_init();
st3m_audio_set_player_function(bl00mbox_player_function);
st3m_mode_set(st3m_mode_kind_starting, "micropython");
st3m_mode_update_display(NULL);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment