1 /*
2 * This file is part of the MicroPython project, http://micropython.org/
3 *
4 * Development of the code in this file was sponsored by Microbric Pty Ltd
5 *
6 * The MIT License (MIT)
7 *
8 * Copyright (c) 2016 Damien P. George
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 * THE SOFTWARE.
27 */
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdarg.h>
32
33 #include "freertos/FreeRTOS.h"
34 #include "freertos/task.h"
35 #include "esp_system.h"
36 #include "nvs_flash.h"
37 #include "esp_task.h"
38 #include "soc/cpu.h"
39 #include "esp_log.h"
40
41 #if CONFIG_IDF_TARGET_ESP32
42 #include "esp32/spiram.h"
43 #elif CONFIG_IDF_TARGET_ESP32S2
44 #include "esp32s2/spiram.h"
45 #elif CONFIG_IDF_TARGET_ESP32S3
46 #include "esp32s3/spiram.h"
47 #endif
48
49 #include "py/stackctrl.h"
50 #include "py/nlr.h"
51 #include "py/compile.h"
52 #include "py/runtime.h"
53 #include "py/persistentcode.h"
54 #include "py/repl.h"
55 #include "py/gc.h"
56 #include "py/mphal.h"
57 #include "shared/readline/readline.h"
58 #include "shared/runtime/pyexec.h"
59 #include "uart.h"
60 #include "usb.h"
61 #include "usb_serial_jtag.h"
62 #include "modmachine.h"
63 #include "modnetwork.h"
64 #include "mpthreadport.h"
65
66 #if MICROPY_BLUETOOTH_NIMBLE
67 #include "extmod/modbluetooth.h"
68 #endif
69
70 // MicroPython runs as a task under FreeRTOS
71 #define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1)
72 #define MP_TASK_STACK_SIZE (16 * 1024)
73
74 // Set the margin for detecting stack overflow, depending on the CPU architecture.
75 #if CONFIG_IDF_TARGET_ESP32C3
76 #define MP_TASK_STACK_LIMIT_MARGIN (2048)
77 #else
78 #define MP_TASK_STACK_LIMIT_MARGIN (1024)
79 #endif
80
vprintf_null(const char * format,va_list ap)81 int vprintf_null(const char *format, va_list ap) {
82 // do nothing: this is used as a log target during raw repl mode
83 return 0;
84 }
85
mp_task(void * pvParameter)86 void mp_task(void *pvParameter) {
87 volatile uint32_t sp = (uint32_t)get_sp();
88 #if MICROPY_PY_THREAD
89 mp_thread_init(pxTaskGetStackStart(NULL), MP_TASK_STACK_SIZE / sizeof(uintptr_t));
90 #endif
91 #if CONFIG_USB_ENABLED
92 usb_init();
93 #elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
94 usb_serial_jtag_init();
95 #else
96 uart_init();
97 #endif
98 machine_init();
99
100 // TODO: CONFIG_SPIRAM_SUPPORT is for 3.3 compatibility, remove after move to 4.0.
101 #if CONFIG_ESP32_SPIRAM_SUPPORT || CONFIG_SPIRAM_SUPPORT
102 // Try to use the entire external SPIRAM directly for the heap
103 size_t mp_task_heap_size;
104 void *mp_task_heap = (void *)0x3f800000;
105 switch (esp_spiram_get_chip_size()) {
106 case ESP_SPIRAM_SIZE_16MBITS:
107 mp_task_heap_size = 2 * 1024 * 1024;
108 break;
109 case ESP_SPIRAM_SIZE_32MBITS:
110 case ESP_SPIRAM_SIZE_64MBITS:
111 mp_task_heap_size = 4 * 1024 * 1024;
112 break;
113 default:
114 // No SPIRAM, fallback to normal allocation
115 mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
116 mp_task_heap = malloc(mp_task_heap_size);
117 break;
118 }
119 #elif CONFIG_ESP32S2_SPIRAM_SUPPORT || CONFIG_ESP32S3_SPIRAM_SUPPORT
120 // Try to use the entire external SPIRAM directly for the heap
121 size_t mp_task_heap_size;
122 size_t esp_spiram_size = esp_spiram_get_size();
123 void *mp_task_heap = (void *)0x3ff80000 - esp_spiram_size;
124 if (esp_spiram_size > 0) {
125 mp_task_heap_size = esp_spiram_size;
126 } else {
127 // No SPIRAM, fallback to normal allocation
128 mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
129 mp_task_heap = malloc(mp_task_heap_size);
130 }
131 #else
132 // Allocate the uPy heap using malloc and get the largest available region
133 size_t mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
134 void *mp_task_heap = malloc(mp_task_heap_size);
135 #endif
136
137 soft_reset:
138 // initialise the stack pointer for the main thread
139 mp_stack_set_top((void *)sp);
140 mp_stack_set_limit(MP_TASK_STACK_SIZE - MP_TASK_STACK_LIMIT_MARGIN);
141 gc_init(mp_task_heap, mp_task_heap + mp_task_heap_size);
142 mp_init();
143 mp_obj_list_init(mp_sys_path, 0);
144 mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
145 mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
146 mp_obj_list_init(mp_sys_argv, 0);
147 readline_init0();
148
149 // initialise peripherals
150 machine_pins_init();
151 #if MICROPY_PY_MACHINE_I2S
152 machine_i2s_init0();
153 #endif
154
155 // run boot-up scripts
156 pyexec_frozen_module("_boot.py");
157 pyexec_file_if_exists("boot.py");
158 if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
159 int ret = pyexec_file_if_exists("main.py");
160 if (ret & PYEXEC_FORCED_EXIT) {
161 goto soft_reset_exit;
162 }
163 }
164
165 for (;;) {
166 if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
167 vprintf_like_t vprintf_log = esp_log_set_vprintf(vprintf_null);
168 if (pyexec_raw_repl() != 0) {
169 break;
170 }
171 esp_log_set_vprintf(vprintf_log);
172 } else {
173 if (pyexec_friendly_repl() != 0) {
174 break;
175 }
176 }
177 }
178
179 soft_reset_exit:
180
181 #if MICROPY_BLUETOOTH_NIMBLE
182 mp_bluetooth_deinit();
183 #endif
184
185 machine_timer_deinit_all();
186
187 #if MICROPY_PY_THREAD
188 mp_thread_deinit();
189 #endif
190
191 gc_sweep_all();
192
193 mp_hal_stdout_tx_str("MPY: soft reboot\r\n");
194
195 // deinitialise peripherals
196 machine_pins_deinit();
197 machine_deinit();
198 usocket_events_deinit();
199
200 mp_deinit();
201 fflush(stdout);
202 goto soft_reset;
203 }
204
app_main(void)205 void app_main(void) {
206 esp_err_t ret = nvs_flash_init();
207 if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
208 nvs_flash_erase();
209 nvs_flash_init();
210 }
211 xTaskCreatePinnedToCore(mp_task, "mp_task", MP_TASK_STACK_SIZE / sizeof(StackType_t), NULL, MP_TASK_PRIORITY, &mp_main_task_handle, MP_TASK_COREID);
212 }
213
nlr_jump_fail(void * val)214 void nlr_jump_fail(void *val) {
215 printf("NLR jump failed, val=%p\n", val);
216 esp_restart();
217 }
218
219 // modussl_mbedtls uses this function but it's not enabled in ESP IDF
mbedtls_debug_set_threshold(int threshold)220 void mbedtls_debug_set_threshold(int threshold) {
221 (void)threshold;
222 }
223
esp_native_code_commit(void * buf,size_t len,void * reloc)224 void *esp_native_code_commit(void *buf, size_t len, void *reloc) {
225 len = (len + 3) & ~3;
226 uint32_t *p = heap_caps_malloc(len, MALLOC_CAP_EXEC);
227 if (p == NULL) {
228 m_malloc_fail(len);
229 }
230 if (reloc) {
231 mp_native_relocate(reloc, buf, (uintptr_t)p);
232 }
233 memcpy(p, buf, len);
234 return p;
235 }
236