/* * This file is part of the MicroPython project, http://micropython.org/ * * Development of the code in this file was sponsored by Microbric Pty Ltd * * The MIT License (MIT) * * Copyright (c) 2016 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" #include "nvs_flash.h" #include "esp_task.h" #include "soc/cpu.h" #include "esp_log.h" #if CONFIG_IDF_TARGET_ESP32 #include "esp32/spiram.h" #elif CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/spiram.h" #elif CONFIG_IDF_TARGET_ESP32S3 #include "esp32s3/spiram.h" #endif #include "py/stackctrl.h" #include "py/nlr.h" #include "py/compile.h" #include "py/runtime.h" #include "py/persistentcode.h" #include "py/repl.h" #include "py/gc.h" #include "py/mphal.h" #include "shared/readline/readline.h" #include "shared/runtime/pyexec.h" #include "uart.h" #include "usb.h" #include "usb_serial_jtag.h" #include "modmachine.h" #include "modnetwork.h" #include "mpthreadport.h" #if MICROPY_BLUETOOTH_NIMBLE #include "extmod/modbluetooth.h" #endif // MicroPython runs as a task under FreeRTOS #define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1) #define MP_TASK_STACK_SIZE (16 * 1024) // Set the margin for detecting stack overflow, depending on the CPU architecture. #if CONFIG_IDF_TARGET_ESP32C3 #define MP_TASK_STACK_LIMIT_MARGIN (2048) #else #define MP_TASK_STACK_LIMIT_MARGIN (1024) #endif int vprintf_null(const char *format, va_list ap) { // do nothing: this is used as a log target during raw repl mode return 0; } void mp_task(void *pvParameter) { volatile uint32_t sp = (uint32_t)get_sp(); #if MICROPY_PY_THREAD mp_thread_init(pxTaskGetStackStart(NULL), MP_TASK_STACK_SIZE / sizeof(uintptr_t)); #endif #if CONFIG_USB_ENABLED usb_init(); #elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG usb_serial_jtag_init(); #else uart_init(); #endif machine_init(); // TODO: CONFIG_SPIRAM_SUPPORT is for 3.3 compatibility, remove after move to 4.0. #if CONFIG_ESP32_SPIRAM_SUPPORT || CONFIG_SPIRAM_SUPPORT // Try to use the entire external SPIRAM directly for the heap size_t mp_task_heap_size; void *mp_task_heap = (void *)SOC_EXTRAM_DATA_LOW; switch (esp_spiram_get_chip_size()) { case ESP_SPIRAM_SIZE_16MBITS: mp_task_heap_size = 2 * 1024 * 1024; break; case ESP_SPIRAM_SIZE_32MBITS: case ESP_SPIRAM_SIZE_64MBITS: mp_task_heap_size = 4 * 1024 * 1024; break; default: // No SPIRAM, fallback to normal allocation mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); mp_task_heap = malloc(mp_task_heap_size); break; } #elif CONFIG_ESP32S2_SPIRAM_SUPPORT || CONFIG_ESP32S3_SPIRAM_SUPPORT // Try to use the entire external SPIRAM directly for the heap size_t mp_task_heap_size; size_t esp_spiram_size = esp_spiram_get_size(); void *mp_task_heap = (void *)SOC_EXTRAM_DATA_HIGH - esp_spiram_size; if (esp_spiram_size > 0) { mp_task_heap_size = esp_spiram_size; } else { // No SPIRAM, fallback to normal allocation mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); mp_task_heap = malloc(mp_task_heap_size); } #else // Allocate the uPy heap using malloc and get the largest available region size_t mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); void *mp_task_heap = malloc(mp_task_heap_size); #endif soft_reset: // initialise the stack pointer for the main thread mp_stack_set_top((void *)sp); mp_stack_set_limit(MP_TASK_STACK_SIZE - MP_TASK_STACK_LIMIT_MARGIN); gc_init(mp_task_heap, mp_task_heap + mp_task_heap_size); mp_init(); mp_obj_list_init(mp_sys_path, 0); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib)); mp_obj_list_init(mp_sys_argv, 0); readline_init0(); // initialise peripherals machine_pins_init(); #if MICROPY_PY_MACHINE_I2S machine_i2s_init0(); #endif // run boot-up scripts pyexec_frozen_module("_boot.py"); pyexec_file_if_exists("boot.py"); if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { int ret = pyexec_file_if_exists("main.py"); if (ret & PYEXEC_FORCED_EXIT) { goto soft_reset_exit; } } for (;;) { if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { vprintf_like_t vprintf_log = esp_log_set_vprintf(vprintf_null); if (pyexec_raw_repl() != 0) { break; } esp_log_set_vprintf(vprintf_log); } else { if (pyexec_friendly_repl() != 0) { break; } } } soft_reset_exit: #if MICROPY_BLUETOOTH_NIMBLE mp_bluetooth_deinit(); #endif machine_timer_deinit_all(); #if MICROPY_PY_THREAD mp_thread_deinit(); #endif gc_sweep_all(); mp_hal_stdout_tx_str("MPY: soft reboot\r\n"); // deinitialise peripherals machine_pwm_deinit_all(); // TODO: machine_rmt_deinit_all(); machine_pins_deinit(); machine_deinit(); usocket_events_deinit(); mp_deinit(); fflush(stdout); goto soft_reset; } void boardctrl_startup(void) { esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { nvs_flash_erase(); nvs_flash_init(); } } void app_main(void) { // Hook for a board to run code at start up. // This defaults to initialising NVS. MICROPY_BOARD_STARTUP(); // Create and transfer control to the MicroPython task. xTaskCreatePinnedToCore(mp_task, "mp_task", MP_TASK_STACK_SIZE / sizeof(StackType_t), NULL, MP_TASK_PRIORITY, &mp_main_task_handle, MP_TASK_COREID); } void nlr_jump_fail(void *val) { printf("NLR jump failed, val=%p\n", val); esp_restart(); } // modussl_mbedtls uses this function but it's not enabled in ESP IDF void mbedtls_debug_set_threshold(int threshold) { (void)threshold; } void *esp_native_code_commit(void *buf, size_t len, void *reloc) { len = (len + 3) & ~3; uint32_t *p = heap_caps_malloc(len, MALLOC_CAP_EXEC); if (p == NULL) { m_malloc_fail(len); } if (reloc) { mp_native_relocate(reloc, buf, (uintptr_t)p); } memcpy(p, buf, len); return p; }