micropython: Add MicroPython support #13

Closed Jookia opened this issue on 24 Aug 2021 - 2 comments

@Jookia Jookia commented on 24 Aug 2021

On embedded platforms regular Python isn't really an option, so it's really important to support MicroPython or CircuitPython.

Worth nothing MicroPython runs in browsers now. It's clunky but it would work.

Okay I've managed to port the current setup to MicroPython. I've tested this on the Unix port of CircuitPython and a Raspberry Pi Pico.

Unfortunately this isn't running on the Seeeduino Xiao. I did manage to sit down and figure out how to make MicroPython load a frozen module at boot and remove the compiler entirely. Even with this we still ran out of RAM.

diff --git a/main.c b/main.c
index f17731950..89cb49b2b 100644
--- a/main.c
+++ b/main.c
@@ -32,6 +32,7 @@
 
 #include "genhdr/mpversion.h"
 #include "py/nlr.h"
+#include "py/builtin.h"
 #include "py/compile.h"
 #include "py/frozenmod.h"
 #include "py/mphal.h"
@@ -348,7 +349,7 @@ STATIC void cleanup_after_vm(supervisor_allocation *heap, mp_obj_t exception) {
 STATIC void print_code_py_status_message(safe_mode_t safe_mode) {
     if (autoreload_is_enabled()) {
         serial_write_compressed(
-            translate("Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.\n"));
+            translate("Auto-reload is on. Simply save files over USB to run them.\n"));
     } else {
         serial_write_compressed(translate("Auto-reload is off.\n"));
     }
@@ -371,7 +372,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
 
     bool skip_repl = false;
     bool skip_wait = false;
-    bool found_main = false;
+    //bool found_main = false;
     uint8_t next_code_options = 0;
     // Collects stickiness bits that apply in the current situation.
     uint8_t next_code_stickiness_situation = SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
@@ -383,14 +384,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
         filesystem_flush();
     }
     if (safe_mode == NO_SAFE_MODE && !autoreload_pending()) {
-        static const char *const supported_filenames[] = STRING_LIST(
-            "code.txt", "code.py", "main.py", "main.txt");
-        #if CIRCUITPY_FULL_BUILD
-        static const char *const double_extension_filenames[] = STRING_LIST(
-            "code.txt.py", "code.py.txt", "code.txt.txt","code.py.py",
-            "main.txt.py", "main.py.txt", "main.txt.txt","main.py.py");
-        #endif
-
         supervisor_allocation *heap = allocate_remaining_memory();
 
         // Prepare the VM state. Includes an alarm check/reset for sleep.
@@ -400,36 +393,16 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
         usb_setup_with_vm();
         #endif
 
-        // Check if a different run file has been allocated
-        if (next_code_allocation) {
-            ((next_code_info_t *)next_code_allocation->ptr)->options &= ~SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
-            next_code_options = ((next_code_info_t *)next_code_allocation->ptr)->options;
-            if (((next_code_info_t *)next_code_allocation->ptr)->filename[0] != '\0') {
-                const char *next_list[] = {((next_code_info_t *)next_code_allocation->ptr)->filename, ""};
-                // This is where the user's python code is actually executed:
-                found_main = maybe_run_list(next_list);
-                if (!found_main) {
-                    serial_write(((next_code_info_t *)next_code_allocation->ptr)->filename);
-                    serial_write_compressed(translate(" not found.\n"));
-                }
-            }
-        }
-        // Otherwise, default to the standard list of filenames
-        if (!found_main) {
-            // This is where the user's python code is actually executed:
-            found_main = maybe_run_list(supported_filenames);
-            // If that didn't work, double check the extensions
-            #if CIRCUITPY_FULL_BUILD
-            if (!found_main) {
-                found_main = maybe_run_list(double_extension_filenames);
-                if (found_main) {
-                    serial_write_compressed(translate("WARNING: Your code filename has two extensions\n"));
-                }
-            }
-            #else
-            (void)found_main;
-            #endif
-        }
+        mp_obj_t import_args[4];
+        import_args[0] = mp_obj_new_str("run", strlen("run"));
+        import_args[1] = import_args[2] = mp_const_none;
+        import_args[3] = mp_const_false;
+        mp_obj_t mod;
+        nlr_buf_t nlr;
+        nlr_push(&nlr);
+        mod = mp_builtin___import__(MP_ARRAY_SIZE(import_args), import_args);
+        (void)mod;
+        nlr_pop();
 
         // Print done before resetting everything so that we get the message over
         // BLE before it is reset and we have a delay before reconnect.
@@ -574,7 +547,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
                 printed_safe_mode_message = true;
             }
             serial_write("\r\n");
-            serial_write_compressed(translate("Press any key to enter the REPL. Use CTRL-D to reload.\n"));
+            serial_write_compressed(translate("Press any key to reload.\n"));
             printed_press_any_key = true;
         }
         if (!serial_connected()) {
@@ -830,6 +803,7 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
     #endif
 }
 
+#if 0
 STATIC int run_repl(bool first_run) {
     int exit_code = PYEXEC_FORCED_EXIT;
     stack_resize();
@@ -887,6 +861,7 @@ STATIC int run_repl(bool first_run) {
     autoreload_resume(AUTORELOAD_SUSPEND_REPL);
     return exit_code;
 }
+#endif
 
 int __attribute__((used)) main(void) {
     // initialise the cpu and peripherals
@@ -968,7 +943,6 @@ int __attribute__((used)) main(void) {
     for (;;) {
         simulate_reset = false;
         if (!skip_repl) {
-            exit_code = run_repl(first_run);
             supervisor_set_run_reason(RUN_REASON_REPL_RELOAD);
         }
         if (exit_code == PYEXEC_FORCED_EXIT) {
diff --git a/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.h b/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.h
index efb2fc340..d889d4f18 100644
--- a/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.h
+++ b/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.h
@@ -1,2 +1,3 @@
 #define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico"
 #define MICROPY_HW_MCU_NAME "rp2040"
+#define MICROPY_ENABLE_COMPILER (0)
diff --git a/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk b/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk
index 608ca280d..308ab6693 100644
--- a/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk
+++ b/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk
@@ -9,3 +9,5 @@ CHIP_FAMILY = rp2
 EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ"
 
 CIRCUITPY__EVE = 1
+
+FROZEN_MPY_DIRS += $(TOP)/frozen/newlang

Dump docs/examples/greeting.txt in the CIRCUITPYTHON USB and the newlang 'src' directory and a 'run.py' containing 'import src.main' and 'src.main.run_file("greeting.txt")' in frozen/newlang.

Pi Pico ships with MicroPython and doesn't seem to support atexit or getenv so the process for using it is to upload the 'src' directory and greeting.txt using ampy then run 'import src.main' and 'src.main.run_file("greeting.txt").

On Unix just run run.py with MicroPython.

@Jookia Jookia closed this issue on 8 Aug 2022
Labels

Priority
default
Milestone
No milestone
Assignee
No one assigned
1 participant
@Jookia