From 7f7b4f2bc68a06c9f47d6b99e953cac0b21c26c9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Feb 2021 16:29:54 +1100 Subject: [PATCH 001/174] rp2/machine_adc: Only initialise the ADC periph if not already enabled. Otherwise it resets the ADC peripheral each time a new ADC object is constructed, which can reset other state that has already been set up. See issue #6833. Signed-off-by: Damien George --- ports/rp2/machine_adc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/rp2/machine_adc.c b/ports/rp2/machine_adc.c index f0f367151c..f8925e5aa3 100644 --- a/ports/rp2/machine_adc.c +++ b/ports/rp2/machine_adc.c @@ -78,7 +78,10 @@ STATIC mp_obj_t machine_adc_make_new(const mp_obj_type_t *type, size_t n_args, s } } - adc_init(); + // Initialise the ADC peripheral if it's not already running. + if (!(adc_hw->cs & ADC_CS_EN_BITS)) { + adc_init(); + } if (ADC_IS_VALID_GPIO(channel)) { // Configure the GPIO pin in ADC mode. From 5fdf351178df9a18df624ae0f5947d8a5a6bce40 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 11 Jan 2021 14:10:25 +0800 Subject: [PATCH 002/174] py/gc: Don't include mpconfig.h and misc.h in gc.h. Because gc.h doesn't reference any symbol from these header files. Signed-off-by: Xiang Xiao --- ports/esp8266/gccollect.c | 1 + py/gc.h | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ports/esp8266/gccollect.c b/ports/esp8266/gccollect.c index 3618a56644..bca0e030cb 100644 --- a/ports/esp8266/gccollect.c +++ b/ports/esp8266/gccollect.c @@ -26,6 +26,7 @@ #include +#include "py/mpconfig.h" #include "py/gc.h" #include "gccollect.h" diff --git a/py/gc.h b/py/gc.h index 4690d39370..f67fb0daad 100644 --- a/py/gc.h +++ b/py/gc.h @@ -26,11 +26,9 @@ #ifndef MICROPY_INCLUDED_PY_GC_H #define MICROPY_INCLUDED_PY_GC_H +#include #include -#include "py/mpconfig.h" -#include "py/misc.h" - void gc_init(void *start, void *end); // These lock/unlock functions can be nested. From 7c4435459261f1ea93577938b1ab281239d159e7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 4 Feb 2021 14:43:24 +1100 Subject: [PATCH 003/174] ports: Remove def of MP_PLAT_PRINT_STRN if it's the same as the default. To simplify config, there's no need to specify MP_PLAT_PRINT_STRN if it's the same as the default definition in py/mpconfig.h. Signed-off-by: Damien George --- ports/cc3200/mpconfigport.h | 2 -- ports/esp32/mpconfigport.h | 1 - ports/esp8266/mpconfigport.h | 1 - ports/javascript/mpconfigport.h | 2 -- ports/mimxrt/mpconfigport.h | 1 - ports/nrf/mpconfigport.h | 2 -- ports/pic16bit/mpconfigport.h | 2 -- ports/powerpc/mpconfigport.h | 2 -- ports/samd/mpconfigport.h | 1 - ports/stm32/mpconfigport.h | 2 -- ports/teensy/mpconfigport.h | 2 -- 11 files changed, 18 deletions(-) diff --git a/ports/cc3200/mpconfigport.h b/ports/cc3200/mpconfigport.h index 6fdb278d86..87689c505e 100644 --- a/ports/cc3200/mpconfigport.h +++ b/ports/cc3200/mpconfigport.h @@ -197,8 +197,6 @@ typedef int32_t mp_int_t; // must be pointer size typedef unsigned int mp_uint_t; // must be pointer size typedef long mp_off_t; -#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) - #define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq() #define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state) #define MICROPY_EVENT_POLL_HOOK __WFI(); diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index f170d70708..5ad5fa18a3 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -223,7 +223,6 @@ struct mp_bluetooth_nimble_root_pointers_t; #define BYTES_PER_WORD (4) #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p))) -#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) void *esp_native_code_commit(void *, size_t, void *); #define MP_PLAT_COMMIT_EXEC(buf, len, reloc) esp_native_code_commit(buf, len, reloc) #define MP_SSIZE_MAX (0x7fffffff) diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 99cf2ade4d..2c56b4188f 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -135,7 +135,6 @@ typedef uint32_t sys_prot_t; // for modlwip // ssize_t, off_t as required by POSIX-signatured functions in stream.h #include -#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) void *esp_native_code_commit(void *, size_t, void *); #define MP_PLAT_COMMIT_EXEC(buf, len, reloc) esp_native_code_commit(buf, len, reloc) diff --git a/ports/javascript/mpconfigport.h b/ports/javascript/mpconfigport.h index 0101e10c8d..d1bfbbd601 100644 --- a/ports/javascript/mpconfigport.h +++ b/ports/javascript/mpconfigport.h @@ -180,8 +180,6 @@ typedef int mp_int_t; // must be pointer size typedef unsigned mp_uint_t; // must be pointer size typedef long mp_off_t; -#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) - // extra built in names to add to the global namespace #define MICROPY_PORT_BUILTINS \ { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index 344867fb81..15a292486f 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -98,7 +98,6 @@ extern const struct _mp_obj_module_t mp_module_utime; } while (0); #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1)) -#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) #define MP_SSIZE_MAX (0x7fffffff) typedef int mp_int_t; // must be pointer size diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index a025feb2ec..581e83ef2f 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -332,8 +332,6 @@ extern const struct _mp_obj_module_t ble_module; __WFI(); \ } while (0); -#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) - // We need to provide a declaration/definition of alloca() #include diff --git a/ports/pic16bit/mpconfigport.h b/ports/pic16bit/mpconfigport.h index f121081e6f..43300d1760 100644 --- a/ports/pic16bit/mpconfigport.h +++ b/ports/pic16bit/mpconfigport.h @@ -84,8 +84,6 @@ typedef unsigned int mp_uint_t; // must be pointer size typedef int mp_off_t; -#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) - // extra builtin names to add to the global namespace #define MICROPY_PORT_BUILTINS \ { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, diff --git a/ports/powerpc/mpconfigport.h b/ports/powerpc/mpconfigport.h index 7a92777362..0b868e3daf 100644 --- a/ports/powerpc/mpconfigport.h +++ b/ports/powerpc/mpconfigport.h @@ -103,8 +103,6 @@ typedef unsigned long mp_uint_t; // must be pointer size typedef long mp_off_t; -#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) - // extra built in names to add to the global namespace #define MICROPY_PORT_BUILTINS \ { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, diff --git a/ports/samd/mpconfigport.h b/ports/samd/mpconfigport.h index ffb30bf5e2..852d9e9ee5 100644 --- a/ports/samd/mpconfigport.h +++ b/ports/samd/mpconfigport.h @@ -98,7 +98,6 @@ extern const struct _mp_obj_module_t mp_module_utime; } while (0); #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1)) -#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) #define MP_SSIZE_MAX (0x7fffffff) typedef int mp_int_t; // must be pointer size diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index b6906ef998..a47529d8b3 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -360,8 +360,6 @@ typedef unsigned int mp_uint_t; // must be pointer size typedef long mp_off_t; -#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) - // We have inlined IRQ functions for efficiency (they are generally // 1 machine instruction). // diff --git a/ports/teensy/mpconfigport.h b/ports/teensy/mpconfigport.h index c00da5ed9e..3acedcf024 100644 --- a/ports/teensy/mpconfigport.h +++ b/ports/teensy/mpconfigport.h @@ -62,8 +62,6 @@ typedef int32_t mp_int_t; // must be pointer size typedef unsigned int mp_uint_t; // must be pointer size typedef long mp_off_t; -#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) - // We have inlined IRQ functions for efficiency (they are generally // 1 machine instruction). // From 8a41ee19c22d7bb85fcbd90c9d06b9937a1b8c87 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 4 Feb 2021 15:27:53 +1100 Subject: [PATCH 004/174] py: Remove BITS_PER_WORD definition. It's only used in one location, to test if << or >> will overflow when shifting mp_uint_t. For such a test it's clearer to use sizeof(lhs_val), which will be valid even if the type of lhs_val changes. Signed-off-by: Damien George --- py/mpconfig.h | 1 - py/runtime.c | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/py/mpconfig.h b/py/mpconfig.h index d9a30cd300..3c1ed28d80 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1538,7 +1538,6 @@ typedef double mp_float_t; #ifndef BITS_PER_BYTE #define BITS_PER_BYTE (8) #endif -#define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD) // mp_int_t value with most significant bit set #define WORD_MSBIT_HIGH (((mp_uint_t)1) << (BYTES_PER_WORD * 8 - 1)) diff --git a/py/runtime.c b/py/runtime.c index c12271f4e2..2e2fa1d173 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -387,7 +387,9 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { if (rhs_val < 0) { // negative shift not allowed mp_raise_ValueError(MP_ERROR_TEXT("negative shift count")); - } else if (rhs_val >= (mp_int_t)BITS_PER_WORD || lhs_val > (MP_SMALL_INT_MAX >> rhs_val) || lhs_val < (MP_SMALL_INT_MIN >> rhs_val)) { + } else if (rhs_val >= (mp_int_t)(sizeof(lhs_val) * BITS_PER_BYTE) + || lhs_val > (MP_SMALL_INT_MAX >> rhs_val) + || lhs_val < (MP_SMALL_INT_MIN >> rhs_val)) { // left-shift will overflow, so use higher precision integer lhs = mp_obj_new_int_from_ll(lhs_val); goto generic_binary_op; @@ -404,10 +406,10 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { mp_raise_ValueError(MP_ERROR_TEXT("negative shift count")); } else { // standard precision is enough for right-shift - if (rhs_val >= (mp_int_t)BITS_PER_WORD) { + if (rhs_val >= (mp_int_t)(sizeof(lhs_val) * BITS_PER_BYTE)) { // Shifting to big amounts is underfined behavior // in C and is CPU-dependent; propagate sign bit. - rhs_val = BITS_PER_WORD - 1; + rhs_val = sizeof(lhs_val) * BITS_PER_BYTE - 1; } lhs_val >>= rhs_val; } From 7e956fae28e4e3fdea30f834d448eacfc4429de7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 4 Feb 2021 15:32:59 +1100 Subject: [PATCH 005/174] py: Rename BITS_PER_BYTE to MP_BITS_PER_BYTE. To give this macro a standard MP_ prefix. Signed-off-by: Damien George --- py/gc.c | 4 ++-- py/mpconfig.h | 5 +++-- py/objfloat.c | 2 +- py/objint.c | 2 +- py/runtime.c | 6 +++--- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/py/gc.c b/py/gc.c index 41bbaa1b57..be35dc2ccc 100644 --- a/py/gc.c +++ b/py/gc.c @@ -118,9 +118,9 @@ void gc_init(void *start, void *end) { // => T = A * (1 + BLOCKS_PER_ATB / BLOCKS_PER_FTB + BLOCKS_PER_ATB * BYTES_PER_BLOCK) size_t total_byte_len = (byte *)end - (byte *)start; #if MICROPY_ENABLE_FINALISER - MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len * BITS_PER_BYTE / (BITS_PER_BYTE + BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK); + MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len * MP_BITS_PER_BYTE / (MP_BITS_PER_BYTE + MP_BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + MP_BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK); #else - MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK); + MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len / (1 + MP_BITS_PER_BYTE / 2 * BYTES_PER_BLOCK); #endif MP_STATE_MEM(gc_alloc_table_start) = (byte *)start; diff --git a/py/mpconfig.h b/py/mpconfig.h index 3c1ed28d80..3a0c5fb6e7 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1535,8 +1535,9 @@ typedef double mp_float_t; #define BYTES_PER_WORD (sizeof(mp_uint_t)) #endif -#ifndef BITS_PER_BYTE -#define BITS_PER_BYTE (8) +// Number of bits in a byte +#ifndef MP_BITS_PER_BYTE +#define MP_BITS_PER_BYTE (8) #endif // mp_int_t value with most significant bit set #define WORD_MSBIT_HIGH (((mp_uint_t)1) << (BYTES_PER_WORD * 8 - 1)) diff --git a/py/objfloat.c b/py/objfloat.c index 451609492e..5194dba51e 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -77,7 +77,7 @@ mp_int_t mp_float_hash(mp_float_t src) { // number may have a fraction; xor the integer part with the fractional part val = (frc >> (MP_FLOAT_FRAC_BITS - adj_exp)) ^ (frc & (((mp_float_uint_t)1 << (MP_FLOAT_FRAC_BITS - adj_exp)) - 1)); - } else if ((unsigned int)adj_exp < BITS_PER_BYTE * sizeof(mp_int_t) - 1) { + } else if ((unsigned int)adj_exp < MP_BITS_PER_BYTE * sizeof(mp_int_t) - 1) { // the number is a (big) whole integer and will fit in val's signed-width val = (mp_int_t)frc << (adj_exp - MP_FLOAT_FRAC_BITS); } else { diff --git a/py/objint.c b/py/objint.c index 4619fb5751..00375d388e 100644 --- a/py/objint.c +++ b/py/objint.c @@ -121,7 +121,7 @@ STATIC mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { return MP_FP_CLASS_FIT_SMALLINT; } #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG - if (e <= (((sizeof(long long) * BITS_PER_BYTE) + MP_FLOAT_EXP_BIAS - 2) << MP_FLOAT_EXP_SHIFT_I32)) { + if (e <= (((sizeof(long long) * MP_BITS_PER_BYTE) + MP_FLOAT_EXP_BIAS - 2) << MP_FLOAT_EXP_SHIFT_I32)) { return MP_FP_CLASS_FIT_LONGINT; } #endif diff --git a/py/runtime.c b/py/runtime.c index 2e2fa1d173..5d476a2764 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -387,7 +387,7 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { if (rhs_val < 0) { // negative shift not allowed mp_raise_ValueError(MP_ERROR_TEXT("negative shift count")); - } else if (rhs_val >= (mp_int_t)(sizeof(lhs_val) * BITS_PER_BYTE) + } else if (rhs_val >= (mp_int_t)(sizeof(lhs_val) * MP_BITS_PER_BYTE) || lhs_val > (MP_SMALL_INT_MAX >> rhs_val) || lhs_val < (MP_SMALL_INT_MIN >> rhs_val)) { // left-shift will overflow, so use higher precision integer @@ -406,10 +406,10 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { mp_raise_ValueError(MP_ERROR_TEXT("negative shift count")); } else { // standard precision is enough for right-shift - if (rhs_val >= (mp_int_t)(sizeof(lhs_val) * BITS_PER_BYTE)) { + if (rhs_val >= (mp_int_t)(sizeof(lhs_val) * MP_BITS_PER_BYTE)) { // Shifting to big amounts is underfined behavior // in C and is CPU-dependent; propagate sign bit. - rhs_val = sizeof(lhs_val) * BITS_PER_BYTE - 1; + rhs_val = sizeof(lhs_val) * MP_BITS_PER_BYTE - 1; } lhs_val >>= rhs_val; } From ad4656b861f94277bed9647ca176e662ce5119e3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 4 Feb 2021 16:39:09 +1100 Subject: [PATCH 006/174] all: Rename BYTES_PER_WORD to MP_BYTES_PER_OBJ_WORD. The "word" referred to by BYTES_PER_WORD is actually the size of mp_obj_t which is not always the same as the size of a pointer on the target architecture. So rename this config value to better reflect what it measures, and also prefix it with MP_. For uses of BYTES_PER_WORD in setting the stack limit this has been changed to sizeof(void *), because the stack usually grows with machine-word sized values (eg an nlr_buf_t has many machine words in it). Signed-off-by: Damien George --- examples/embedding/hello-embed.c | 2 +- mpy-cross/main.c | 4 ++-- ports/esp32/mpconfigport.h | 1 - ports/nrf/mpconfigport.h | 2 -- ports/unix/main.c | 4 ++-- ports/unix/mpthreadport.c | 2 +- py/binary.c | 4 ++-- py/emitbc.c | 2 +- py/gc.c | 2 +- py/mpconfig.h | 10 +++++----- py/persistentcode.c | 2 +- 11 files changed, 16 insertions(+), 19 deletions(-) diff --git a/examples/embedding/hello-embed.c b/examples/embedding/hello-embed.c index 2000b703c1..9a90288cf6 100644 --- a/examples/embedding/hello-embed.c +++ b/examples/embedding/hello-embed.c @@ -53,7 +53,7 @@ mp_obj_t execute_from_str(const char *str) { int main() { // Initialized stack limit - mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4)); + mp_stack_set_limit(40000 * (sizeof(void *) / 4)); // Initialize heap gc_init(heap, heap + sizeof(heap)); // Initialize interpreter diff --git a/mpy-cross/main.c b/mpy-cross/main.c index a403c0504d..635e53a719 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -170,7 +170,7 @@ STATIC void pre_process_options(int argc, char **argv) { heap_size *= 1024 * 1024; } if (word_adjust) { - heap_size = heap_size * BYTES_PER_WORD / 4; + heap_size = heap_size * MP_BYTES_PER_OBJ_WORD / 4; } } else { exit(usage(argv)); @@ -182,7 +182,7 @@ STATIC void pre_process_options(int argc, char **argv) { } MP_NOINLINE int main_(int argc, char **argv) { - mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4)); + mp_stack_set_limit(40000 * (sizeof(void *) / 4)); pre_process_options(argc, argv); diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 5ad5fa18a3..81f8297c50 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -221,7 +221,6 @@ struct mp_bluetooth_nimble_root_pointers_t; // type definitions for the specific machine -#define BYTES_PER_WORD (4) #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p))) void *esp_native_code_commit(void *, size_t, void *); #define MP_PLAT_COMMIT_EXEC(buf, len, reloc) esp_native_code_commit(buf, len, reloc) diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index 581e83ef2f..c246c53dd5 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -201,8 +201,6 @@ // type definitions for the specific machine -#define BYTES_PER_WORD (4) - #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1)) #define MP_SSIZE_MAX (0x7fffffff) diff --git a/ports/unix/main.c b/ports/unix/main.c index af4328a4db..07db8d22c6 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -387,7 +387,7 @@ STATIC void pre_process_options(int argc, char **argv) { goto invalid_arg; } if (word_adjust) { - heap_size = heap_size * BYTES_PER_WORD / 4; + heap_size = heap_size * MP_BYTES_PER_OBJ_WORD / 4; } // If requested size too small, we'll crash anyway if (heap_size < 700) { @@ -446,7 +446,7 @@ MP_NOINLINE int main_(int argc, char **argv) { signal(SIGPIPE, SIG_IGN); #endif - mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4)); + mp_stack_set_limit(40000 * (sizeof(void *) / 4)); pre_process_options(argc, argv); diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c index de0f5923ba..cbc4901f69 100644 --- a/ports/unix/mpthreadport.c +++ b/ports/unix/mpthreadport.c @@ -206,7 +206,7 @@ void mp_thread_start(void) { void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { // default stack size is 8k machine-words if (*stack_size == 0) { - *stack_size = 8192 * BYTES_PER_WORD; + *stack_size = 8192 * sizeof(void *); } // minimum stack size is set by pthreads diff --git a/py/binary.c b/py/binary.c index 1847894b71..5c098b223d 100644 --- a/py/binary.c +++ b/py/binary.c @@ -321,7 +321,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p double f; } fp_dp; fp_dp.f = mp_obj_get_float_to_d(val_in); - if (BYTES_PER_WORD == 8) { + if (MP_BYTES_PER_OBJ_WORD == 8) { val = fp_dp.i64; } else { int be = struct_type == '>'; @@ -342,7 +342,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p val = mp_obj_get_int(val_in); // zero/sign extend if needed - if (BYTES_PER_WORD < 8 && size > sizeof(val)) { + if (MP_BYTES_PER_OBJ_WORD < 8 && size > sizeof(val)) { int c = (mp_int_t)val < 0 ? 0xff : 0x00; memset(p, c, size); if (struct_type == '>') { diff --git a/py/emitbc.c b/py/emitbc.c index c74b7fbc4d..d7e8e05f0f 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -36,7 +36,7 @@ #if MICROPY_ENABLE_COMPILER -#define BYTES_FOR_INT ((BYTES_PER_WORD * 8 + 6) / 7) +#define BYTES_FOR_INT ((MP_BYTES_PER_OBJ_WORD * 8 + 6) / 7) #define DUMMY_DATA_SIZE (BYTES_FOR_INT) struct _emit_t { diff --git a/py/gc.c b/py/gc.c index be35dc2ccc..53a0d9da4a 100644 --- a/py/gc.c +++ b/py/gc.c @@ -49,7 +49,7 @@ // detect untraced object still in use #define CLEAR_ON_SWEEP (0) -#define WORDS_PER_BLOCK ((MICROPY_BYTES_PER_GC_BLOCK) / BYTES_PER_WORD) +#define WORDS_PER_BLOCK ((MICROPY_BYTES_PER_GC_BLOCK) / MP_BYTES_PER_OBJ_WORD) #define BYTES_PER_BLOCK (MICROPY_BYTES_PER_GC_BLOCK) // ATB = allocation table byte diff --git a/py/mpconfig.h b/py/mpconfig.h index 3a0c5fb6e7..e87c52f2be 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -126,7 +126,7 @@ // Number of bytes in memory allocation/GC block. Any size allocated will be // rounded up to be multiples of this. #ifndef MICROPY_BYTES_PER_GC_BLOCK -#define MICROPY_BYTES_PER_GC_BLOCK (4 * BYTES_PER_WORD) +#define MICROPY_BYTES_PER_GC_BLOCK (4 * MP_BYTES_PER_OBJ_WORD) #endif // Number of words allocated (in BSS) to the GC stack (minimum is 1) @@ -1530,9 +1530,9 @@ typedef double mp_float_t; #define STATIC static #endif -// Number of bytes in a word -#ifndef BYTES_PER_WORD -#define BYTES_PER_WORD (sizeof(mp_uint_t)) +// Number of bytes in an object word: mp_obj_t, mp_uint_t, mp_uint_t +#ifndef MP_BYTES_PER_OBJ_WORD +#define MP_BYTES_PER_OBJ_WORD (sizeof(mp_uint_t)) #endif // Number of bits in a byte @@ -1540,7 +1540,7 @@ typedef double mp_float_t; #define MP_BITS_PER_BYTE (8) #endif // mp_int_t value with most significant bit set -#define WORD_MSBIT_HIGH (((mp_uint_t)1) << (BYTES_PER_WORD * 8 - 1)) +#define WORD_MSBIT_HIGH (((mp_uint_t)1) << (MP_BYTES_PER_OBJ_WORD * MP_BITS_PER_BYTE - 1)) // Make sure both MP_ENDIANNESS_LITTLE and MP_ENDIANNESS_BIG are // defined and that they are the opposite of each other. diff --git a/py/persistentcode.c b/py/persistentcode.c index 084632a60f..ac523990c1 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -595,7 +595,7 @@ STATIC void mp_print_bytes(mp_print_t *print, const byte *data, size_t len) { print->print_strn(print->data, (const char *)data, len); } -#define BYTES_FOR_INT ((BYTES_PER_WORD * 8 + 6) / 7) +#define BYTES_FOR_INT ((MP_BYTES_PER_OBJ_WORD * 8 + 6) / 7) STATIC void mp_print_uint(mp_print_t *print, size_t n) { byte buf[BYTES_FOR_INT]; byte *p = buf + sizeof(buf); From c891190c693ec04289f5773b2b27d125f8c6059f Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 4 Feb 2021 16:39:46 +1100 Subject: [PATCH 007/174] py: Rename WORD_MSBIT_HIGH to MP_OBJ_WORD_MSBIT_HIGH. To make it clear it is for mp_obj_t/mp_uint_t "word" types, and to prefix this macro with MP_. Signed-off-by: Damien George --- py/mpconfig.h | 2 +- py/mpz.c | 4 ++-- py/smallint.h | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/py/mpconfig.h b/py/mpconfig.h index e87c52f2be..454fc12b7c 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1540,7 +1540,7 @@ typedef double mp_float_t; #define MP_BITS_PER_BYTE (8) #endif // mp_int_t value with most significant bit set -#define WORD_MSBIT_HIGH (((mp_uint_t)1) << (MP_BYTES_PER_OBJ_WORD * MP_BITS_PER_BYTE - 1)) +#define MP_OBJ_WORD_MSBIT_HIGH (((mp_uint_t)1) << (MP_BYTES_PER_OBJ_WORD * MP_BITS_PER_BYTE - 1)) // Make sure both MP_ENDIANNESS_LITTLE and MP_ENDIANNESS_BIG are // defined and that they are the opposite of each other. diff --git a/py/mpz.c b/py/mpz.c index 7515930538..51d0c96890 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -1573,7 +1573,7 @@ bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) { mpz_dig_t *d = i->dig + i->len; while (d-- > i->dig) { - if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) { + if (val > (~(MP_OBJ_WORD_MSBIT_HIGH) >> DIG_SIZE)) { // will overflow return false; } @@ -1598,7 +1598,7 @@ bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) { mpz_dig_t *d = i->dig + i->len; while (d-- > i->dig) { - if (val > (~(WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) { + if (val > (~(MP_OBJ_WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) { // will overflow return false; } diff --git a/py/smallint.h b/py/smallint.h index 6a3c75236c..58d843e8a1 100644 --- a/py/smallint.h +++ b/py/smallint.h @@ -36,17 +36,17 @@ // In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C -#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)WORD_MSBIT_HIGH) >> 1)) -#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0) +#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)MP_OBJ_WORD_MSBIT_HIGH) >> 1)) +#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & MP_OBJ_WORD_MSBIT_HIGH) == 0) // Mask to truncate mp_int_t to positive value -#define MP_SMALL_INT_POSITIVE_MASK ~(WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1)) +#define MP_SMALL_INT_POSITIVE_MASK ~(MP_OBJ_WORD_MSBIT_HIGH | (MP_OBJ_WORD_MSBIT_HIGH >> 1)) #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B -#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)WORD_MSBIT_HIGH) >> 2)) +#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)MP_OBJ_WORD_MSBIT_HIGH) >> 2)) #define MP_SMALL_INT_FITS(n) ((((n) & MP_SMALL_INT_MIN) == 0) || (((n) & MP_SMALL_INT_MIN) == MP_SMALL_INT_MIN)) // Mask to truncate mp_int_t to positive value -#define MP_SMALL_INT_POSITIVE_MASK ~(WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1) | (WORD_MSBIT_HIGH >> 2)) +#define MP_SMALL_INT_POSITIVE_MASK ~(MP_OBJ_WORD_MSBIT_HIGH | (MP_OBJ_WORD_MSBIT_HIGH >> 1) | (MP_OBJ_WORD_MSBIT_HIGH >> 2)) #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D From 1f800cac3c4f56418486f24c3824418a890f759f Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 5 Feb 2021 01:10:30 +1100 Subject: [PATCH 008/174] rp2/micropy_rules.cmake: Fix makemoduledefs vpath to work with abs path. In particular the firmware can now be built in a build directory that lives outside the source tree, and the py/modarray.c file will still be found. See issue #6837. Signed-off-by: Damien George --- ports/rp2/micropy_rules.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ports/rp2/micropy_rules.cmake b/ports/rp2/micropy_rules.cmake index ade9b8c92d..9eee4ac14d 100644 --- a/ports/rp2/micropy_rules.cmake +++ b/ports/rp2/micropy_rules.cmake @@ -24,11 +24,10 @@ add_custom_command( ) # Generate moduledefs.h -# This is currently hard-coded to support modarray.c only, because makemoduledefs.py doesn't support absolute paths add_custom_command( OUTPUT ${MPY_MODULEDEFS} - COMMAND python3 ${MPY_PY_DIR}/makemoduledefs.py --vpath="." ../../../py/modarray.c > ${MPY_MODULEDEFS} + COMMAND python3 ${MPY_PY_DIR}/makemoduledefs.py --vpath="/" ${SOURCE_QSTR} > ${MPY_MODULEDEFS} DEPENDS ${MPY_MPVERSION} ${SOURCE_QSTR} ) From 9dedcf122d19c6b7452adb48ff5567509adfb073 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 5 Feb 2021 15:45:38 +1100 Subject: [PATCH 009/174] py/gc: Change include of stdint.h to stddef.h. No std-int types are used in gc.h, but size_t is which needs stddef.h. Signed-off-by: Damien George --- ports/esp8266/gccollect.h | 2 ++ py/gc.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ports/esp8266/gccollect.h b/ports/esp8266/gccollect.h index 4323e95075..b86d3d6e1c 100644 --- a/ports/esp8266/gccollect.h +++ b/ports/esp8266/gccollect.h @@ -26,6 +26,8 @@ #ifndef MICROPY_INCLUDED_ESP8266_GCCOLLECT_H #define MICROPY_INCLUDED_ESP8266_GCCOLLECT_H +#include + extern uint32_t _text_start; extern uint32_t _text_end; extern uint32_t _irom0_text_start; diff --git a/py/gc.h b/py/gc.h index f67fb0daad..5aef27c006 100644 --- a/py/gc.h +++ b/py/gc.h @@ -27,7 +27,7 @@ #define MICROPY_INCLUDED_PY_GC_H #include -#include +#include void gc_init(void *start, void *end); From 0a59938574502b19b3d685133084399c090d3c11 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 5 Feb 2021 00:26:08 +1100 Subject: [PATCH 010/174] py/mpz: Fix overflow of borrow in mpn_div. For certain operands to mpn_div, the existing code path for `DIG_SIZE == MPZ_DBL_DIG_SIZE / 2` had a bug in it where borrow could still overflow in the `(x >= *n || *n - x <= borrow)` branch, ie `borrow + x - (mpz_dbl_dig_t)*n` overflows the borrow variable. In such cases the subsequent right-shift of borrow would not bring in the overflow bit, leading to an error in the result. An example division that had overflow when MPZ_DIG_SIZE = 16 is `(2 ** 48 - 1) ** 2 // (2 ** 48 - 1)`. This is fixed in this commit by simplifying the code and handling the low digits of borrow first, and then the upper bits (to shift down) separately. There is no longer a distinction between `DIG_SIZE < MPZ_DBL_DIG_SIZE / 2` and `DIG_SIZE == MPZ_DBL_DIG_SIZE / 2`. This commit also simplifies the second part of the calculation so that borrow does not need to be negated (instead the code just works knowing that borrow is negative and using + instead of - in calculations involving borrow). Fixes #6777. Signed-off-by: Damien George --- py/mpz.c | 55 +++++++++++-------------------------- tests/basics/int_big_div.py | 4 +++ 2 files changed, 20 insertions(+), 39 deletions(-) diff --git a/py/mpz.c b/py/mpz.c index 51d0c96890..e0d249c214 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -531,60 +531,37 @@ STATIC void mpn_div(mpz_dig_t *num_dig, size_t *num_len, const mpz_dig_t *den_di quo /= lead_den_digit; // Multiply quo by den and subtract from num to get remainder. - // We have different code here to handle different compile-time - // configurations of mpz: - // - // 1. DIG_SIZE is stricly less than half the number of bits - // available in mpz_dbl_dig_t. In this case we can use a - // slightly more optimal (in time and space) routine that - // uses the extra bits in mpz_dbl_dig_signed_t to store a - // sign bit. - // - // 2. DIG_SIZE is exactly half the number of bits available in - // mpz_dbl_dig_t. In this (common) case we need to be careful - // not to overflow the borrow variable. And the shifting of - // borrow needs some special logic (it's a shift right with - // round up). - // + // Must be careful with overflow of the borrow variable. Both + // borrow and low_digs are signed values and need signed right-shift, + // but x is unsigned and may take a full-range value. const mpz_dig_t *d = den_dig; mpz_dbl_dig_t d_norm = 0; - mpz_dbl_dig_t borrow = 0; + mpz_dbl_dig_signed_t borrow = 0; for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { + // Get the next digit in (den). d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); + // Multiply the next digit in (quo * den). mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK); - #if DIG_SIZE < MPZ_DBL_DIG_SIZE / 2 - borrow += (mpz_dbl_dig_t)*n - x; // will overflow if DIG_SIZE >= MPZ_DBL_DIG_SIZE/2 - *n = borrow & DIG_MASK; - borrow = (mpz_dbl_dig_signed_t)borrow >> DIG_SIZE; - #else // DIG_SIZE == MPZ_DBL_DIG_SIZE / 2 - if (x >= *n || *n - x <= borrow) { - borrow += x - (mpz_dbl_dig_t)*n; - *n = (-borrow) & DIG_MASK; - borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up - } else { - *n = ((mpz_dbl_dig_t)*n - x - borrow) & DIG_MASK; - borrow = 0; - } - #endif + // Compute the low DIG_MASK bits of the next digit in (num - quo * den) + mpz_dbl_dig_signed_t low_digs = (borrow & DIG_MASK) + *n - (x & DIG_MASK); + // Store the digit result for (num). + *n = low_digs & DIG_MASK; + // Compute the borrow, shifted right before summing to avoid overflow. + borrow = (borrow >> DIG_SIZE) - (x >> DIG_SIZE) + (low_digs >> DIG_SIZE); } - #if DIG_SIZE < MPZ_DBL_DIG_SIZE / 2 - // Borrow was negative in the above for-loop, make it positive for next if-block. - borrow = -borrow; - #endif - // At this point we have either: // // 1. quo was the correct value and the most-sig-digit of num is exactly - // cancelled by borrow (borrow == *num_dig). In this case there is + // cancelled by borrow (borrow + *num_dig == 0). In this case there is // nothing more to do. // // 2. quo was too large, we subtracted too many den from num, and the - // most-sig-digit of num is 1 less than borrow (borrow == *num_dig + 1). + // most-sig-digit of num is less than needed (borrow + *num_dig < 0). // In this case we must reduce quo and add back den to num until the // carry from this operation cancels out the borrow. // - borrow -= *num_dig; + borrow += *num_dig; for (; borrow != 0; --quo) { d = den_dig; d_norm = 0; @@ -595,7 +572,7 @@ STATIC void mpn_div(mpz_dig_t *num_dig, size_t *num_len, const mpz_dig_t *den_di *n = carry & DIG_MASK; carry >>= DIG_SIZE; } - borrow -= carry; + borrow += carry; } // store this digit of the quotient diff --git a/tests/basics/int_big_div.py b/tests/basics/int_big_div.py index 642f051d41..29fd405970 100644 --- a/tests/basics/int_big_div.py +++ b/tests/basics/int_big_div.py @@ -8,3 +8,7 @@ x = 0x8000000000000000 print((x + 1) // x) x = 0x86c60128feff5330 print((x + 1) // x) + +# these check edge cases where borrow overflows +print((2 ** 48 - 1) ** 2 // (2 ** 48 - 1)) +print((2 ** 256 - 2 ** 32) ** 2 // (2 ** 256 - 2 ** 32)) From c7aaee2b2ba0cb19d3b3deb6092e0bfe55d79052 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 9 Feb 2021 10:42:19 +1100 Subject: [PATCH 011/174] esp8266/modules: Fix fs_corrupted() to use start_sec not START_SEC. START_SEC was changed in e0905e85a7ad2961aa9192f6130565860e531ad3. Also, update the error message to mention how to format the partition at the REPL, and make the total message shorter to save a bit of flash. Signed-off-by: Damien George --- ports/esp8266/modules/inisetup.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ports/esp8266/modules/inisetup.py b/ports/esp8266/modules/inisetup.py index e711a57d4b..9500b8048c 100644 --- a/ports/esp8266/modules/inisetup.py +++ b/ports/esp8266/modules/inisetup.py @@ -30,13 +30,12 @@ def fs_corrupted(): while 1: print( """\ -The filesystem starting at sector %d with size %d sectors appears to -be corrupted. If you had important data there, you may want to make a flash -snapshot to try to recover it. Otherwise, perform factory reprogramming -of MicroPython firmware (completely erase flash, followed by firmware -programming). +The filesystem starting at sector %d with size %d sectors looks corrupt. +You may want to make a flash snapshot and try to recover it. Otherwise, +format it with uos.VfsLfs2.mkfs(bdev), or completely erase the flash and +reprogram MicroPython. """ - % (bdev.START_SEC, bdev.blocks) + % (bdev.start_sec, bdev.blocks) ) time.sleep(3) From 26b4ef4c46520f595f39d53bbea7f247c9467370 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 11 Feb 2021 22:53:36 +1100 Subject: [PATCH 012/174] extmod/vfs_posix_file: Allow closing an already closed file. Signed-off-by: Damien George --- extmod/vfs_posix_file.c | 6 +++++- tests/extmod/vfs_posix.py | 25 +++++++++++++++++++++++++ tests/extmod/vfs_posix.py.exp | 1 + tests/io/file1.py | 3 +++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index 264764b4ee..f3eac98ce3 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -163,7 +163,11 @@ STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); - check_fd_is_open(o); + + if (request != MP_STREAM_CLOSE) { + check_fd_is_open(o); + } + switch (request) { case MP_STREAM_FLUSH: { int ret; diff --git a/tests/extmod/vfs_posix.py b/tests/extmod/vfs_posix.py index 3bea99365d..aea447e182 100644 --- a/tests/extmod/vfs_posix.py +++ b/tests/extmod/vfs_posix.py @@ -8,6 +8,15 @@ except (ImportError, AttributeError): print("SKIP") raise SystemExit +# We need a file for testing that doesn't already exist. +# Skip the test if it does exist. +temp_file = "micropy_test_file.txt" +try: + uos.stat(temp_file) + print("SKIP") + raise SystemExit +except OSError: + pass # getcwd and chdir curdir = uos.getcwd() @@ -21,3 +30,19 @@ print(type(uos.stat("/"))) # listdir and ilistdir print(type(uos.listdir("/"))) + +# file create +f = open(temp_file, "w") +f.write("hello") +f.close() + +# close on a closed file should succeed +f.close() + +# file read +f = open(temp_file, "r") +print(f.read()) +f.close() + +# remove +uos.remove(temp_file) diff --git a/tests/extmod/vfs_posix.py.exp b/tests/extmod/vfs_posix.py.exp index 1b1f59b43e..c0a4ed000b 100644 --- a/tests/extmod/vfs_posix.py.exp +++ b/tests/extmod/vfs_posix.py.exp @@ -2,3 +2,4 @@ True +hello diff --git a/tests/io/file1.py b/tests/io/file1.py index 2a46c9c63e..de30045d31 100644 --- a/tests/io/file1.py +++ b/tests/io/file1.py @@ -44,3 +44,6 @@ try: except OSError: print("OSError") f.close() + +# close() on a closed file +f.close() From df85e4881396d0ebb5942a111fba974ea5c80b77 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 11 Feb 2021 23:24:39 +1100 Subject: [PATCH 013/174] tests/extmod/vfs_posix.py: Add more tests for VfsPosix class. Signed-off-by: Damien George --- tests/extmod/vfs_posix.py | 52 +++++++++++++++++++++++++++++++---- tests/extmod/vfs_posix.py.exp | 11 ++++++++ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/tests/extmod/vfs_posix.py b/tests/extmod/vfs_posix.py index aea447e182..f8c4aae406 100644 --- a/tests/extmod/vfs_posix.py +++ b/tests/extmod/vfs_posix.py @@ -8,11 +8,11 @@ except (ImportError, AttributeError): print("SKIP") raise SystemExit -# We need a file for testing that doesn't already exist. +# We need a directory for testing that doesn't already exist. # Skip the test if it does exist. -temp_file = "micropy_test_file.txt" +temp_dir = "micropy_test_dir" try: - uos.stat(temp_file) + uos.stat(temp_dir) print("SKIP") raise SystemExit except OSError: @@ -31,18 +31,58 @@ print(type(uos.stat("/"))) # listdir and ilistdir print(type(uos.listdir("/"))) +# mkdir +uos.mkdir(temp_dir) + # file create -f = open(temp_file, "w") +f = open(temp_dir + "/test", "w") f.write("hello") f.close() # close on a closed file should succeed f.close() +# construct a file object using the type constructor, with a raw fileno +f = type(f)(2) +print(f) + # file read -f = open(temp_file, "r") +f = open(temp_dir + "/test", "r") print(f.read()) f.close() +# rename +uos.rename(temp_dir + "/test", temp_dir + "/test2") +print(uos.listdir(temp_dir)) + +# construct new VfsPosix with path argument +vfs = uos.VfsPosix(temp_dir) +print(list(i[0] for i in vfs.ilistdir("."))) + +# stat, statvfs +print(type(vfs.stat("."))) +print(type(vfs.statvfs("."))) + +# check types of ilistdir with str/bytes arguments +print(type(list(vfs.ilistdir("."))[0][0])) +print(type(list(vfs.ilistdir(b"."))[0][0])) + # remove -uos.remove(temp_file) +uos.remove(temp_dir + "/test2") +print(uos.listdir(temp_dir)) + +# remove with error +try: + uos.remove(temp_dir + "/test2") +except OSError: + print("remove OSError") + +# rmdir +uos.rmdir(temp_dir) +print(temp_dir in uos.listdir()) + +# rmdir with error +try: + uos.rmdir(temp_dir) +except OSError: + print("rmdir OSError") diff --git a/tests/extmod/vfs_posix.py.exp b/tests/extmod/vfs_posix.py.exp index c0a4ed000b..e7d68f38ec 100644 --- a/tests/extmod/vfs_posix.py.exp +++ b/tests/extmod/vfs_posix.py.exp @@ -2,4 +2,15 @@ True + hello +['test2'] +['test2'] + + + + +[] +remove OSError +False +rmdir OSError From 7815dd2cc5306b72c84dbbc27638d9d3f6b32ac9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 10 Feb 2021 21:37:10 +1100 Subject: [PATCH 014/174] unix/mpbtstackport_common: Implement mp_bluetooth_hci_active. So that BTSTACK can be enabled with SYNC_EVENTS. Signed-off-by: Damien George --- ports/unix/mpbtstackport_common.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/unix/mpbtstackport_common.c b/ports/unix/mpbtstackport_common.c index 621e661f9e..ec40db65bc 100644 --- a/ports/unix/mpbtstackport_common.c +++ b/ports/unix/mpbtstackport_common.c @@ -57,6 +57,11 @@ bool mp_bluetooth_hci_poll(void) { return false; } +bool mp_bluetooth_hci_active(void) { + return mp_bluetooth_btstack_state != MP_BLUETOOTH_BTSTACK_STATE_OFF + && mp_bluetooth_btstack_state != MP_BLUETOOTH_BTSTACK_STATE_TIMEOUT; +} + // The IRQ functionality in btstack_run_loop_embedded.c is not used, so the // following three functions are empty. From 7535f67dfbbcd0f2f47ffbf893d6f66f96becae6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 10 Feb 2021 16:00:27 +1100 Subject: [PATCH 015/174] extmod/btstack: Add HCI trace debugging option in btstack_hci_uart. Signed-off-by: Damien George --- extmod/btstack/btstack_hci_uart.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/extmod/btstack/btstack_hci_uart.c b/extmod/btstack/btstack_hci_uart.c index ae18628a9c..0a137bbae4 100644 --- a/extmod/btstack/btstack_hci_uart.c +++ b/extmod/btstack/btstack_hci_uart.c @@ -38,6 +38,11 @@ #include "mpbtstackport.h" +#define HCI_TRACE (0) +#define COL_OFF "\033[0m" +#define COL_GREEN "\033[0;32m" +#define COL_BLUE "\033[0;34m" + // Implements a btstack btstack_uart_block_t on top of the mphciuart.h // interface to an HCI UART provided by the port. @@ -114,6 +119,14 @@ STATIC void btstack_uart_receive_block(uint8_t *buf, uint16_t len) { } STATIC void btstack_uart_send_block(const uint8_t *buf, uint16_t len) { + #if HCI_TRACE + printf(COL_GREEN "< [% 8d] %02x", (int)mp_hal_ticks_ms(), buf[0]); + for (size_t i = 1; i < len; ++i) { + printf(":%02x", buf[i]); + } + printf(COL_OFF "\n"); + #endif + mp_bluetooth_hci_uart_write(buf, len); send_done = true; } @@ -165,6 +178,13 @@ void mp_bluetooth_btstack_hci_uart_process(void) { while (recv_idx < recv_len && (chr = mp_bluetooth_hci_uart_readchar()) >= 0) { recv_buf[recv_idx++] = chr; if (recv_idx == recv_len) { + #if HCI_TRACE + printf(COL_BLUE "> [% 8d] %02x", (int)mp_hal_ticks_ms(), recv_buf[0]); + for (size_t i = 1; i < recv_len; ++i) { + printf(":%02x", recv_buf[i]); + } + printf(COL_OFF "\n"); + #endif recv_idx = 0; recv_len = 0; if (recv_handler) { From 24a8a408a9f5cc6cb26f2295a87303e75a48a312 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 10 Feb 2021 21:39:32 +1100 Subject: [PATCH 016/174] extmod/btstack: Add stub functions for passkey, l2cap bindings. Signed-off-by: Damien George --- extmod/btstack/modbluetooth_btstack.c | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/extmod/btstack/modbluetooth_btstack.c b/extmod/btstack/modbluetooth_btstack.c index f6af664a4e..540b0fb7a9 100644 --- a/extmod/btstack/modbluetooth_btstack.c +++ b/extmod/btstack/modbluetooth_btstack.c @@ -1168,11 +1168,18 @@ int mp_bluetooth_gap_disconnect(uint16_t conn_handle) { } #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING + int mp_bluetooth_gap_pair(uint16_t conn_handle) { DEBUG_printf("mp_bluetooth_gap_pair: conn_handle=%d\n", conn_handle); sm_request_pairing(conn_handle); return 0; } + +int mp_bluetooth_gap_passkey(uint16_t conn_handle, uint8_t action, mp_int_t passkey) { + DEBUG_printf("mp_bluetooth_gap_passkey: conn_handle=%d action=%d passkey=%d\n", conn_handle, action, (int)passkey); + return MP_EOPNOTSUPP; +} + #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE @@ -1341,4 +1348,33 @@ int mp_bluetooth_gattc_exchange_mtu(uint16_t conn_handle) { } #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS + +int mp_bluetooth_l2cap_listen(uint16_t psm, uint16_t mtu) { + DEBUG_printf("mp_bluetooth_l2cap_listen: psm=%d, mtu=%d\n", psm, mtu); + return MP_EOPNOTSUPP; +} + +int mp_bluetooth_l2cap_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu) { + DEBUG_printf("mp_bluetooth_l2cap_connect: conn_handle=%d, psm=%d, mtu=%d\n", conn_handle, psm, mtu); + return MP_EOPNOTSUPP; +} + +int mp_bluetooth_l2cap_disconnect(uint16_t conn_handle, uint16_t cid) { + DEBUG_printf("mp_bluetooth_l2cap_disconnect: conn_handle=%d, cid=%d\n", conn_handle, cid); + return MP_EOPNOTSUPP; +} + +int mp_bluetooth_l2cap_send(uint16_t conn_handle, uint16_t cid, const uint8_t *buf, size_t len, bool *stalled) { + DEBUG_printf("mp_bluetooth_l2cap_send: conn_handle=%d, cid=%d, len=%d\n", conn_handle, cid, (int)len); + return MP_EOPNOTSUPP; +} + +int mp_bluetooth_l2cap_recvinto(uint16_t conn_handle, uint16_t cid, uint8_t *buf, size_t *len) { + DEBUG_printf("mp_bluetooth_l2cap_recvinto: conn_handle=%d, cid=%d, len=%d\n", conn_handle, cid, (int)*len); + return MP_EOPNOTSUPP; +} + +#endif // MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS + #endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK From 50615fef89787f8b55a8ba6e718298421d7e3cb0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 10 Feb 2021 21:40:11 +1100 Subject: [PATCH 017/174] extmod/btstack: Enable SYNC_EVENTS, PAIRING_BONDING by default. Synchronous events work on stm32 and unix ports. Signed-off-by: Damien George --- extmod/btstack/btstack.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extmod/btstack/btstack.mk b/extmod/btstack/btstack.mk index e3309b61db..17bbb16f88 100644 --- a/extmod/btstack/btstack.mk +++ b/extmod/btstack/btstack.mk @@ -11,6 +11,8 @@ EXTMOD_SRC_C += extmod/btstack/modbluetooth_btstack.c INC += -I$(TOP)/$(BTSTACK_EXTMOD_DIR) CFLAGS_MOD += -DMICROPY_BLUETOOTH_BTSTACK=1 +CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS=1 +CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING=1 BTSTACK_DIR = $(TOP)/lib/btstack From 9b7d8b87ee317ed69c8c9963d4eb27174ac33230 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Feb 2021 16:33:06 +1100 Subject: [PATCH 018/174] lib/tinyusb: Update to version 0.8.0. Includes support for RP2040. Signed-off-by: Damien George --- lib/tinyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tinyusb b/lib/tinyusb index a6b916ba85..7b62c71dd5 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit a6b916ba85bef6aad50f1652532b02984dfe2484 +Subproject commit 7b62c71dd5ec42e61499d2d83902df9484842670 From 035d16126ac2e4ea9b9c1c33a15104cd952897a1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 8 Feb 2021 23:47:49 +1100 Subject: [PATCH 019/174] ports: Update to build with new tinyusb. Signed-off-by: Damien George --- ports/mimxrt/board_init.c | 4 ++-- ports/mimxrt/tusb_config.h | 1 - ports/mimxrt/tusb_port.c | 4 ++-- ports/nrf/drivers/usb/usb_descriptors.c | 4 ++-- ports/samd/tusb_port.c | 14 +++++++------- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c index 6f5235d3b6..102764cac1 100644 --- a/ports/mimxrt/board_init.c +++ b/ports/mimxrt/board_init.c @@ -90,11 +90,11 @@ void SysTick_Handler(void) { } void USB_OTG1_IRQHandler(void) { - tud_isr(0); + tud_int_handler(0); tud_task(); } void USB_OTG2_IRQHandler(void) { - tud_isr(1); + tud_int_handler(1); tud_task(); } diff --git a/ports/mimxrt/tusb_config.h b/ports/mimxrt/tusb_config.h index c7ec05e632..862fb6c52d 100644 --- a/ports/mimxrt/tusb_config.h +++ b/ports/mimxrt/tusb_config.h @@ -32,6 +32,5 @@ #define CFG_TUD_CDC (1) #define CFG_TUD_CDC_RX_BUFSIZE (512) #define CFG_TUD_CDC_TX_BUFSIZE (512) -#define CFG_TUD_CDC_EPSIZE (512) #endif // MICROPY_INCLUDED_MIMXRT_TUSB_CONFIG_H diff --git a/ports/mimxrt/tusb_port.c b/ports/mimxrt/tusb_port.c index f6b09a362d..0d73b09235 100644 --- a/ports/mimxrt/tusb_port.c +++ b/ports/mimxrt/tusb_port.c @@ -67,7 +67,7 @@ static const tusb_desc_device_t usbd_desc_device = { }; static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = { - TUD_CONFIG_DESCRIPTOR(USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN, + TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA), TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, @@ -90,7 +90,7 @@ const uint8_t *tud_descriptor_configuration_cb(uint8_t index) { return usbd_desc_cfg; } -const uint16_t *tud_descriptor_string_cb(uint8_t index) { +const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { #define DESC_STR_MAX (20) static uint16_t desc_str[DESC_STR_MAX]; diff --git a/ports/nrf/drivers/usb/usb_descriptors.c b/ports/nrf/drivers/usb/usb_descriptors.c index f6724c1bc0..e9436ded54 100644 --- a/ports/nrf/drivers/usb/usb_descriptors.c +++ b/ports/nrf/drivers/usb/usb_descriptors.c @@ -67,7 +67,7 @@ static const tusb_desc_device_t usbd_desc_device = { }; static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = { - TUD_CONFIG_DESCRIPTOR(USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN, + TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA), TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, @@ -90,7 +90,7 @@ const uint8_t *tud_descriptor_configuration_cb(uint8_t index) { return usbd_desc_cfg; } -const uint16_t *tud_descriptor_string_cb(uint8_t index) { +const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { #define DESC_STR_MAX (20) static uint16_t desc_str[DESC_STR_MAX]; diff --git a/ports/samd/tusb_port.c b/ports/samd/tusb_port.c index f3d417f1a1..e96f332464 100644 --- a/ports/samd/tusb_port.c +++ b/ports/samd/tusb_port.c @@ -68,7 +68,7 @@ static const tusb_desc_device_t usbd_desc_device = { }; static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = { - TUD_CONFIG_DESCRIPTOR(USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN, + TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA), TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, @@ -91,7 +91,7 @@ const uint8_t *tud_descriptor_configuration_cb(uint8_t index) { return usbd_desc_cfg; } -const uint16_t *tud_descriptor_string_cb(uint8_t index) { +const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { #define DESC_STR_MAX (20) static uint16_t desc_str[DESC_STR_MAX]; @@ -118,29 +118,29 @@ const uint16_t *tud_descriptor_string_cb(uint8_t index) { #if defined(MCU_SAMD21) void USB_Handler_wrapper(void) { - USB_Handler(); + tud_int_handler(0); tud_task(); } #elif defined(MCU_SAMD51) void USB_0_Handler_wrapper(void) { - USB_0_Handler(); + tud_int_handler(0); tud_task(); } void USB_1_Handler_wrapper(void) { - USB_1_Handler(); + tud_int_handler(0); tud_task(); } void USB_2_Handler_wrapper(void) { - USB_2_Handler(); + tud_int_handler(0); tud_task(); } void USB_3_Handler_wrapper(void) { - USB_3_Handler(); + tud_int_handler(0); tud_task(); } From c9260dda23bfdaea042d3bb94e1a830af0dbfa18 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Feb 2021 16:33:55 +1100 Subject: [PATCH 020/174] rp2: Use local tinyusb instead of the one in pico-sdk. So that all MicroPython ports that use tinyusb use the same version. Also requires fewer submodule checkouts when building rp2 along with other ports that use tinyusb. Signed-off-by: Damien George --- ports/rp2/CMakeLists.txt | 3 +++ tools/ci.sh | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 160456c6b1..bd58d8f707 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -14,6 +14,9 @@ else() set(PICO_SDK_PATH ../../lib/pico-sdk) endif() +# Use the local tinyusb instead of the one in pico-sdk +set(PICO_TINYUSB_PATH ${MPY_DIR}/lib/tinyusb) + # Include component cmake fragments include(micropy_py.cmake) include(micropy_extmod.cmake) diff --git a/tools/ci.sh b/tools/ci.sh index c6b641dae9..8661f532ef 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -195,8 +195,7 @@ function ci_rp2_setup { function ci_rp2_build { make ${MAKEOPTS} -C mpy-cross - git submodule update --init lib/pico-sdk - git -C lib/pico-sdk submodule update --init lib/tinyusb + git submodule update --init lib/pico-sdk lib/tinyusb make ${MAKEOPTS} -C ports/rp2 } From f31c6b484060eb3554aa13bb758cc9a5974cafbb Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 12 Feb 2021 13:32:27 +1100 Subject: [PATCH 021/174] mimxrt: Fix USB CDC handling so it works reliably. On i.MX the SysTick IRQ cannot wake the CPU from a WFI so the CPU was blocked on WFI waiting for USB data in mp_hal_stdin_rx_chr() even though it had already arrived (because it may arrive just after calling the check tud_cdc_available()). This commit fixes this problem by using SEV/WFE to indicate that there has been a USB event. The mp_hal_stdout_tx_strn() function is also fixed so that it doesn't overflow the USB buffers. Signed-off-by: Damien George --- ports/mimxrt/board_init.c | 2 ++ ports/mimxrt/mpconfigport.h | 2 +- ports/mimxrt/mphalport.c | 17 ++++++++--------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c index 102764cac1..cd7dc9a7dd 100644 --- a/ports/mimxrt/board_init.c +++ b/ports/mimxrt/board_init.c @@ -92,9 +92,11 @@ void SysTick_Handler(void) { void USB_OTG1_IRQHandler(void) { tud_int_handler(0); tud_task(); + __SEV(); } void USB_OTG2_IRQHandler(void) { tud_int_handler(1); tud_task(); + __SEV(); } diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index 15a292486f..68c7a89422 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -94,7 +94,7 @@ extern const struct _mp_obj_module_t mp_module_utime; do { \ extern void mp_handle_pending(bool); \ mp_handle_pending(true); \ - __WFI(); \ + __WFE(); \ } while (0); #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1)) diff --git a/ports/mimxrt/mphalport.c b/ports/mimxrt/mphalport.c index d7642d6b6d..3032464d39 100644 --- a/ports/mimxrt/mphalport.c +++ b/ports/mimxrt/mphalport.c @@ -75,7 +75,7 @@ int mp_hal_stdin_rx_chr(void) { return buf[0]; } } - __WFI(); + MICROPY_EVENT_POLL_HOOK } } @@ -83,17 +83,16 @@ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { if (tud_cdc_connected()) { for (size_t i = 0; i < len;) { uint32_t n = len - i; - uint32_t n2 = tud_cdc_write(str + i, n); - if (n2 < n) { - while (!tud_cdc_write_flush()) { - __WFI(); - } + if (n > CFG_TUD_CDC_EP_BUFSIZE) { + n = CFG_TUD_CDC_EP_BUFSIZE; } + while (n > tud_cdc_write_available()) { + __WFE(); + } + uint32_t n2 = tud_cdc_write(str + i, n); + tud_cdc_write_flush(); i += n2; } - while (!tud_cdc_write_flush()) { - __WFI(); - } } // TODO // while (len--) { From ede6b86a08ea3a749e1785c5263723c875b08359 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 12 Feb 2021 14:09:01 +1100 Subject: [PATCH 022/174] samd/mphalport: Fix USB CDC tx handling to work reliably. Signed-off-by: Damien George --- ports/samd/mphalport.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/ports/samd/mphalport.c b/ports/samd/mphalport.c index 67fc2cb0d6..357ec93a68 100644 --- a/ports/samd/mphalport.c +++ b/ports/samd/mphalport.c @@ -80,17 +80,16 @@ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { if (tud_cdc_connected()) { for (size_t i = 0; i < len;) { uint32_t n = len - i; - uint32_t n2 = tud_cdc_write(str + i, n); - if (n2 < n) { - while (!tud_cdc_write_flush()) { - __WFI(); - } + if (n > CFG_TUD_CDC_EP_BUFSIZE) { + n = CFG_TUD_CDC_EP_BUFSIZE; } + while (n > tud_cdc_write_available()) { + __WFI(); + } + uint32_t n2 = tud_cdc_write(str + i, n); + tud_cdc_write_flush(); i += n2; } - while (!tud_cdc_write_flush()) { - __WFI(); - } } while (len--) { while (!(USARTx->USART.INTFLAG.bit.DRE)) { From 701fdcacafe017c88c8cf18f64d8c26f25987e97 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 13 Feb 2021 13:52:53 +1100 Subject: [PATCH 023/174] nrf/drivers/usb: Add USBD_IRQHandler which calls tud_int_handler. This is needed for TinyUSB to process USB device IRQs. Related to #6325. Signed-off-by: Damien George --- ports/nrf/drivers/usb/usb_cdc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/nrf/drivers/usb/usb_cdc.c b/ports/nrf/drivers/usb/usb_cdc.c index c90bced6bb..9d7c832e20 100644 --- a/ports/nrf/drivers/usb/usb_cdc.c +++ b/ports/nrf/drivers/usb/usb_cdc.c @@ -223,4 +223,8 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len) { } } +void USBD_IRQHandler(void) { + tud_int_handler(0); +} + #endif // MICROPY_HW_USB_CDC From d128999938d6b44f52f4d0c6e1f5169ab3c1e7a5 Mon Sep 17 00:00:00 2001 From: Brianna Laugher Date: Fri, 12 Feb 2021 22:15:43 +1100 Subject: [PATCH 024/174] tools: Add filesystem action examples to pyboard.py help. Signed-off-by: Brianna Laugher --- docs/reference/pyboard.py.rst | 4 +++- tools/pyboard.py | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/reference/pyboard.py.rst b/docs/reference/pyboard.py.rst index 30230eebc3..4fedbb7aab 100644 --- a/docs/reference/pyboard.py.rst +++ b/docs/reference/pyboard.py.rst @@ -48,7 +48,9 @@ Running ``pyboard.py --help`` gives the following output: available --follow follow the output after running the scripts [default if no scripts given] - -f, --filesystem perform a filesystem action + -f, --filesystem perform a filesystem action: cp local :device | cp + :device local | cat path | ls [path] | rm path | mkdir + path | rmdir path Running a command on the device ------------------------------- diff --git a/tools/pyboard.py b/tools/pyboard.py index 3ecdf03f15..069f7490d0 100755 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -651,7 +651,11 @@ def main(): help="Do not follow the output after running the scripts.", ) cmd_parser.add_argument( - "-f", "--filesystem", action="store_true", help="perform a filesystem action" + "-f", + "--filesystem", + action="store_true", + help="perform a filesystem action: " + "cp local :device | cp :device local | cat path | ls [path] | rm path | mkdir path | rmdir path", ) cmd_parser.add_argument("files", nargs="*", help="input files") args = cmd_parser.parse_args() From 7ed99544e4cc1c09bd5abf9f54869c3122fa033b Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 12 Feb 2021 14:11:18 +1100 Subject: [PATCH 025/174] extmod/uasyncio: Add asyncio.current_task(). Matches CPython behavior. Fixes #6686 --- docs/library/uasyncio.rst | 4 ++++ extmod/uasyncio/core.py | 4 ++++ tests/extmod/uasyncio_current_task.py | 25 +++++++++++++++++++++++ tests/extmod/uasyncio_current_task.py.exp | 1 + 4 files changed, 34 insertions(+) create mode 100644 tests/extmod/uasyncio_current_task.py create mode 100644 tests/extmod/uasyncio_current_task.py.exp diff --git a/docs/library/uasyncio.rst b/docs/library/uasyncio.rst index a81e532d7f..3316f908d6 100644 --- a/docs/library/uasyncio.rst +++ b/docs/library/uasyncio.rst @@ -40,6 +40,10 @@ Core functions Returns the corresponding `Task` object. +.. function:: current_task() + + Return the `Task` object associated with the currently running task. + .. function:: run(coro) Create a new task from the given coroutine and run it until it completes. diff --git a/extmod/uasyncio/core.py b/extmod/uasyncio/core.py index 6a84b0982c..d74763f6a6 100644 --- a/extmod/uasyncio/core.py +++ b/extmod/uasyncio/core.py @@ -264,6 +264,10 @@ def get_event_loop(runq_len=0, waitq_len=0): return Loop +def current_task(): + return cur_task + + def new_event_loop(): global _task_queue, _io_queue # TaskQueue of Task instances diff --git a/tests/extmod/uasyncio_current_task.py b/tests/extmod/uasyncio_current_task.py new file mode 100644 index 0000000000..3165a2cf16 --- /dev/null +++ b/tests/extmod/uasyncio_current_task.py @@ -0,0 +1,25 @@ +# Test current_task() function + +try: + import uasyncio as asyncio +except ImportError: + try: + import asyncio + except ImportError: + print("SKIP") + raise SystemExit + + +async def task(result): + result[0] = asyncio.current_task() + + +async def main(): + result = [None] + t = asyncio.create_task(task(result)) + await asyncio.sleep(0) + await asyncio.sleep(0) + print(t is result[0]) + + +asyncio.run(main()) diff --git a/tests/extmod/uasyncio_current_task.py.exp b/tests/extmod/uasyncio_current_task.py.exp new file mode 100644 index 0000000000..0ca95142bb --- /dev/null +++ b/tests/extmod/uasyncio_current_task.py.exp @@ -0,0 +1 @@ +True From d2a34c62e73f63a7822c823b5523e5924c28831d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Feb 2021 16:18:35 +1100 Subject: [PATCH 026/174] stm32/uart: Add uart_set_baudrate function. This allows changing the baudrate of the UART without reinitialising it (reinitialising can lead to spurious characters sent on the TX line). Signed-off-by: Damien George --- ports/stm32/boards/stm32f0xx_hal_conf_base.h | 1 + ports/stm32/boards/stm32f4xx_hal_conf_base.h | 1 + ports/stm32/boards/stm32f7xx_hal_conf_base.h | 1 + ports/stm32/boards/stm32h7xx_hal_conf_base.h | 1 + ports/stm32/boards/stm32l0xx_hal_conf_base.h | 1 + ports/stm32/boards/stm32l4xx_hal_conf_base.h | 1 + ports/stm32/boards/stm32wbxx_hal_conf_base.h | 1 + ports/stm32/uart.c | 18 ++++++++++++++---- ports/stm32/uart.h | 2 ++ 9 files changed, 23 insertions(+), 4 deletions(-) diff --git a/ports/stm32/boards/stm32f0xx_hal_conf_base.h b/ports/stm32/boards/stm32f0xx_hal_conf_base.h index 5c6f31d1dd..70e6ccf758 100644 --- a/ports/stm32/boards/stm32f0xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32f0xx_hal_conf_base.h @@ -49,6 +49,7 @@ #include "stm32f0xx_hal_wwdg.h" #include "stm32f0xx_ll_adc.h" #include "stm32f0xx_ll_rtc.h" +#include "stm32f0xx_ll_usart.h" // Enable various HAL modules #define HAL_MODULE_ENABLED diff --git a/ports/stm32/boards/stm32f4xx_hal_conf_base.h b/ports/stm32/boards/stm32f4xx_hal_conf_base.h index 057a9e81e4..134a30018c 100644 --- a/ports/stm32/boards/stm32f4xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32f4xx_hal_conf_base.h @@ -56,6 +56,7 @@ #include "stm32f4xx_ll_adc.h" #include "stm32f4xx_ll_pwr.h" #include "stm32f4xx_ll_rtc.h" +#include "stm32f4xx_ll_usart.h" // Enable various HAL modules #define HAL_ADC_MODULE_ENABLED diff --git a/ports/stm32/boards/stm32f7xx_hal_conf_base.h b/ports/stm32/boards/stm32f7xx_hal_conf_base.h index 6e7dff3042..efb15d471d 100644 --- a/ports/stm32/boards/stm32f7xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32f7xx_hal_conf_base.h @@ -56,6 +56,7 @@ #include "stm32f7xx_ll_adc.h" #include "stm32f7xx_ll_pwr.h" #include "stm32f7xx_ll_rtc.h" +#include "stm32f7xx_ll_usart.h" // Enable various HAL modules #define HAL_ADC_MODULE_ENABLED diff --git a/ports/stm32/boards/stm32h7xx_hal_conf_base.h b/ports/stm32/boards/stm32h7xx_hal_conf_base.h index a451cfde76..c07ae93e37 100644 --- a/ports/stm32/boards/stm32h7xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32h7xx_hal_conf_base.h @@ -56,6 +56,7 @@ #include "stm32h7xx_ll_adc.h" #include "stm32h7xx_ll_pwr.h" #include "stm32h7xx_ll_rtc.h" +#include "stm32h7xx_ll_usart.h" // Enable various HAL modules #define HAL_ADC_MODULE_ENABLED diff --git a/ports/stm32/boards/stm32l0xx_hal_conf_base.h b/ports/stm32/boards/stm32l0xx_hal_conf_base.h index 6b5ece766a..cc033666af 100644 --- a/ports/stm32/boards/stm32l0xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32l0xx_hal_conf_base.h @@ -48,6 +48,7 @@ #include "stm32l0xx_hal_wwdg.h" #include "stm32l0xx_ll_adc.h" #include "stm32l0xx_ll_rtc.h" +#include "stm32l0xx_ll_usart.h" // Enable various HAL modules #define HAL_MODULE_ENABLED diff --git a/ports/stm32/boards/stm32l4xx_hal_conf_base.h b/ports/stm32/boards/stm32l4xx_hal_conf_base.h index 215e798b92..8d77a80a70 100644 --- a/ports/stm32/boards/stm32l4xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32l4xx_hal_conf_base.h @@ -52,6 +52,7 @@ #include "stm32l4xx_hal_wwdg.h" #include "stm32l4xx_ll_adc.h" #include "stm32l4xx_ll_rtc.h" +#include "stm32l4xx_ll_usart.h" // Enable various HAL modules #define HAL_MODULE_ENABLED diff --git a/ports/stm32/boards/stm32wbxx_hal_conf_base.h b/ports/stm32/boards/stm32wbxx_hal_conf_base.h index 91309e286f..72af0262a2 100644 --- a/ports/stm32/boards/stm32wbxx_hal_conf_base.h +++ b/ports/stm32/boards/stm32wbxx_hal_conf_base.h @@ -43,6 +43,7 @@ #include "stm32wbxx_hal_usart.h" #include "stm32wbxx_ll_adc.h" #include "stm32wbxx_ll_rtc.h" +#include "stm32wbxx_ll_usart.h" // Enable various HAL modules #define HAL_MODULE_ENABLED diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index b14a18c6dd..8091ba05f9 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -603,7 +603,7 @@ void uart_attach_to_repl(pyb_uart_obj_t *self, bool attached) { self->attached_to_repl = attached; } -uint32_t uart_get_baudrate(pyb_uart_obj_t *self) { +uint32_t uart_get_source_freq(pyb_uart_obj_t *self) { uint32_t uart_clk = 0; #if defined(STM32F0) @@ -672,10 +672,20 @@ uint32_t uart_get_baudrate(pyb_uart_obj_t *self) { } #endif - // This formula assumes UART_OVERSAMPLING_16 - uint32_t baudrate = uart_clk / self->uartx->BRR; + return uart_clk; +} - return baudrate; +uint32_t uart_get_baudrate(pyb_uart_obj_t *self) { + // This formula assumes UART_OVERSAMPLING_16 + return uart_get_source_freq(self) / self->uartx->BRR; +} + +void uart_set_baudrate(pyb_uart_obj_t *self, uint32_t baudrate) { + LL_USART_SetBaudRate(self->uartx, uart_get_source_freq(self), + #if defined(STM32H7) || defined(STM32WB) + LL_USART_PRESCALER_DIV1, + #endif + LL_USART_OVERSAMPLING_16, baudrate); } mp_uint_t uart_rx_any(pyb_uart_obj_t *self) { diff --git a/ports/stm32/uart.h b/ports/stm32/uart.h index 9a38db593d..570a79c932 100644 --- a/ports/stm32/uart.h +++ b/ports/stm32/uart.h @@ -86,6 +86,8 @@ void uart_irq_handler(mp_uint_t uart_id); void uart_attach_to_repl(pyb_uart_obj_t *self, bool attached); uint32_t uart_get_baudrate(pyb_uart_obj_t *self); +void uart_set_baudrate(pyb_uart_obj_t *self, uint32_t baudrate); + mp_uint_t uart_rx_any(pyb_uart_obj_t *uart_obj); bool uart_rx_wait(pyb_uart_obj_t *self, uint32_t timeout); int uart_rx_char(pyb_uart_obj_t *uart_obj); From bffb71f523e4bcc21b913af291deeb67091bed88 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 3 Feb 2021 16:19:47 +1100 Subject: [PATCH 027/174] stm32/mpbthciport: Only init the uart once, then use uart_set_baudrate. Signed-off-by: Damien George --- ports/stm32/mpbthciport.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/ports/stm32/mpbthciport.c b/ports/stm32/mpbthciport.c index ee9f4e31eb..5e51892e6f 100644 --- a/ports/stm32/mpbthciport.c +++ b/ports/stm32/mpbthciport.c @@ -32,8 +32,6 @@ #include "pendsv.h" #include "lib/utils/mpirq.h" -#include "py/obj.h" - #if MICROPY_PY_BLUETOOTH #define DEBUG_printf(...) // printf("mpbthciport.c: " __VA_ARGS__) @@ -197,8 +195,18 @@ int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) { mp_bluetooth_hci_uart_obj.timeout_char = 200; MP_STATE_PORT(pyb_uart_obj_all)[mp_bluetooth_hci_uart_obj.uart_id - 1] = &mp_bluetooth_hci_uart_obj; - // This also initialises the UART and adds the RXIDLE IRQ handler. - mp_bluetooth_hci_uart_set_baudrate(baudrate); + // Initialise the UART. + uart_init(&mp_bluetooth_hci_uart_obj, 115200, UART_WORDLENGTH_8B, UART_PARITY_NONE, UART_STOPBITS_1, UART_HWCONTROL_RTS | UART_HWCONTROL_CTS); + uart_set_rxbuf(&mp_bluetooth_hci_uart_obj, sizeof(hci_uart_rxbuf), hci_uart_rxbuf); + + // Add IRQ handler for IDLE (i.e. packet finished). + uart_irq_config(&mp_bluetooth_hci_uart_obj, false); + mp_irq_init(&mp_bluetooth_hci_uart_irq_obj, &uart_irq_methods, MP_OBJ_FROM_PTR(&mp_bluetooth_hci_uart_obj)); + mp_bluetooth_hci_uart_obj.mp_irq_obj = &mp_bluetooth_hci_uart_irq_obj; + mp_bluetooth_hci_uart_obj.mp_irq_trigger = UART_FLAG_IDLE; + mp_bluetooth_hci_uart_irq_obj.handler = MP_OBJ_FROM_PTR(&mp_uart_interrupt_obj); + mp_bluetooth_hci_uart_irq_obj.ishard = true; + uart_irq_config(&mp_bluetooth_hci_uart_obj, true); return 0; } @@ -213,22 +221,7 @@ int mp_bluetooth_hci_uart_deinit(void) { int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate) { DEBUG_printf("mp_bluetooth_hci_uart_set_baudrate(%lu) (stm32)\n", baudrate); - if (!baudrate) { - return -1; - } - - uart_init(&mp_bluetooth_hci_uart_obj, baudrate, UART_WORDLENGTH_8B, UART_PARITY_NONE, UART_STOPBITS_1, UART_HWCONTROL_RTS | UART_HWCONTROL_CTS); - uart_set_rxbuf(&mp_bluetooth_hci_uart_obj, sizeof(hci_uart_rxbuf), hci_uart_rxbuf); - - // Add IRQ handler for IDLE (i.e. packet finished). - uart_irq_config(&mp_bluetooth_hci_uart_obj, false); - mp_irq_init(&mp_bluetooth_hci_uart_irq_obj, &uart_irq_methods, MP_OBJ_FROM_PTR(&mp_bluetooth_hci_uart_obj)); - mp_bluetooth_hci_uart_obj.mp_irq_obj = &mp_bluetooth_hci_uart_irq_obj; - mp_bluetooth_hci_uart_obj.mp_irq_trigger = UART_FLAG_IDLE; - mp_bluetooth_hci_uart_irq_obj.handler = MP_OBJ_FROM_PTR(&mp_uart_interrupt_obj); - mp_bluetooth_hci_uart_irq_obj.ishard = true; - uart_irq_config(&mp_bluetooth_hci_uart_obj, true); - + uart_set_baudrate(&mp_bluetooth_hci_uart_obj, baudrate); return 0; } From 66098c09850ccc31b49b341e7eb7a5f8526e359d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 23 Sep 2020 15:53:46 +1000 Subject: [PATCH 028/174] py,extmod: Add core cmake rule files. These allow a port to use cmake natively instead of make. Signed-off-by: Damien George --- extmod/extmod.cmake | 44 +++++++++++++++ py/mkrules.cmake | 128 ++++++++++++++++++++++++++++++++++++++++++++ py/py.cmake | 124 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 296 insertions(+) create mode 100644 extmod/extmod.cmake create mode 100644 py/mkrules.cmake create mode 100644 py/py.cmake diff --git a/extmod/extmod.cmake b/extmod/extmod.cmake new file mode 100644 index 0000000000..6668a2d8aa --- /dev/null +++ b/extmod/extmod.cmake @@ -0,0 +1,44 @@ +# CMake fragment for MicroPython extmod component + +set(MICROPY_EXTMOD_DIR "${MICROPY_DIR}/extmod") +set(MICROPY_OOFATFS_DIR "${MICROPY_DIR}/lib/oofatfs") + +set(MICROPY_SOURCE_EXTMOD + ${MICROPY_EXTMOD_DIR}/machine_i2c.c + ${MICROPY_EXTMOD_DIR}/machine_mem.c + ${MICROPY_EXTMOD_DIR}/machine_pulse.c + ${MICROPY_EXTMOD_DIR}/machine_signal.c + ${MICROPY_EXTMOD_DIR}/machine_spi.c + ${MICROPY_EXTMOD_DIR}/modbluetooth.c + ${MICROPY_EXTMOD_DIR}/modbtree.c + ${MICROPY_EXTMOD_DIR}/modframebuf.c + ${MICROPY_EXTMOD_DIR}/moduasyncio.c + ${MICROPY_EXTMOD_DIR}/modubinascii.c + ${MICROPY_EXTMOD_DIR}/moducryptolib.c + ${MICROPY_EXTMOD_DIR}/moductypes.c + ${MICROPY_EXTMOD_DIR}/moduhashlib.c + ${MICROPY_EXTMOD_DIR}/moduheapq.c + ${MICROPY_EXTMOD_DIR}/modujson.c + ${MICROPY_EXTMOD_DIR}/modurandom.c + ${MICROPY_EXTMOD_DIR}/modure.c + ${MICROPY_EXTMOD_DIR}/moduselect.c + ${MICROPY_EXTMOD_DIR}/modussl_axtls.c + ${MICROPY_EXTMOD_DIR}/modussl_mbedtls.c + ${MICROPY_EXTMOD_DIR}/modutimeq.c + ${MICROPY_EXTMOD_DIR}/moduwebsocket.c + ${MICROPY_EXTMOD_DIR}/moduzlib.c + ${MICROPY_EXTMOD_DIR}/modwebrepl.c + ${MICROPY_EXTMOD_DIR}/uos_dupterm.c + ${MICROPY_EXTMOD_DIR}/utime_mphal.c + ${MICROPY_EXTMOD_DIR}/vfs.c + ${MICROPY_EXTMOD_DIR}/vfs_blockdev.c + ${MICROPY_EXTMOD_DIR}/vfs_fat.c + ${MICROPY_EXTMOD_DIR}/vfs_fat_diskio.c + ${MICROPY_EXTMOD_DIR}/vfs_fat_file.c + ${MICROPY_EXTMOD_DIR}/vfs_lfs.c + ${MICROPY_EXTMOD_DIR}/vfs_posix.c + ${MICROPY_EXTMOD_DIR}/vfs_posix_file.c + ${MICROPY_EXTMOD_DIR}/vfs_reader.c + ${MICROPY_EXTMOD_DIR}/virtpin.c + ${MICROPY_EXTMOD_DIR}/nimble/modbluetooth_nimble.c +) diff --git a/py/mkrules.cmake b/py/mkrules.cmake new file mode 100644 index 0000000000..bdff385815 --- /dev/null +++ b/py/mkrules.cmake @@ -0,0 +1,128 @@ +# CMake fragment for MicroPython rules + +set(MICROPY_PY_QSTRDEFS "${MICROPY_PY_DIR}/qstrdefs.h") +set(MICROPY_GENHDR_DIR "${CMAKE_BINARY_DIR}/genhdr") +set(MICROPY_MPVERSION "${MICROPY_GENHDR_DIR}/mpversion.h") +set(MICROPY_MODULEDEFS "${MICROPY_GENHDR_DIR}/moduledefs.h") +set(MICROPY_QSTR_DEFS_LAST "${MICROPY_GENHDR_DIR}/qstr.i.last") +set(MICROPY_QSTR_DEFS_SPLIT "${MICROPY_GENHDR_DIR}/qstr.split") +set(MICROPY_QSTR_DEFS_COLLECTED "${MICROPY_GENHDR_DIR}/qstrdefs.collected.h") +set(MICROPY_QSTR_DEFS_PREPROCESSED "${MICROPY_GENHDR_DIR}/qstrdefs.preprocessed.h") +set(MICROPY_QSTR_DEFS_GENERATED "${MICROPY_GENHDR_DIR}/qstrdefs.generated.h") + +# Provide defaults for preprocessor flags if not already defined +if(NOT MICROPY_CPP_FLAGS) + get_target_property(MICROPY_CPP_INC ${MICROPY_TARGET} INCLUDE_DIRECTORIES) + get_target_property(MICROPY_CPP_DEF ${MICROPY_TARGET} COMPILE_DEFINITIONS) +endif() + +# Compute MICROPY_CPP_FLAGS for preprocessor +list(APPEND MICROPY_CPP_INC ${MICROPY_CPP_INC_EXTRA}) +list(APPEND MICROPY_CPP_DEF ${MICROPY_CPP_DEF_EXTRA}) +set(_prefix "-I") +foreach(_arg ${MICROPY_CPP_INC}) + list(APPEND MICROPY_CPP_FLAGS ${_prefix}${_arg}) +endforeach() +set(_prefix "-D") +foreach(_arg ${MICROPY_CPP_DEF}) + list(APPEND MICROPY_CPP_FLAGS ${_prefix}${_arg}) +endforeach() +list(APPEND MICROPY_CPP_FLAGS ${MICROPY_CPP_FLAGS_EXTRA}) + +find_package(Python3 REQUIRED COMPONENTS Interpreter) + +target_sources(${MICROPY_TARGET} PRIVATE + ${MICROPY_MPVERSION} + ${MICROPY_QSTR_DEFS_GENERATED} +) + +# Command to force the build of another command + +add_custom_command( + OUTPUT MICROPY_FORCE_BUILD + COMMENT "" + COMMAND echo -n +) + +# Generate mpversion.h + +add_custom_command( + OUTPUT ${MICROPY_MPVERSION} + COMMAND ${CMAKE_COMMAND} -E make_directory ${MICROPY_GENHDR_DIR} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_DIR}/py/makeversionhdr.py ${MICROPY_MPVERSION} + DEPENDS MICROPY_FORCE_BUILD +) + +# Generate moduledefs.h + +add_custom_command( + OUTPUT ${MICROPY_MODULEDEFS} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makemoduledefs.py --vpath="/" ${MICROPY_SOURCE_QSTR} > ${MICROPY_MODULEDEFS} + DEPENDS ${MICROPY_MPVERSION} + ${MICROPY_SOURCE_QSTR} +) + +# Generate qstrs + +# If any of the dependencies in this rule change then the C-preprocessor step must be run. +# It only needs to be passed the list of MICROPY_SOURCE_QSTR files that have changed since +# it was last run, but it looks like it's not possible to specify that with cmake. +add_custom_command( + OUTPUT ${MICROPY_QSTR_DEFS_LAST} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py pp ${CMAKE_C_COMPILER} -E output ${MICROPY_GENHDR_DIR}/qstr.i.last cflags ${MICROPY_CPP_FLAGS} -DNO_QSTR sources ${MICROPY_SOURCE_QSTR} + DEPENDS ${MICROPY_MODULEDEFS} + ${MICROPY_SOURCE_QSTR} + VERBATIM +) + +add_custom_command( + OUTPUT ${MICROPY_QSTR_DEFS_SPLIT} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py split qstr ${MICROPY_GENHDR_DIR}/qstr.i.last ${MICROPY_GENHDR_DIR}/qstr _ + COMMAND touch ${MICROPY_QSTR_DEFS_SPLIT} + DEPENDS ${MICROPY_QSTR_DEFS_LAST} + VERBATIM +) + +add_custom_command( + OUTPUT ${MICROPY_QSTR_DEFS_COLLECTED} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py cat qstr _ ${MICROPY_GENHDR_DIR}/qstr ${MICROPY_QSTR_DEFS_COLLECTED} + DEPENDS ${MICROPY_QSTR_DEFS_SPLIT} + VERBATIM +) + +add_custom_command( + OUTPUT ${MICROPY_QSTR_DEFS_PREPROCESSED} + COMMAND cat ${MICROPY_PY_QSTRDEFS} ${MICROPY_QSTR_DEFS_COLLECTED} | sed "s/^Q(.*)/\"&\"/" | ${CMAKE_C_COMPILER} -E ${MICROPY_CPP_FLAGS} - | sed "s/^\\\"\\(Q(.*)\\)\\\"/\\1/" > ${MICROPY_QSTR_DEFS_PREPROCESSED} + DEPENDS ${MICROPY_QSTR_DEFS_COLLECTED} + VERBATIM +) + +add_custom_command( + OUTPUT ${MICROPY_QSTR_DEFS_GENERATED} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdata.py ${MICROPY_QSTR_DEFS_PREPROCESSED} > ${MICROPY_QSTR_DEFS_GENERATED} + DEPENDS ${MICROPY_QSTR_DEFS_PREPROCESSED} + VERBATIM +) + +# Build frozen code if enabled + +if(MICROPY_FROZEN_MANIFEST) + set(MICROPY_FROZEN_CONTENT "${CMAKE_BINARY_DIR}/frozen_content.c") + + target_sources(${MICROPY_TARGET} PRIVATE + ${MICROPY_FROZEN_CONTENT} + ) + + target_compile_definitions(${MICROPY_TARGET} PUBLIC + MICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool + MICROPY_MODULE_FROZEN_MPY=\(1\) + ) + + add_custom_command( + OUTPUT ${MICROPY_FROZEN_CONTENT} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_DIR}/tools/makemanifest.py -o ${MICROPY_FROZEN_CONTENT} -v "MPY_DIR=${MICROPY_DIR}" -v "PORT_DIR=${MICROPY_PORT_DIR}" -b "${CMAKE_BINARY_DIR}" -f${MICROPY_CROSS_FLAGS} ${MICROPY_FROZEN_MANIFEST} + DEPENDS MICROPY_FORCE_BUILD + ${MICROPY_QSTR_DEFS_GENERATED} + VERBATIM + ) +endif() diff --git a/py/py.cmake b/py/py.cmake new file mode 100644 index 0000000000..52baaa8efc --- /dev/null +++ b/py/py.cmake @@ -0,0 +1,124 @@ +# CMake fragment for MicroPython core py component + +set(MICROPY_PY_DIR "${MICROPY_DIR}/py") + +# All py/ source files +set(MICROPY_SOURCE_PY + ${MICROPY_PY_DIR}/argcheck.c + ${MICROPY_PY_DIR}/asmarm.c + ${MICROPY_PY_DIR}/asmbase.c + ${MICROPY_PY_DIR}/asmthumb.c + ${MICROPY_PY_DIR}/asmx64.c + ${MICROPY_PY_DIR}/asmx86.c + ${MICROPY_PY_DIR}/asmxtensa.c + ${MICROPY_PY_DIR}/bc.c + ${MICROPY_PY_DIR}/binary.c + ${MICROPY_PY_DIR}/builtinevex.c + ${MICROPY_PY_DIR}/builtinhelp.c + ${MICROPY_PY_DIR}/builtinimport.c + ${MICROPY_PY_DIR}/compile.c + ${MICROPY_PY_DIR}/emitbc.c + ${MICROPY_PY_DIR}/emitcommon.c + ${MICROPY_PY_DIR}/emitglue.c + ${MICROPY_PY_DIR}/emitinlinethumb.c + ${MICROPY_PY_DIR}/emitinlinextensa.c + ${MICROPY_PY_DIR}/emitnarm.c + ${MICROPY_PY_DIR}/emitnthumb.c + ${MICROPY_PY_DIR}/emitnx64.c + ${MICROPY_PY_DIR}/emitnx86.c + ${MICROPY_PY_DIR}/emitnxtensa.c + ${MICROPY_PY_DIR}/emitnxtensawin.c + ${MICROPY_PY_DIR}/formatfloat.c + ${MICROPY_PY_DIR}/frozenmod.c + ${MICROPY_PY_DIR}/gc.c + ${MICROPY_PY_DIR}/lexer.c + ${MICROPY_PY_DIR}/malloc.c + ${MICROPY_PY_DIR}/map.c + ${MICROPY_PY_DIR}/modarray.c + ${MICROPY_PY_DIR}/modbuiltins.c + ${MICROPY_PY_DIR}/modcmath.c + ${MICROPY_PY_DIR}/modcollections.c + ${MICROPY_PY_DIR}/modgc.c + ${MICROPY_PY_DIR}/modio.c + ${MICROPY_PY_DIR}/modmath.c + ${MICROPY_PY_DIR}/modmicropython.c + ${MICROPY_PY_DIR}/modstruct.c + ${MICROPY_PY_DIR}/modsys.c + ${MICROPY_PY_DIR}/modthread.c + ${MICROPY_PY_DIR}/moduerrno.c + ${MICROPY_PY_DIR}/mpprint.c + ${MICROPY_PY_DIR}/mpstate.c + ${MICROPY_PY_DIR}/mpz.c + ${MICROPY_PY_DIR}/nativeglue.c + ${MICROPY_PY_DIR}/nlr.c + ${MICROPY_PY_DIR}/nlrpowerpc.c + ${MICROPY_PY_DIR}/nlrsetjmp.c + ${MICROPY_PY_DIR}/nlrthumb.c + ${MICROPY_PY_DIR}/nlrx64.c + ${MICROPY_PY_DIR}/nlrx86.c + ${MICROPY_PY_DIR}/nlrxtensa.c + ${MICROPY_PY_DIR}/obj.c + ${MICROPY_PY_DIR}/objarray.c + ${MICROPY_PY_DIR}/objattrtuple.c + ${MICROPY_PY_DIR}/objbool.c + ${MICROPY_PY_DIR}/objboundmeth.c + ${MICROPY_PY_DIR}/objcell.c + ${MICROPY_PY_DIR}/objclosure.c + ${MICROPY_PY_DIR}/objcomplex.c + ${MICROPY_PY_DIR}/objdeque.c + ${MICROPY_PY_DIR}/objdict.c + ${MICROPY_PY_DIR}/objenumerate.c + ${MICROPY_PY_DIR}/objexcept.c + ${MICROPY_PY_DIR}/objfilter.c + ${MICROPY_PY_DIR}/objfloat.c + ${MICROPY_PY_DIR}/objfun.c + ${MICROPY_PY_DIR}/objgenerator.c + ${MICROPY_PY_DIR}/objgetitemiter.c + ${MICROPY_PY_DIR}/objint.c + ${MICROPY_PY_DIR}/objint_longlong.c + ${MICROPY_PY_DIR}/objint_mpz.c + ${MICROPY_PY_DIR}/objlist.c + ${MICROPY_PY_DIR}/objmap.c + ${MICROPY_PY_DIR}/objmodule.c + ${MICROPY_PY_DIR}/objnamedtuple.c + ${MICROPY_PY_DIR}/objnone.c + ${MICROPY_PY_DIR}/objobject.c + ${MICROPY_PY_DIR}/objpolyiter.c + ${MICROPY_PY_DIR}/objproperty.c + ${MICROPY_PY_DIR}/objrange.c + ${MICROPY_PY_DIR}/objreversed.c + ${MICROPY_PY_DIR}/objset.c + ${MICROPY_PY_DIR}/objsingleton.c + ${MICROPY_PY_DIR}/objslice.c + ${MICROPY_PY_DIR}/objstr.c + ${MICROPY_PY_DIR}/objstringio.c + ${MICROPY_PY_DIR}/objstrunicode.c + ${MICROPY_PY_DIR}/objtuple.c + ${MICROPY_PY_DIR}/objtype.c + ${MICROPY_PY_DIR}/objzip.c + ${MICROPY_PY_DIR}/opmethods.c + ${MICROPY_PY_DIR}/pairheap.c + ${MICROPY_PY_DIR}/parse.c + ${MICROPY_PY_DIR}/parsenum.c + ${MICROPY_PY_DIR}/parsenumbase.c + ${MICROPY_PY_DIR}/persistentcode.c + ${MICROPY_PY_DIR}/profile.c + ${MICROPY_PY_DIR}/pystack.c + ${MICROPY_PY_DIR}/qstr.c + ${MICROPY_PY_DIR}/reader.c + ${MICROPY_PY_DIR}/repl.c + ${MICROPY_PY_DIR}/ringbuf.c + ${MICROPY_PY_DIR}/runtime.c + ${MICROPY_PY_DIR}/runtime_utils.c + ${MICROPY_PY_DIR}/scheduler.c + ${MICROPY_PY_DIR}/scope.c + ${MICROPY_PY_DIR}/sequence.c + ${MICROPY_PY_DIR}/showbc.c + ${MICROPY_PY_DIR}/smallint.c + ${MICROPY_PY_DIR}/stackctrl.c + ${MICROPY_PY_DIR}/stream.c + ${MICROPY_PY_DIR}/unicode.c + ${MICROPY_PY_DIR}/vm.c + ${MICROPY_PY_DIR}/vstr.c + ${MICROPY_PY_DIR}/warning.c +) From 9b9088214687221d06f75a2932e9e0bd1c1b4103 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 23 Sep 2020 15:55:55 +1000 Subject: [PATCH 029/174] esp32: Add support to build using IDF with cmake. This commit adds support for building the esp32 port with cmake, and in particular it builds MicroPython as a component within the ESP-IDF. Using cmake and the ESP-IDF build infrastructure makes it much easier to maintain the port, especially with the various new ESP32 MCUs and their required toolchains. Signed-off-by: Damien George --- ports/esp32/CMakeLists.txt | 38 ++++ .../esp32/boards/GENERIC/mpconfigboard.cmake | 2 + .../boards/GENERIC_D2WD/mpconfigboard.cmake | 6 + .../esp32/boards/GENERIC_D2WD/sdkconfig.board | 5 + .../boards/GENERIC_OTA/mpconfigboard.cmake | 6 + .../esp32/boards/GENERIC_OTA/sdkconfig.board | 2 + .../boards/GENERIC_SPIRAM/mpconfigboard.cmake | 6 + .../esp32/boards/TINYPICO/mpconfigboard.cmake | 8 + ports/esp32/boards/sdkconfig.base | 5 + ports/esp32/main/CMakeLists.txt | 168 ++++++++++++++++++ 10 files changed, 246 insertions(+) create mode 100644 ports/esp32/CMakeLists.txt create mode 100644 ports/esp32/boards/GENERIC/mpconfigboard.cmake create mode 100644 ports/esp32/boards/GENERIC_D2WD/mpconfigboard.cmake create mode 100644 ports/esp32/boards/GENERIC_D2WD/sdkconfig.board create mode 100644 ports/esp32/boards/GENERIC_OTA/mpconfigboard.cmake create mode 100644 ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake create mode 100644 ports/esp32/boards/TINYPICO/mpconfigboard.cmake create mode 100644 ports/esp32/main/CMakeLists.txt diff --git a/ports/esp32/CMakeLists.txt b/ports/esp32/CMakeLists.txt new file mode 100644 index 0000000000..fa419202f9 --- /dev/null +++ b/ports/esp32/CMakeLists.txt @@ -0,0 +1,38 @@ +# Top-level cmake file for building MicroPython on ESP32. + +cmake_minimum_required(VERSION 3.5) + +# Set the location of this port's directory. +set(MICROPY_PORT_DIR ${CMAKE_SOURCE_DIR}) + +# Set the board if it's not already set. +if(NOT MICROPY_BOARD) + set(MICROPY_BOARD GENERIC) +endif() + +# Set the board directory and check that it exists. +if(NOT MICROPY_BOARD_DIR) + set(MICROPY_BOARD_DIR ${MICROPY_PORT_DIR}/boards/${MICROPY_BOARD}) +endif() +if(NOT EXISTS ${MICROPY_BOARD_DIR}/mpconfigboard.cmake) + message(FATAL_ERROR "Invalid MICROPY_BOARD specified: ${MICROPY_BOARD}") +endif() + +# Define the output sdkconfig so it goes in the build directory. +set(SDKCONFIG ${CMAKE_BINARY_DIR}/sdkconfig) + +# Include board config; this is expected to set SDKCONFIG_DEFAULTS (among other options). +include(${MICROPY_BOARD_DIR}/mpconfigboard.cmake) + +# Concatenate all sdkconfig files into a combined one for the IDF to use. +file(WRITE ${CMAKE_BINARY_DIR}/sdkconfig.combined.in "") +foreach(SDKCONFIG_DEFAULT ${SDKCONFIG_DEFAULTS}) + file(READ ${SDKCONFIG_DEFAULT} CONTENTS) + file(APPEND ${CMAKE_BINARY_DIR}/sdkconfig.combined.in "${CONTENTS}") +endforeach() +configure_file(${CMAKE_BINARY_DIR}/sdkconfig.combined.in ${CMAKE_BINARY_DIR}/sdkconfig.combined COPYONLY) +set(SDKCONFIG_DEFAULTS ${CMAKE_BINARY_DIR}/sdkconfig.combined) + +# Include main IDF cmake file and define the project. +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(micropython) diff --git a/ports/esp32/boards/GENERIC/mpconfigboard.cmake b/ports/esp32/boards/GENERIC/mpconfigboard.cmake new file mode 100644 index 0000000000..8fea524555 --- /dev/null +++ b/ports/esp32/boards/GENERIC/mpconfigboard.cmake @@ -0,0 +1,2 @@ +set(SDKCONFIG_DEFAULTS boards/sdkconfig.base) +set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py) diff --git a/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.cmake new file mode 100644 index 0000000000..4e23666f15 --- /dev/null +++ b/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.cmake @@ -0,0 +1,6 @@ +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/GENERIC_D2WD/sdkconfig.board +) + +set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py) diff --git a/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board b/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board new file mode 100644 index 0000000000..367283ded3 --- /dev/null +++ b/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board @@ -0,0 +1,5 @@ +CONFIG_ESPTOOLPY_FLASHMODE_DIO=y +CONFIG_ESPTOOLPY_FLASHFREQ_40M=y +CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-2MiB.csv" diff --git a/ports/esp32/boards/GENERIC_OTA/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_OTA/mpconfigboard.cmake new file mode 100644 index 0000000000..7b1e146005 --- /dev/null +++ b/ports/esp32/boards/GENERIC_OTA/mpconfigboard.cmake @@ -0,0 +1,6 @@ +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/GENERIC_OTA/sdkconfig.board +) + +set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py) diff --git a/ports/esp32/boards/GENERIC_OTA/sdkconfig.board b/ports/esp32/boards/GENERIC_OTA/sdkconfig.board index b0ed171d81..ca1f4276f4 100644 --- a/ports/esp32/boards/GENERIC_OTA/sdkconfig.board +++ b/ports/esp32/boards/GENERIC_OTA/sdkconfig.board @@ -1,4 +1,6 @@ CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-ota.csv" # ESP-IDF v3: CONFIG_APP_ROLLBACK_ENABLE=y diff --git a/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake new file mode 100644 index 0000000000..bb441d9ebf --- /dev/null +++ b/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake @@ -0,0 +1,6 @@ +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.spiram +) + +set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py) diff --git a/ports/esp32/boards/TINYPICO/mpconfigboard.cmake b/ports/esp32/boards/TINYPICO/mpconfigboard.cmake new file mode 100644 index 0000000000..990e3e035b --- /dev/null +++ b/ports/esp32/boards/TINYPICO/mpconfigboard.cmake @@ -0,0 +1,8 @@ +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.240mhz + boards/sdkconfig.spiram + boards/TINYPICO/sdkconfig.board +) + +set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index 67e2424a12..de6e42c8f3 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -51,3 +51,8 @@ CONFIG_PPP_SUPPORT=y CONFIG_PPP_PAP_SUPPORT=y CONFIG_PPP_CHAP_SUPPORT=y CONFIG_ULP_COPROC_ENABLED=y + +# For cmake build +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt new file mode 100644 index 0000000000..a46e0112c9 --- /dev/null +++ b/ports/esp32/main/CMakeLists.txt @@ -0,0 +1,168 @@ +# Set location of base MicroPython directory. +get_filename_component(MICROPY_DIR ${PROJECT_DIR}/../.. ABSOLUTE) + +# Include core source components. +include(${MICROPY_DIR}/py/py.cmake) +include(${MICROPY_DIR}/extmod/extmod.cmake) + +set(MICROPY_SOURCE_EXTMOD_EXTRA + ${MICROPY_DIR}/extmod/modonewire.c +) + +set(MICROPY_SOURCE_LIB + ${MICROPY_DIR}/lib/littlefs/lfs1.c + ${MICROPY_DIR}/lib/littlefs/lfs1_util.c + ${MICROPY_DIR}/lib/littlefs/lfs2.c + ${MICROPY_DIR}/lib/littlefs/lfs2_util.c + ${MICROPY_DIR}/lib/mbedtls_errors/mp_mbedtls_errors.c + ${MICROPY_DIR}/lib/mp-readline/readline.c + ${MICROPY_DIR}/lib/netutils/netutils.c + ${MICROPY_DIR}/lib/oofatfs/ff.c + ${MICROPY_DIR}/lib/oofatfs/ffunicode.c + ${MICROPY_DIR}/lib/timeutils/timeutils.c + ${MICROPY_DIR}/lib/utils/interrupt_char.c + ${MICROPY_DIR}/lib/utils/stdout_helpers.c + ${MICROPY_DIR}/lib/utils/sys_stdio_mphal.c + ${MICROPY_DIR}/lib/utils/pyexec.c +) + +set(MICROPY_SOURCE_DRIVERS + ${MICROPY_DIR}/drivers/bus/softspi.c + ${MICROPY_DIR}/drivers/dht/dht.c +) + +set(MICROPY_SOURCE_PORT + ${PROJECT_DIR}/main.c + ${PROJECT_DIR}/uart.c + ${PROJECT_DIR}/gccollect.c + ${PROJECT_DIR}/mphalport.c + ${PROJECT_DIR}/fatfs_port.c + ${PROJECT_DIR}/help.c + ${PROJECT_DIR}/modutime.c + ${PROJECT_DIR}/moduos.c + ${PROJECT_DIR}/machine_timer.c + ${PROJECT_DIR}/machine_pin.c + ${PROJECT_DIR}/machine_touchpad.c + ${PROJECT_DIR}/machine_adc.c + ${PROJECT_DIR}/machine_dac.c + ${PROJECT_DIR}/machine_i2c.c + ${PROJECT_DIR}/machine_pwm.c + ${PROJECT_DIR}/machine_uart.c + ${PROJECT_DIR}/modmachine.c + ${PROJECT_DIR}/modnetwork.c + ${PROJECT_DIR}/network_lan.c + ${PROJECT_DIR}/network_ppp.c + ${PROJECT_DIR}/mpnimbleport.c + ${PROJECT_DIR}/modsocket.c + ${PROJECT_DIR}/modesp.c + ${PROJECT_DIR}/esp32_partition.c + ${PROJECT_DIR}/esp32_rmt.c + ${PROJECT_DIR}/esp32_ulp.c + ${PROJECT_DIR}/modesp32.c + ${PROJECT_DIR}/espneopixel.c + ${PROJECT_DIR}/machine_hw_spi.c + ${PROJECT_DIR}/machine_wdt.c + ${PROJECT_DIR}/mpthreadport.c + ${PROJECT_DIR}/machine_rtc.c + ${PROJECT_DIR}/machine_sdcard.c +) + +set(MICROPY_SOURCE_QSTR + ${MICROPY_SOURCE_PY} + ${MICROPY_SOURCE_EXTMOD} + ${MICROPY_SOURCE_EXTMOD_EXTRA} + ${MICROPY_SOURCE_LIB} + ${MICROPY_SOURCE_PORT} +) + +set(IDF_COMPONENTS + app_update + bootloader_support + driver + esp32 + esp_common + esp_eth + esp_event + esp_ringbuf + esp_rom + esp_wifi + freertos + heap + log + lwip + mbedtls + mdns + newlib + nvs_flash + sdmmc + soc + spi_flash + tcpip_adapter + ulp + vfs + xtensa +) + +# Register the main IDF component. +idf_component_register( + SRCS + ${MICROPY_SOURCE_PY} + ${MICROPY_SOURCE_EXTMOD} + ${MICROPY_SOURCE_EXTMOD_EXTRA} + ${MICROPY_SOURCE_LIB} + ${MICROPY_SOURCE_DRIVERS} + ${MICROPY_SOURCE_PORT} + INCLUDE_DIRS + ${MICROPY_DIR} + ${MICROPY_PORT_DIR} + ${MICROPY_BOARD_DIR} + ${CMAKE_BINARY_DIR} + REQUIRES + ${IDF_COMPONENTS} +) + +# Set the MicroPython target as the current (main) IDF component target. +set(MICROPY_TARGET ${COMPONENT_TARGET}) + +# Define mpy-cross flags, for use with frozen code. +set(MICROPY_CROSS_FLAGS -march=xtensawin) + +# Set compile options for this port. +target_compile_definitions(${MICROPY_TARGET} PUBLIC + MICROPY_ESP_IDF_4=1 + MICROPY_VFS_FAT=1 + MICROPY_VFS_LFS2=1 + FFCONF_H=\"${MICROPY_OOFATFS_DIR}/ffconf.h\" + LFS1_NO_MALLOC LFS1_NO_DEBUG LFS1_NO_WARN LFS1_NO_ERROR LFS1_NO_ASSERT + LFS2_NO_MALLOC LFS2_NO_DEBUG LFS2_NO_WARN LFS2_NO_ERROR LFS2_NO_ASSERT +) + +# Disable some warnings to keep the build output clean. +target_compile_options(${MICROPY_TARGET} PUBLIC + -Wno-clobbered + -Wno-deprecated-declarations + -Wno-missing-field-initializers +) + +# Collect all of the include directories and compile definitions for the IDF components. +foreach(comp ${IDF_COMPONENTS}) + get_target_property(type __idf_${comp} TYPE) + set(_inc OFF) + set(_def OFF) + if(${type} STREQUAL STATIC_LIBRARY) + get_target_property(_inc __idf_${comp} INCLUDE_DIRECTORIES) + get_target_property(_def __idf_${comp} COMPILE_DEFINITIONS) + elseif(${type} STREQUAL INTERFACE_LIBRARY) + get_target_property(_inc __idf_${comp} INTERFACE_INCLUDE_DIRECTORIES) + get_target_property(_def __idf_${comp} INTERFACE_COMPILE_DEFINITIONS) + endif() + if(_inc) + list(APPEND MICROPY_CPP_INC_EXTRA ${_inc}) + endif() + if(_def) + list(APPEND MICROPY_CPP_DEF_EXTRA ${_def}) + endif() +endforeach() + +# Include the main MicroPython cmake rules. +include(${MICROPY_DIR}/py/mkrules.cmake) From 9c2231f47ad1d30d3436561dfbeefd44c7a3e2f9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 6 Oct 2020 18:06:09 +1100 Subject: [PATCH 030/174] esp32/esp32_rmt: Don't do unnecessary check for unsigned less than zero. Signed-off-by: Damien George --- ports/esp32/esp32_rmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/esp32_rmt.c b/ports/esp32/esp32_rmt.c index 7971ca5d1c..b547af5539 100644 --- a/ports/esp32/esp32_rmt.c +++ b/ports/esp32/esp32_rmt.c @@ -209,7 +209,7 @@ STATIC mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *pos_args, mp_obj_t pulses = args[1].u_obj; mp_uint_t start = args[2].u_int; - if (start < 0 || start > 1) { + if (start > 1) { mp_raise_ValueError(MP_ERROR_TEXT("start must be 0 or 1")); } From 97072b72246abd69ee0d5892f8571bb4d13609a9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 28 Oct 2020 14:28:17 +1100 Subject: [PATCH 031/174] esp32: Add explicit initialisers to silence compiler warnings. This makes no functional change. See similar commit 9aa58cf8bac353297ff5e7b4f3331e5618046095 Signed-off-by: Damien George --- ports/esp32/machine_i2c.c | 2 +- ports/esp32/modnetwork.c | 2 +- ports/esp32/mphalport.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/esp32/machine_i2c.c b/ports/esp32/machine_i2c.c index 87b08fc9bc..3993c7b52b 100644 --- a/ports/esp32/machine_i2c.c +++ b/ports/esp32/machine_i2c.c @@ -120,7 +120,7 @@ mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_ // Parse args enum { ARG_id, ARG_scl, ARG_sda, ARG_freq, ARG_timeout }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 64f1c91dc7..d981b60805 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -331,7 +331,7 @@ STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - wifi_config_t wifi_sta_config = {{{0}}}; + wifi_config_t wifi_sta_config = {0}; // configure any parameters that are given if (n_args > 1) { diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index ad571bf961..5403382684 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -52,7 +52,7 @@ TaskHandle_t mp_main_task_handle; STATIC uint8_t stdin_ringbuf_array[256]; -ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array)}; +ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0}; // Check the ESP-IDF error code and raise an OSError if it's not ESP_OK. void check_esp_err(esp_err_t code) { From 9f035d6bb71e35ff9acd05b65dbc751887f03af2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 14 Feb 2021 00:52:35 +1100 Subject: [PATCH 032/174] esp32: Remove traditional "make" capability. It's now replaced by cmake/idf.py. But a convenience Makefile is still provided with traditional targets like "all" and "deploy". Signed-off-by: Damien George --- ports/esp32/Makefile | 981 +----------------- ports/esp32/boards/GENERIC/mpconfigboard.mk | 1 - .../boards/GENERIC_D2WD/mpconfigboard.mk | 5 - .../esp32/boards/GENERIC_OTA/mpconfigboard.mk | 4 - .../boards/GENERIC_SPIRAM/mpconfigboard.mk | 2 - ports/esp32/boards/TINYPICO/mpconfigboard.mk | 8 - 6 files changed, 26 insertions(+), 975 deletions(-) delete mode 100644 ports/esp32/boards/GENERIC/mpconfigboard.mk delete mode 100644 ports/esp32/boards/GENERIC_D2WD/mpconfigboard.mk delete mode 100644 ports/esp32/boards/GENERIC_OTA/mpconfigboard.mk delete mode 100644 ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.mk delete mode 100644 ports/esp32/boards/TINYPICO/mpconfigboard.mk diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 756bc8f894..1249795993 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -1,972 +1,43 @@ -# Select the board to build for: if not given on the command line, -# then default to GENERIC. +# Makefile for MicroPython on ESP32. +# +# This is a simple, convenience wrapper around idf.py (which uses cmake). + +# Select the board to build for, defaulting to GENERIC. BOARD ?= GENERIC # If the build directory is not given, make it reflect the board name. BUILD ?= build-$(BOARD) -BOARD_DIR ?= boards/$(BOARD) -ifeq ($(wildcard $(BOARD_DIR)/.),) -$(error Invalid BOARD specified: $(BOARD_DIR)) -endif +# Device serial settings. +PORT ?= /dev/ttyUSB0 +BAUD ?= 460800 -include ../../py/mkenv.mk - -# Optional (not currently used for ESP32) --include mpconfigport.mk - -ifneq ($(SDKCONFIG),) -$(error Use the BOARD variable instead of SDKCONFIG) -endif - -# Expected to set SDKCONFIG -include $(BOARD_DIR)/mpconfigboard.mk - -# qstr definitions (must come before including py.mk) -QSTR_DEFS = qstrdefsport.h -QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h -QSTR_GLOBAL_REQUIREMENTS = $(SDKCONFIG_H) - -# MicroPython feature configurations -MICROPY_ROM_TEXT_COMPRESSION ?= 1 -MICROPY_PY_USSL = 0 -MICROPY_SSL_AXTLS = 0 -MICROPY_PY_BTREE = 1 -MICROPY_VFS_FAT = 1 -MICROPY_VFS_LFS2 = 1 - -FROZEN_MANIFEST ?= boards/manifest.py - -# include py core make definitions -include $(TOP)/py/py.mk +PYTHON ?= python3 GIT_SUBMODULES = lib/berkeley-db-1.xx -PORT ?= /dev/ttyUSB0 -BAUD ?= 460800 -FLASH_MODE ?= dio -FLASH_FREQ ?= 40m -FLASH_SIZE ?= 4MB -CROSS_COMPILE ?= xtensa-esp32-elf- -OBJDUMP = $(CROSS_COMPILE)objdump +.PHONY: all clean deploy erase submodules FORCE -SDKCONFIG_COMBINED = $(BUILD)/sdkconfig.combined -SDKCONFIG_H = $(BUILD)/sdkconfig.h +IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -B $(BUILD) -# The git hash of the currently supported ESP IDF version. -# These correspond to v3.3.2 and v4.0.1. -ESPIDF_SUPHASH_V3 := 9e70825d1e1cbf7988cf36981774300066580ea7 -ESPIDF_SUPHASH_V4 := 4c81978a3e2220674a432a588292a4c860eef27b +all: + idf.py $(IDFPY_FLAGS) build + @$(PYTHON) makeimg.py \ + $(BUILD)/bootloader/bootloader.bin \ + $(BUILD)/partition_table/partition-table.bin \ + $(BUILD)/micropython.bin \ + $(BUILD)/firmware.bin -define print_supported_git_hash -$(info Supported git hash (v3.3): $(ESPIDF_SUPHASH_V3)) -$(info Supported git hash (v4.0) (experimental): $(ESPIDF_SUPHASH_V4)) -endef +$(BUILD)/bootloader/bootloader.bin $(BUILD)/partition_table/partition -table.bin $(BUILD)/micropython.bin: FORCE -# paths to ESP IDF and its components -ifeq ($(ESPIDF),) -ifneq ($(IDF_PATH),) -ESPIDF = $(IDF_PATH) -else -$(info The ESPIDF variable has not been set, please set it to the root of the esp-idf repository.) -$(info See README.md for installation instructions.) -dummy := $(call print_supported_git_hash) -$(error ESPIDF not set) -endif -endif +clean: + idf.py $(IDFPY_FLAGS) fullclean -ESPCOMP = $(ESPIDF)/components -ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py -ESPCOMP_KCONFIGS = $(shell find $(ESPCOMP) -name Kconfig) -ESPCOMP_KCONFIGS_PROJBUILD = $(shell find $(ESPCOMP) -name Kconfig.projbuild) - -# verify the ESP IDF version -ESPIDF_CURHASH := $(shell git -C $(ESPIDF) show -s --pretty=format:'%H') - -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V3)) -$(info Building with ESP IDF v3) -else ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) -$(info Building with ESP IDF v4) - -PYPARSING_VERSION = $(shell python3 -c 'import pyparsing; print(pyparsing.__version__)') -ifneq ($(PYPARSING_VERSION),2.3.1) -$(info ** ERROR **) -$(info EDP IDF requires pyparsing version less than 2.4) -$(info You will need to set up a Python virtual environment with pyparsing 2.3.1) -$(info Please see README.md for more information) -$(error Incorrect pyparsing version) -endif -else -$(info ** WARNING **) -$(info The git hash of ESP IDF does not match the supported version) -$(info The build may complete and the firmware may work but it is not guaranteed) -$(info ESP IDF path: $(ESPIDF)) -$(info Current git hash: $(ESPIDF_CURHASH)) -dummy := $(call print_supported_git_hash) -endif - -# pretty format of ESP IDF version, used internally by the IDF -IDF_VER := $(shell git -C $(ESPIDF) describe) - -ifeq ($(shell which $(CC) 2> /dev/null),) -$(info ** ERROR **) -$(info Cannot find C compiler $(CC)) -$(info Add the xtensa toolchain to your PATH. See README.md) -$(error C compiler missing) -endif - -# Support BLE by default. -# Can be explicitly disabled on the command line or board config. -MICROPY_PY_BLUETOOTH ?= 1 -ifeq ($(MICROPY_PY_BLUETOOTH),1) -SDKCONFIG += boards/sdkconfig.ble - -# Use NimBLE on ESP32. -MICROPY_BLUETOOTH_NIMBLE ?= 1 -# Use Nimble bindings, but ESP32 IDF provides the Nimble library. -MICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY = 1 -include $(TOP)/extmod/nimble/nimble.mk -endif - -# include sdkconfig to get needed configuration values -include $(SDKCONFIG) - -################################################################################ -# Compiler and linker flags - -INC += -I. -INC += -I$(TOP) -INC += -I$(BUILD) - -INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include -INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include_bootloader -INC_ESPCOMP += -I$(ESPCOMP)/console -INC_ESPCOMP += -I$(ESPCOMP)/driver/include -INC_ESPCOMP += -I$(ESPCOMP)/driver/include/driver -INC_ESPCOMP += -I$(ESPCOMP)/efuse/include -INC_ESPCOMP += -I$(ESPCOMP)/efuse/esp32/include -INC_ESPCOMP += -I$(ESPCOMP)/esp32/include -INC_ESPCOMP += -I$(ESPCOMP)/espcoredump/include -INC_ESPCOMP += -I$(ESPCOMP)/soc/include -INC_ESPCOMP += -I$(ESPCOMP)/soc/esp32/include -INC_ESPCOMP += -I$(ESPCOMP)/heap/include -INC_ESPCOMP += -I$(ESPCOMP)/log/include -INC_ESPCOMP += -I$(ESPCOMP)/nvs_flash/include -INC_ESPCOMP += -I$(ESPCOMP)/freertos/include -INC_ESPCOMP += -I$(ESPCOMP)/esp_ringbuf/include -INC_ESPCOMP += -I$(ESPCOMP)/esp_event/include -INC_ESPCOMP += -I$(ESPCOMP)/tcpip_adapter/include -INC_ESPCOMP += -I$(ESPCOMP)/lwip/lwip/src/include -INC_ESPCOMP += -I$(ESPCOMP)/lwip/port/esp32/include -INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/apps -INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/apps/sntp -INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include -INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include -INC_ESPCOMP += -I$(ESPCOMP)/mdns/include -INC_ESPCOMP += -I$(ESPCOMP)/mdns/private_include -INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include -INC_ESPCOMP += -I$(ESPCOMP)/ulp/include -INC_ESPCOMP += -I$(ESPCOMP)/vfs/include -INC_ESPCOMP += -I$(ESPCOMP)/xtensa-debug-module/include -INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include -INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/port/include -INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include -INC_ESPCOMP += -I$(ESPCOMP)/app_update/include -INC_ESPCOMP += -I$(ESPCOMP)/pthread/include -INC_ESPCOMP += -I$(ESPCOMP)/smartconfig_ack/include -INC_ESPCOMP += -I$(ESPCOMP)/sdmmc/include - -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) -INC_ESPCOMP += -I$(ESPCOMP)/esp_common/include -INC_ESPCOMP += -I$(ESPCOMP)/esp_eth/include -INC_ESPCOMP += -I$(ESPCOMP)/esp_event/private_include -INC_ESPCOMP += -I$(ESPCOMP)/esp_rom/include -INC_ESPCOMP += -I$(ESPCOMP)/esp_wifi/include -INC_ESPCOMP += -I$(ESPCOMP)/esp_wifi/esp32/include -INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/apps/sntp -INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/private_include -INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include/esp_supplicant -INC_ESPCOMP += -I$(ESPCOMP)/xtensa/include -INC_ESPCOMP += -I$(ESPCOMP)/xtensa/esp32/include -ifeq ($(CONFIG_BT_NIMBLE_ENABLED),y) -INC_ESPCOMP += -I$(ESPCOMP)/bt/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/common/osi/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/common/btc/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/common/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/porting/nimble/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/port/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/ans/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/bas/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/gap/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/gatt/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/ias/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/lls/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/tps/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/util/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/store/ram/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/nimble/host/store/config/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/porting/npl/freertos/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/nimble/ext/tinycrypt/include -INC_ESPCOMP += -I$(ESPCOMP)/bt/host/nimble/esp-hci/include -endif -else -INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include -INC_ESPCOMP += -I$(ESPCOMP)/expat/expat/expat/lib -INC_ESPCOMP += -I$(ESPCOMP)/expat/port/include -INC_ESPCOMP += -I$(ESPCOMP)/json/include -INC_ESPCOMP += -I$(ESPCOMP)/json/port/include -INC_ESPCOMP += -I$(ESPCOMP)/micro-ecc/micro-ecc -INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include -INC_ESPCOMP += -I$(ESPCOMP)/nghttp/nghttp2/lib/includes -ifeq ($(CONFIG_NIMBLE_ENABLED),y) -INC_ESPCOMP += -I$(ESPCOMP)/bt/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/porting/nimble/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/port/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/services/ans/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/services/bas/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/services/gap/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/services/gatt/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/services/ias/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/services/lls/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/services/tps/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/util/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/store/ram/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/nimble/host/store/config/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/porting/npl/freertos/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/nimble/ext/tinycrypt/include -INC_ESPCOMP += -I$(ESPCOMP)/nimble/esp-hci/include -endif -endif - -INC_NEWLIB += -I$(ESPCOMP)/newlib/platform_include -INC_NEWLIB += -I$(ESPCOMP)/newlib/include - -ifeq ($(MICROPY_PY_BLUETOOTH),1) -CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH=1 -CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE=1 -endif - -# these flags are common to C and C++ compilation -CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields \ - -mlongcalls -nostdlib \ - -Wall -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable \ - -Wno-error=unused-variable -Wno-error=deprecated-declarations \ - -DESP_PLATFORM - -CFLAGS_BASE = -std=gnu99 $(CFLAGS_COMMON) -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' -DHAVE_CONFIG_H -CFLAGS = $(CFLAGS_BASE) $(INC) $(INC_ESPCOMP) $(INC_NEWLIB) -CFLAGS += -DIDF_VER=\"$(IDF_VER)\" -CFLAGS += $(CFLAGS_MOD) $(CFLAGS_EXTRA) -CFLAGS += -I$(BOARD_DIR) - -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) -CFLAGS += -DMICROPY_ESP_IDF_4=1 -endif - -# this is what ESPIDF uses for c++ compilation -CXXFLAGS = -std=gnu++11 $(CFLAGS_COMMON) $(INC) $(INC_ESPCOMP) $(CXXFLAGS_MOD) - -LDFLAGS = -nostdlib -Map=$(@:.elf=.map) --cref -LDFLAGS += --gc-sections -static -EL -LDFLAGS += -u call_user_start_cpu0 -u uxTopUsedPriority -u ld_include_panic_highint_hdl -LDFLAGS += -u __cxa_guard_dummy # so that implementation of static guards is taken from cxx_guards.o instead of libstdc++.a -LDFLAGS += -L$(ESPCOMP)/esp32/ld -LDFLAGS += -L$(ESPCOMP)/esp_rom/esp32/ld -LDFLAGS += -T $(BUILD)/esp32_out.ld -LDFLAGS += -T $(BUILD)/esp32.project.ld -LDFLAGS += -T esp32.rom.ld -LDFLAGS += -T esp32.rom.libgcc.ld -LDFLAGS += -T esp32.peripherals.ld - -LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) -LIBSTDCXX_FILE_NAME = $(shell $(CXX) $(CXXFLAGS) -print-file-name=libstdc++.a) - -# Debugging/Optimization -ifeq ($(DEBUG), 1) -CFLAGS += -g -COPT = -O0 -else -#CFLAGS += -fdata-sections -ffunction-sections -COPT += -Os -DNDEBUG -#LDFLAGS += --gc-sections -endif - -# Options for mpy-cross -MPY_CROSS_FLAGS += -march=xtensawin - -# Enable SPIRAM support if CONFIG_ESP32_SPIRAM_SUPPORT=y in sdkconfig -ifeq ($(CONFIG_ESP32_SPIRAM_SUPPORT),y) -CFLAGS_COMMON += -mfix-esp32-psram-cache-issue -LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc-psram-workaround.a $(ESPCOMP)/newlib/lib/libm-psram-workaround.a -else -# Additional newlib symbols that can only be used with spiram disabled. -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) -LDFLAGS += -T esp32.rom.newlib-funcs.ld -LDFLAGS += -T esp32.rom.newlib-locale.ld -LDFLAGS += -T esp32.rom.newlib-data.ld -else -LDFLAGS += -T esp32.rom.spiram_incompatible_fns.ld -endif -LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc.a $(ESPCOMP)/newlib/lib/libm.a -endif - -################################################################################ -# List of MicroPython source and object files - -SRC_C = \ - main.c \ - uart.c \ - gccollect.c \ - mphalport.c \ - fatfs_port.c \ - help.c \ - modutime.c \ - moduos.c \ - machine_timer.c \ - machine_pin.c \ - machine_touchpad.c \ - machine_adc.c \ - machine_dac.c \ - machine_i2c.c \ - machine_pwm.c \ - machine_uart.c \ - modmachine.c \ - modnetwork.c \ - network_lan.c \ - network_ppp.c \ - mpnimbleport.c \ - modsocket.c \ - modesp.c \ - esp32_partition.c \ - esp32_rmt.c \ - esp32_ulp.c \ - modesp32.c \ - espneopixel.c \ - machine_hw_spi.c \ - machine_wdt.c \ - mpthreadport.c \ - machine_rtc.c \ - machine_sdcard.c \ - $(wildcard $(BOARD_DIR)/*.c) \ - $(SRC_MOD) - -SRC_CXX += \ - $(SRC_MOD_CXX) - -EXTMOD_SRC_C += $(addprefix extmod/,\ - modonewire.c \ - ) - -LIB_SRC_C = $(addprefix lib/,\ - mbedtls_errors/mp_mbedtls_errors.c \ - mp-readline/readline.c \ - netutils/netutils.c \ - timeutils/timeutils.c \ - utils/pyexec.c \ - utils/interrupt_char.c \ - utils/sys_stdio_mphal.c \ - ) - -DRIVERS_SRC_C = $(addprefix drivers/,\ - bus/softspi.c \ - dht/dht.c \ - ) - -OBJ_MP = -OBJ_MP += $(PY_O) -OBJ_MP += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) -OBJ_MP += $(addprefix $(BUILD)/, $(SRC_CXX:.cpp=.o)) -OBJ_MP += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) -OBJ_MP += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) -OBJ_MP += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) - -# Only enable this for the MicroPython source: ignore warnings from esp-idf. -$(OBJ_MP): CFLAGS += -Wdouble-promotion -Wfloat-conversion - -# List of sources for qstr extraction -SRC_QSTR += $(SRC_C) $(SRC_CXX) $(EXTMOD_SRC_C) $(LIB_SRC_C) $(DRIVERS_SRC_C) -# Append any auto-generated sources that are needed by sources listed in SRC_QSTR -SRC_QSTR_AUTO_DEPS += - -################################################################################ -# Generate sdkconfig.h from sdkconfig - -$(SDKCONFIG_COMBINED): $(SDKCONFIG) - $(Q)$(MKDIR) -p $(dir $@) - $(Q)$(CAT) $^ > $@ - -$(SDKCONFIG_H): $(SDKCONFIG_COMBINED) - $(ECHO) "GEN $@" - $(Q)$(MKDIR) -p $(dir $@) - $(Q)$(PYTHON) $(ESPIDF)/tools/kconfig_new/confgen.py \ - --output header $@ \ - --config $< \ - --kconfig $(ESPIDF)/Kconfig \ - --env "IDF_TARGET=esp32" \ - --env "IDF_CMAKE=n" \ - --env "COMPONENT_KCONFIGS=$(ESPCOMP_KCONFIGS)" \ - --env "COMPONENT_KCONFIGS_PROJBUILD=$(ESPCOMP_KCONFIGS_PROJBUILD)" \ - --env "IDF_PATH=$(ESPIDF)" - $(Q)touch $@ - -$(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H) $(BOARD_DIR)/mpconfigboard.h - -################################################################################ -# List of object files from the ESP32 IDF components - -ESPIDF_BOOTLOADER_SUPPORT_O = $(patsubst %.c,%.o,\ - $(filter-out $(ESPCOMP)/bootloader_support/src/bootloader_init.c,\ - $(wildcard $(ESPCOMP)/bootloader_support/src/*.c) \ - $(wildcard $(ESPCOMP)/bootloader_support/src/idf/*.c) \ - )) - -ESPIDF_DRIVER_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/driver/*.c)) - -ESPIDF_EFUSE_O = $(patsubst %.c,%.o,\ - $(wildcard $(ESPCOMP)/efuse/esp32/*.c)\ - $(wildcard $(ESPCOMP)/efuse/src/*.c)\ - ) - -$(BUILD)/$(ESPCOMP)/esp32/dport_access.o: CFLAGS += -Wno-array-bounds -ESPIDF_ESP32_O = \ - $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp32/*.c)) \ - $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp32/hwcrypto/*.c)) \ - $(patsubst %.S,%.o,$(wildcard $(ESPCOMP)/esp32/*.S)) \ - -ESPIDF_ESP_RINGBUF_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp_ringbuf/*.c)) - -ESPIDF_HEAP_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/heap/*.c)) - -ESPIDF_SOC_O = $(patsubst %.c,%.o,\ - $(wildcard $(ESPCOMP)/soc/esp32/*.c) \ - $(wildcard $(ESPCOMP)/soc/src/*.c) \ - $(wildcard $(ESPCOMP)/soc/src/hal/*.c) \ - ) - -$(BUILD)/$(ESPCOMP)/cxx/cxx_guards.o: CXXFLAGS += -Wno-error=sign-compare -ESPIDF_CXX_O = $(patsubst %.cpp,%.o,$(wildcard $(ESPCOMP)/cxx/*.cpp)) - -ESPIDF_PTHREAD_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/pthread/*.c)) - -# Assembler .S files need only basic flags, and in particular should not have -# -Os because that generates subtly different code. -# We also need custom CFLAGS for .c files because FreeRTOS has headers with -# generic names (eg queue.h) which can clash with other files in the port. -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) -CFLAGS_ASM = -I$(BUILD) -I$(ESPCOMP)/esp32/include -I$(ESPCOMP)/soc/esp32/include -I$(ESPCOMP)/freertos/include/freertos -I. -I$(ESPCOMP)/xtensa/include -I$(ESPCOMP)/xtensa/esp32/include -I$(ESPCOMP)/esp_common/include -else -CFLAGS_ASM = -I$(BUILD) -I$(ESPCOMP)/esp32/include -I$(ESPCOMP)/soc/esp32/include -I$(ESPCOMP)/freertos/include/freertos -I. -endif -$(BUILD)/$(ESPCOMP)/freertos/portasm.o: CFLAGS = $(CFLAGS_ASM) -$(BUILD)/$(ESPCOMP)/freertos/xtensa_context.o: CFLAGS = $(CFLAGS_ASM) -$(BUILD)/$(ESPCOMP)/freertos/xtensa_intr_asm.o: CFLAGS = $(CFLAGS_ASM) -$(BUILD)/$(ESPCOMP)/freertos/xtensa_vectors.o: CFLAGS = $(CFLAGS_ASM) -$(BUILD)/$(ESPCOMP)/freertos/xtensa_vector_defaults.o: CFLAGS = $(CFLAGS_ASM) -$(BUILD)/$(ESPCOMP)/freertos/%.o: CFLAGS = $(CFLAGS_BASE) -I. -I$(BUILD) $(INC_ESPCOMP) $(INC_NEWLIB) -I$(ESPCOMP)/freertos/include/freertos -D_ESP_FREERTOS_INTERNAL -ESPIDF_FREERTOS_O = \ - $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/freertos/*.c)) \ - $(patsubst %.S,%.o,$(wildcard $(ESPCOMP)/freertos/*.S)) \ - -ESPIDF_VFS_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/vfs/*.c)) - -ESPIDF_LOG_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/log/*.c)) - -ESPIDF_XTENSA_DEBUG_MODULE_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/xtensa-debug-module/*.c)) - -ESPIDF_TCPIP_ADAPTER_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/tcpip_adapter/*.c)) - -ESPIDF_APP_TRACE_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/app_trace/*.c)) - -ESPIDF_APP_UPDATE_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/app_update/*.c)) - -ESPIDF_NEWLIB_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/newlib/*.c)) - -$(BUILD)/$(ESPCOMP)/nvs_flash/src/nvs_api.o: CXXFLAGS += -Wno-error=sign-compare -ESPIDF_NVS_FLASH_O = $(patsubst %.cpp,%.o,$(wildcard $(ESPCOMP)/nvs_flash/src/*.cpp)) - -ESPIDF_SMARTCONFIG_ACK_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/smartconfig_ack/*.c)) - -ESPIDF_SPI_FLASH_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/spi_flash/*.c)) - -ESPIDF_ULP_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/ulp/*.c)) - -$(BUILD)/$(ESPCOMP)/lwip/%.o: CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable -ESPIDF_LWIP_O = $(patsubst %.c,%.o,\ - $(wildcard $(ESPCOMP)/lwip/apps/dhcpserver/*.c) \ - $(wildcard $(ESPCOMP)/lwip/lwip/src/api/*.c) \ - $(wildcard $(ESPCOMP)/lwip/lwip/src/apps/sntp/*.c) \ - $(wildcard $(ESPCOMP)/lwip/lwip/src/core/*.c) \ - $(wildcard $(ESPCOMP)/lwip/lwip/src/core/*/*.c) \ - $(wildcard $(ESPCOMP)/lwip/lwip/src/netif/*.c) \ - $(wildcard $(ESPCOMP)/lwip/lwip/src/netif/*/*.c) \ - $(wildcard $(ESPCOMP)/lwip/lwip/src/netif/*/*/*.c) \ - $(wildcard $(ESPCOMP)/lwip/port/esp32/*.c) \ - $(wildcard $(ESPCOMP)/lwip/port/esp32/*/*.c) \ - ) - -# Mbedtls source files, exclude error.c in favor of lib/mbedtls_errors/mp_mbedtls_errors.c -ESPIDF_MBEDTLS_O = $(patsubst %.c,%.o, $(filter-out %/error.c,\ - $(wildcard $(ESPCOMP)/mbedtls/mbedtls/library/*.c) \ - $(wildcard $(ESPCOMP)/mbedtls/port/*.c) \ - $(wildcard $(ESPCOMP)/mbedtls/port/esp32/*.c) \ - )) - -ESPIDF_MDNS_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/mdns/*.c)) - -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) -$(BUILD)/$(ESPCOMP)/wpa_supplicant/%.o: CFLAGS += -DCONFIG_WPA3_SAE -DCONFIG_IEEE80211W -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -D__ets__ -Wno-strict-aliasing -I$(ESPCOMP)/wpa_supplicant/src -Wno-implicit-function-declaration -else -$(BUILD)/$(ESPCOMP)/wpa_supplicant/%.o: CFLAGS += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DALLOW_EVEN_MOD -D__ets__ -Wno-strict-aliasing -endif -ESPIDF_WPA_SUPPLICANT_O = $(patsubst %.c,%.o,\ - $(wildcard $(ESPCOMP)/wpa_supplicant/port/*.c) \ - $(wildcard $(ESPCOMP)/wpa_supplicant/src/*/*.c) \ - ) - -ESPIDF_SDMMC_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/sdmmc/*.c)) - -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) -ESPIDF_ESP_COMMON_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp_common/src/*.c)) - -ESPIDF_ESP_EVENT_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp_event/*.c)) - -ESPIDF_ESP_WIFI_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp_wifi/src/*.c)) - -ifeq ($(CONFIG_BT_NIMBLE_ENABLED),y) -ESPIDF_BT_NIMBLE_O = $(patsubst %.c,%.o,\ - $(wildcard $(ESPCOMP)/bt/controller/*.c) \ - $(wildcard $(ESPCOMP)/bt/common/btc/core/*.c) \ - $(wildcard $(ESPCOMP)/bt/common/osi/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/esp-hci/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/ext/tinycrypt/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/ans/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/bas/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/gap/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/gatt/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/ias/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/lls/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/services/tps/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_config.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_nvs.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/store/ram/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/host/util/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/nimble/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/porting/nimble/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/nimble/porting/npl/freertos/src/*.c) \ - $(wildcard $(ESPCOMP)/bt/host/nimble/port/src/*.c) \ - ) -endif - -$(BUILD)/$(ESPCOMP)/esp_eth/src/esp_eth_mac_dm9051.o: CFLAGS += -fno-strict-aliasing -ESPIDF_ESP_ETH_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/esp_eth/src/*.c)) - -ESPIDF_XTENSA_O = $(patsubst %.c,%.o,\ - $(wildcard $(ESPCOMP)/xtensa/*.c) \ - $(wildcard $(ESPCOMP)/xtensa/esp32/*.c) \ - ) -else -ESPIDF_JSON_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/json/cJSON/cJSON*.c)) - -ESPIDF_ETHERNET_O = $(patsubst %.c,%.o,\ - $(wildcard $(ESPCOMP)/ethernet/*.c) \ - $(wildcard $(ESPCOMP)/ethernet/eth_phy/*.c) \ - ) - -ifeq ($(CONFIG_NIMBLE_ENABLED),y) -ESPIDF_BT_NIMBLE_O = $(patsubst %.c,%.o,\ - $(wildcard $(ESPCOMP)/bt/*.c) \ - $(wildcard $(ESPCOMP)/nimble/esp-hci/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/ext/tinycrypt/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/services/ans/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/services/bas/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/services/gap/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/services/gatt/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/services/ias/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/services/lls/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/services/tps/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/store/config/src/ble_store_config.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/store/config/src/ble_store_nvs.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/store/ram/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/nimble/host/util/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/nimble/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/porting/nimble/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/nimble/porting/npl/freertos/src/*.c) \ - $(wildcard $(ESPCOMP)/nimble/port/src/*.c) \ - ) -endif -endif - -OBJ_ESPIDF = -LIB_ESPIDF = -BUILD_ESPIDF_LIB = $(BUILD)/esp-idf - -define gen_espidf_lib_rule -OBJ_ESPIDF += $(addprefix $$(BUILD)/,$(2)) -LIB_ESPIDF += $(1) -$(BUILD_ESPIDF_LIB)/$(1)/lib$(1).a: $(addprefix $$(BUILD)/,$(2)) - $(ECHO) "AR $$@" - $(Q)$(AR) cru $$@ $$^ -endef - -$(eval $(call gen_espidf_lib_rule,bootloader_support,$(ESPIDF_BOOTLOADER_SUPPORT_O))) -$(eval $(call gen_espidf_lib_rule,driver,$(ESPIDF_DRIVER_O))) -$(eval $(call gen_espidf_lib_rule,efuse,$(ESPIDF_EFUSE_O))) -$(eval $(call gen_espidf_lib_rule,esp32,$(ESPIDF_ESP32_O))) -$(eval $(call gen_espidf_lib_rule,esp_ringbuf,$(ESPIDF_ESP_RINGBUF_O))) -$(eval $(call gen_espidf_lib_rule,heap,$(ESPIDF_HEAP_O))) -$(eval $(call gen_espidf_lib_rule,soc,$(ESPIDF_SOC_O))) -$(eval $(call gen_espidf_lib_rule,cxx,$(ESPIDF_CXX_O))) -$(eval $(call gen_espidf_lib_rule,pthread,$(ESPIDF_PTHREAD_O))) -$(eval $(call gen_espidf_lib_rule,freertos,$(ESPIDF_FREERTOS_O))) -$(eval $(call gen_espidf_lib_rule,vfs,$(ESPIDF_VFS_O))) -$(eval $(call gen_espidf_lib_rule,json,$(ESPIDF_JSON_O))) -$(eval $(call gen_espidf_lib_rule,log,$(ESPIDF_LOG_O))) -$(eval $(call gen_espidf_lib_rule,xtensa-debug-module,$(ESPIDF_XTENSA_DEBUG_MODULE_O))) -$(eval $(call gen_espidf_lib_rule,tcpip_adapter,$(ESPIDF_TCPIP_ADAPTER_O))) -$(eval $(call gen_espidf_lib_rule,app_trace,$(ESPIDF_APP_TRACE_O))) -$(eval $(call gen_espidf_lib_rule,app_update,$(ESPIDF_APP_UPDATE_O))) -$(eval $(call gen_espidf_lib_rule,newlib,$(ESPIDF_NEWLIB_O))) -$(eval $(call gen_espidf_lib_rule,nvs_flash,$(ESPIDF_NVS_FLASH_O))) -$(eval $(call gen_espidf_lib_rule,smartconfig_ack,$(ESPIDF_SMARTCONFIG_ACK_O))) -$(eval $(call gen_espidf_lib_rule,spi_flash,$(ESPIDF_SPI_FLASH_O))) -$(eval $(call gen_espidf_lib_rule,ulp,$(ESPIDF_ULP_O))) -$(eval $(call gen_espidf_lib_rule,lwip,$(ESPIDF_LWIP_O))) -$(eval $(call gen_espidf_lib_rule,mbedtls,$(ESPIDF_MBEDTLS_O))) -$(eval $(call gen_espidf_lib_rule,mdns,$(ESPIDF_MDNS_O))) -$(eval $(call gen_espidf_lib_rule,wpa_supplicant,$(ESPIDF_WPA_SUPPLICANT_O))) -$(eval $(call gen_espidf_lib_rule,sdmmc,$(ESPIDF_SDMMC_O))) -$(eval $(call gen_espidf_lib_rule,bt_nimble,$(ESPIDF_BT_NIMBLE_O))) - -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) -$(eval $(call gen_espidf_lib_rule,esp_common,$(ESPIDF_ESP_COMMON_O))) -$(eval $(call gen_espidf_lib_rule,esp_event,$(ESPIDF_ESP_EVENT_O))) -$(eval $(call gen_espidf_lib_rule,esp_wifi,$(ESPIDF_ESP_WIFI_O))) -$(eval $(call gen_espidf_lib_rule,esp_eth,$(ESPIDF_ESP_ETH_O))) -$(eval $(call gen_espidf_lib_rule,xtensa,$(ESPIDF_XTENSA_O))) -else -$(eval $(call gen_espidf_lib_rule,ethernet,$(ESPIDF_ETHERNET_O))) -endif - -# Create all destination build dirs before compiling IDF source -OBJ_ESPIDF_DIRS = $(sort $(dir $(OBJ_ESPIDF))) $(BUILD_ESPIDF_LIB) $(addprefix $(BUILD_ESPIDF_LIB)/,$(LIB_ESPIDF)) -$(OBJ_ESPIDF): | $(OBJ_ESPIDF_DIRS) -$(OBJ_ESPIDF_DIRS): - $(MKDIR) -p $@ - -# Make all IDF object files depend on sdkconfig -$(OBJ_ESPIDF): $(SDKCONFIG_H) - -# Add all IDF components to the set of libraries -LIB = $(foreach lib,$(LIB_ESPIDF),$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a) - -################################################################################ -# ESP IDF ldgen - -LDGEN_FRAGMENTS = $(shell find $(ESPCOMP) -name "*.lf") - -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) - -LDGEN_LIBRARIES=$(foreach lib,$(LIB_ESPIDF),$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a) - -$(BUILD_ESPIDF_LIB)/ldgen_libraries: $(LDGEN_LIBRARIES) $(ESPIDF)/make/ldgen.mk - printf "$(foreach library,$(LDGEN_LIBRARIES),$(library)\n)" > $(BUILD_ESPIDF_LIB)/ldgen_libraries - -$(BUILD)/esp32.project.ld: $(ESPCOMP)/esp32/ld/esp32.project.ld.in $(LDGEN_FRAGMENTS) $(SDKCONFIG_COMBINED) $(BUILD_ESPIDF_LIB)/ldgen_libraries - $(ECHO) "GEN $@" - $(Q)$(PYTHON) $(ESPIDF)/tools/ldgen/ldgen.py \ - --input $< \ - --output $@ \ - --config $(SDKCONFIG_COMBINED) \ - --kconfig $(ESPIDF)/Kconfig \ - --fragments $(LDGEN_FRAGMENTS) \ - --libraries-file $(BUILD_ESPIDF_LIB)/ldgen_libraries \ - --env "IDF_TARGET=esp32" \ - --env "IDF_CMAKE=n" \ - --env "COMPONENT_KCONFIGS=$(ESPCOMP_KCONFIGS)" \ - --env "COMPONENT_KCONFIGS_PROJBUILD=$(ESPCOMP_KCONFIGS_PROJBUILD)" \ - --env "IDF_PATH=$(ESPIDF)" \ - --objdump $(OBJDUMP) - -else - -LDGEN_SECTIONS_INFO = $(foreach lib,$(LIB_ESPIDF),$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a.sections_info) -LDGEN_SECTION_INFOS = $(BUILD_ESPIDF_LIB)/ldgen.section_infos - -define gen_sections_info_rule -$(1).sections_info: $(1) - $(ECHO) "GEN $(1).sections_info" - $(Q)$(OBJDUMP) -h $(1) > $(1).sections_info -endef - -$(eval $(foreach lib,$(LIB_ESPIDF),$(eval $(call gen_sections_info_rule,$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a)))) - -$(LDGEN_SECTION_INFOS): $(LDGEN_SECTIONS_INFO) $(ESPIDF)/make/ldgen.mk - $(Q)printf "$(foreach info,$(LDGEN_SECTIONS_INFO),$(info)\n)" > $@ - -$(BUILD)/esp32.project.ld: $(ESPCOMP)/esp32/ld/esp32.project.ld.in $(LDGEN_FRAGMENTS) $(SDKCONFIG_COMBINED) $(LDGEN_SECTION_INFOS) - $(ECHO) "GEN $@" - $(Q)$(PYTHON) $(ESPIDF)/tools/ldgen/ldgen.py \ - --input $< \ - --output $@ \ - --config $(SDKCONFIG_COMBINED) \ - --kconfig $(ESPIDF)/Kconfig \ - --fragments $(LDGEN_FRAGMENTS) \ - --sections $(LDGEN_SECTION_INFOS) \ - --env "IDF_TARGET=esp32" \ - --env "IDF_CMAKE=n" \ - --env "COMPONENT_KCONFIGS=$(ESPCOMP_KCONFIGS)" \ - --env "COMPONENT_KCONFIGS_PROJBUILD=$(ESPCOMP_KCONFIGS_PROJBUILD)" \ - --env "IDF_PATH=$(ESPIDF)" - -endif - -################################################################################ -# Main targets - -all: $(BUILD)/firmware.bin - -.PHONY: idf-version deploy erase - -idf-version: - $(ECHO) "ESP IDF supported hash: $(ESPIDF_SUPHASH)" - -$(BUILD)/firmware.bin: $(BUILD)/bootloader.bin $(BUILD)/partitions.bin $(BUILD)/application.bin - $(ECHO) "Create $@" - $(Q)$(PYTHON) makeimg.py $^ $@ - -deploy: $(BUILD)/firmware.bin - $(ECHO) "Writing $^ to the board" - $(Q)$(ESPTOOL) --chip esp32 --port $(PORT) --baud $(BAUD) write_flash -z --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) 0x1000 $^ +deploy: + idf.py $(IDFPY_FLAGS) -p $(PORT) -b $(BAUD) flash erase: - $(ECHO) "Erasing flash" - $(Q)$(ESPTOOL) --chip esp32 --port $(PORT) --baud $(BAUD) erase_flash + idf.py $(IDFPY_FLAGS) erase_flash -################################################################################ -# Declarations to build the application - -OBJ = $(OBJ_MP) - -APP_LD_ARGS = -APP_LD_ARGS += $(LDFLAGS_MOD) -APP_LD_ARGS += $(addprefix -T,$(LD_FILES)) -APP_LD_ARGS += --start-group -APP_LD_ARGS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc -APP_LD_ARGS += -L$(dir $(LIBSTDCXX_FILE_NAME)) -lstdc++ -APP_LD_ARGS += $(LIBC_LIBM) -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) -APP_LD_ARGS += -L$(ESPCOMP)/xtensa/esp32 -lhal -APP_LD_ARGS += -L$(ESPCOMP)/bt/controller/lib -lbtdm_app -APP_LD_ARGS += -L$(ESPCOMP)/esp_wifi/lib_esp32 -lcore -lmesh -lnet80211 -lphy -lrtc -lpp -lsmartconfig -lcoexist -else -APP_LD_ARGS += $(ESPCOMP)/esp32/libhal.a -APP_LD_ARGS += -L$(ESPCOMP)/bt/lib -lbtdm_app -APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lmesh -lnet80211 -lphy -lrtc -lpp -lwpa -lsmartconfig -lcoexist -lwps -lwpa2 -endif -APP_LD_ARGS += $(OBJ) -APP_LD_ARGS += $(LIB) -APP_LD_ARGS += --end-group - -$(BUILD)/esp32_out.ld: $(SDKCONFIG_H) - $(Q)$(CC) -I$(BUILD) -C -P -x c -E $(ESPCOMP)/esp32/ld/esp32.ld -o $@ - -$(BUILD)/application.bin: $(BUILD)/application.elf - $(ECHO) "Create $@" - $(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $< - -$(BUILD)/application.elf: $(OBJ) $(LIB) $(BUILD)/esp32_out.ld $(BUILD)/esp32.project.ld - $(ECHO) "LINK $@" - $(Q)$(LD) $(LDFLAGS) -o $@ $(APP_LD_ARGS) - $(Q)$(SIZE) $@ - -################################################################################ -# Declarations to build the bootloader - -BOOTLOADER_LIB_DIR = $(BUILD)/bootloader -BOOTLOADER_LIB_ALL = - -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) -$(BUILD)/bootloader/$(ESPCOMP)/%.o: CFLAGS += -DBOOTLOADER_BUILD=1 -I$(ESPCOMP)/bootloader_support/include_priv -I$(ESPCOMP)/bootloader_support/include -I$(ESPCOMP)/efuse/include -I$(ESPCOMP)/esp_rom/include -Wno-error=format \ - -I$(ESPCOMP)/esp_common/include \ - -I$(ESPCOMP)/xtensa/include \ - -I$(ESPCOMP)/xtensa/esp32/include -else -$(BUILD)/bootloader/$(ESPCOMP)/%.o: CFLAGS += -DBOOTLOADER_BUILD=1 -I$(ESPCOMP)/bootloader_support/include_priv -I$(ESPCOMP)/bootloader_support/include -I$(ESPCOMP)/micro-ecc/micro-ecc -I$(ESPCOMP)/efuse/include -I$(ESPCOMP)/esp32 -Wno-error=format -endif - -# libbootloader_support.a -BOOTLOADER_LIB_ALL += bootloader_support -BOOTLOADER_LIB_BOOTLOADER_SUPPORT_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ - bootloader_support/src/bootloader_clock.o \ - bootloader_support/src/bootloader_common.o \ - bootloader_support/src/bootloader_flash.o \ - bootloader_support/src/bootloader_flash_config.o \ - bootloader_support/src/bootloader_init.o \ - bootloader_support/src/bootloader_random.o \ - bootloader_support/src/bootloader_utility.o \ - bootloader_support/src/flash_qio_mode.o \ - bootloader_support/src/esp_image_format.o \ - bootloader_support/src/flash_encrypt.o \ - bootloader_support/src/flash_partitions.o \ - ) - -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) -BOOTLOADER_LIB_BOOTLOADER_SUPPORT_OBJ += $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ - bootloader_support/src/esp32/bootloader_sha.o \ - bootloader_support/src/bootloader_flash_config.o \ - bootloader_support/src/esp32/secure_boot.o \ - ) -else -BOOTLOADER_LIB_BOOTLOADER_SUPPORT_OBJ += $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ - bootloader_support/src/bootloader_sha.o \ - bootloader_support/src/secure_boot_signatures.o \ - bootloader_support/src/secure_boot.o \ - ) -endif - -$(BOOTLOADER_LIB_DIR)/libbootloader_support.a: $(BOOTLOADER_LIB_BOOTLOADER_SUPPORT_OBJ) - $(ECHO) "AR $@" - $(Q)$(AR) cr $@ $^ - -# liblog.a -BOOTLOADER_LIB_ALL += log -BOOTLOADER_LIB_LOG_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ - log/log.o \ - ) -$(BOOTLOADER_LIB_DIR)/liblog.a: $(BOOTLOADER_LIB_LOG_OBJ) - $(ECHO) "AR $@" - $(Q)$(AR) cr $@ $^ - -# libspi_flash.a -BOOTLOADER_LIB_ALL += spi_flash -BOOTLOADER_LIB_SPI_FLASH_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ - spi_flash/spi_flash_rom_patch.o \ - ) -$(BOOTLOADER_LIB_DIR)/libspi_flash.a: $(BOOTLOADER_LIB_SPI_FLASH_OBJ) - $(ECHO) "AR $@" - $(Q)$(AR) cr $@ $^ - -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V3)) -# libmicro-ecc.a -BOOTLOADER_LIB_ALL += micro-ecc -BOOTLOADER_LIB_MICRO_ECC_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ - micro-ecc/micro-ecc/uECC.o \ - ) -$(BOOTLOADER_LIB_DIR)/libmicro-ecc.a: $(BOOTLOADER_LIB_MICRO_ECC_OBJ) - $(ECHO) "AR $@" - $(Q)$(AR) cr $@ $^ -endif - -# libsoc.a -$(BUILD)/bootloader/$(ESPCOMP)/soc/esp32/rtc_clk.o: CFLAGS += -fno-jump-tables -fno-tree-switch-conversion -BOOTLOADER_LIB_ALL += soc -BOOTLOADER_LIB_SOC_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/soc/,\ - esp32/cpu_util.o \ - esp32/gpio_periph.o \ - esp32/rtc_clk.o \ - esp32/rtc_clk_init.o \ - esp32/rtc_init.o \ - esp32/rtc_periph.o \ - esp32/rtc_pm.o \ - esp32/rtc_sleep.o \ - esp32/rtc_time.o \ - esp32/rtc_wdt.o \ - esp32/sdio_slave_periph.o \ - esp32/sdmmc_periph.o \ - esp32/soc_memory_layout.o \ - esp32/spi_periph.o \ - src/memory_layout_utils.o \ - ) -$(BOOTLOADER_LIB_DIR)/libsoc.a: $(BOOTLOADER_LIB_SOC_OBJ) - $(ECHO) "AR $@" - $(Q)$(AR) cr $@ $^ - -# libmain.a -BOOTLOADER_LIB_ALL += main -BOOTLOADER_LIB_MAIN_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ - bootloader/subproject/main/bootloader_start.o \ - ) -$(BOOTLOADER_LIB_DIR)/libmain.a: $(BOOTLOADER_LIB_MAIN_OBJ) - $(ECHO) "AR $@" - $(Q)$(AR) cr $@ $^ - -# all objects files -BOOTLOADER_OBJ_ALL = \ - $(BOOTLOADER_LIB_BOOTLOADER_SUPPORT_OBJ) \ - $(BOOTLOADER_LIB_LOG_OBJ) \ - $(BOOTLOADER_LIB_SPI_FLASH_OBJ) \ - $(BOOTLOADER_LIB_MICRO_ECC_OBJ) \ - $(BOOTLOADER_LIB_SOC_OBJ) \ - $(BOOTLOADER_LIB_MAIN_OBJ) - -$(BOOTLOADER_OBJ_ALL): $(SDKCONFIG_H) - -BOOTLOADER_LIBS = -BOOTLOADER_LIBS += -Wl,--start-group -BOOTLOADER_LIBS += $(BOOTLOADER_OBJ) -BOOTLOADER_LIBS += -L$(BUILD)/bootloader $(addprefix -l,$(BOOTLOADER_LIB_ALL)) -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) -BOOTLOADER_LIBS += -L$(ESPCOMP)/esp_wifi/lib_esp32 -lrtc -else -BOOTLOADER_LIBS += -L$(ESPCOMP)/esp32/lib -lrtc -endif -BOOTLOADER_LIBS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc -BOOTLOADER_LIBS += -Wl,--end-group - -BOOTLOADER_LDFLAGS = -BOOTLOADER_LDFLAGS += -nostdlib -BOOTLOADER_LDFLAGS += -L$(ESPIDF)/lib -BOOTLOADER_LDFLAGS += -L$(ESPIDF)/ld -BOOTLOADER_LDFLAGS += -u call_user_start_cpu0 -BOOTLOADER_LDFLAGS += -Wl,--gc-sections -BOOTLOADER_LDFLAGS += -static -BOOTLOADER_LDFLAGS += -Wl,-EL -BOOTLOADER_LDFLAGS += -Wl,-Map=$(@:.elf=.map) -Wl,--cref -BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.ld -BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.rom.ld -ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4)) -BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp_rom/esp32/ld/esp32.rom.ld -BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp_rom/esp32/ld/esp32.rom.newlib-funcs.ld -else -BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.ld -BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.spiram_incompatible_fns.ld -endif -BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.peripherals.ld - -BOOTLOADER_OBJ_DIRS = $(sort $(dir $(BOOTLOADER_OBJ_ALL))) -$(BOOTLOADER_OBJ_ALL): | $(BOOTLOADER_OBJ_DIRS) -$(BOOTLOADER_OBJ_DIRS): - $(MKDIR) -p $@ - -$(BUILD)/bootloader/%.o: %.c - $(call compile_c) - -$(BUILD)/bootloader.bin: $(BUILD)/bootloader.elf - $(ECHO) "Create $@" - $(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $< - -$(BUILD)/bootloader.elf: $(BOOTLOADER_OBJ) $(addprefix $(BOOTLOADER_LIB_DIR)/lib,$(addsuffix .a,$(BOOTLOADER_LIB_ALL))) - $(ECHO) "LINK $@" - $(Q)$(CC) $(BOOTLOADER_LDFLAGS) -o $@ $(BOOTLOADER_LIBS) - -################################################################################ -# Declarations to build the partitions - -PYTHON2 ?= python2 - -# Can be overriden by mkconfigboard.mk. -PART_SRC ?= partitions.csv - -$(BUILD)/partitions.bin: $(PART_SRC) - $(ECHO) "Create $@" - $(Q)$(PYTHON2) $(ESPCOMP)/partition_table/gen_esp32part.py -q $< $@ - -################################################################################ - -include $(TOP)/py/mkrules.mk +submodules: + git submodule update --init $(addprefix ../../,$(GIT_SUBMODULES)) diff --git a/ports/esp32/boards/GENERIC/mpconfigboard.mk b/ports/esp32/boards/GENERIC/mpconfigboard.mk deleted file mode 100644 index fc49d2a8c2..0000000000 --- a/ports/esp32/boards/GENERIC/mpconfigboard.mk +++ /dev/null @@ -1 +0,0 @@ -SDKCONFIG += boards/sdkconfig.base diff --git a/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.mk b/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.mk deleted file mode 100644 index 65de5dcd08..0000000000 --- a/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.mk +++ /dev/null @@ -1,5 +0,0 @@ -SDKCONFIG += boards/sdkconfig.base -PART_SRC = partitions-2MiB.csv -FLASH_SIZE = 2MB -FLASH_MODE = dio -FLASH_FREQ = 40m diff --git a/ports/esp32/boards/GENERIC_OTA/mpconfigboard.mk b/ports/esp32/boards/GENERIC_OTA/mpconfigboard.mk deleted file mode 100644 index db6492cac2..0000000000 --- a/ports/esp32/boards/GENERIC_OTA/mpconfigboard.mk +++ /dev/null @@ -1,4 +0,0 @@ -SDKCONFIG += boards/sdkconfig.base -SDKCONFIG += boards/GENERIC_OTA/sdkconfig.board - -PART_SRC = partitions-ota.csv diff --git a/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.mk b/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.mk deleted file mode 100644 index 59aa75f857..0000000000 --- a/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.mk +++ /dev/null @@ -1,2 +0,0 @@ -SDKCONFIG += boards/sdkconfig.base -SDKCONFIG += boards/sdkconfig.spiram diff --git a/ports/esp32/boards/TINYPICO/mpconfigboard.mk b/ports/esp32/boards/TINYPICO/mpconfigboard.mk deleted file mode 100644 index 5c96ec45a7..0000000000 --- a/ports/esp32/boards/TINYPICO/mpconfigboard.mk +++ /dev/null @@ -1,8 +0,0 @@ -FLASH_FREQ = 80m - -SDKCONFIG += boards/sdkconfig.base -SDKCONFIG += boards/sdkconfig.240mhz -SDKCONFIG += boards/sdkconfig.spiram -SDKCONFIG += boards/TINYPICO/sdkconfig.board - -FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py From 26b17fd28a359567788b4bd2fe4a7bbac4c9a69d Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 14 Feb 2021 00:56:58 +1100 Subject: [PATCH 033/174] esp32/boards: Remove old IDF v3 sdkconfig values. IDF v3 is no longer supported with the move to cmake. Signed-off-by: Damien George --- ports/esp32/boards/GENERIC_OTA/sdkconfig.board | 3 --- ports/esp32/boards/sdkconfig.base | 11 ----------- ports/esp32/boards/sdkconfig.ble | 10 ---------- ports/esp32/boards/sdkconfig.spiram | 3 --- 4 files changed, 27 deletions(-) diff --git a/ports/esp32/boards/GENERIC_OTA/sdkconfig.board b/ports/esp32/boards/GENERIC_OTA/sdkconfig.board index ca1f4276f4..d314860cc9 100644 --- a/ports/esp32/boards/GENERIC_OTA/sdkconfig.board +++ b/ports/esp32/boards/GENERIC_OTA/sdkconfig.board @@ -1,6 +1,3 @@ CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-ota.csv" - -# ESP-IDF v3: -CONFIG_APP_ROLLBACK_ENABLE=y diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index de6e42c8f3..e326831a15 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -41,17 +41,6 @@ CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y # ULP coprocessor support CONFIG_ESP32_ULP_COPROC_ENABLED=y -# v3.3-only (renamed in 4.0) -CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y -CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n -CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=n -CONFIG_SUPPORT_STATIC_ALLOCATION=y -CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK=y -CONFIG_PPP_SUPPORT=y -CONFIG_PPP_PAP_SUPPORT=y -CONFIG_PPP_CHAP_SUPPORT=y -CONFIG_ULP_COPROC_ENABLED=y - # For cmake build CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_PARTITION_TABLE_CUSTOM=y diff --git a/ports/esp32/boards/sdkconfig.ble b/ports/esp32/boards/sdkconfig.ble index f714ce4629..5565fd81a8 100644 --- a/ports/esp32/boards/sdkconfig.ble +++ b/ports/esp32/boards/sdkconfig.ble @@ -15,13 +15,3 @@ CONFIG_BT_NIMBLE_MAX_CONNECTIONS=4 CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=y CONFIG_BT_NIMBLE_PINNED_TO_CORE_1=n CONFIG_BT_NIMBLE_PINNED_TO_CORE=0 - -# v3.3-only (renamed in 4.0) -CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y -CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY= -CONFIG_BTDM_CONTROLLER_MODE_BTDM= -CONFIG_BLUEDROID_ENABLED=n -CONFIG_NIMBLE_ENABLED=y -CONFIG_NIMBLE_MAX_CONNECTIONS=4 -CONFIG_NIMBLE_PINNED_TO_CORE_0=n -CONFIG_NIMBLE_PINNED_TO_CORE_1=y diff --git a/ports/esp32/boards/sdkconfig.spiram b/ports/esp32/boards/sdkconfig.spiram index db1a83af8c..5b4ce118b8 100644 --- a/ports/esp32/boards/sdkconfig.spiram +++ b/ports/esp32/boards/sdkconfig.spiram @@ -4,6 +4,3 @@ CONFIG_ESP32_SPIRAM_SUPPORT=y CONFIG_SPIRAM_CACHE_WORKAROUND=y CONFIG_SPIRAM_IGNORE_NOTFOUND=y CONFIG_SPIRAM_USE_MEMMAP=y - -# v3.3-only (renamed in 4.0) -CONFIG_SPIRAM_SUPPORT=y From da2b5fa1c1a569faa0d139d97369cce9c0b55a00 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 14 Feb 2021 01:36:30 +1100 Subject: [PATCH 034/174] esp32/boards: Enable BLE on all boards. BLE was enabled by default on all boards in the existing make build. Signed-off-by: Damien George --- ports/esp32/boards/GENERIC/mpconfigboard.cmake | 6 +++++- ports/esp32/boards/GENERIC_D2WD/mpconfigboard.cmake | 1 + ports/esp32/boards/GENERIC_OTA/mpconfigboard.cmake | 1 + ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake | 1 + ports/esp32/boards/TINYPICO/mpconfigboard.cmake | 1 + ports/esp32/boards/sdkconfig.base | 4 ++++ ports/esp32/main/CMakeLists.txt | 1 + ports/esp32/mpconfigport.h | 6 ++++++ 8 files changed, 20 insertions(+), 1 deletion(-) diff --git a/ports/esp32/boards/GENERIC/mpconfigboard.cmake b/ports/esp32/boards/GENERIC/mpconfigboard.cmake index 8fea524555..f69b05f47b 100644 --- a/ports/esp32/boards/GENERIC/mpconfigboard.cmake +++ b/ports/esp32/boards/GENERIC/mpconfigboard.cmake @@ -1,2 +1,6 @@ -set(SDKCONFIG_DEFAULTS boards/sdkconfig.base) +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.ble +) + set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py) diff --git a/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.cmake index 4e23666f15..686c78df97 100644 --- a/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.cmake +++ b/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.cmake @@ -1,5 +1,6 @@ set(SDKCONFIG_DEFAULTS boards/sdkconfig.base + boards/sdkconfig.ble boards/GENERIC_D2WD/sdkconfig.board ) diff --git a/ports/esp32/boards/GENERIC_OTA/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_OTA/mpconfigboard.cmake index 7b1e146005..ca552d470c 100644 --- a/ports/esp32/boards/GENERIC_OTA/mpconfigboard.cmake +++ b/ports/esp32/boards/GENERIC_OTA/mpconfigboard.cmake @@ -1,5 +1,6 @@ set(SDKCONFIG_DEFAULTS boards/sdkconfig.base + boards/sdkconfig.ble boards/GENERIC_OTA/sdkconfig.board ) diff --git a/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake index bb441d9ebf..2128edb592 100644 --- a/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake +++ b/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake @@ -1,5 +1,6 @@ set(SDKCONFIG_DEFAULTS boards/sdkconfig.base + boards/sdkconfig.ble boards/sdkconfig.spiram ) diff --git a/ports/esp32/boards/TINYPICO/mpconfigboard.cmake b/ports/esp32/boards/TINYPICO/mpconfigboard.cmake index 990e3e035b..5c31f5c600 100644 --- a/ports/esp32/boards/TINYPICO/mpconfigboard.cmake +++ b/ports/esp32/boards/TINYPICO/mpconfigboard.cmake @@ -1,5 +1,6 @@ set(SDKCONFIG_DEFAULTS boards/sdkconfig.base + boards/sdkconfig.ble boards/sdkconfig.240mhz boards/sdkconfig.spiram boards/TINYPICO/sdkconfig.board diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index e326831a15..c84dd606b2 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -45,3 +45,7 @@ CONFIG_ESP32_ULP_COPROC_ENABLED=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" + +# To reduce iRAM usage +CONFIG_ESP32_WIFI_IRAM_OPT=n +CONFIG_ESP32_WIFI_RX_IRAM_OPT=n diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index a46e0112c9..eedf3ae9a5 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -78,6 +78,7 @@ set(MICROPY_SOURCE_QSTR set(IDF_COMPONENTS app_update bootloader_support + bt driver esp32 esp_common diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 81f8297c50..34be9405e4 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -126,6 +126,12 @@ #define MICROPY_PY_THREAD_GIL_VM_DIVISOR (32) // extended modules +#ifndef MICROPY_PY_BLUETOOTH +#define MICROPY_PY_BLUETOOTH (1) +#define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (1) +#define MICROPY_BLUETOOTH_NIMBLE (1) +#define MICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY (1) +#endif #define MICROPY_PY_UASYNCIO (1) #define MICROPY_PY_UCTYPES (1) #define MICROPY_PY_UZLIB (1) From aa3d6b6aa5ec9fdf15b5c2d30a1c9f9c9064cd3c Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 14 Feb 2021 10:28:05 +1100 Subject: [PATCH 035/174] tools/ci.sh: Change esp32 CI to work with idf.py and IDF v4.0.2. Signed-off-by: Damien George --- .github/workflows/ports_esp32.yml | 19 +++------------ tools/ci.sh | 40 ++++++++++--------------------- 2 files changed, 15 insertions(+), 44 deletions(-) diff --git a/.github/workflows/ports_esp32.yml b/.github/workflows/ports_esp32.yml index 041074557e..0ad3f87a25 100644 --- a/.github/workflows/ports_esp32.yml +++ b/.github/workflows/ports_esp32.yml @@ -13,24 +13,11 @@ on: - 'ports/esp32/**' jobs: - idf3_build: + build: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - name: Install packages - run: source tools/ci.sh && ci_esp32_idf3_setup && ci_esp32_idf3_path >> $GITHUB_PATH + run: source tools/ci.sh && ci_esp32_setup - name: Build - env: - IDF_PATH: ${{ github.workspace }}/esp-idf - run: source tools/ci.sh && ci_esp32_idf3_build - - idf4_build: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - name: Install packages - run: source tools/ci.sh && ci_esp32_idf4_setup && ci_esp32_idf4_path >> $GITHUB_PATH - - name: Build - env: - IDF_PATH: ${{ github.workspace }}/esp-idf - run: source tools/ci.sh && ci_esp32_idf4_build + run: source tools/ci.sh && ci_esp32_build diff --git a/tools/ci.sh b/tools/ci.sh index 8661f532ef..4f99551468 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -82,38 +82,22 @@ function ci_cc3200_build { ######################################################################################## # ports/esp32 -function ci_esp32_idf3_setup { - sudo pip3 install pyserial 'pyparsing<2.4' - curl -L https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz | tar zxf - +function ci_esp32_setup { git clone https://github.com/espressif/esp-idf.git + git -C esp-idf checkout v4.0.2 + git -C esp-idf submodule update --init \ + components/bt/controller/lib \ + components/bt/host/nimble/nimble \ + components/esp_wifi/lib_esp32 \ + components/esptool_py/esptool \ + components/lwip/lwip \ + components/mbedtls/mbedtls + ./esp-idf/install.sh } -function ci_esp32_idf3_path { - echo $(pwd)/xtensa-esp32-elf/bin -} - -function ci_esp32_idf3_build { +function ci_esp32_build { + source esp-idf/export.sh make ${MAKEOPTS} -C mpy-cross - git -C esp-idf checkout $(grep "ESPIDF_SUPHASH_V3 :=" ports/esp32/Makefile | cut -d " " -f 3) - git -C esp-idf submodule update --init components/json/cJSON components/esp32/lib components/esptool_py/esptool components/expat/expat components/lwip/lwip components/mbedtls/mbedtls components/micro-ecc/micro-ecc components/nghttp/nghttp2 components/nimble components/bt - make ${MAKEOPTS} -C ports/esp32 submodules - make ${MAKEOPTS} -C ports/esp32 -} - -function ci_esp32_idf4_setup { - sudo pip3 install pyserial 'pyparsing<2.4' - curl -L https://dl.espressif.com/dl/xtensa-esp32-elf-gcc8_2_0-esp-2019r2-linux-amd64.tar.gz | tar zxf - - git clone https://github.com/espressif/esp-idf.git -} - -function ci_esp32_idf4_path { - echo $(pwd)/xtensa-esp32-elf/bin -} - -function ci_esp32_idf4_build { - make ${MAKEOPTS} -C mpy-cross - git -C esp-idf checkout $(grep "ESPIDF_SUPHASH_V4 :=" ports/esp32/Makefile | cut -d " " -f 3) - git -C esp-idf submodule update --init components/bt/controller/lib components/bt/host/nimble/nimble components/esp_wifi/lib_esp32 components/esptool_py/esptool components/lwip/lwip components/mbedtls/mbedtls make ${MAKEOPTS} -C ports/esp32 submodules make ${MAKEOPTS} -C ports/esp32 } From e017f276f7f95c7412b18939ba91784fdc69b734 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 14 Feb 2021 17:51:31 +1100 Subject: [PATCH 036/174] esp32/README: Update based on new IDF v4 cmake build process. Signed-off-by: Damien George --- ports/esp32/README.md | 247 +++++++++++++----------------------------- 1 file changed, 77 insertions(+), 170 deletions(-) diff --git a/ports/esp32/README.md b/ports/esp32/README.md index 54fb41cf6f..4f63750593 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -1,13 +1,13 @@ MicroPython port to the ESP32 ============================= -This is an experimental port of MicroPython to the Espressif ESP32 -microcontroller. It uses the ESP-IDF framework and MicroPython runs as +This is a port of MicroPython to the Espressif ESP32 series of +microcontrollers. It uses the ESP-IDF framework and MicroPython runs as a task under FreeRTOS. Supported features include: - REPL (Python prompt) over UART0. -- 16k stack for the MicroPython task and 96k Python heap. +- 16k stack for the MicroPython task and approximately 100k Python heap. - Many of MicroPython's features are enabled: unicode, arbitrary-precision integers, single-precision floats, complex numbers, frozen bytecode, as well as many of the internal modules. @@ -15,16 +15,24 @@ Supported features include: - The machine module with GPIO, UART, SPI, software I2C, ADC, DAC, PWM, TouchPad, WDT and Timer. - The network module with WLAN (WiFi) support. +- Bluetooth low-energy (BLE) support via the bluetooth module. -Development of this ESP32 port was sponsored in part by Microbric Pty Ltd. +Initial development of this ESP32 port was sponsored in part by Microbric Pty Ltd. -Setting up the toolchain and ESP-IDF ------------------------------------- +Setting up ESP-IDF and the build environment +-------------------------------------------- -There are two main components that are needed to build the firmware: -- the Xtensa cross-compiler that targets the CPU in the ESP32 (this is - different to the compiler used by the ESP8266) -- the Espressif IDF (IoT development framework, aka SDK) +MicroPython on ESP32 requires the Espressif IDF version 4 (IoT development +framework, aka SDK). The ESP-IDF includes the libraries and RTOS needed to +manage the ESP32 microcontroller, as well as a way to manage the required +build environment and toolchains needed to build the firmware. + +The ESP-IDF changes quickly and MicroPython only supports certain versions. +Currently MicroPython supports v4.0.2, although other IDF v4 versions may also +work. + +To install the ESP-IDF the full instructions can be found at the +[Espressif Getting Started guide](https://docs.espressif.com/projects/esp-idf/en/v4.0.2/get-started/index.html#installation-step-by-step). If you are on a Windows machine then the [Windows Subsystem for Linux](https://msdn.microsoft.com/en-au/commandline/wsl/install_guide) is the @@ -32,164 +40,31 @@ most efficient way to install the ESP32 toolchain and build the project. If you use WSL then follow the Linux instructions rather than the Windows instructions. -The ESP-IDF changes quickly and MicroPython only supports certain versions. -The git hash of these versions (one for 3.x, one for 4.x) can be found by -running `make` without a configured `ESPIDF`. Then you can fetch the -required IDF using the following command: +The Espressif instructions will guide you through using the `install.sh` +(or `install.bat`) script to download the toolchain and set up your environment. +The steps to take are summarised below. + +To check out a copy of the IDF use git clone: ```bash -$ cd ports/esp32 -$ make ESPIDF= # This will print the supported hashes, copy the one you want. -$ export ESPIDF=$HOME/src/github.com/espressif/esp-idf # Or any path you like. -$ mkdir -p $ESPIDF -$ cd $ESPIDF -$ git clone https://github.com/espressif/esp-idf.git $ESPIDF -$ git checkout -$ git submodule update --init --recursive +$ git clone -b v4.0.2 --recursive https://github.com/espressif/esp-idf.git ``` -Note: The ESP IDF v4.x support is currently experimental. It does not -currently support PPP or wired Ethernet. +(You don't need a full recursive clone; see the `ci_esp32_setup` function in +`tools/ci.sh` in this repository for more detailed set-up commands.) -Python dependencies -=================== - -You will also need other dependencies from the IDF, see -`$ESPIDF/requirements.txt`, but at a minimum you need `pyserial>=3.0` and -`pyparsing>=2.0.3,<2.4.0`. - -You can use Python 2 or Python 3. If you need to override the system default -add (for example) `PYTHON=python3` to any of the `make` commands below. - -It is recommended to use a Python virtual environment. Even if your system -package manager already provides these libraries, the IDF v4.x is currently -incompatible with pyparsing 2.4 and higher. - -For example, to set up a Python virtual environment from scratch: +After you've cloned and checked out the IDF to the correct version, run the +`install.sh` script: ```bash -$ cd ports/esp32 -$ python3 -m venv build-venv -$ source build-venv/bin/activate -$ pip install --upgrade pip -$ pip install -r path/to/esp-idf/requirements.txt -``` - -To re-enter this virtual environment in future sessions, you only need to -source the `activate` script, i.e.: - -```bash -$ cd ports/esp32 -$ source build-venv/bin/activate -``` - -Then, to install the toolchain (which includes the GCC compiler, linker, binutils, -etc), there are two options: - -1. Using the IDF scripts to install the toolchain (IDF 4.x only) -================================================================ - -Follow the steps at the [Espressif Getting Started guide](https://docs.espressif.com/projects/esp-idf/en/v4.0/get-started/index.html#step-3-set-up-the-tools). - -This will guide you through using the `install.sh` (or `install.bat`) script -to download the toolchain and add it to your `PATH`. The steps are summarised -below: - -After you've cloned and checked out the IDF to the correct version (see -above), run the `install.sh` script: - -```bash -$ cd $ESPIDF -$ ./install.sh # (or install.bat on Windows) -``` - -Then in the `ports/esp32` directory, source the `export.sh` script to set the -`PATH`. - -```bash -$ cd micropython/ports/esp32 -$ source $ESPIDF/export.sh # (or path\to\esp-idf\export.bat on Windows) -$ # Run make etc, see below. +$ cd esp-idf +$ ./install.sh # (or install.bat on Windows) +$ source export.sh # (or export.bat on Windows) ``` The `install.sh` step only needs to be done once. You will need to source `export.sh` for every new session. -Note: If you get an error about `--no-site-packages`, then modify -`$ESPIDF/tools/idf_tools.py` and make the same change as [this -commit](https://github.com/espressif/esp-idf/commit/7a18f02acd7005f7c56e62175a8d1968a1a9019d). - -2. or, Downloading pre-built toolchain manually (IDF 3.x and 4.x) -============================================================= - -Note: while this works with 4.x, if you're using the 4.x IDF, it's much -simpler to use the guide above, which will also get a more recent version of -the toolchain. - -You can follow the 3.x guide at: - - * [Linux installation](https://docs.espressif.com/projects/esp-idf/en/v3.3.2/get-started/linux-setup.html) - * [MacOS installation](https://docs.espressif.com/projects/esp-idf/en/v3.3.2/get-started/macos-setup.html) - * [Windows installation](https://docs.espressif.com/projects/esp-idf/en/v3.3.2/get-started/windows-setup.html) - -You will need to update your `PATH` environment variable to include the ESP32 -toolchain. For example, you can issue the following commands on (at least) -Linux: - - $ export PATH=$PATH:$HOME/esp/crosstool-NG/builds/xtensa-esp32-elf/bin - -You can put this command in your `.profile` or `.bash_login`, or do it manually. - -Configuring the MicroPython build ---------------------------------- - -You then need to set the `ESPIDF` environment/makefile variable to point to -the root of the ESP-IDF repository. The recommended way to do this is to have -a custom `makefile` in `ports/esp32` which sets any additional variables, then -includes the main `Makefile`. Note that GNU Make will preferentially run -`GNUmakefile`, then `makefile`, then `Makefile`, which is what allows this to -work. On case-insensitive filesystems, you'll need to use `GNUmakefile` rather -than `makefile`. - -Create a new file in the esp32 directory called `makefile` (or `GNUmakefile`) -and add the following lines to that file: - -``` -ESPIDF ?= -BOARD ?= GENERIC -#PORT ?= /dev/ttyUSB0 -#FLASH_MODE ?= qio -#FLASH_SIZE ?= 4MB -#CROSS_COMPILE ?= xtensa-esp32-elf- - -include Makefile -``` - -Be sure to enter the correct path to your local copy of the IDF repository -(and use `$(HOME)`, not tilde (`~`), to reference your home directory). - -If the Xtensa cross-compiler is not in your path you can use the -`CROSS_COMPILE` variable to set its location. Other options of interest are -`PORT` for the serial port of your ESP32 module, and `FLASH_MODE` (which may -need to be `dio` for some modules) and `FLASH_SIZE`. See the Makefile for -further information. - -The default ESP IDF configuration settings are provided by the `GENERIC` -board definition in the directory `boards/GENERIC`. For a custom configuration -you can define your own board directory. - -Any of these variables can also be set on the make command line, e.g. to set -the `BOARD` variable, use: - -```bash -$ make BOARD=TINYPICO -``` - -Note the use of `?=` in the `makefile` which allows them to be overridden on -the command line. There is also a `GENERIC_SPIRAM` board for for ESP32 -modules that have external SPIRAM, but prefer to use a specific board target -(or define your own as necessary). - Building the firmware --------------------- @@ -198,8 +73,7 @@ built-in scripts to bytecode. This can be done by (from the root of this repository): ```bash -$ cd mpy-cross -$ make mpy-cross +$ make -C mpy-cross ``` Then to build MicroPython for the ESP32 run: @@ -210,16 +84,14 @@ $ make submodules $ make ``` -This will produce binary firmware images in the `build/` subdirectory -(three of them: bootloader.bin, partitions.bin and application.bin). +This will produce a combined `firmware.bin` image in the `build-GENERIC/` +subdirectory (this firmware image is made up of: bootloader.bin, partitions.bin +and micropython.bin). To flash the firmware you must have your ESP32 module in the bootloader mode and connected to a serial port on your PC. Refer to the documentation -for your particular ESP32 module for how to do this. The serial port and -flash settings are set in the `Makefile`, and can be overridden in your -local `makefile`; see above for more details. - -You will also need to have user permissions to access the /dev/ttyUSB0 device. +for your particular ESP32 module for how to do this. +You will also need to have user permissions to access the `/dev/ttyUSB0` device. On Linux, you can enable this by adding your user to the `dialout` group, and rebooting or logging out and in again. (Note: on some distributions this may be the `uucp` group, run `ls -la /dev/ttyUSB0` to check.) @@ -242,8 +114,23 @@ To flash the MicroPython firmware to your ESP32 use: $ make deploy ``` -This will use the `esptool.py` script (provided by ESP-IDF) to flash the -binary images to the device. +The default ESP32 board build by the above commands is the `GENERIC` one, which +should work on most ESP32 modules. You can specify a different board by passing +`BOARD=` to the make commands, for example: + +```bash +$ make BOARD=GENERIC_SPIRAM +``` + +Note: the above "make" commands are thin wrappers for the underlying `idf.py` +build tool that is part of the ESP-IDF. You can instead use `idf.py` directly, +for example: + +```bash +$ idf.py build +$ idf.py -D MICROPY_BOARD=GENERIC_SPIRAM build +$ idf.py flash +``` Getting a Python prompt on the device ------------------------------------- @@ -262,6 +149,8 @@ or $ miniterm.py /dev/ttyUSB0 115200 ``` +You can also use `idf.py monitor`. + Configuring the WiFi and using the board ---------------------------------------- @@ -301,9 +190,27 @@ import machine antenna = machine.Pin(16, machine.Pin.OUT, value=0) ``` +Defining a custom ESP32 board +----------------------------- + +The default ESP-IDF configuration settings are provided by the `GENERIC` +board definition in the directory `boards/GENERIC`. For a custom configuration +you can define your own board directory. Start a new board configuration by +copying an existing one (like `GENERIC`) and modifying it to suit your board. + +MicroPython specific configuration values are defined in the board-specific +`mpconfigboard.h` file, which is included by `mpconfigport.h`. Additional +settings are put in `mpconfigboard.cmake`, including a list of `sdkconfig` +files that configure ESP-IDF settings. Some standard `sdkconfig` files are +provided in the `boards/` directory, like `boards/sdkconfig.ble`. You can +also define custom ones in your board directory. + +See existing board definitions for further examples of configuration. + +Configuration Troubleshooting --------------- -* Continuous reboots after programming: Ensure FLASH_MODE is correct for your - board (e.g. ESP-WROOM-32 should be DIO). Then perform a `make clean`, rebuild, - redeploy. +* Continuous reboots after programming: Ensure `CONFIG_ESPTOOLPY_FLASHMODE` is + correct for your board (e.g. ESP-WROOM-32 should be DIO). Then perform a + `make clean`, rebuild, redeploy. From d191d88cabec9bf328f6f46b11ce6642af70cfc7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 15 Feb 2021 21:00:01 +1100 Subject: [PATCH 037/174] esp32: Add support to build with ESP-IDF v4.1.1. ESP-IDF v4.0.2 is still supported. Signed-off-by: Damien George --- ports/esp32/README.md | 5 +++-- ports/esp32/machine_uart.c | 38 ++++++++++++++++++++++----------- ports/esp32/main/CMakeLists.txt | 4 ++++ ports/esp32/modnetwork.c | 13 +++++++---- ports/esp32/modsocket.c | 6 +++++- ports/esp32/uart.c | 1 + 6 files changed, 48 insertions(+), 19 deletions(-) diff --git a/ports/esp32/README.md b/ports/esp32/README.md index 4f63750593..d8818ccadb 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -28,8 +28,8 @@ manage the ESP32 microcontroller, as well as a way to manage the required build environment and toolchains needed to build the firmware. The ESP-IDF changes quickly and MicroPython only supports certain versions. -Currently MicroPython supports v4.0.2, although other IDF v4 versions may also -work. +Currently MicroPython supports v4.0.2 and v4.1.1, +although other IDF v4 versions may also work. To install the ESP-IDF the full instructions can be found at the [Espressif Getting Started guide](https://docs.espressif.com/projects/esp-idf/en/v4.0.2/get-started/index.html#installation-step-by-step). @@ -50,6 +50,7 @@ To check out a copy of the IDF use git clone: $ git clone -b v4.0.2 --recursive https://github.com/espressif/esp-idf.git ``` +You can replace `v4.0.2` with `v4.1.1` or any other supported version. (You don't need a full recursive clone; see the `ci_esp32_setup` function in `tools/ci.sh` in this repository for more detailed set-up commands.) diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c index c334e694b2..7fce83f2c4 100644 --- a/ports/esp32/machine_uart.c +++ b/ports/esp32/machine_uart.c @@ -36,6 +36,20 @@ #include "py/mperrno.h" #include "modmachine.h" +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0) +#define UART_INV_TX UART_INVERSE_TXD +#define UART_INV_RX UART_INVERSE_RXD +#define UART_INV_RTS UART_INVERSE_RTS +#define UART_INV_CTS UART_INVERSE_CTS +#else +#define UART_INV_TX UART_SIGNAL_TXD_INV +#define UART_INV_RX UART_SIGNAL_RXD_INV +#define UART_INV_RTS UART_SIGNAL_RTS_INV +#define UART_INV_CTS UART_SIGNAL_CTS_INV +#endif + +#define UART_INV_MASK (UART_INV_TX | UART_INV_RX | UART_INV_RTS | UART_INV_CTS) + typedef struct _machine_uart_obj_t { mp_obj_base_t base; uart_port_t uart_num; @@ -68,28 +82,28 @@ STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_pri if (self->invert) { mp_printf(print, ", invert="); uint32_t invert_mask = self->invert; - if (invert_mask & UART_INVERSE_TXD) { + if (invert_mask & UART_INV_TX) { mp_printf(print, "INV_TX"); - invert_mask &= ~UART_INVERSE_TXD; + invert_mask &= ~UART_INV_TX; if (invert_mask) { mp_printf(print, "|"); } } - if (invert_mask & UART_INVERSE_RXD) { + if (invert_mask & UART_INV_RX) { mp_printf(print, "INV_RX"); - invert_mask &= ~UART_INVERSE_RXD; + invert_mask &= ~UART_INV_RX; if (invert_mask) { mp_printf(print, "|"); } } - if (invert_mask & UART_INVERSE_RTS) { + if (invert_mask & UART_INV_RTS) { mp_printf(print, "INV_RTS"); - invert_mask &= ~UART_INVERSE_RTS; + invert_mask &= ~UART_INV_RTS; if (invert_mask) { mp_printf(print, "|"); } } - if (invert_mask & UART_INVERSE_CTS) { + if (invert_mask & UART_INV_CTS) { mp_printf(print, "INV_CTS"); } } @@ -238,7 +252,7 @@ STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, co } // set line inversion - if (args[ARG_invert].u_int & ~UART_LINE_INV_MASK) { + if (args[ARG_invert].u_int & ~UART_INV_MASK) { mp_raise_ValueError(MP_ERROR_TEXT("invalid inversion mask")); } self->invert = args[ARG_invert].u_int; @@ -380,10 +394,10 @@ STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&machine_uart_sendbreak_obj) }, - { MP_ROM_QSTR(MP_QSTR_INV_TX), MP_ROM_INT(UART_INVERSE_TXD) }, - { MP_ROM_QSTR(MP_QSTR_INV_RX), MP_ROM_INT(UART_INVERSE_RXD) }, - { MP_ROM_QSTR(MP_QSTR_INV_RTS), MP_ROM_INT(UART_INVERSE_RTS) }, - { MP_ROM_QSTR(MP_QSTR_INV_CTS), MP_ROM_INT(UART_INVERSE_CTS) }, + { MP_ROM_QSTR(MP_QSTR_INV_TX), MP_ROM_INT(UART_INV_TX) }, + { MP_ROM_QSTR(MP_QSTR_INV_RX), MP_ROM_INT(UART_INV_RX) }, + { MP_ROM_QSTR(MP_QSTR_INV_RTS), MP_ROM_INT(UART_INV_RTS) }, + { MP_ROM_QSTR(MP_QSTR_INV_CTS), MP_ROM_INT(UART_INV_CTS) }, }; STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table); diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index eedf3ae9a5..2455a4cdd2 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -104,6 +104,10 @@ set(IDF_COMPONENTS xtensa ) +if(IDF_VERSION_MINOR GREATER_EQUAL 1) + list(APPEND IDF_COMPONENTS esp_netif) +endif() + # Register the main IDF component. idf_component_register( SRCS diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index d981b60805..f772fa2cf6 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -45,7 +45,6 @@ #include "esp_wifi.h" #include "esp_log.h" #include "lwip/dns.h" -#include "tcpip_adapter.h" #include "mdns.h" #if !MICROPY_ESP_IDF_4 @@ -55,6 +54,12 @@ #include "modnetwork.h" +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0) +#define DNS_MAIN TCPIP_ADAPTER_DNS_MAIN +#else +#define DNS_MAIN ESP_NETIF_DNS_MAIN +#endif + #define MODNETWORK_INCLUDE_CONSTANTS (1) NORETURN void _esp_exceptions(esp_err_t e) { @@ -491,7 +496,7 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { tcpip_adapter_ip_info_t info; tcpip_adapter_dns_info_t dns_info; tcpip_adapter_get_ip_info(self->if_id, &info); - tcpip_adapter_get_dns_info(self->if_id, TCPIP_ADAPTER_DNS_MAIN, &dns_info); + tcpip_adapter_get_dns_info(self->if_id, DNS_MAIN, &dns_info); if (n_args == 1) { // get mp_obj_t tuple[4] = { @@ -526,14 +531,14 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { _esp_exceptions(e); } ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(self->if_id, &info)); - ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(self->if_id, TCPIP_ADAPTER_DNS_MAIN, &dns_info)); + ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(self->if_id, DNS_MAIN, &dns_info)); } else if (self->if_id == WIFI_IF_AP) { esp_err_t e = tcpip_adapter_dhcps_stop(WIFI_IF_AP); if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) { _esp_exceptions(e); } ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(WIFI_IF_AP, &info)); - ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(WIFI_IF_AP, TCPIP_ADAPTER_DNS_MAIN, &dns_info)); + ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(WIFI_IF_AP, DNS_MAIN, &dns_info)); ESP_EXCEPTIONS(tcpip_adapter_dhcps_start(WIFI_IF_AP)); } } else { diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 85433e575f..8a4cf3e165 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -46,7 +46,6 @@ #include "py/stream.h" #include "py/mperrno.h" #include "lib/netutils/netutils.h" -#include "tcpip_adapter.h" #include "mdns.h" #include "modnetwork.h" @@ -181,7 +180,12 @@ static int _socket_getaddrinfo3(const char *nodename, const char *servname, memcpy(nodename_no_local, nodename, nodename_len - local_len); nodename_no_local[nodename_len - local_len] = '\0'; + #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0) struct ip4_addr addr = {0}; + #else + esp_ip4_addr_t addr = {0}; + #endif + esp_err_t err = mdns_query_a(nodename_no_local, MDNS_QUERY_TIMEOUT_MS, &addr); if (err != ESP_OK) { if (err == ESP_ERR_NOT_FOUND) { diff --git a/ports/esp32/uart.c b/ports/esp32/uart.c index 381be7f4f0..c837c8dcfe 100644 --- a/ports/esp32/uart.c +++ b/ports/esp32/uart.c @@ -29,6 +29,7 @@ #include #include "driver/uart.h" +#include "soc/uart_periph.h" #include "py/runtime.h" #include "py/mphal.h" From a91500217757d9f7dc9791f014cfb465955f7d42 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 15 Feb 2021 21:00:09 +1100 Subject: [PATCH 038/174] esp32: Add support to build with ESP-IDF v4.2. Signed-off-by: Damien George --- ports/esp32/README.md | 2 +- ports/esp32/main/CMakeLists.txt | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ports/esp32/README.md b/ports/esp32/README.md index d8818ccadb..c349f44b27 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -28,7 +28,7 @@ manage the ESP32 microcontroller, as well as a way to manage the required build environment and toolchains needed to build the firmware. The ESP-IDF changes quickly and MicroPython only supports certain versions. -Currently MicroPython supports v4.0.2 and v4.1.1, +Currently MicroPython supports v4.0.2, v4.1.1 and v4.2, although other IDF v4 versions may also work. To install the ESP-IDF the full instructions can be found at the diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index 2455a4cdd2..52985383f9 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -108,6 +108,11 @@ if(IDF_VERSION_MINOR GREATER_EQUAL 1) list(APPEND IDF_COMPONENTS esp_netif) endif() +if(IDF_VERSION_MINOR GREATER_EQUAL 2) + list(APPEND IDF_COMPONENTS esp_system) + list(APPEND IDF_COMPONENTS esp_timer) +endif() + # Register the main IDF component. idf_component_register( SRCS @@ -169,5 +174,12 @@ foreach(comp ${IDF_COMPONENTS}) endif() endforeach() +if(IDF_VERSION_MINOR GREATER_EQUAL 2) + # These paths cannot currently be found by the IDF_COMPONENTS search loop above, + # so add them explicitly. + list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/soc/soc/${IDF_TARGET}/include) + list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/soc/soc/include) +endif() + # Include the main MicroPython cmake rules. include(${MICROPY_DIR}/py/mkrules.cmake) From f12462ddc4cd847896a38412539a49ccb0579c94 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 15 Feb 2021 23:22:05 +1100 Subject: [PATCH 039/174] esp32: Remove obsolete IDF v3 code wrapped in MICROPY_ESP_IDF_4. Signed-off-by: Damien George --- ports/esp32/esp32_ulp.c | 4 ---- ports/esp32/main.c | 4 ---- ports/esp32/modesp.c | 3 --- ports/esp32/modmachine.c | 6 ------ ports/esp32/modsocket.c | 12 ------------ ports/esp32/mpconfigport.h | 4 ---- ports/esp32/mphalport.c | 5 ----- ports/esp32/mpthreadport.c | 3 --- 8 files changed, 41 deletions(-) diff --git a/ports/esp32/esp32_ulp.c b/ports/esp32/esp32_ulp.c index 4e9d768146..50244cdf25 100644 --- a/ports/esp32/esp32_ulp.c +++ b/ports/esp32/esp32_ulp.c @@ -85,11 +85,7 @@ STATIC const mp_rom_map_elem_t esp32_ulp_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_set_wakeup_period), MP_ROM_PTR(&esp32_ulp_set_wakeup_period_obj) }, { MP_ROM_QSTR(MP_QSTR_load_binary), MP_ROM_PTR(&esp32_ulp_load_binary_obj) }, { MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&esp32_ulp_run_obj) }, - #if !MICROPY_ESP_IDF_4 - { MP_ROM_QSTR(MP_QSTR_RESERVE_MEM), MP_ROM_INT(CONFIG_ULP_COPROC_RESERVE_MEM) }, - #else { MP_ROM_QSTR(MP_QSTR_RESERVE_MEM), MP_ROM_INT(CONFIG_ESP32_ULP_COPROC_RESERVE_MEM) }, - #endif }; STATIC MP_DEFINE_CONST_DICT(esp32_ulp_locals_dict, esp32_ulp_locals_dict_table); diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 6f9ab82d05..001f2beaeb 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -37,11 +37,7 @@ #include "esp_task.h" #include "soc/cpu.h" #include "esp_log.h" -#if MICROPY_ESP_IDF_4 #include "esp32/spiram.h" -#else -#include "esp_spiram.h" -#endif #include "py/stackctrl.h" #include "py/nlr.h" diff --git a/ports/esp32/modesp.c b/ports/esp32/modesp.c index 369649c119..59a261e8c2 100644 --- a/ports/esp32/modesp.c +++ b/ports/esp32/modesp.c @@ -29,9 +29,6 @@ #include -#if !MICROPY_ESP_IDF_4 -#include "rom/gpio.h" -#endif #include "esp_log.h" #include "esp_spi_flash.h" diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index 303d25ee8b..bb346ea1cd 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -32,15 +32,9 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#if MICROPY_ESP_IDF_4 #include "esp32/rom/rtc.h" #include "esp32/clk.h" #include "esp_sleep.h" -#else -#include "rom/ets_sys.h" -#include "rom/rtc.h" -#include "esp_clk.h" -#endif #include "esp_pm.h" #include "driver/touch_pad.h" diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 8a4cf3e165..ce7a714eb2 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -55,18 +55,6 @@ #include "lwip/igmp.h" #include "esp_log.h" -#if !MICROPY_ESP_IDF_4 -#define lwip_bind lwip_bind_r -#define lwip_listen lwip_listen_r -#define lwip_accept lwip_accept_r -#define lwip_setsockopt lwip_setsockopt_r -#define lwip_fnctl lwip_fnctl_r -#define lwip_recvfrom lwip_recvfrom_r -#define lwip_write lwip_write_r -#define lwip_sendto lwip_sendto_r -#define lwip_close lwip_close_r -#endif - #define SOCKET_POLL_US (100000) #define MDNS_QUERY_TIMEOUT_MS (5000) #define MDNS_LOCAL_SUFFIX ".local" diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 34be9405e4..7b0a00250b 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -8,10 +8,6 @@ #include #include "esp_system.h" -#if !MICROPY_ESP_IDF_4 -#include "rom/ets_sys.h" -#endif - // object representation and NLR handling #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A) #define MICROPY_NLR_SETJMP (1) diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index 5403382684..65fa88e4d0 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -32,12 +32,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" - -#if MICROPY_ESP_IDF_4 #include "esp32/rom/uart.h" -#else -#include "rom/uart.h" -#endif #include "py/obj.h" #include "py/objstr.h" diff --git a/ports/esp32/mpthreadport.c b/ports/esp32/mpthreadport.c index d294c92727..140a76464f 100644 --- a/ports/esp32/mpthreadport.c +++ b/ports/esp32/mpthreadport.c @@ -34,9 +34,6 @@ #include "mpthreadport.h" #include "esp_task.h" -#if !MICROPY_ESP_IDF_4 -#include "freertos/semphr.h" -#endif #if MICROPY_PY_THREAD From 771376a0cb26c7a74554ff421feff9c92eadceeb Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Sat, 24 Oct 2020 12:34:23 -0700 Subject: [PATCH 040/174] esp32/modsocket: Remove unix socket error code translation. The ESP-IDF has its own errno codes which should propagate out to the user. --- ports/esp32/modsocket.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index ce7a714eb2..61761d8194 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -140,16 +140,6 @@ void usocket_events_handler(void) { #endif // MICROPY_PY_USOCKET_EVENTS -NORETURN static void exception_from_errno(int _errno) { - // Here we need to convert from lwip errno values to MicroPython's standard ones - if (_errno == EADDRINUSE) { - _errno = MP_EADDRINUSE; - } else if (_errno == EINPROGRESS) { - _errno = MP_EINPROGRESS; - } - mp_raise_OSError(_errno); -} - static inline void check_for_exceptions(void) { mp_handle_pending(true); } @@ -277,7 +267,7 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, siz sock->fd = lwip_socket(sock->domain, sock->type, sock->proto); if (sock->fd < 0) { - exception_from_errno(errno); + mp_raise_OSError(errno); } _socket_settimeout(sock, UINT64_MAX); @@ -291,7 +281,7 @@ STATIC mp_obj_t socket_bind(const mp_obj_t arg0, const mp_obj_t arg1) { int r = lwip_bind(self->fd, res->ai_addr, res->ai_addrlen); lwip_freeaddrinfo(res); if (r < 0) { - exception_from_errno(errno); + mp_raise_OSError(errno); } return mp_const_none; } @@ -302,7 +292,7 @@ STATIC mp_obj_t socket_listen(const mp_obj_t arg0, const mp_obj_t arg1) { int backlog = mp_obj_get_int(arg1); int r = lwip_listen(self->fd, backlog); if (r < 0) { - exception_from_errno(errno); + mp_raise_OSError(errno); } return mp_const_none; } @@ -323,7 +313,7 @@ STATIC mp_obj_t socket_accept(const mp_obj_t arg0) { break; } if (errno != EAGAIN) { - exception_from_errno(errno); + mp_raise_OSError(errno); } check_for_exceptions(); } @@ -365,7 +355,7 @@ STATIC mp_obj_t socket_connect(const mp_obj_t arg0, const mp_obj_t arg1) { MP_THREAD_GIL_ENTER(); lwip_freeaddrinfo(res); if (r != 0) { - exception_from_errno(errno); + mp_raise_OSError(errno); } return mp_const_none; @@ -384,7 +374,7 @@ STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { int val = mp_obj_get_int(args[3]); int ret = lwip_setsockopt(self->fd, SOL_SOCKET, opt, &val, sizeof(int)); if (ret != 0) { - exception_from_errno(errno); + mp_raise_OSError(errno); } break; } @@ -535,7 +525,7 @@ mp_obj_t _socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in, int errcode; mp_uint_t ret = _socket_read_data(self_in, vstr.buf, len, from, from_len, &errcode); if (ret == MP_STREAM_ERROR) { - exception_from_errno(errcode); + mp_raise_OSError(errcode); } vstr.len = ret; @@ -569,7 +559,7 @@ int _socket_send(socket_obj_t *sock, const char *data, size_t datalen) { int r = lwip_write(sock->fd, data + sentlen, datalen - sentlen); MP_THREAD_GIL_ENTER(); if (r < 0 && errno != EWOULDBLOCK) { - exception_from_errno(errno); + mp_raise_OSError(errno); } if (r > 0) { sentlen += r; @@ -627,7 +617,7 @@ STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_ return mp_obj_new_int_from_uint(ret); } if (ret == -1 && errno != EWOULDBLOCK) { - exception_from_errno(errno); + mp_raise_OSError(errno); } check_for_exceptions(); } From 902da05a180d40e62373656f8be94a01ca39eb94 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Wed, 11 Nov 2020 17:46:18 -0800 Subject: [PATCH 041/174] esp32: Set MICROPY_USE_INTERNAL_ERRNO=0 to use toolchain's errno.h. The underlying OS (the ESP-IDF) uses it's own internal errno codes and so it's simpler and cleaner to use those rather than trying to convert everything to the values defined in py/mperrno.h. --- ports/esp32/mpconfigport.h | 2 +- tests/net_hosted/connect_nonblock.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 7b0a00250b..392f8c749c 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -51,7 +51,7 @@ #define MICROPY_MODULE_FROZEN_MPY (1) #define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool #define MICROPY_CAN_OVERRIDE_BUILTINS (1) -#define MICROPY_USE_INTERNAL_ERRNO (1) +#define MICROPY_USE_INTERNAL_ERRNO (0) // errno.h from xtensa-esp32-elf/sys-include/sys #define MICROPY_USE_INTERNAL_PRINTF (0) // ESP32 SDK requires its own printf #define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_SCHEDULER_DEPTH (8) diff --git a/tests/net_hosted/connect_nonblock.py b/tests/net_hosted/connect_nonblock.py index 3a3eaa2ba0..c024b65a0a 100644 --- a/tests/net_hosted/connect_nonblock.py +++ b/tests/net_hosted/connect_nonblock.py @@ -2,8 +2,9 @@ try: import usocket as socket + import uerrno as errno except: - import socket + import socket, errno def test(peer_addr): @@ -12,7 +13,7 @@ def test(peer_addr): try: s.connect(peer_addr) except OSError as er: - print(er.args[0] == 115) # 115 is EINPROGRESS + print(er.args[0] == errno.EINPROGRESS) s.close() From a1a28157993756255eca067acb23145b08151546 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 12 Feb 2021 13:25:11 +1100 Subject: [PATCH 042/174] extmod/nimble: Ensure handle is set on read error. On error, the handle is only available on err->att_handle rather than in attr->handle used in the non-error case. Signed-off-by: Jim Mussared --- extmod/nimble/modbluetooth_nimble.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c index a2eb8a588c..3910c599cb 100644 --- a/extmod/nimble/modbluetooth_nimble.c +++ b/extmod/nimble/modbluetooth_nimble.c @@ -1281,14 +1281,15 @@ int mp_bluetooth_gattc_discover_descriptors(uint16_t conn_handle, uint16_t start } STATIC int ble_gatt_attr_read_cb(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { - DEBUG_printf("ble_gatt_attr_read_cb: conn_handle=%d status=%d handle=%d\n", conn_handle, error->status, attr ? attr->handle : -1); + uint16_t handle = attr ? attr->handle : (error ? error->att_handle : 0xffff); + DEBUG_printf("ble_gatt_attr_read_cb: conn_handle=%d status=%d handle=%d\n", conn_handle, error->status, handle); if (!mp_bluetooth_is_active()) { return 0; } if (error->status == 0) { gattc_on_data_available(MP_BLUETOOTH_IRQ_GATTC_READ_RESULT, conn_handle, attr->handle, attr->om); } - mp_bluetooth_gattc_on_read_write_status(MP_BLUETOOTH_IRQ_GATTC_READ_DONE, conn_handle, attr ? attr->handle : -1, error->status); + mp_bluetooth_gattc_on_read_write_status(MP_BLUETOOTH_IRQ_GATTC_READ_DONE, conn_handle, handle, error->status); return 0; } @@ -1302,11 +1303,12 @@ int mp_bluetooth_gattc_read(uint16_t conn_handle, uint16_t value_handle) { } STATIC int ble_gatt_attr_write_cb(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { - DEBUG_printf("ble_gatt_attr_write_cb: conn_handle=%d status=%d handle=%d\n", conn_handle, error->status, attr ? attr->handle : -1); + uint16_t handle = attr ? attr->handle : (error ? error->att_handle : 0xffff); + DEBUG_printf("ble_gatt_attr_write_cb: conn_handle=%d status=%d handle=%d\n", conn_handle, error->status, handle); if (!mp_bluetooth_is_active()) { return 0; } - mp_bluetooth_gattc_on_read_write_status(MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE, conn_handle, attr->handle, error->status); + mp_bluetooth_gattc_on_read_write_status(MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE, conn_handle, handle, error->status); return 0; } From fce0bd1a2af5aebd81d30d79b50210c80f768bc4 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 1 Feb 2021 13:12:23 +1100 Subject: [PATCH 043/174] extmod/moduselect: Fix unsigned/signed comparison for timeout!=-1. Signed-off-by: Jim Mussared --- extmod/moduselect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extmod/moduselect.c b/extmod/moduselect.c index 80beb8e09b..6d8249f427 100644 --- a/extmod/moduselect.c +++ b/extmod/moduselect.c @@ -148,7 +148,7 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) { // poll the objects mp_uint_t n_ready = poll_map_poll(&poll_map, rwx_len); - if (n_ready > 0 || (timeout != -1 && mp_hal_ticks_ms() - start_tick >= timeout)) { + if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) { // one or more objects are ready, or we had a timeout mp_obj_t list_array[3]; list_array[0] = mp_obj_new_list(rwx_len[0], NULL); @@ -250,7 +250,7 @@ STATIC mp_uint_t poll_poll_internal(uint n_args, const mp_obj_t *args) { for (;;) { // poll the objects n_ready = poll_map_poll(&self->poll_map, NULL); - if (n_ready > 0 || (timeout != -1 && mp_hal_ticks_ms() - start_tick >= timeout)) { + if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) { break; } MICROPY_EVENT_POLL_HOOK From 4c54012373e6546704f534d0de3e900704ae9d11 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 15 Feb 2021 15:49:20 +1100 Subject: [PATCH 044/174] unix/moduselect: Don't allow both posix and non-posix configurations. Signed-off-by: Jim Mussared --- ports/unix/moduselect.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/unix/moduselect.c b/ports/unix/moduselect.c index 6a0ee79aa6..a9390a146b 100644 --- a/ports/unix/moduselect.c +++ b/ports/unix/moduselect.c @@ -29,6 +29,10 @@ #if MICROPY_PY_USELECT_POSIX +#if MICROPY_PY_USELECT +#error "Can't have both MICROPY_PY_USELECT and MICROPY_PY_USELECT_POSIX." +#endif + #include #include #include From 5e96e89999cd3b922dbc1a6ed473b44c81db92f4 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 12 Feb 2021 14:14:07 +1100 Subject: [PATCH 045/174] extmod/uasyncio: Add ThreadSafeFlag. This is a MicroPython-extension that allows for code running in IRQ (hard or soft) or scheduler context to sequence asyncio code. Signed-off-by: Jim Mussared --- extmod/uasyncio/__init__.py | 1 + extmod/uasyncio/event.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/extmod/uasyncio/__init__.py b/extmod/uasyncio/__init__.py index 08f924cf29..fa64438f6b 100644 --- a/extmod/uasyncio/__init__.py +++ b/extmod/uasyncio/__init__.py @@ -10,6 +10,7 @@ _attrs = { "wait_for_ms": "funcs", "gather": "funcs", "Event": "event", + "ThreadSafeFlag": "event", "Lock": "lock", "open_connection": "stream", "start_server": "stream", diff --git a/extmod/uasyncio/event.py b/extmod/uasyncio/event.py index 31cb00e055..c28ad1fb31 100644 --- a/extmod/uasyncio/event.py +++ b/extmod/uasyncio/event.py @@ -14,6 +14,8 @@ class Event: def set(self): # Event becomes set, schedule any tasks waiting on it + # Note: This must not be called from anything except the thread running + # the asyncio loop (i.e. neither hard or soft IRQ, or a different thread). while self.waiting.peek(): core._task_queue.push_head(self.waiting.pop_head()) self.state = True @@ -29,3 +31,32 @@ class Event: core.cur_task.data = self.waiting yield return True + + +# MicroPython-extension: This can be set from outside the asyncio event loop, +# such as other threads, IRQs or scheduler context. Implementation is a stream +# that asyncio will poll until a flag is set. +# Note: Unlike Event, this is self-clearing. +try: + import uio + + class ThreadSafeFlag(uio.IOBase): + def __init__(self): + self._flag = 0 + + def ioctl(self, req, flags): + if req == 3: # MP_STREAM_POLL + return self._flag * flags + return None + + def set(self): + self._flag = 1 + + async def wait(self): + if not self._flag: + yield core._io_queue.queue_read(self) + self._flag = 0 + + +except ImportError: + pass From cdf9c8648f81dd4f2795a71b075aab75f01a9f1f Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 15 Feb 2021 17:28:15 +1100 Subject: [PATCH 046/174] docs/library/uasyncio.rst: Add docs for ThreadSafeFlag. Signed-off-by: Jim Mussared --- docs/library/uasyncio.rst | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/docs/library/uasyncio.rst b/docs/library/uasyncio.rst index 3316f908d6..1efee56e96 100644 --- a/docs/library/uasyncio.rst +++ b/docs/library/uasyncio.rst @@ -125,6 +125,9 @@ class Event Set the event. Any tasks waiting on the event will be scheduled to run. + Note: This must be called from within a task. It is not safe to call this + from an IRQ, scheduler callback, or other thread. See `ThreadSafeFlag`. + .. method:: Event.clear() Clear the event. @@ -136,6 +139,29 @@ class Event This is a coroutine. +class ThreadSafeFlag +-------------------- + +.. class:: ThreadSafeFlag() + + Create a new flag which can be used to synchronise a task with code running + outside the asyncio loop, such as other threads, IRQs, or scheduler + callbacks. Flags start in the cleared state. + +.. method:: ThreadSafeFlag.set() + + Set the flag. If there is a task waiting on the event, it will be scheduled + to run. + +.. method:: ThreadSafeFlag.wait() + + Wait for the flag to be set. If the flag is already set then it returns + immediately. + + A flag may only be waited on by a single task at a time. + + This is a coroutine. + class Lock ---------- @@ -188,7 +214,7 @@ TCP stream connections This is a coroutine. .. class:: Stream() - + This represents a TCP stream connection. To minimise code this class implements both a reader and a writer, and both ``StreamReader`` and ``StreamWriter`` alias to this class. From 83d23059ef80d0d28d1e0769a721c83665b0095f Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 15 Feb 2021 17:28:39 +1100 Subject: [PATCH 047/174] tests/extmod: Add test for ThreadSafeFlag. Signed-off-by: Jim Mussared --- tests/extmod/uasyncio_threadsafeflag.py | 79 +++++++++++++++++++++ tests/extmod/uasyncio_threadsafeflag.py.exp | 21 ++++++ 2 files changed, 100 insertions(+) create mode 100644 tests/extmod/uasyncio_threadsafeflag.py create mode 100644 tests/extmod/uasyncio_threadsafeflag.py.exp diff --git a/tests/extmod/uasyncio_threadsafeflag.py b/tests/extmod/uasyncio_threadsafeflag.py new file mode 100644 index 0000000000..4e002a3d2a --- /dev/null +++ b/tests/extmod/uasyncio_threadsafeflag.py @@ -0,0 +1,79 @@ +# Test Event class + +try: + import uasyncio as asyncio +except ImportError: + print("SKIP") + raise SystemExit + + +import micropython + +try: + micropython.schedule +except AttributeError: + print("SKIP") + raise SystemExit + + +try: + # Unix port can't select/poll on user-defined types. + import uselect as select + + poller = select.poll() + poller.register(asyncio.ThreadSafeFlag()) +except TypeError: + print("SKIP") + raise SystemExit + + +async def task(id, flag): + print("task", id) + await flag.wait() + print("task", id, "done") + + +def set_from_schedule(flag): + print("schedule") + flag.set() + print("schedule done") + + +async def main(): + flag = asyncio.ThreadSafeFlag() + + # Set the flag from within the loop. + t = asyncio.create_task(task(1, flag)) + print("yield") + await asyncio.sleep(0) + print("set event") + flag.set() + print("yield") + await asyncio.sleep(0) + print("wait task") + await t + + # Set the flag from scheduler context. + print("----") + t = asyncio.create_task(task(2, flag)) + print("yield") + await asyncio.sleep(0) + print("set event") + micropython.schedule(set_from_schedule, flag) + print("yield") + await asyncio.sleep(0) + print("wait task") + await t + + # Flag already set. + print("----") + print("set event") + flag.set() + t = asyncio.create_task(task(3, flag)) + print("yield") + await asyncio.sleep(0) + print("wait task") + await t + + +asyncio.run(main()) diff --git a/tests/extmod/uasyncio_threadsafeflag.py.exp b/tests/extmod/uasyncio_threadsafeflag.py.exp new file mode 100644 index 0000000000..aef4e479ba --- /dev/null +++ b/tests/extmod/uasyncio_threadsafeflag.py.exp @@ -0,0 +1,21 @@ +yield +task 1 +set event +yield +wait task +task 1 done +---- +yield +task 2 +set event +yield +schedule +schedule done +wait task +task 2 done +---- +set event +yield +task 3 +task 3 done +wait task From 566020034fc64448d33718c575809fcfe8f271db Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 12 Feb 2021 16:11:38 +1100 Subject: [PATCH 048/174] tools/makemanifest.py: Allow passing option args to include(). This allows customising which features can be enabled in a frozen library. e.g. `include("path.py", extra_features=True)` in path.py: options.defaults(standard_features=True) if options.standard_features: # freeze standard modules. if options.extra_features: # freeze extra modules. Signed-off-by: Jim Mussared --- tools/makemanifest.py | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/tools/makemanifest.py b/tools/makemanifest.py index c07a3a6c77..117d1536e8 100644 --- a/tools/makemanifest.py +++ b/tools/makemanifest.py @@ -34,13 +34,27 @@ import subprocess # Public functions to be used in the manifest -def include(manifest): +def include(manifest, **kwargs): """Include another manifest. The manifest argument can be a string (filename) or an iterable of strings. Relative paths are resolved with respect to the current manifest file. + + Optional kwargs can be provided which will be available to the + included script via the `options` variable. + + e.g. include("path.py", extra_features=True) + + in path.py: + options.defaults(standard_features=True) + + # freeze minimal modules. + if options.standard_features: + # freeze standard modules. + if options.extra_features: + # freeze extra modules. """ if not isinstance(manifest, str): @@ -53,7 +67,7 @@ def include(manifest): # Applies to includes and input files. prev_cwd = os.getcwd() os.chdir(os.path.dirname(manifest)) - exec(f.read()) + exec(f.read(), globals(), {"options": IncludeOptions(**kwargs)}) os.chdir(prev_cwd) @@ -125,6 +139,18 @@ VARS = {} manifest_list = [] +class IncludeOptions: + def __init__(self, **kwargs): + self._kwargs = kwargs + self._defaults = {} + + def defaults(self, **kwargs): + self._defaults = kwargs + + def __getattr__(self, name): + return self._kwargs.get(name, self._defaults.get(name, None)) + + class FreezeError(Exception): pass From 2aa57931a6e23e39adddc717c25fa8a499966cb9 Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Mon, 15 Feb 2021 08:51:48 -0600 Subject: [PATCH 049/174] zephyr: Update to zephyr v2.5.0. Updates the zephyr port build instructions and CI to use the latest zephyr release tag. Signed-off-by: Maureen Helm --- ports/zephyr/README.md | 6 +++--- tools/ci.sh | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ports/zephyr/README.md b/ports/zephyr/README.md index d69030dc2c..d1cc841977 100644 --- a/ports/zephyr/README.md +++ b/ports/zephyr/README.md @@ -4,7 +4,7 @@ MicroPython port to Zephyr RTOS This is a work-in-progress port of MicroPython to Zephyr RTOS (http://zephyrproject.org). -This port requires Zephyr version 2.4.0, and may also work on higher +This port requires Zephyr version v2.5.0, and may also work on higher versions. All boards supported by Zephyr (with standard level of features support, like UART console) should work with MicroPython (but not all were tested). @@ -38,13 +38,13 @@ setup is correct. If you already have Zephyr installed but are having issues building the MicroPython port then try installing the correct version of Zephyr via: - $ west init zephyrproject -m https://github.com/zephyrproject-rtos/zephyr --mr v2.4.0 + $ west init zephyrproject -m https://github.com/zephyrproject-rtos/zephyr --mr v2.5.0 Alternatively, you don't have to redo the Zephyr installation to just switch from master to a tagged release, you can instead do: $ cd zephyrproject/zephyr - $ git checkout v2.4.0 + $ git checkout v2.5.0 $ west update With Zephyr installed you may then need to configure your environment, diff --git a/tools/ci.sh b/tools/ci.sh index 4f99551468..d945375562 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -466,7 +466,7 @@ function ci_zephyr_setup { } function ci_zephyr_install { - docker exec zephyr-ci west init --mr v2.4.0 /zephyrproject + docker exec zephyr-ci west init --mr v2.5.0 /zephyrproject docker exec -w /zephyrproject zephyr-ci west update docker exec -w /zephyrproject zephyr-ci west zephyr-export } From dff6fc64d23c548dce2b43096c3f1522db303de8 Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Tue, 10 Nov 2020 19:05:30 -0600 Subject: [PATCH 050/174] py: Expand lists in core cmake custom commands. The core cmake rules use custom commands to invoke qstr processing scripts. For the zephyr port, it's possible that list arguments to these commands may contain generator expressions, therefore we need to expand them properly. Signed-off-by: Maureen Helm --- py/mkrules.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/py/mkrules.cmake b/py/mkrules.cmake index bdff385815..e05dcb836a 100644 --- a/py/mkrules.cmake +++ b/py/mkrules.cmake @@ -73,6 +73,7 @@ add_custom_command( DEPENDS ${MICROPY_MODULEDEFS} ${MICROPY_SOURCE_QSTR} VERBATIM + COMMAND_EXPAND_LISTS ) add_custom_command( @@ -81,6 +82,7 @@ add_custom_command( COMMAND touch ${MICROPY_QSTR_DEFS_SPLIT} DEPENDS ${MICROPY_QSTR_DEFS_LAST} VERBATIM + COMMAND_EXPAND_LISTS ) add_custom_command( @@ -88,6 +90,7 @@ add_custom_command( COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py cat qstr _ ${MICROPY_GENHDR_DIR}/qstr ${MICROPY_QSTR_DEFS_COLLECTED} DEPENDS ${MICROPY_QSTR_DEFS_SPLIT} VERBATIM + COMMAND_EXPAND_LISTS ) add_custom_command( @@ -95,6 +98,7 @@ add_custom_command( COMMAND cat ${MICROPY_PY_QSTRDEFS} ${MICROPY_QSTR_DEFS_COLLECTED} | sed "s/^Q(.*)/\"&\"/" | ${CMAKE_C_COMPILER} -E ${MICROPY_CPP_FLAGS} - | sed "s/^\\\"\\(Q(.*)\\)\\\"/\\1/" > ${MICROPY_QSTR_DEFS_PREPROCESSED} DEPENDS ${MICROPY_QSTR_DEFS_COLLECTED} VERBATIM + COMMAND_EXPAND_LISTS ) add_custom_command( @@ -102,6 +106,7 @@ add_custom_command( COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdata.py ${MICROPY_QSTR_DEFS_PREPROCESSED} > ${MICROPY_QSTR_DEFS_GENERATED} DEPENDS ${MICROPY_QSTR_DEFS_PREPROCESSED} VERBATIM + COMMAND_EXPAND_LISTS ) # Build frozen code if enabled From f49a73641ac677ea49a031ae7efc5822441f0cb5 Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Sun, 18 Oct 2020 14:54:38 -0500 Subject: [PATCH 051/174] zephyr: Disable frozen source modules. Disables frozen source modules in the zephyr port. They are deprecated in the makefile rules and not implemented in the new cmake rules. Signed-off-by: Maureen Helm --- ports/zephyr/mpconfigport.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr/mpconfigport.h b/ports/zephyr/mpconfigport.h index 6bfd9ff884..966f7f7e94 100644 --- a/ports/zephyr/mpconfigport.h +++ b/ports/zephyr/mpconfigport.h @@ -110,7 +110,7 @@ #define MICROPY_HW_MCU_NAME "unknown-cpu" #endif -#define MICROPY_MODULE_FROZEN_STR (1) +#define MICROPY_MODULE_FROZEN_STR (0) typedef int mp_int_t; // must be pointer size typedef unsigned mp_uint_t; // must be pointer size From 51fa1339f12bace6be49647336f8c9bf57302d4d Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Fri, 28 Aug 2020 14:26:31 -0500 Subject: [PATCH 052/174] zephyr: Remove unused build files. Removes zephyr port build files that aren't being used anymore. Signed-off-by: Maureen Helm --- ports/zephyr/Kbuild | 3 --- ports/zephyr/Makefile.zephyr | 30 ------------------------------ ports/zephyr/src/Makefile | 17 ----------------- ports/zephyr/z_config.mk | 17 ----------------- 4 files changed, 67 deletions(-) delete mode 100644 ports/zephyr/Kbuild delete mode 100644 ports/zephyr/Makefile.zephyr delete mode 100644 ports/zephyr/src/Makefile delete mode 100644 ports/zephyr/z_config.mk diff --git a/ports/zephyr/Kbuild b/ports/zephyr/Kbuild deleted file mode 100644 index 9e656d5f48..0000000000 --- a/ports/zephyr/Kbuild +++ /dev/null @@ -1,3 +0,0 @@ -#subdir-ccflags-y += -I$(SOURCE_DIR)/../mylib/include - -obj-y += src/ diff --git a/ports/zephyr/Makefile.zephyr b/ports/zephyr/Makefile.zephyr deleted file mode 100644 index 16f0a9452f..0000000000 --- a/ports/zephyr/Makefile.zephyr +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2016 Intel Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -KERNEL_TYPE = micro -# BOARD must be passed on command line from main Makefile -#BOARD = -CONF_FILE = prj.conf -QEMU_NET = 1 - -#export SOURCE_DIR = $(ZEPHYR_BASE)/samples/static_lib/hello_world -export LDFLAGS_zephyr += -L$(CURDIR) -export ALL_LIBS += micropython - -include ${ZEPHYR_BASE}/Makefile.inc -ifeq ($(QEMU_NET), 1) -include ${ZEPHYR_BASE}/samples/net/common/Makefile.ipstack -endif diff --git a/ports/zephyr/src/Makefile b/ports/zephyr/src/Makefile deleted file mode 100644 index 36dd8c64ef..0000000000 --- a/ports/zephyr/src/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2016 Intel Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -obj-y += zephyr_start.o zephyr_getchar.o diff --git a/ports/zephyr/z_config.mk b/ports/zephyr/z_config.mk deleted file mode 100644 index 28addd8f29..0000000000 --- a/ports/zephyr/z_config.mk +++ /dev/null @@ -1,17 +0,0 @@ -srctree = $(ZEPHYR_BASE) - -include $(Z_DOTCONFIG) -override ARCH = $(subst $(DQUOTE),,$(CONFIG_ARCH)) -SOC_NAME = $(subst $(DQUOTE),,$(CONFIG_SOC)) -SOC_SERIES = $(subst $(DQUOTE),,$(CONFIG_SOC_SERIES)) -SOC_FAMILY = $(subst $(DQUOTE),,$(CONFIG_SOC_FAMILY)) -ifeq ($(SOC_SERIES),) -SOC_PATH = $(SOC_NAME) -else -SOC_PATH = $(SOC_FAMILY)/$(SOC_SERIES) -endif - -KBUILD_CFLAGS := -c -include $(ZEPHYR_BASE)/scripts/Kbuild.include - -include $(ZEPHYR_BASE)/arch/$(ARCH)/Makefile From f573e73baeddfb8fde59413e8053b538cf908f9b Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Sun, 11 Oct 2020 13:11:31 -0500 Subject: [PATCH 053/174] zephyr: Build MicroPython as a cmake target. Refactors the zephyr build infrastructure to build MicroPython as a cmake target, using the recently introduced core cmake rules. This change makes it possible to build the zephyr port like most other zephyr applications using west or cmake directly. It simplifies building with extra cmake arguments, such as specifying an alternate conf file or adding an Arduino shield. It also enables building the zephyr port anywhere in the host file system, which will allow regressing across multiple boards with the zephyr twister script. Signed-off-by: Maureen Helm --- ports/zephyr/.gitignore | 1 - ports/zephyr/CMakeLists.txt | 128 +++++++++++++++++++++++++++++++----- ports/zephyr/Kconfig | 46 +++++++++++++ ports/zephyr/Makefile | 116 -------------------------------- ports/zephyr/README.md | 56 ++++++++-------- ports/zephyr/make-minimal | 18 ----- ports/zephyr/prj.conf | 5 ++ tools/ci.sh | 13 ++-- 8 files changed, 198 insertions(+), 185 deletions(-) delete mode 100644 ports/zephyr/.gitignore create mode 100644 ports/zephyr/Kconfig delete mode 100644 ports/zephyr/Makefile delete mode 100755 ports/zephyr/make-minimal diff --git a/ports/zephyr/.gitignore b/ports/zephyr/.gitignore deleted file mode 100644 index 00ca089d15..0000000000 --- a/ports/zephyr/.gitignore +++ /dev/null @@ -1 +0,0 @@ -outdir/ diff --git a/ports/zephyr/CMakeLists.txt b/ports/zephyr/CMakeLists.txt index 50cd031d4d..08868d716d 100644 --- a/ports/zephyr/CMakeLists.txt +++ b/ports/zephyr/CMakeLists.txt @@ -1,24 +1,118 @@ +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright 2020 NXP +# +# 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. + cmake_minimum_required(VERSION 3.13.1) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(NONE) +project(micropython) -target_sources(app PRIVATE src/zephyr_start.c src/zephyr_getchar.c) +set(MICROPY_PORT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(MICROPY_DIR ${MICROPY_PORT_DIR}/../..) +set(MICROPY_TARGET micropython) -add_library(libmicropython STATIC IMPORTED) -set_target_properties(libmicropython PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libmicropython.a) -target_link_libraries(app PUBLIC libmicropython) +include(${MICROPY_DIR}/py/py.cmake) +include(${MICROPY_DIR}/extmod/extmod.cmake) -zephyr_get_include_directories_for_lang_as_string(C includes) -zephyr_get_system_include_directories_for_lang_as_string(C system_includes) -zephyr_get_compile_definitions_for_lang_as_string(C definitions) -zephyr_get_compile_options_for_lang_as_string(C options) - -add_custom_target( - outputexports - COMMAND echo CC="${CMAKE_C_COMPILER}" - COMMAND echo AR="${CMAKE_AR}" - COMMAND echo Z_CFLAGS=${system_includes} ${includes} ${definitions} ${options} - VERBATIM - USES_TERMINAL +set(MICROPY_SOURCE_PORT + main.c + help.c + machine_i2c.c + machine_pin.c + machine_uart.c + modmachine.c + moduos.c + modusocket.c + modutime.c + modzephyr.c + modzsensor.c + uart_core.c + zephyr_storage.c ) +list(TRANSFORM MICROPY_SOURCE_PORT PREPEND ${MICROPY_PORT_DIR}/) + +set(MICROPY_SOURCE_LIB + timeutils/timeutils.c + utils/mpirq.c + utils/stdout_helpers.c + utils/printf.c + utils/pyexec.c + utils/interrupt_char.c + mp-readline/readline.c + oofatfs/ff.c + oofatfs/ffunicode.c + littlefs/lfs1.c + littlefs/lfs1_util.c + littlefs/lfs2.c + littlefs/lfs2_util.c +) +list(TRANSFORM MICROPY_SOURCE_LIB PREPEND ${MICROPY_DIR}/lib/) + +set(MICROPY_SOURCE_QSTR + ${MICROPY_SOURCE_PY} + ${MICROPY_SOURCE_EXTMOD} + ${MICROPY_SOURCE_LIB} + ${MICROPY_SOURCE_PORT} +) + +zephyr_get_include_directories_for_lang(C includes) +zephyr_get_system_include_directories_for_lang(C system_includes) +zephyr_get_compile_definitions_for_lang(C definitions) +zephyr_get_compile_options_for_lang(C options) + +set(MICROPY_CPP_FLAGS_EXTRA ${includes} ${system_includes} ${definitions} ${options}) + +zephyr_library_named(${MICROPY_TARGET}) + +zephyr_library_include_directories( + ${MICROPY_DIR} + ${MICROPY_PORT_DIR} + ${CMAKE_CURRENT_BINARY_DIR} +) + +zephyr_library_compile_options( + -std=gnu99 -fomit-frame-pointer +) + +zephyr_library_compile_definitions( + NDEBUG + MP_CONFIGFILE=<${CONFIG_MICROPY_CONFIGFILE}> + MICROPY_HEAP_SIZE=${CONFIG_MICROPY_HEAP_SIZE} + FFCONF_H=\"${MICROPY_OOFATFS_DIR}/ffconf.h\" + MICROPY_VFS_FAT=$ + MICROPY_VFS_LFS1=$ + MICROPY_VFS_LFS2=$ +) + +zephyr_library_sources(${MICROPY_SOURCE_QSTR}) + +add_dependencies(${MICROPY_TARGET} zephyr_generated_headers) + +include(${MICROPY_DIR}/py/mkrules.cmake) + +target_sources(app PRIVATE + src/zephyr_start.c + src/zephyr_getchar.c +) + +target_link_libraries(app PRIVATE ${MICROPY_TARGET}) diff --git a/ports/zephyr/Kconfig b/ports/zephyr/Kconfig new file mode 100644 index 0000000000..5545cf3b15 --- /dev/null +++ b/ports/zephyr/Kconfig @@ -0,0 +1,46 @@ +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright 2020 NXP +# +# 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. + +menu "MicroPython Options" + +config MICROPY_CONFIGFILE + string "Configuration file" + default "mpconfigport_minimal.h" + +config MICROPY_HEAP_SIZE + int "Heap size" + default 16384 + +config MICROPY_VFS_FAT + bool "FatFS file system" + +config MICROPY_VFS_LFS1 + bool "LittleFs version 1 file system" + +config MICROPY_VFS_LFS2 + bool "LittleFs version 2 file system" + +endmenu # MicroPython Options + +source "Kconfig.zephyr" diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile deleted file mode 100644 index c200062a3f..0000000000 --- a/ports/zephyr/Makefile +++ /dev/null @@ -1,116 +0,0 @@ -# -# This is the main Makefile, which uses MicroPython build system, -# but Zephyr arch-specific toolchain and target-specific flags. -# This Makefile builds MicroPython as a library, and then calls -# recursively Makefile.zephyr to build complete application binary -# using Zephyr build system. -# -# To build a "minimal" configuration, use "make-minimal" wrapper. - -BOARD ?= qemu_x86 -OUTDIR_PREFIX = $(BOARD) - -# Default heap size is 16KB, which is on conservative side, to let -# it build for smaller boards, but it won't be enough for larger -# applications, and will need to be increased. -MICROPY_HEAP_SIZE = 16384 -FROZEN_DIR = scripts - -MICROPY_VFS_FAT ?= 1 -MICROPY_VFS_LFS1 ?= 0 -MICROPY_VFS_LFS2 ?= 1 - -# Default target -all: - -include ../../py/mkenv.mk -include $(TOP)/py/py.mk - -# Zephyr (generated) config files - must be defined before include below -Z_EXPORTS = outdir/$(OUTDIR_PREFIX)/Makefile.export -ifneq ($(MAKECMDGOALS), clean) -include $(Z_EXPORTS) -endif - -INC += -I. -INC += -I$(TOP) -INC += -I$(BUILD) -INC += -I$(ZEPHYR_BASE)/net/ip -INC += -I$(ZEPHYR_BASE)/net/ip/contiki -INC += -I$(ZEPHYR_BASE)/net/ip/contiki/os - -SRC_C = main.c \ - help.c \ - moduos.c \ - modusocket.c \ - modutime.c \ - modzephyr.c \ - modzsensor.c \ - modmachine.c \ - machine_i2c.c \ - machine_pin.c \ - machine_uart.c \ - uart_core.c \ - zephyr_storage.c \ - lib/timeutils/timeutils.c \ - lib/utils/mpirq.c \ - lib/utils/stdout_helpers.c \ - lib/utils/printf.c \ - lib/utils/pyexec.c \ - lib/utils/interrupt_char.c \ - lib/mp-readline/readline.c \ - $(SRC_MOD) - -# List of sources for qstr extraction -SRC_QSTR += $(SRC_C) - -OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) - -CFLAGS = $(Z_CFLAGS) \ - -std=gnu99 -fomit-frame-pointer -DNDEBUG -DMICROPY_HEAP_SIZE=$(MICROPY_HEAP_SIZE) $(CFLAGS_MOD) $(CFLAGS_EXTRA) $(INC) - -include $(TOP)/py/mkrules.mk - -GENERIC_TARGETS = all zephyr run qemu qemugdb flash debug debugserver \ - ram_report rom_report -KCONFIG_TARGETS = \ - initconfig config nconfig menuconfig xconfig gconfig \ - oldconfig silentoldconfig defconfig savedefconfig \ - allnoconfig allyesconfig alldefconfig randconfig \ - listnewconfig olddefconfig -CLEAN_TARGETS = pristine mrproper - -$(GENERIC_TARGETS): $(LIBMICROPYTHON) -$(CLEAN_TARGETS): clean - -$(GENERIC_TARGETS) $(KCONFIG_TARGETS) $(CLEAN_TARGETS): - $(MAKE) -C outdir/$(BOARD) $@ - -$(LIBMICROPYTHON): | $(Z_EXPORTS) -build/genhdr/qstr.i.last: | $(Z_EXPORTS) - -# If we recreate libmicropython, also cause zephyr.bin relink -LIBMICROPYTHON_EXTRA_CMD = -$(RM) -f outdir/$(OUTDIR_PREFIX)/zephyr.lnk - -# MicroPython's global clean cleans everything, fast -CLEAN_EXTRA = outdir libmicropython.a - -# Clean Zephyr things in Zephyr way -z_clean: - $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) clean - -test: - cd $(TOP)/tests && ./run-tests --target minimal --device "execpty:make -C ../ports/zephyr run BOARD=$(BOARD) QEMU_PTY=1" - -cmake: outdir/$(BOARD)/Makefile - -ifneq ($(CONF_FILE),) -CMAKE_MOD += -DCONF_FILE=$(CONF_FILE) -endif - -outdir/$(BOARD)/Makefile: - mkdir -p outdir/$(BOARD) && cmake -DBOARD=$(BOARD) $(CMAKE_MOD) -Boutdir/$(BOARD) -H. - -$(Z_EXPORTS): outdir/$(BOARD)/Makefile - make --no-print-directory -C outdir/$(BOARD) outputexports CMAKE_COMMAND=: >$@ - make -C outdir/$(BOARD) syscall_list_h_target kobj_types_h_target diff --git a/ports/zephyr/README.md b/ports/zephyr/README.md index d1cc841977..cdc3c70f0e 100644 --- a/ports/zephyr/README.md +++ b/ports/zephyr/README.md @@ -50,48 +50,49 @@ switch from master to a tagged release, you can instead do: With Zephyr installed you may then need to configure your environment, for example by sourcing `zephyrproject/zephyr/zephyr-env.sh`. -Once Zephyr is ready to use you can build the MicroPython port. -In the port subdirectory `ports/zephyr/` run: +Once Zephyr is ready to use you can build the MicroPython port just like any +other Zephyr application. You can do this anywhere in your file system, it does +not have to be in the `ports/zephyr` directory. Assuming you have cloned the +MicroPython repository into your home directory, you can build the Zephyr port +for a frdm_k64f board like this: - $ make BOARD= + $ west build -b frdm_k64f ~/micropython/ports/zephyr -If you don't specify BOARD, the default is `qemu_x86` (x86 target running -in QEMU emulator). Consult the Zephyr documentation above for the list of +To build for QEMU instead: + + $ west build -b qemu_x86 ~/micropython/ports/zephyr + +Consult the Zephyr documentation above for the list of supported boards. Board configuration files appearing in `ports/zephyr/boards/` correspond to boards that have been tested with MicroPython and may have additional options enabled, like filesystem support. - Running ------- +To flash the resulting firmware to your board: + + $ west flash + +Or, to flash it to your board and start a gdb debug session: + + $ west debug + To run the resulting firmware in QEMU (for BOARDs like qemu_x86, qemu_cortex_m3): - make run + $ west build -t run -With the default configuration, networking is now enabled, so you need to -follow instructions in https://wiki.zephyrproject.org/view/Networking-with-Qemu -to setup host side of TAP/SLIP networking. If you get error like: +Networking is enabled with the default configuration, so you need to follow +instructions in +https://docs.zephyrproject.org/latest/guides/networking/qemu_setup.html#networking-with-qemu +to setup the host side of TAP/SLIP networking. If you get an error like: could not connect serial device to character backend 'unix:/tmp/slip.sock' -it's a sign that you didn't followed instructions above. If you would like +it's a sign that you didn't follow the instructions above. If you would like to just run it quickly without extra setup, see "minimal" build below. -For deploying/flashing a firmware on a real board, follow Zephyr -documentation for a given board, including known issues for that board -(if any). (Mind again that networking is enabled for the default build, -so you should know if there're any special requirements in that regard, -cf. for example QEMU networking requirements above; real hardware boards -generally should not have any special requirements, unless there're known -issues). - -For example, to deploy firmware on the FRDM-K64F board run: - - $ make BOARD=frdm_k64f flash - - Quick example ------------- @@ -151,9 +152,10 @@ enabled over time. To make a minimal build: - ./make-minimal BOARD= + $ west build -b qemu_x86 ~/micropython/ports/zephyr -- -DCONF_FILE=prj_minimal.conf To run a minimal build in QEMU without requiring TAP networking setup -run the following after you built image with the previous command: +run the following after you built an image with the previous command: + + $ west build -t run - ./make-minimal BOARD= run diff --git a/ports/zephyr/make-minimal b/ports/zephyr/make-minimal deleted file mode 100755 index d7dddc3342..0000000000 --- a/ports/zephyr/make-minimal +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -# -# This is a wrapper for make to build a "minimal" Zephyr port. -# It should be run just like make (i.e. extra vars can be passed on the -# command line, etc.), e.g.: -# -# ./make-minimal BOARD=qemu_cortex_m3 -# ./make-minimal BOARD=qemu_cortex_m3 run -# - -make \ - CONF_FILE=prj_minimal.conf \ - CFLAGS_EXTRA='-DMP_CONFIGFILE=""' \ - MICROPY_VFS_FAT=0 \ - MICROPY_VFS_LFS2=0 \ - FROZEN_DIR= \ - QEMU_NET=0 \ - "$@" diff --git a/ports/zephyr/prj.conf b/ports/zephyr/prj.conf index 9824f48e33..c9c2e96da9 100644 --- a/ports/zephyr/prj.conf +++ b/ports/zephyr/prj.conf @@ -69,3 +69,8 @@ CONFIG_NET_BUF_POOL_USAGE=y #CONFIG_NET_DEBUG_NET_BUF=y # Change to 4 for "DEBUG" level #CONFIG_SYS_LOG_NET_LEVEL=3 + +# MicroPython options +CONFIG_MICROPY_CONFIGFILE="mpconfigport.h" +CONFIG_MICROPY_VFS_FAT=y +CONFIG_MICROPY_VFS_LFS2=y diff --git a/tools/ci.sh b/tools/ci.sh index d945375562..616e78f197 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -460,6 +460,7 @@ function ci_zephyr_setup { -v "$(pwd)":/micropython \ -e ZEPHYR_SDK_INSTALL_DIR=/opt/sdk/zephyr-sdk-0.11.3 \ -e ZEPHYR_TOOLCHAIN_VARIANT=zephyr \ + -e ZEPHYR_BASE=/zephyrproject/zephyr \ -w /micropython/ports/zephyr \ zephyrprojectrtos/ci:v0.11.8 docker ps -a @@ -472,10 +473,10 @@ function ci_zephyr_install { } function ci_zephyr_build { - docker exec zephyr-ci bash -c "make clean; ./make-minimal ${MAKEOPTS}" - docker exec zephyr-ci bash -c "make clean; ./make-minimal ${MAKEOPTS} BOARD=frdm_k64f" - docker exec zephyr-ci bash -c "make clean; make ${MAKEOPTS}" - docker exec zephyr-ci bash -c "make clean; make ${MAKEOPTS} BOARD=frdm_k64f" - docker exec zephyr-ci bash -c "make clean; make ${MAKEOPTS} BOARD=mimxrt1050_evk" - docker exec zephyr-ci bash -c "make clean; make ${MAKEOPTS} BOARD=reel_board" + docker exec zephyr-ci west build -p auto -b qemu_x86 -- -DCONF_FILE=prj_minimal.conf + docker exec zephyr-ci west build -p auto -b frdm_k64f -- -DCONF_FILE=prj_minimal.conf + docker exec zephyr-ci west build -p auto -b qemu_x86 + docker exec zephyr-ci west build -p auto -b frdm_k64f + docker exec zephyr-ci west build -p auto -b mimxrt1050_evk + docker exec zephyr-ci west build -p auto -b reel_board } From 56a36899bdb472d5c2003164079bedeba42fa24d Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Tue, 16 Feb 2021 08:59:53 -0600 Subject: [PATCH 054/174] tools/ci.sh: Update zephyr docker image to v0.11.13. Updates the zephyr docker image to the latest, v0.11.13. This updates CI to use zephyr SDK v0.12.2 and GCC v10.2.0 for the zephyr port. Signed-off-by: Maureen Helm --- tools/ci.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/ci.sh b/tools/ci.sh index 616e78f197..5e0686f301 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -455,14 +455,14 @@ function ci_windows_build { # ports/zephyr function ci_zephyr_setup { - docker pull zephyrprojectrtos/ci:v0.11.8 + docker pull zephyrprojectrtos/ci:v0.11.13 docker run --name zephyr-ci -d -it \ -v "$(pwd)":/micropython \ - -e ZEPHYR_SDK_INSTALL_DIR=/opt/sdk/zephyr-sdk-0.11.3 \ + -e ZEPHYR_SDK_INSTALL_DIR=/opt/sdk/zephyr-sdk-0.12.2 \ -e ZEPHYR_TOOLCHAIN_VARIANT=zephyr \ -e ZEPHYR_BASE=/zephyrproject/zephyr \ -w /micropython/ports/zephyr \ - zephyrprojectrtos/ci:v0.11.8 + zephyrprojectrtos/ci:v0.11.13 docker ps -a } From 6c4a5d185d7e70c22c0f72fb1cd8add251600548 Mon Sep 17 00:00:00 2001 From: PTH Date: Thu, 11 Feb 2021 15:23:00 +0100 Subject: [PATCH 055/174] zephyr/boards: Add support for the nucleo_h743zi board. --- ports/zephyr/boards/nucleo_h743zi.conf | 7 +++++++ ports/zephyr/boards/nucleo_h743zi.overlay | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 ports/zephyr/boards/nucleo_h743zi.conf create mode 100644 ports/zephyr/boards/nucleo_h743zi.overlay diff --git a/ports/zephyr/boards/nucleo_h743zi.conf b/ports/zephyr/boards/nucleo_h743zi.conf new file mode 100644 index 0000000000..942415b796 --- /dev/null +++ b/ports/zephyr/boards/nucleo_h743zi.conf @@ -0,0 +1,7 @@ +# disable console subsys to get REPL working +CONFIG_CONSOLE_SUBSYS=n + +# flash config +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_FLASH_PAGE_LAYOUT=y diff --git a/ports/zephyr/boards/nucleo_h743zi.overlay b/ports/zephyr/boards/nucleo_h743zi.overlay new file mode 100644 index 0000000000..f5e6d4f921 --- /dev/null +++ b/ports/zephyr/boards/nucleo_h743zi.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 Thomas Popp + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* delete the already defined storage partition and create a new and bigger one */ +/delete-node/ &storage_partition; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + + /* storage slot: 1024 KB in Flash Memory Bank 2 */ + storage_partition: partition@100000 { + label = "storage"; + reg = <0x00100000 0x100000>; + }; + }; +}; From 5cb91afb9b3b34bbf0ee022a3f69af90c01d1d54 Mon Sep 17 00:00:00 2001 From: PTH Date: Fri, 12 Feb 2021 15:08:02 +0100 Subject: [PATCH 056/174] zephyr/modusocket: Fix parameter in calls to net_context_get_XXX(). The following simple usocket example throws an error EINVAL on connect import usocket s = usocket.socket() s.connect(usocket.getaddrinfo('www.micropython.org', 80)[0][-1]) Traceback (most recent call last): File "", line 1, in OSError: [Errno 22] EINVAL Fixing the context parameter in calls of net_context_get_family() and net_context_get_type(), the connect works fine. Tested on a nucleo_h743zi board. --- ports/zephyr/modusocket.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/zephyr/modusocket.c b/ports/zephyr/modusocket.c index 6c900753c8..f9fc96a2b1 100644 --- a/ports/zephyr/modusocket.c +++ b/ports/zephyr/modusocket.c @@ -79,7 +79,8 @@ STATIC void parse_inet_addr(socket_obj_t *socket, mp_obj_t addr_in, struct socka mp_obj_t *addr_items; mp_obj_get_array_fixed_n(addr_in, 2, &addr_items); - sockaddr_in->sin_family = net_context_get_family((void *)socket->ctx); + void *context = zsock_get_context_object(socket->ctx); + sockaddr_in->sin_family = net_context_get_family(context); RAISE_ERRNO(net_addr_pton(sockaddr_in->sin_family, mp_obj_str_get_str(addr_items[0]), &sockaddr_in->sin_addr)); sockaddr_in->sin_port = htons(mp_obj_get_int(addr_items[1])); } @@ -119,8 +120,8 @@ STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kin if (self->ctx == -1) { mp_printf(print, ""); } else { - struct net_context *ctx = (void *)self->ctx; - mp_printf(print, "", ctx, net_context_get_type(ctx)); + void *context = zsock_get_context_object(self->ctx); + mp_printf(print, "", self->ctx, net_context_get_type(context)); } } From 236274f08fb51d36eba9cd0458483bd398bfed0a Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 12 Feb 2021 14:31:29 +1100 Subject: [PATCH 057/174] extmod/nimble/hal/hal_uart: Fix HCI_TRACE format specifiers. Makes this work consistently on unix and stm32 ports. --- extmod/nimble/hal/hal_uart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extmod/nimble/hal/hal_uart.c b/extmod/nimble/hal/hal_uart.c index 230970b089..cd5e49e30b 100644 --- a/extmod/nimble/hal/hal_uart.c +++ b/extmod/nimble/hal/hal_uart.c @@ -66,7 +66,7 @@ void hal_uart_start_tx(uint32_t port) { } #if HCI_TRACE - printf("< [% 8d] %02x", mp_hal_ticks_ms(), mp_bluetooth_hci_cmd_buf[0]); + printf("< [% 8d] %02x", (int)mp_hal_ticks_ms(), mp_bluetooth_hci_cmd_buf[0]); for (size_t i = 1; i < len; ++i) { printf(":%02x", mp_bluetooth_hci_cmd_buf[i]); } @@ -86,7 +86,7 @@ void mp_bluetooth_nimble_hci_uart_process(bool run_events) { int chr; while ((chr = mp_bluetooth_hci_uart_readchar()) >= 0) { #if HCI_TRACE - printf("> %02x (%d)\n", chr); + printf("> %02x\n", chr); #endif hal_uart_rx_cb(hal_uart_rx_arg, chr); From 4005138882757ae536482c1d105b28c9869ab8ce Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 12 Feb 2021 14:33:03 +1100 Subject: [PATCH 058/174] extmod/modbluetooth: Allow NimBLE to use Zephyr static address. Zephyr controllers can be queried for a static address (computed from the device ID). BlueKitchen already supports this, but make them both use the same macro to enable the feature. --- extmod/btstack/modbluetooth_btstack.c | 12 ++++++------ extmod/nimble/modbluetooth_nimble.c | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/extmod/btstack/modbluetooth_btstack.c b/extmod/btstack/modbluetooth_btstack.c index 540b0fb7a9..c861c76d22 100644 --- a/extmod/btstack/modbluetooth_btstack.c +++ b/extmod/btstack/modbluetooth_btstack.c @@ -282,7 +282,7 @@ STATIC void btstack_packet_handler_att_server(uint8_t packet_type, uint16_t chan } } -#if MICROPY_BLUETOOTH_BTSTACK_ZEPHYR_STATIC_ADDRESS +#if MICROPY_BLUETOOTH_USE_ZEPHYR_STATIC_ADDRESS // During startup, the controller (e.g. Zephyr) might give us a static address that we can use. STATIC uint8_t controller_static_addr[6] = {0}; STATIC bool controller_static_addr_available = false; @@ -349,13 +349,13 @@ STATIC void btstack_packet_handler(uint8_t packet_type, uint8_t *packet, uint8_t DEBUG_printf(" --> hci transport packet sent\n"); } else if (event_type == HCI_EVENT_COMMAND_COMPLETE) { DEBUG_printf(" --> hci command complete\n"); - #if MICROPY_BLUETOOTH_BTSTACK_ZEPHYR_STATIC_ADDRESS + #if MICROPY_BLUETOOTH_USE_ZEPHYR_STATIC_ADDRESS if (memcmp(packet, read_static_address_command_complete_prefix, sizeof(read_static_address_command_complete_prefix)) == 0) { DEBUG_printf(" --> static address available\n"); reverse_48(&packet[7], controller_static_addr); controller_static_addr_available = true; } - #endif // MICROPY_BLUETOOTH_BTSTACK_ZEPHYR_STATIC_ADDRESS + #endif // MICROPY_BLUETOOTH_USE_ZEPHYR_STATIC_ADDRESS } else if (event_type == HCI_EVENT_COMMAND_STATUS) { DEBUG_printf(" --> hci command status\n"); } else if (event_type == HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS) { @@ -575,12 +575,12 @@ STATIC bool set_public_address(void) { } STATIC void set_random_address(void) { - #if MICROPY_BLUETOOTH_BTSTACK_ZEPHYR_STATIC_ADDRESS + #if MICROPY_BLUETOOTH_USE_ZEPHYR_STATIC_ADDRESS if (controller_static_addr_available) { DEBUG_printf("set_random_address: Using static address supplied by controller.\n"); gap_random_address_set(controller_static_addr); } else - #endif // MICROPY_BLUETOOTH_BTSTACK_ZEPHYR_STATIC_ADDRESS + #endif // MICROPY_BLUETOOTH_USE_ZEPHYR_STATIC_ADDRESS { bd_addr_t static_addr; @@ -635,7 +635,7 @@ int mp_bluetooth_init(void) { btstack_memory_init(); - #if MICROPY_BLUETOOTH_BTSTACK_ZEPHYR_STATIC_ADDRESS + #if MICROPY_BLUETOOTH_USE_ZEPHYR_STATIC_ADDRESS controller_static_addr_available = false; #endif diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c index 3910c599cb..a0a3998c66 100644 --- a/extmod/nimble/modbluetooth_nimble.c +++ b/extmod/nimble/modbluetooth_nimble.c @@ -48,6 +48,11 @@ #include "nimble/host/src/ble_l2cap_priv.h" #endif +#if MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD || MICROPY_BLUETOOTH_USE_ZEPHYR_STATIC_ADDRESS +// For ble_hs_hci_cmd_tx +#include "nimble/host/src/ble_hs_hci_priv.h" +#endif + #ifndef MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME #define MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME "MPY NIMBLE" #endif @@ -179,6 +184,14 @@ STATIC void set_random_address(bool nrpa) { // Mark it as STATIC (not RPA or NRPA). addr.val[5] |= 0xc0; } else + #elif MICROPY_BLUETOOTH_USE_ZEPHYR_STATIC_ADDRESS + if (!nrpa) { + DEBUG_printf("set_random_address: Generating static address from Zephyr controller\n"); + uint8_t buf[23]; + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_VENDOR, 0x09), NULL, 0, buf, sizeof(buf)); + assert(rc == 0); + memcpy(addr.val, buf + 1, 6); + } else #endif { DEBUG_printf("set_random_address: Generating random static address\n"); @@ -1688,9 +1701,6 @@ int mp_bluetooth_l2cap_recvinto(uint16_t conn_handle, uint16_t cid, uint8_t *buf #if MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD -// For ble_hs_hci_cmd_tx -#include "nimble/host/src/ble_hs_hci_priv.h" - int mp_bluetooth_hci_cmd(uint16_t ogf, uint16_t ocf, const uint8_t *req, size_t req_len, uint8_t *resp, size_t resp_len, uint8_t *status) { int rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(ogf, ocf), req, req_len, resp, resp_len); if (rc < BLE_HS_ERR_HCI_BASE || rc >= BLE_HS_ERR_HCI_BASE + 0x100) { From 2eed9780ba7074de9e464a2bc771ad14f0332a6c Mon Sep 17 00:00:00 2001 From: David Michieli Date: Tue, 16 Feb 2021 12:34:34 +1100 Subject: [PATCH 059/174] stm32/mboot: Add unpack-dfu command to mboot_pack_dfu.py tool. This command unpacks a previously packed DFU file, writing out a DFU which should be the same as the original (before packing). --- ports/stm32/mboot/mboot_pack_dfu.py | 26 ++++++++++++++++++++++++++ tools/ci.sh | 5 +++++ 2 files changed, 31 insertions(+) diff --git a/ports/stm32/mboot/mboot_pack_dfu.py b/ports/stm32/mboot/mboot_pack_dfu.py index 47382f5910..540057e06e 100644 --- a/ports/stm32/mboot/mboot_pack_dfu.py +++ b/ports/stm32/mboot/mboot_pack_dfu.py @@ -211,9 +211,16 @@ def pack_dfu(keys, args): def verify_pack_dfu(keys, filename): + """Verify packed dfu file against keys. Gathers decrypted binary data.""" full_sig = pyhy.hydro_sign(MBOOT_PACK_HYDRO_CONTEXT) _, elems = dfu_read(filename) + base_addr = None + binary_data = b"" + for addr, data in elems: + if base_addr is None: + base_addr = addr + header = struct.unpack(" Date: Thu, 2 Apr 2020 10:01:16 -0700 Subject: [PATCH 060/174] extmod/modussl: Fix ussl read/recv/send/write errors when non-blocking. Also fix related problems with socket on esp32, improve docs for wrap_socket, and add more tests. --- docs/library/ussl.rst | 22 +++- extmod/modussl_axtls.c | 29 ++++- extmod/modussl_mbedtls.c | 3 +- ports/esp32/modsocket.c | 8 +- tests/net_hosted/accept_timeout.py | 6 +- tests/net_hosted/connect_nonblock_xfer.py | 147 ++++++++++++++++++++++ tests/net_inet/ssl_errors.py | 51 ++++++++ tests/net_inet/test_tls_nonblock.py | 116 +++++++++++++++++ tests/net_inet/test_tls_sites.py | 6 +- tests/net_inet/test_tls_sites.py.exp | 3 +- 10 files changed, 372 insertions(+), 19 deletions(-) create mode 100644 tests/net_hosted/connect_nonblock_xfer.py create mode 100644 tests/net_inet/ssl_errors.py create mode 100644 tests/net_inet/test_tls_nonblock.py diff --git a/docs/library/ussl.rst b/docs/library/ussl.rst index ffe146331c..14e3f3ad14 100644 --- a/docs/library/ussl.rst +++ b/docs/library/ussl.rst @@ -13,16 +13,23 @@ facilities for network sockets, both client-side and server-side. Functions --------- -.. function:: ussl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, ca_certs=None) - +.. function:: ussl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, ca_certs=None, do_handshake=True) Takes a `stream` *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type), and returns an instance of ssl.SSLSocket, which wraps the underlying stream in an SSL context. Returned object has the usual `stream` interface methods like - ``read()``, ``write()``, etc. In MicroPython, the returned object does not expose - socket interface and methods like ``recv()``, ``send()``. In particular, a - server-side SSL socket should be created from a normal socket returned from + ``read()``, ``write()``, etc. + A server-side SSL socket should be created from a normal socket returned from :meth:`~usocket.socket.accept()` on a non-SSL listening server socket. + - *do_handshake* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + (there is no ``do_handshake`` method as in CPython). + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + Depending on the underlying module implementation in a particular :term:`MicroPython port`, some or all keyword arguments above may be not supported. @@ -31,6 +38,11 @@ Functions Some implementations of ``ussl`` module do NOT validate server certificates, which makes an SSL connection established prone to man-in-the-middle attacks. + CPython's ``wrap_socket`` returns an ``SSLSocket`` object which has methods typical + for sockets, such as ``send``, ``recv``, etc. MicroPython's ``wrap_socket`` + returns an object more similar to CPython's ``SSLObject`` which does not have + these socket methods. + Exceptions ---------- diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c index da5941a55b..9d59342067 100644 --- a/extmod/modussl_axtls.c +++ b/extmod/modussl_axtls.c @@ -167,10 +167,15 @@ STATIC mp_obj_ssl_socket_t *ussl_socket_new(mp_obj_t sock, struct ssl_args *args o->ssl_sock = ssl_client_new(o->ssl_ctx, (long)sock, NULL, 0, ext); if (args->do_handshake.u_bool) { - int res = ssl_handshake_status(o->ssl_sock); + int r = ssl_handshake_status(o->ssl_sock); - if (res != SSL_OK) { - ussl_raise_error(res); + if (r != SSL_OK) { + if (r == SSL_CLOSE_NOTIFY) { // EOF + r = MP_ENOTCONN; + } else if (r == SSL_EAGAIN) { + r = MP_EAGAIN; + } + ussl_raise_error(r); } } @@ -242,8 +247,24 @@ STATIC mp_uint_t ussl_socket_write(mp_obj_t o_in, const void *buf, mp_uint_t siz return MP_STREAM_ERROR; } - mp_int_t r = ssl_write(o->ssl_sock, buf, size); + mp_int_t r; +eagain: + r = ssl_write(o->ssl_sock, buf, size); + if (r == 0) { + // see comment in ussl_socket_read above + if (o->blocking) { + goto eagain; + } else { + r = SSL_EAGAIN; + } + } if (r < 0) { + if (r == SSL_CLOSE_NOTIFY || r == SSL_ERROR_CONN_LOST) { + return 0; // EOF + } + if (r == SSL_EAGAIN) { + r = MP_EAGAIN; + } *errcode = r; return MP_STREAM_ERROR; } diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c index 1677dc6e1c..277af37c7c 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -133,6 +133,7 @@ STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) { } } +// _mbedtls_ssl_recv is called by mbedtls to receive bytes from the underlying socket STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { mp_obj_t sock = *(mp_obj_t *)ctx; @@ -171,7 +172,7 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { mbedtls_pk_init(&o->pkey); mbedtls_ctr_drbg_init(&o->ctr_drbg); #ifdef MBEDTLS_DEBUG_C - // Debug level (0-4) + // Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose mbedtls_debug_set_threshold(0); #endif diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 61761d8194..5135e31631 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -558,7 +558,8 @@ int _socket_send(socket_obj_t *sock, const char *data, size_t datalen) { MP_THREAD_GIL_EXIT(); int r = lwip_write(sock->fd, data + sentlen, datalen - sentlen); MP_THREAD_GIL_ENTER(); - if (r < 0 && errno != EWOULDBLOCK) { + // lwip returns EINPROGRESS when trying to send right after a non-blocking connect + if (r < 0 && errno != EWOULDBLOCK && errno != EINPROGRESS) { mp_raise_OSError(errno); } if (r > 0) { @@ -567,7 +568,7 @@ int _socket_send(socket_obj_t *sock, const char *data, size_t datalen) { check_for_exceptions(); } if (sentlen == 0) { - mp_raise_OSError(MP_ETIMEDOUT); + mp_raise_OSError(sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT); } return sentlen; } @@ -650,7 +651,8 @@ STATIC mp_uint_t socket_stream_write(mp_obj_t self_in, const void *buf, mp_uint_ if (r > 0) { return r; } - if (r < 0 && errno != EWOULDBLOCK) { + // lwip returns MP_EINPROGRESS when trying to write right after a non-blocking connect + if (r < 0 && errno != EWOULDBLOCK && errno != EINPROGRESS) { *errcode = errno; return MP_STREAM_ERROR; } diff --git a/tests/net_hosted/accept_timeout.py b/tests/net_hosted/accept_timeout.py index ff989110ae..5f528d557d 100644 --- a/tests/net_hosted/accept_timeout.py +++ b/tests/net_hosted/accept_timeout.py @@ -1,9 +1,9 @@ # test that socket.accept() on a socket with timeout raises ETIMEDOUT try: - import usocket as socket + import uerrno as errno, usocket as socket except: - import socket + import errno, socket try: socket.socket.settimeout @@ -18,5 +18,5 @@ s.listen(1) try: s.accept() except OSError as er: - print(er.args[0] in (110, "timed out")) # 110 is ETIMEDOUT; CPython uses a string + print(er.args[0] in (errno.ETIMEDOUT, "timed out")) # CPython uses a string instead of errno s.close() diff --git a/tests/net_hosted/connect_nonblock_xfer.py b/tests/net_hosted/connect_nonblock_xfer.py new file mode 100644 index 0000000000..feb648ea0a --- /dev/null +++ b/tests/net_hosted/connect_nonblock_xfer.py @@ -0,0 +1,147 @@ +# test that socket.connect() on a non-blocking socket raises EINPROGRESS +# and that an immediate write/send/read/recv does the right thing + +try: + import sys, time + import uerrno as errno, usocket as socket, ussl as ssl +except: + import socket, errno, ssl +isMP = sys.implementation.name == "micropython" + + +def dp(e): + # uncomment next line for development and testing, to print the actual exceptions + # print(repr(e)) + pass + + +# do_connect establishes the socket and wraps it if tls is True. +# If handshake is true, the initial connect (and TLS handshake) is +# allowed to be performed before returning. +def do_connect(peer_addr, tls, handshake): + s = socket.socket() + s.setblocking(False) + try: + # print("Connecting to", peer_addr) + s.connect(peer_addr) + except OSError as er: + print("connect:", er.args[0] == errno.EINPROGRESS) + if er.args[0] != errno.EINPROGRESS: + print(" got", er.args[0]) + # wrap with ssl/tls if desired + if tls: + try: + if sys.implementation.name == "micropython": + s = ssl.wrap_socket(s, do_handshake=handshake) + else: + s = ssl.wrap_socket(s, do_handshake_on_connect=handshake) + print("wrap: True") + except Exception as e: + dp(e) + print("wrap:", e) + elif handshake: + # just sleep a little bit, this allows any connect() errors to happen + time.sleep(0.2) + return s + + +# test runs the test against a specific peer address. +def test(peer_addr, tls=False, handshake=False): + # MicroPython plain sockets have read/write, but CPython's don't + # MicroPython TLS sockets and CPython's have read/write + # hasRW captures this wonderful state of affairs + hasRW = isMP or tls + + # MicroPython plain sockets and CPython's have send/recv + # MicroPython TLS sockets don't have send/recv, but CPython's do + # hasSR captures this wonderful state of affairs + hasSR = not (isMP and tls) + + # connect + send + if hasSR: + s = do_connect(peer_addr, tls, handshake) + # send -> 4 or EAGAIN + try: + ret = s.send(b"1234") + print("send:", handshake and ret == 4) + except OSError as er: + # + dp(er) + print("send:", er.args[0] in (errno.EAGAIN, errno.EINPROGRESS)) + s.close() + else: # fake it... + print("connect:", True) + if tls: + print("wrap:", True) + print("send:", True) + + # connect + write + if hasRW: + s = do_connect(peer_addr, tls, handshake) + # write -> None + try: + ret = s.write(b"1234") + print("write:", ret in (4, None)) # SSL may accept 4 into buffer + except OSError as er: + dp(er) + print("write:", False) # should not raise + except ValueError as er: # CPython + dp(er) + print("write:", er.args[0] == "Write on closed or unwrapped SSL socket.") + s.close() + else: # fake it... + print("connect:", True) + if tls: + print("wrap:", True) + print("write:", True) + + if hasSR: + # connect + recv + s = do_connect(peer_addr, tls, handshake) + # recv -> EAGAIN + try: + print("recv:", s.recv(10)) + except OSError as er: + dp(er) + print("recv:", er.args[0] == errno.EAGAIN) + s.close() + else: # fake it... + print("connect:", True) + if tls: + print("wrap:", True) + print("recv:", True) + + # connect + read + if hasRW: + s = do_connect(peer_addr, tls, handshake) + # read -> None + try: + ret = s.read(10) + print("read:", ret is None) + except OSError as er: + dp(er) + print("read:", False) # should not raise + except ValueError as er: # CPython + dp(er) + print("read:", er.args[0] == "Read on closed or unwrapped SSL socket.") + s.close() + else: # fake it... + print("connect:", True) + if tls: + print("wrap:", True) + print("read:", True) + + +if __name__ == "__main__": + # these tests use a non-existent test IP address, this way the connect takes forever and + # we can see EAGAIN/None (https://tools.ietf.org/html/rfc5737) + print("--- Plain sockets to nowhere ---") + test(socket.getaddrinfo("192.0.2.1", 80)[0][-1], False, False) + print("--- SSL sockets to nowhere ---") + # this test fails with AXTLS because do_handshake=False blocks on first read/write and + # there it times out until the connect is aborted + test(socket.getaddrinfo("192.0.2.1", 443)[0][-1], True, False) + print("--- Plain sockets ---") + test(socket.getaddrinfo("micropython.org", 80)[0][-1], False, True) + print("--- SSL sockets ---") + test(socket.getaddrinfo("micropython.org", 443)[0][-1], True, True) diff --git a/tests/net_inet/ssl_errors.py b/tests/net_inet/ssl_errors.py new file mode 100644 index 0000000000..fd281b1c49 --- /dev/null +++ b/tests/net_inet/ssl_errors.py @@ -0,0 +1,51 @@ +# test that socket.connect() on a non-blocking socket raises EINPROGRESS +# and that an immediate write/send/read/recv does the right thing + +import sys + +try: + import uerrno as errno, usocket as socket, ussl as ssl +except: + import errno, socket, ssl + + +def test(addr, hostname, block=True): + print("---", hostname or addr) + s = socket.socket() + s.setblocking(block) + try: + s.connect(addr) + print("connected") + except OSError as e: + if e.args[0] != errno.EINPROGRESS: + raise + print("EINPROGRESS") + + try: + if sys.implementation.name == "micropython": + s = ssl.wrap_socket(s, do_handshake=block) + else: + s = ssl.wrap_socket(s, do_handshake_on_connect=block) + print("wrap: True") + except OSError: + print("wrap: error") + + if not block: + try: + while s.write(b"0") is None: + pass + except (ValueError, OSError): # CPython raises ValueError, MicroPython raises OSError + print("write: error") + s.close() + + +if __name__ == "__main__": + # connect to plain HTTP port, oops! + addr = socket.getaddrinfo("micropython.org", 80)[0][-1] + test(addr, None) + # connect to plain HTTP port, oops! + addr = socket.getaddrinfo("micropython.org", 80)[0][-1] + test(addr, None, False) + # connect to server with self-signed cert, oops! + addr = socket.getaddrinfo("test.mosquitto.org", 8883)[0][-1] + test(addr, "test.mosquitto.org") diff --git a/tests/net_inet/test_tls_nonblock.py b/tests/net_inet/test_tls_nonblock.py new file mode 100644 index 0000000000..c27ead3d50 --- /dev/null +++ b/tests/net_inet/test_tls_nonblock.py @@ -0,0 +1,116 @@ +try: + import usocket as socket, ussl as ssl, uerrno as errno, sys +except: + import socket, ssl, errno, sys, time, select + + +def test_one(site, opts): + ai = socket.getaddrinfo(site, 443) + addr = ai[0][-1] + print(addr) + + # Connect the raw socket + s = socket.socket() + s.setblocking(False) + try: + s.connect(addr) + raise OSError(-1, "connect blocks") + except OSError as e: + if e.args[0] != errno.EINPROGRESS: + raise + + if sys.implementation.name != "micropython": + # in CPython we have to wait, otherwise wrap_socket is not happy + select.select([], [s], []) + + try: + # Wrap with SSL + try: + if sys.implementation.name == "micropython": + s = ssl.wrap_socket(s, do_handshake=False) + else: + s = ssl.wrap_socket(s, do_handshake_on_connect=False) + except OSError as e: + if e.args[0] != errno.EINPROGRESS: + raise + print("wrapped") + + # CPython needs to be told to do the handshake + if sys.implementation.name != "micropython": + while True: + try: + s.do_handshake() + break + except ssl.SSLError as err: + if err.args[0] == ssl.SSL_ERROR_WANT_READ: + select.select([s], [], []) + elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: + select.select([], [s], []) + else: + raise + time.sleep(0.1) + # print("shook hands") + + # Write HTTP request + out = b"GET / HTTP/1.0\r\nHost: %s\r\n\r\n" % bytes(site, "latin") + while len(out) > 0: + n = s.write(out) + if n is None: + continue + if n > 0: + out = out[n:] + elif n == 0: + raise OSError(-1, "unexpected EOF in write") + print("wrote") + + # Read response + resp = b"" + while True: + try: + b = s.read(128) + except OSError as err: + if err.args[0] == 2: # 2=ssl.SSL_ERROR_WANT_READ: + continue + raise + if b is None: + continue + if len(b) > 0: + if len(resp) < 1024: + resp += b + elif len(b) == 0: + break + print("read") + + if resp[:7] != b"HTTP/1.": + raise ValueError("response doesn't start with HTTP/1.") + # print(resp) + + finally: + s.close() + + +SITES = [ + "google.com", + {"host": "www.google.com"}, + "micropython.org", + "pypi.org", + "api.telegram.org", + {"host": "api.pushbullet.com", "sni": True}, +] + + +def main(): + for site in SITES: + opts = {} + if isinstance(site, dict): + opts = site + site = opts["host"] + try: + test_one(site, opts) + print(site, "ok") + except Exception as e: + print(site, "error") + print("DONE") + + +main() diff --git a/tests/net_inet/test_tls_sites.py b/tests/net_inet/test_tls_sites.py index d2cb928c8d..3f945efb83 100644 --- a/tests/net_inet/test_tls_sites.py +++ b/tests/net_inet/test_tls_sites.py @@ -27,6 +27,8 @@ def test_one(site, opts): s.write(b"GET / HTTP/1.0\r\nHost: %s\r\n\r\n" % bytes(site, "latin")) resp = s.read(4096) + if resp[:7] != b"HTTP/1.": + raise ValueError("response doesn't start with HTTP/1.") # print(resp) finally: @@ -36,10 +38,10 @@ def test_one(site, opts): SITES = [ "google.com", "www.google.com", + "micropython.org", + "pypi.org", "api.telegram.org", {"host": "api.pushbullet.com", "sni": True}, - # "w9rybpfril.execute-api.ap-southeast-2.amazonaws.com", - {"host": "w9rybpfril.execute-api.ap-southeast-2.amazonaws.com", "sni": True}, ] diff --git a/tests/net_inet/test_tls_sites.py.exp b/tests/net_inet/test_tls_sites.py.exp index 2f3c113d2f..bc4a8dbd11 100644 --- a/tests/net_inet/test_tls_sites.py.exp +++ b/tests/net_inet/test_tls_sites.py.exp @@ -1,5 +1,6 @@ google.com ok www.google.com ok +micropython.org ok +pypi.org ok api.telegram.org ok api.pushbullet.com ok -w9rybpfril.execute-api.ap-southeast-2.amazonaws.com ok From caeec80a9c34f950da41ffe4d5e6f3b4adc680fd Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Feb 2021 12:04:38 +1100 Subject: [PATCH 061/174] stm32/usb: Allow a board to configure USBD_VID and all PIDs. If a board defines USBD_VID then that will be used instead of the default. And then the board must also define all USBD_PID_xxx values that it needs. Signed-off-by: Damien George --- ports/stm32/usb.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h index f69af86e5b..295038ebd4 100644 --- a/ports/stm32/usb.h +++ b/ports/stm32/usb.h @@ -30,6 +30,7 @@ #define PYB_USB_FLAG_USB_MODE_CALLED (0x0002) +#ifndef USBD_VID // Windows needs a different PID to distinguish different device configurations #define USBD_VID (0xf055) #define USBD_PID_CDC_MSC (0x9800) @@ -43,6 +44,7 @@ #define USBD_PID_CDC_MSC_HID (0x9808) #define USBD_PID_CDC2_MSC_HID (0x9809) #define USBD_PID_CDC3_MSC_HID (0x980a) +#endif typedef enum { PYB_USB_STORAGE_MEDIUM_NONE = 0, From 9b78f3e6c6b3eee84dcce2ff75764d8e7d4c713c Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Feb 2021 13:03:52 +1100 Subject: [PATCH 062/174] stm32: Make pyb, uos, utime, machine and onewire modules configurable. The default for these is to enable them, but they can now be disabled individually by a board configuration. Signed-off-by: Damien George --- ports/stm32/modmachine.c | 4 ++ ports/stm32/mpconfigboard_common.h | 5 +++ ports/stm32/mpconfigport.h | 67 ++++++++++++++++++++++++------ 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index c5f49b6ef4..f9fd1d9a64 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -406,7 +406,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) }, + #if MICROPY_PY_MACHINE_PULSE { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, @@ -425,8 +427,10 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { #endif { MP_ROM_QSTR(MP_QSTR_SoftI2C), MP_ROM_PTR(&mp_machine_soft_i2c_type) }, #endif + #if MICROPY_PY_MACHINE_SPI { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hard_spi_type) }, { MP_ROM_QSTR(MP_QSTR_SoftSPI), MP_ROM_PTR(&mp_machine_soft_spi_type) }, + #endif { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&pyb_wdt_type) }, { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index f493bb5d4a..615310e51b 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -37,6 +37,11 @@ #define MICROPY_PY_STM (1) #endif +// Whether to include the pyb module +#ifndef MICROPY_PY_PYB +#define MICROPY_PY_PYB (1) +#endif + // Whether to include legacy functions and classes in the pyb module #ifndef MICROPY_PY_PYB_LEGACY #define MICROPY_PY_PYB_LEGACY (1) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index a47529d8b3..407a3e6c6a 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -166,6 +166,11 @@ #ifndef MICROPY_PY_UBINASCII #define MICROPY_PY_UBINASCII (1) #endif +#ifndef MICROPY_PY_UOS +#define MICROPY_PY_UOS (1) +#endif +#define MICROPY_PY_OS_DUPTERM (3) +#define MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM (1) #ifndef MICROPY_PY_URANDOM #define MICROPY_PY_URANDOM (1) #define MICROPY_PY_URANDOM_SEED_INIT_FUNC (rng_get()) @@ -174,13 +179,15 @@ #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) #endif #define MICROPY_PY_USELECT (1) +#ifndef MICROPY_PY_UTIME +#define MICROPY_PY_UTIME (1) +#endif +#define MICROPY_PY_UTIME_MP_HAL (MICROPY_PY_UTIME) #ifndef MICROPY_PY_UTIMEQ #define MICROPY_PY_UTIMEQ (1) #endif -#define MICROPY_PY_UTIME_MP_HAL (1) -#define MICROPY_PY_OS_DUPTERM (3) -#define MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM (1) #define MICROPY_PY_LWIP_SOCK_RAW (MICROPY_PY_LWIP) +#ifndef MICROPY_PY_MACHINE #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_PULSE (1) #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new @@ -188,6 +195,7 @@ #define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_MACHINE_SPI_MSB (SPI_FIRSTBIT_MSB) #define MICROPY_PY_MACHINE_SPI_LSB (SPI_FIRSTBIT_LSB) +#endif #define MICROPY_HW_SOFTSPI_MIN_DELAY (0) #define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48) #define MICROPY_PY_UWEBSOCKET (MICROPY_PY_LWIP) @@ -201,6 +209,9 @@ #ifndef MICROPY_PY_NETWORK #define MICROPY_PY_NETWORK (1) #endif +#ifndef MICROPY_PY_ONEWIRE +#define MICROPY_PY_ONEWIRE (1) +#endif // fatfs configuration used in ffconf.h #define MICROPY_FATFS_ENABLE_LFN (1) @@ -246,12 +257,38 @@ extern const struct _mp_obj_module_t mp_module_usocket; extern const struct _mp_obj_module_t mp_module_network; extern const struct _mp_obj_module_t mp_module_onewire; +#if MICROPY_PY_PYB +#define PYB_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, +#else +#define PYB_BUILTIN_MODULE +#endif + #if MICROPY_PY_STM -#define STM_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_stm), MP_ROM_PTR(&stm_module) }, +#define STM_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_stm), MP_ROM_PTR(&stm_module) }, #else #define STM_BUILTIN_MODULE #endif +#if MICROPY_PY_MACHINE +#define MACHINE_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, +#define MACHINE_BUILTIN_MODULE_CONSTANTS { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, +#else +#define MACHINE_BUILTIN_MODULE +#define MACHINE_BUILTIN_MODULE_CONSTANTS +#endif + +#if MICROPY_PY_UOS +#define UOS_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, +#else +#define UOS_BUILTIN_MODULE +#endif + +#if MICROPY_PY_UTIME +#define UTIME_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, +#else +#define UTIME_BUILTIN_MODULE +#endif + #if MICROPY_PY_USOCKET && MICROPY_PY_LWIP // usocket implementation provided by lwIP #define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_lwip) }, @@ -269,21 +306,27 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define NETWORK_BUILTIN_MODULE #endif +#if MICROPY_PY_ONEWIRE +#define ONEWIRE_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR__onewire), MP_ROM_PTR(&mp_module_onewire) }, +#else +#define ONEWIRE_BUILTIN_MODULE +#endif + #define MICROPY_PORT_BUILTIN_MODULES \ - { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \ - { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ + MACHINE_BUILTIN_MODULE \ + PYB_BUILTIN_MODULE \ STM_BUILTIN_MODULE \ - { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \ - { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ + UOS_BUILTIN_MODULE \ + UTIME_BUILTIN_MODULE \ SOCKET_BUILTIN_MODULE \ NETWORK_BUILTIN_MODULE \ - { MP_ROM_QSTR(MP_QSTR__onewire), MP_ROM_PTR(&mp_module_onewire) }, \ + ONEWIRE_BUILTIN_MODULE \ // extra constants #define MICROPY_PORT_CONSTANTS \ - { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \ - { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ - { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ + MACHINE_BUILTIN_MODULE \ + MACHINE_BUILTIN_MODULE_CONSTANTS \ + PYB_BUILTIN_MODULE \ STM_BUILTIN_MODULE \ #define MP_STATE_PORT MP_STATE_VM From 5c92ff53fed97ca1f5f5b8cd427b49ee79037298 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Feb 2021 13:05:28 +1100 Subject: [PATCH 063/174] stm32/boards: Disable onewire module on boards with small flash. Signed-off-by: Damien George --- ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h | 1 + ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h | 1 + ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h | 1 + 3 files changed, 3 insertions(+) diff --git a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h index 531794de66..b330e8fdc1 100644 --- a/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h +++ b/ports/stm32/boards/B_L072Z_LRWAN1/mpconfigboard.h @@ -13,6 +13,7 @@ #define MICROPY_PY_FRAMEBUF (0) #define MICROPY_PY_USOCKET (0) #define MICROPY_PY_NETWORK (0) +#define MICROPY_PY_ONEWIRE (0) #define MICROPY_PY_STM (0) #define MICROPY_PY_PYB_LEGACY (0) #define MICROPY_PY_UHEAPQ (0) diff --git a/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h index 2b01bd33a3..a5c5dc9a0e 100644 --- a/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L073RZ/mpconfigboard.h @@ -13,6 +13,7 @@ #define MICROPY_PY_FRAMEBUF (0) #define MICROPY_PY_USOCKET (0) #define MICROPY_PY_NETWORK (0) +#define MICROPY_PY_ONEWIRE (0) #define MICROPY_PY_STM (0) #define MICROPY_PY_PYB_LEGACY (0) #define MICROPY_PY_UHEAPQ (0) diff --git a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h index 6a3a364dc5..14b3bab8a7 100644 --- a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h @@ -7,6 +7,7 @@ #define MICROPY_PY_GENERATOR_PEND_THROW (0) #define MICROPY_PY_USOCKET (0) #define MICROPY_PY_NETWORK (0) +#define MICROPY_PY_ONEWIRE (0) #define MICROPY_PY_STM (0) #define MICROPY_PY_PYB_LEGACY (0) #define MICROPY_PY_UHEAPQ (0) From 629fdc366adacf345bbacd83145be2f78823ee57 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Wed, 17 Feb 2021 13:45:14 +1100 Subject: [PATCH 064/174] stm32/mpbthciport: Fix initial baudrate to use provided value. Fixes bug introduced in the recent bffb71f523e4bcc21b913af291deeb67091bed88 --- ports/stm32/mpbthciport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/mpbthciport.c b/ports/stm32/mpbthciport.c index 5e51892e6f..2d34e5e2b7 100644 --- a/ports/stm32/mpbthciport.c +++ b/ports/stm32/mpbthciport.c @@ -196,7 +196,7 @@ int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) { MP_STATE_PORT(pyb_uart_obj_all)[mp_bluetooth_hci_uart_obj.uart_id - 1] = &mp_bluetooth_hci_uart_obj; // Initialise the UART. - uart_init(&mp_bluetooth_hci_uart_obj, 115200, UART_WORDLENGTH_8B, UART_PARITY_NONE, UART_STOPBITS_1, UART_HWCONTROL_RTS | UART_HWCONTROL_CTS); + uart_init(&mp_bluetooth_hci_uart_obj, baudrate, UART_WORDLENGTH_8B, UART_PARITY_NONE, UART_STOPBITS_1, UART_HWCONTROL_RTS | UART_HWCONTROL_CTS); uart_set_rxbuf(&mp_bluetooth_hci_uart_obj, sizeof(hci_uart_rxbuf), hci_uart_rxbuf); // Add IRQ handler for IDLE (i.e. packet finished). From 89cb2c6b80ccf302fd7519bd7b3e00680fc717f3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Feb 2021 15:45:06 +1100 Subject: [PATCH 065/174] stm32/mpbthciport: Use mp_printf instead of printf for error message. Signed-off-by: Damien George --- ports/stm32/mpbthciport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/mpbthciport.c b/ports/stm32/mpbthciport.c index 2d34e5e2b7..c3cd864e2b 100644 --- a/ports/stm32/mpbthciport.c +++ b/ports/stm32/mpbthciport.c @@ -232,7 +232,7 @@ int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len) { int errcode; uart_tx_data(&mp_bluetooth_hci_uart_obj, (void *)buf, len, &errcode); if (errcode != 0) { - printf("\nmp_bluetooth_hci_uart_write: failed to write to UART %d\n", errcode); + mp_printf(&mp_plat_print, "\nmp_bluetooth_hci_uart_write: failed to write to UART %d\n", errcode); } return 0; } From 301fe805caaa4ff6a566fb4ef494ef18553dfbfe Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Feb 2021 15:45:54 +1100 Subject: [PATCH 066/174] stm32/mpbtstackport: Allow chipset and secondary baudrate to be set. Signed-off-by: Damien George --- ports/stm32/boards/PYBD_SF2/mpconfigboard.h | 1 + ports/stm32/mpbtstackport.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h index 45d968f353..dc42751fff 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h @@ -185,6 +185,7 @@ extern struct _spi_bdev_t spi_bdev2; // Bluetooth config #define MICROPY_HW_BLE_UART_ID (PYB_UART_6) #define MICROPY_HW_BLE_UART_BAUDRATE (115200) +#define MICROPY_HW_BLE_UART_BAUDRATE_SECONDARY (3000000) /******************************************************************************/ // Bootloader configuration diff --git a/ports/stm32/mpbtstackport.c b/ports/stm32/mpbtstackport.c index a031a6a151..3dfd8cb3c4 100644 --- a/ports/stm32/mpbtstackport.c +++ b/ports/stm32/mpbtstackport.c @@ -58,7 +58,7 @@ uint32_t hal_time_ms(void) { STATIC const hci_transport_config_uart_t hci_transport_config_uart = { HCI_TRANSPORT_CONFIG_UART, MICROPY_HW_BLE_UART_BAUDRATE, - 3000000, + MICROPY_HW_BLE_UART_BAUDRATE_SECONDARY, 0, NULL, }; @@ -90,9 +90,9 @@ void mp_bluetooth_btstack_port_init(void) { const hci_transport_t *transport = hci_transport_h4_instance(&mp_bluetooth_btstack_hci_uart_block); hci_init(transport, &hci_transport_config_uart); - // TODO: Probably not necessary for BCM (we have our own firmware loader in the cyw43 driver), - // but might be worth investigating for other controllers in the future. - // hci_set_chipset(btstack_chipset_bcm_instance()); + #ifdef MICROPY_HW_BLE_BTSTACK_CHIPSET_INSTANCE + hci_set_chipset(MICROPY_HW_BLE_BTSTACK_CHIPSET_INSTANCE); + #endif } void mp_bluetooth_btstack_port_deinit(void) { From cf6a0158806b11c521b9c9f8a1104f577a78fe1e Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Feb 2021 16:06:56 +1100 Subject: [PATCH 067/174] extmod/btstack: Use MICROPY_HW_BLE_UART_BAUDRATE for first UART init. Otherwise the UART may be left in a state at baudrate=0. Signed-off-by: Damien George --- extmod/btstack/btstack_hci_uart.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extmod/btstack/btstack_hci_uart.c b/extmod/btstack/btstack_hci_uart.c index 0a137bbae4..7205dba069 100644 --- a/extmod/btstack/btstack_hci_uart.c +++ b/extmod/btstack/btstack_hci_uart.c @@ -67,8 +67,7 @@ STATIC int btstack_uart_init(const btstack_uart_config_t *uart_config) { send_handler = NULL; // Set up the UART peripheral, attach IRQ and power up the HCI controller. - // We haven't been told the baud rate yet, so defer that until btstack_uart_set_baudrate. - if (mp_bluetooth_hci_uart_init(MICROPY_HW_BLE_UART_ID, 0)) { + if (mp_bluetooth_hci_uart_init(MICROPY_HW_BLE_UART_ID, MICROPY_HW_BLE_UART_BAUDRATE)) { init_success = false; return -1; } From d4b45898f58aae66c706ca5f832f11727daef46b Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 18 Feb 2021 13:59:03 +1100 Subject: [PATCH 068/174] stm32/mboot: After sig verify, only write firmware-head if latter valid. So that mboot can be used to program encrypted/signed firmware to regions of flash that are not the main application, eg that are the filesystem. Signed-off-by: Damien George --- ports/stm32/mboot/pack.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/ports/stm32/mboot/pack.c b/ports/stm32/mboot/pack.c index 63ab93ea30..88529ec50a 100644 --- a/ports/stm32/mboot/pack.c +++ b/ports/stm32/mboot/pack.c @@ -61,10 +61,14 @@ static uint8_t uncompressed_buf[MBOOT_PACK_GZIP_BUFFER_SIZE] __attribute__((alig // that a double-word write to flash can only be done once (due to ECC). static uint8_t firmware_head[8]; +// Flag to indicate that firmware_head contains valid data. +static bool firmware_head_valid; + void mboot_pack_init(void) { erased_base_addr = 0; erased_top_addr = 0; firmware_chunk_base_addr = 0; + firmware_head_valid = false; } // In encrypted mode the erase is automatically managed. @@ -103,6 +107,7 @@ static int mboot_pack_commit_chunk(uint32_t addr, uint8_t *data, size_t len) { addr += sizeof(firmware_head); data += sizeof(firmware_head); len -= sizeof(firmware_head); + firmware_head_valid = true; } // Commit this piece of the firmware. @@ -131,7 +136,7 @@ static int mboot_pack_handle_full_sig(void) { while (len) { uint32_t l = len <= buf_alloc ? len : buf_alloc; hw_read(addr, l, buf); - if (addr == APPLICATION_ADDR) { + if (addr == APPLICATION_ADDR && firmware_head_valid) { // The start of the firmware was not yet written to flash so copy // it out of the temporary buffer to compute the full signature. memcpy(buf, firmware_head, sizeof(firmware_head)); @@ -154,8 +159,13 @@ static int mboot_pack_handle_full_sig(void) { } // Full firmware passed the signature check. - // Write the start of the firmware so it boots. - return hw_write(APPLICATION_ADDR, firmware_head, sizeof(firmware_head)); + + if (firmware_head_valid) { + // Write the start of the firmware so it boots. + ret = hw_write(APPLICATION_ADDR, firmware_head, sizeof(firmware_head)); + } + + return ret; } // Handle a chunk with firmware data. From 466ad35a725742928ef7b12522cc75929083af35 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 18 Feb 2021 11:51:01 +1100 Subject: [PATCH 069/174] esp32/boards: Enable size optimisation for builds. This enables -Os for compilation, but still keeps full assertion messages. With IDF v4.2, -Os changes the GENERIC firmware size from 1512176 down to 1384640, and the GENERIC_SPIRAM firmware is now 1452320 which fits in the allocated partition. Signed-off-by: Damien George --- ports/esp32/boards/sdkconfig.base | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index c84dd606b2..91e68c7bf6 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -4,6 +4,12 @@ CONFIG_IDF_TARGET="esp32" CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 +# Compiler options: use -Os to reduce size, but keep full assertions +# (CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is for IDF 4.0.2) +CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y + # Application manager CONFIG_APP_EXCLUDE_PROJECT_VER_VAR=y CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR=y From 143372ab5e41a609b5b7d8bb60af1a5fd478e7ea Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 19 Feb 2021 10:38:01 +1100 Subject: [PATCH 070/174] esp32: Add support to build with ESP-IDF v4.3 pre-release. The esp32 port now builds against IDF v4.3-beta1, as well as v4.4-dev. Signed-off-by: Damien George --- ports/esp32/main/CMakeLists.txt | 6 ++++++ ports/esp32/modesp32.c | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index 52985383f9..b6cf214bba 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -113,6 +113,12 @@ if(IDF_VERSION_MINOR GREATER_EQUAL 2) list(APPEND IDF_COMPONENTS esp_timer) endif() +if(IDF_VERSION_MINOR GREATER_EQUAL 3) + list(APPEND IDF_COMPONENTS esp_hw_support) + list(APPEND IDF_COMPONENTS esp_pm) + list(APPEND IDF_COMPONENTS hal) +endif() + # Register the main IDF component. idf_component_register( SRCS diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c index 28d1762d24..d7c6bf0fa3 100644 --- a/ports/esp32/modesp32.c +++ b/ports/esp32/modesp32.c @@ -35,7 +35,6 @@ #include "driver/adc.h" #include "esp_heap_caps.h" #include "multi_heap.h" -#include "../heap_private.h" #include "py/nlr.h" #include "py/obj.h" @@ -46,6 +45,13 @@ #include "machine_rtc.h" #include "modesp32.h" +// These private includes are needed for idf_heap_info. +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) +#define MULTI_HEAP_FREERTOS +#include "../multi_heap_platform.h" +#endif +#include "../heap_private.h" + STATIC mp_obj_t esp32_wake_on_touch(const mp_obj_t wake) { if (machine_rtc_config.ext0_pin != -1) { From c10d431819f9f7095c3573c98f01c98526a2cb0b Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Mon, 18 Jan 2021 01:06:12 -0800 Subject: [PATCH 071/174] esp32: Add basic support for Non-Volatile-Storage in esp32 module. This commit implements basic NVS support for the esp32. It follows the pattern of the esp32.Partition class and exposes an NVS object per NVS namespace. The initial support provided is only for signed 32-bit integers and binary blobs. It's easy (albeit a bit tedious) to add support for more types. See discussions in: #4436, #4707, #6780 --- docs/library/esp32.rst | 48 ++++++++++ ports/esp32/esp32_nvs.c | 151 ++++++++++++++++++++++++++++++++ ports/esp32/main/CMakeLists.txt | 1 + ports/esp32/modesp32.c | 1 + ports/esp32/modesp32.h | 1 + tests/esp32/esp32_nvs.py | 67 ++++++++++++++ tests/esp32/esp32_nvs.py.exp | 14 +++ 7 files changed, 283 insertions(+) create mode 100644 ports/esp32/esp32_nvs.c create mode 100644 tests/esp32/esp32_nvs.py create mode 100644 tests/esp32/esp32_nvs.py.exp diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index c6777b8a7d..f179a31ef6 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -269,3 +269,51 @@ Constants esp32.WAKEUP_ANY_HIGH Selects the wake level for pins. + +Non-Volatile Storage +-------------------- + +This class gives access to the Non-Volatile storage managed by ESP-IDF. The NVS is partitioned +into namespaces and each namespace contains typed key-value pairs. The keys are strings and the +values may be various integer types, strings, and binary blobs. The driver currently only +supports 32-bit signed integers and blobs. + +.. warning:: + + Changes to NVS need to be committed to flash by calling the commit method. Failure + to call commit results in changes being lost at the next reset. + +.. class:: NVS(namespace) + + Create an object providing access to a namespace (which is automatically created if not + present). + +.. method:: NVS.set_i32(key, value) + + Sets a 32-bit signed integer value for the specified key. Remember to call *commit*! + +.. method:: NVS.get_i32(key) + + Returns the signed integer value for the specified key. Raises an OSError if the key does not + exist or has a different type. + +.. method:: NVS.set_blob(key, value) + + Sets a binary blob value for the specified key. The value passed in must support the buffer + protocol, e.g. bytes, bytearray, str. (Note that esp-idf distinguishes blobs and strings, this + method always writes a blob even if a string is passed in as value.) + Remember to call *commit*! + +.. method:: NVS.get_blob(key, buffer) + + Reads the value of the blob for the specified key into the buffer, which must be a bytearray. + Returns the actual length read. Raises an OSError if the key does not exist, has a different + type, or if the buffer is too small. + +.. method:: NVS.erase_key(key) + + Erases a key-value pair. + +.. method:: NVS.commit() + + Commits changes made by *set_xxx* methods to flash. diff --git a/ports/esp32/esp32_nvs.c b/ports/esp32/esp32_nvs.c new file mode 100644 index 0000000000..d13151d3ce --- /dev/null +++ b/ports/esp32/esp32_nvs.c @@ -0,0 +1,151 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 by Thorsten von Eicken + * + * 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 "py/runtime.h" +#include "py/mperrno.h" +#include "mphalport.h" +#include "modesp32.h" +#include "nvs_flash.h" +#include "nvs.h" + +// This file implements the NVS (Non-Volatile Storage) class in the esp32 module. +// It provides simple access to the NVS feature provided by ESP-IDF. + +// NVS python object that represents an NVS namespace. +typedef struct _esp32_nvs_obj_t { + mp_obj_base_t base; + nvs_handle_t namespace; +} esp32_nvs_obj_t; + +// *esp32_nvs_new allocates a python NVS object given a handle to an esp-idf namespace C obj. +STATIC esp32_nvs_obj_t *esp32_nvs_new(nvs_handle_t namespace) { + esp32_nvs_obj_t *self = m_new_obj(esp32_nvs_obj_t); + self->base.type = &esp32_nvs_type; + self->namespace = namespace; + return self; +} + +// esp32_nvs_print prints an NVS object, unfortunately it doesn't seem possible to extract the +// namespace string or anything else from the opaque handle provided by esp-idf. +STATIC void esp32_nvs_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + // esp32_nvs_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, ""); +} + +// esp32_nvs_make_new constructs a handle to an NVS namespace. +STATIC mp_obj_t esp32_nvs_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // Check args + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // Get requested nvs namespace + const char *ns_name = mp_obj_str_get_str(all_args[0]); + nvs_handle_t namespace; + check_esp_err(nvs_open(ns_name, NVS_READWRITE, &namespace)); + return MP_OBJ_FROM_PTR(esp32_nvs_new(namespace)); +} + +// esp32_nvs_set_i32 sets a 32-bit integer value +STATIC mp_obj_t esp32_nvs_set_i32(mp_obj_t self_in, mp_obj_t key_in, mp_obj_t value_in) { + esp32_nvs_obj_t *self = MP_OBJ_TO_PTR(self_in); + const char *key = mp_obj_str_get_str(key_in); + int32_t value = mp_obj_get_int(value_in); + check_esp_err(nvs_set_i32(self->namespace, key, value)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_nvs_set_i32_obj, esp32_nvs_set_i32); + +// esp32_nvs_get_i32 reads a 32-bit integer value +STATIC mp_obj_t esp32_nvs_get_i32(mp_obj_t self_in, mp_obj_t key_in) { + esp32_nvs_obj_t *self = MP_OBJ_TO_PTR(self_in); + const char *key = mp_obj_str_get_str(key_in); + int32_t value; + check_esp_err(nvs_get_i32(self->namespace, key, &value)); + return mp_obj_new_int(value); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp32_nvs_get_i32_obj, esp32_nvs_get_i32); + +// esp32_nvs_set_blob writes a buffer object into a binary blob value. +STATIC mp_obj_t esp32_nvs_set_blob(mp_obj_t self_in, mp_obj_t key_in, mp_obj_t value_in) { + esp32_nvs_obj_t *self = MP_OBJ_TO_PTR(self_in); + const char *key = mp_obj_str_get_str(key_in); + mp_buffer_info_t value; + mp_get_buffer_raise(value_in, &value, MP_BUFFER_READ); + check_esp_err(nvs_set_blob(self->namespace, key, value.buf, value.len)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_nvs_set_blob_obj, esp32_nvs_set_blob); + +// esp32_nvs_get_blob reads a binary blob value into a bytearray. Returns actual length. +STATIC mp_obj_t esp32_nvs_get_blob(mp_obj_t self_in, mp_obj_t key_in, mp_obj_t value_in) { + esp32_nvs_obj_t *self = MP_OBJ_TO_PTR(self_in); + const char *key = mp_obj_str_get_str(key_in); + // get buffer to be filled + mp_buffer_info_t value; + mp_get_buffer_raise(value_in, &value, MP_BUFFER_WRITE); + size_t length = value.len; + // fill the buffer with the value, will raise an esp-idf error if the length of + // the provided buffer (bytearray) is too small + check_esp_err(nvs_get_blob(self->namespace, key, value.buf, &length)); + return MP_OBJ_NEW_SMALL_INT(length); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_nvs_get_blob_obj, esp32_nvs_get_blob); + +// esp32_nvs_erase_key erases one key. +STATIC mp_obj_t esp32_nvs_erase_key(mp_obj_t self_in, mp_obj_t key_in) { + esp32_nvs_obj_t *self = MP_OBJ_TO_PTR(self_in); + const char *key = mp_obj_str_get_str(key_in); + check_esp_err(nvs_erase_key(self->namespace, key)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp32_nvs_erase_key_obj, esp32_nvs_erase_key); + +// esp32_nvs_commit commits any changes to flash. +STATIC mp_obj_t esp32_nvs_commit(mp_obj_t self_in) { + esp32_nvs_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_esp_err(nvs_commit(self->namespace)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_nvs_commit_obj, esp32_nvs_commit); + +STATIC const mp_rom_map_elem_t esp32_nvs_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_get_i32), MP_ROM_PTR(&esp32_nvs_get_i32_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_i32), MP_ROM_PTR(&esp32_nvs_set_i32_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_blob), MP_ROM_PTR(&esp32_nvs_get_blob_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_blob), MP_ROM_PTR(&esp32_nvs_set_blob_obj) }, + { MP_ROM_QSTR(MP_QSTR_erase_key), MP_ROM_PTR(&esp32_nvs_erase_key_obj) }, + { MP_ROM_QSTR(MP_QSTR_commit), MP_ROM_PTR(&esp32_nvs_commit_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(esp32_nvs_locals_dict, esp32_nvs_locals_dict_table); + +const mp_obj_type_t esp32_nvs_type = { + { &mp_type_type }, + .name = MP_QSTR_NVS, + .print = esp32_nvs_print, + .make_new = esp32_nvs_make_new, + .locals_dict = (mp_obj_dict_t *)&esp32_nvs_locals_dict, +}; diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index b6cf214bba..9fb48a9041 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -55,6 +55,7 @@ set(MICROPY_SOURCE_PORT ${PROJECT_DIR}/mpnimbleport.c ${PROJECT_DIR}/modsocket.c ${PROJECT_DIR}/modesp.c + ${PROJECT_DIR}/esp32_nvs.c ${PROJECT_DIR}/esp32_partition.c ${PROJECT_DIR}/esp32_rmt.c ${PROJECT_DIR}/esp32_ulp.c diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c index d7c6bf0fa3..53ca7fdc60 100644 --- a/ports/esp32/modesp32.c +++ b/ports/esp32/modesp32.c @@ -186,6 +186,7 @@ STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_hall_sensor), MP_ROM_PTR(&esp32_hall_sensor_obj) }, { MP_ROM_QSTR(MP_QSTR_idf_heap_info), MP_ROM_PTR(&esp32_idf_heap_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_NVS), MP_ROM_PTR(&esp32_nvs_type) }, { MP_ROM_QSTR(MP_QSTR_Partition), MP_ROM_PTR(&esp32_partition_type) }, { MP_ROM_QSTR(MP_QSTR_RMT), MP_ROM_PTR(&esp32_rmt_type) }, { MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) }, diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h index f4c0491f7c..18bd62ee41 100644 --- a/ports/esp32/modesp32.h +++ b/ports/esp32/modesp32.h @@ -26,6 +26,7 @@ #define RTC_LAST_EXT_PIN 39 #define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS) +extern const mp_obj_type_t esp32_nvs_type; extern const mp_obj_type_t esp32_partition_type; extern const mp_obj_type_t esp32_rmt_type; extern const mp_obj_type_t esp32_ulp_type; diff --git a/tests/esp32/esp32_nvs.py b/tests/esp32/esp32_nvs.py new file mode 100644 index 0000000000..fd8b152ca7 --- /dev/null +++ b/tests/esp32/esp32_nvs.py @@ -0,0 +1,67 @@ +# Test the esp32 NVS class - access to esp-idf's Non-Volatile-Storage + +from esp32 import NVS + +nvs = NVS("mp-test") + +# test setting and gettin an integer kv +nvs.set_i32("key1", 1234) +print(nvs.get_i32("key1")) +nvs.set_i32("key2", -503) +print(nvs.get_i32("key2")) +print(nvs.get_i32("key1")) + +# test setting and getting a blob kv using a bytearray +blob1 = "testing a string as a blob" +nvs.set_blob("blob1", blob1) +buf1 = bytearray(len(blob1)) +len1 = nvs.get_blob("blob1", buf1) +print(buf1) +print(len(blob1), len1) + +# test setting and getting a blob kv using a string +blob2 = b"testing a bytearray" +nvs.set_blob("blob2", blob2) +buf2 = bytearray(len(blob2)) +len2 = nvs.get_blob("blob2", buf2) +print(buf2) +print(len(blob2), len2) + +# test raising of error exceptions +nvs.erase_key("key1") +try: + nvs.erase_key("key1") # not found +except OSError as e: + print(e) +try: + nvs.get_i32("key1") # not found +except OSError as e: + print(e) +try: + nvs.get_i32("blob1") # not found (blob1 exists but diff type) +except OSError as e: + print(e) +try: + buf3 = bytearray(10) + nvs.get_blob("blob1", buf3) # invalid length (too short) +except OSError as e: + print(e) + +nvs.commit() # we're not verifying that this does anything, just doesn't error + +# test using a second namespace and that it doesn't interfere with first +nvs2 = NVS("mp-test2") +try: + print(nvs2.get_i32("key2")) +except OSError as e: + print(e) +nvs2.set_i32("key2", 7654) +print(nvs.get_i32("key2")) +print(nvs2.get_i32("key2")) + +# clean-up (the namespaces will remain) +nvs.erase_key("key2") +nvs.erase_key("blob1") +nvs.erase_key("blob2") +nvs2.erase_key("key2") +nvs.commit() diff --git a/tests/esp32/esp32_nvs.py.exp b/tests/esp32/esp32_nvs.py.exp new file mode 100644 index 0000000000..33cdfd6df9 --- /dev/null +++ b/tests/esp32/esp32_nvs.py.exp @@ -0,0 +1,14 @@ +1234 +-503 +1234 +bytearray(b'testing a string as a blob') +26 26 +bytearray(b'testing a bytearray') +19 19 +(-4354, 'ESP_ERR_NVS_NOT_FOUND') +(-4354, 'ESP_ERR_NVS_NOT_FOUND') +(-4354, 'ESP_ERR_NVS_NOT_FOUND') +(-4364, 'ESP_ERR_NVS_INVALID_LENGTH') +(-4354, 'ESP_ERR_NVS_NOT_FOUND') +-503 +7654 From d28dbcd6c783bc45bc4661abbb53d2b6c5397102 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Wed, 3 Jun 2020 22:42:37 -0700 Subject: [PATCH 072/174] esp32: Make machine.soft_reset() work in main.py and reset_cause(). This commit fixes two issues on the esp32: - it enables machine.soft_reset() to be called in main.py; - it enables machine.reset_cause() to correctly identify a soft reset. The former is useful in that it enables soft resets in applications that are started at boot time. The support is patterned after the stm32 port. --- ports/esp32/main.c | 9 ++++++++- ports/esp32/modmachine.c | 14 ++++++++++++++ ports/esp32/modmachine.h | 2 ++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 001f2beaeb..7413798d0c 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -73,6 +73,7 @@ void mp_task(void *pvParameter) { mp_thread_init(pxTaskGetStackStart(NULL), MP_TASK_STACK_SIZE / sizeof(uintptr_t)); #endif uart_init(); + 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 @@ -118,7 +119,10 @@ soft_reset: pyexec_frozen_module("_boot.py"); pyexec_file_if_exists("boot.py"); if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { - pyexec_file_if_exists("main.py"); + int ret = pyexec_file_if_exists("main.py"); + if (ret & PYEXEC_FORCED_EXIT) { + goto soft_reset_exit; + } } for (;;) { @@ -135,6 +139,8 @@ soft_reset: } } +soft_reset_exit: + #if MICROPY_BLUETOOTH_NIMBLE mp_bluetooth_deinit(); #endif @@ -151,6 +157,7 @@ soft_reset: // deinitialise peripherals machine_pins_deinit(); + machine_deinit(); usocket_events_deinit(); mp_deinit(); diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index bb346ea1cd..3925bcb64e 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -59,6 +59,8 @@ typedef enum { MP_SOFT_RESET } reset_reason_t; +STATIC bool is_soft_reset = 0; + STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { if (n_args == 0) { // get @@ -140,6 +142,9 @@ STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_ma STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_deepsleep_obj, 0, machine_deepsleep); STATIC mp_obj_t machine_reset_cause(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if (is_soft_reset) { + return MP_OBJ_NEW_SMALL_INT(MP_SOFT_RESET); + } switch (esp_reset_reason()) { case ESP_RST_POWERON: case ESP_RST_BROWNOUT: @@ -171,6 +176,15 @@ STATIC mp_obj_t machine_reset_cause(size_t n_args, const mp_obj_t *pos_args, mp_ } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_reset_cause_obj, 0, machine_reset_cause); +void machine_init(void) { + is_soft_reset = 0; +} + +void machine_deinit(void) { + // we are doing a soft-reset so change the reset_cause + is_soft_reset = 1; +} + STATIC mp_obj_t machine_wake_reason(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { return MP_OBJ_NEW_SMALL_INT(esp_sleep_get_wakeup_cause()); } diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h index 98b36e32b0..3e99e11205 100644 --- a/ports/esp32/modmachine.h +++ b/ports/esp32/modmachine.h @@ -22,6 +22,8 @@ extern const mp_obj_type_t machine_uart_type; extern const mp_obj_type_t machine_rtc_type; extern const mp_obj_type_t machine_sdcard_type; +void machine_init(void); +void machine_deinit(void); void machine_pins_init(void); void machine_pins_deinit(void); void machine_timer_deinit_all(void); From a76604afba109d990e466cdcd5a69a82077a7f56 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 19 Feb 2021 14:47:51 +1100 Subject: [PATCH 073/174] extmod/modbluetooth: Separate enabling of "client" from "central". Previously, the MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE macro controlled enabling both the central mode and the GATT client functionality (because usually the two go together). This commits adds a new MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT macro that separately enables the GATT client functionality. This defaults to MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE. This also fixes a bug in the NimBLE bindings where a notification or indication would not be received by a peripheral (acting as client) as gap_event_cb wasn't handling it. Now both central_gap_event_cb and peripheral_gap_event_cb share the same common handler for these events. Signed-off-by: Jim Mussared --- extmod/btstack/modbluetooth_btstack.c | 30 ++- extmod/modbluetooth.c | 32 ++- extmod/modbluetooth.h | 24 +- extmod/nimble/modbluetooth_nimble.c | 336 +++++++++++++++----------- 4 files changed, 246 insertions(+), 176 deletions(-) diff --git a/extmod/btstack/modbluetooth_btstack.c b/extmod/btstack/modbluetooth_btstack.c index c861c76d22..5f047e3254 100644 --- a/extmod/btstack/modbluetooth_btstack.c +++ b/extmod/btstack/modbluetooth_btstack.c @@ -91,7 +91,7 @@ STATIC mp_obj_bluetooth_uuid_t create_mp_uuid(uint16_t uuid16, const uint8_t *uu } return result; } -#endif +#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE // Notes on supporting background ops (e.g. an attempt to gatts_notify while // an existing notification is in progress): @@ -218,7 +218,7 @@ STATIC mp_btstack_pending_op_t *btstack_enqueue_pending_operation(uint16_t op_ty return pending_op; } -#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT // Cleans up a pending op of the specified type for this conn_handle (and if specified, value_handle). // Used by MP_BLUETOOTH_BTSTACK_PENDING_WRITE and MP_BLUETOOTH_BTSTACK_PENDING_WRITE_NO_RESPONSE. @@ -418,6 +418,8 @@ STATIC void btstack_packet_handler(uint8_t packet_type, uint8_t *packet, uint8_t uint8_t length = gap_event_advertising_report_get_data_length(packet); const uint8_t *data = gap_event_advertising_report_get_data(packet); mp_bluetooth_gap_on_scan_result(address_type, address, adv_event_type, rssi, data, length); + #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT } else if (event_type == GATT_EVENT_QUERY_COMPLETE) { uint16_t conn_handle = gatt_event_query_complete_get_handle(packet); uint16_t status = gatt_event_query_complete_get_att_status(packet); @@ -487,7 +489,7 @@ STATIC void btstack_packet_handler(uint8_t packet_type, uint8_t *packet, uint8_t // Note: Can't "del" the pending_op from IRQ context. Leave it for the GC. } - #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + #endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT } else { DEBUG_printf(" --> hci event type: unknown (0x%02x)\n", event_type); } @@ -506,7 +508,7 @@ STATIC btstack_packet_callback_registration_t hci_event_callback_registration = .callback = &btstack_packet_handler_generic }; -#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT // For when the handler is being used for service discovery. STATIC void btstack_packet_handler_discover_services(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { (void)channel; @@ -541,7 +543,7 @@ STATIC void btstack_packet_handler_write_with_response(uint8_t packet_type, uint (void)size; btstack_packet_handler(packet_type, packet, MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE); } -#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT STATIC btstack_timer_source_t btstack_init_deinit_timeout; @@ -662,12 +664,12 @@ int mp_bluetooth_init(void) { sm_set_er(dummy_key); sm_set_ir(dummy_key); - #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT gatt_client_init(); // We always require explicitly exchanging MTU with ble.gattc_exchange_mtu(). gatt_client_mtu_enable_auto_negotiation(false); - #endif + #endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT // Register for HCI events. hci_add_event_handler(&hci_event_callback_registration); @@ -719,10 +721,10 @@ int mp_bluetooth_init(void) { set_random_address(); } - #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT // Enable GATT_EVENT_NOTIFICATION/GATT_EVENT_INDICATION for all connections and handles. gatt_client_listen_for_characteristic_value_updates(&MP_STATE_PORT(bluetooth_btstack_root_pointers)->notification, &btstack_packet_handler_generic, GATT_CLIENT_ANY_CONNECTION, NULL); - #endif + #endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT return 0; } @@ -737,10 +739,10 @@ void mp_bluetooth_deinit(void) { mp_bluetooth_gap_advertise_stop(); - #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT // Remove our registration for notify/indicate. gatt_client_stop_listening_for_characteristic_value_updates(&MP_STATE_PORT(bluetooth_btstack_root_pointers)->notification); - #endif + #endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT // Set a timer that will forcibly set the state to TIMEOUT, which will stop the loop below. btstack_run_loop_set_timer(&btstack_init_deinit_timeout, BTSTACK_INIT_DEINIT_TIMEOUT_MS); @@ -1232,6 +1234,10 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, return btstack_error_to_errno(gap_connect(btstack_addr, addr_type)); } +#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + +#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT + int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle, const mp_obj_bluetooth_uuid_t *uuid) { DEBUG_printf("mp_bluetooth_gattc_discover_primary_services\n"); uint8_t err; @@ -1346,7 +1352,7 @@ int mp_bluetooth_gattc_exchange_mtu(uint16_t conn_handle) { return 0; } -#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT #if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 8870a21c4d..269493f0a9 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -761,7 +761,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_set_buffer_obj, 3 // Bluetooth object: GATTC (Central/Scanner role) // ---------------------------------------------------------------------------- -#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT STATIC mp_obj_t bluetooth_ble_gattc_discover_services(size_t n_args, const mp_obj_t *args) { mp_int_t conn_handle = mp_obj_get_int(args[1]); @@ -830,7 +830,7 @@ STATIC mp_obj_t bluetooth_ble_gattc_exchange_mtu(mp_obj_t self_in, mp_obj_t conn } STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gattc_exchange_mtu_obj, bluetooth_ble_gattc_exchange_mtu); -#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT #if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS @@ -921,15 +921,15 @@ STATIC const mp_rom_map_elem_t bluetooth_ble_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_gap_pair), MP_ROM_PTR(&bluetooth_ble_gap_pair_obj) }, { MP_ROM_QSTR(MP_QSTR_gap_passkey), MP_ROM_PTR(&bluetooth_ble_gap_passkey_obj) }, #endif - // GATT Server (i.e. peripheral/advertiser role) + // GATT Server { MP_ROM_QSTR(MP_QSTR_gatts_register_services), MP_ROM_PTR(&bluetooth_ble_gatts_register_services_obj) }, { MP_ROM_QSTR(MP_QSTR_gatts_read), MP_ROM_PTR(&bluetooth_ble_gatts_read_obj) }, { MP_ROM_QSTR(MP_QSTR_gatts_write), MP_ROM_PTR(&bluetooth_ble_gatts_write_obj) }, { MP_ROM_QSTR(MP_QSTR_gatts_notify), MP_ROM_PTR(&bluetooth_ble_gatts_notify_obj) }, { MP_ROM_QSTR(MP_QSTR_gatts_indicate), MP_ROM_PTR(&bluetooth_ble_gatts_indicate_obj) }, { MP_ROM_QSTR(MP_QSTR_gatts_set_buffer), MP_ROM_PTR(&bluetooth_ble_gatts_set_buffer_obj) }, - #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE - // GATT Client (i.e. central/scanner role) + #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT + // GATT Client { MP_ROM_QSTR(MP_QSTR_gattc_discover_services), MP_ROM_PTR(&bluetooth_ble_gattc_discover_services_obj) }, { MP_ROM_QSTR(MP_QSTR_gattc_discover_characteristics), MP_ROM_PTR(&bluetooth_ble_gattc_discover_characteristics_obj) }, { MP_ROM_QSTR(MP_QSTR_gattc_discover_descriptors), MP_ROM_PTR(&bluetooth_ble_gattc_discover_descriptors_obj) }, @@ -1067,6 +1067,8 @@ STATIC mp_obj_t bluetooth_ble_invoke_irq(mp_obj_t none_in) { } else if (event == MP_BLUETOOTH_IRQ_SCAN_DONE) { // No params required. data_tuple->len = 0; + #endif + #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT } else if (event == MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT) { // conn_handle, start_handle, end_handle, uuid ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, &o->irq_data_uuid, NULL); @@ -1085,7 +1087,7 @@ STATIC mp_obj_t bluetooth_ble_invoke_irq(mp_obj_t none_in) { } else if (event == MP_BLUETOOTH_IRQ_GATTC_READ_DONE || event == MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE) { // conn_handle, value_handle, status ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, NULL, NULL); - #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + #endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT } MICROPY_PY_BLUETOOTH_EXIT @@ -1228,7 +1230,7 @@ void mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle, uint16_t value) { } #if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS -mp_int_t mp_bluetooth_gattc_on_l2cap_accept(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu) { +mp_int_t mp_bluetooth_on_l2cap_accept(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu) { mp_int_t args[] = {conn_handle, cid, psm, our_mtu, peer_mtu}; mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_ACCEPT, args, 5, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0); // Return non-zero from IRQ handler to fail the accept. @@ -1237,22 +1239,22 @@ mp_int_t mp_bluetooth_gattc_on_l2cap_accept(uint16_t conn_handle, uint16_t cid, return ret; } -void mp_bluetooth_gattc_on_l2cap_connect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu) { +void mp_bluetooth_on_l2cap_connect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu) { mp_int_t args[] = {conn_handle, cid, psm, our_mtu, peer_mtu}; invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_CONNECT, args, 5, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0); } -void mp_bluetooth_gattc_on_l2cap_disconnect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t status) { +void mp_bluetooth_on_l2cap_disconnect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t status) { mp_int_t args[] = {conn_handle, cid, psm, status}; invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_DISCONNECT, args, 4, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0); } -void mp_bluetooth_gattc_on_l2cap_send_ready(uint16_t conn_handle, uint16_t cid, uint8_t status) { +void mp_bluetooth_on_l2cap_send_ready(uint16_t conn_handle, uint16_t cid, uint8_t status) { mp_int_t args[] = {conn_handle, cid, status}; invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_SEND_READY, args, 3, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0); } -void mp_bluetooth_gattc_on_l2cap_recv(uint16_t conn_handle, uint16_t cid) { +void mp_bluetooth_on_l2cap_recv(uint16_t conn_handle, uint16_t cid) { mp_int_t args[] = {conn_handle, cid}; invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_RECV, args, 2, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0); } @@ -1267,7 +1269,9 @@ void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, uin mp_int_t args[] = {addr_type, adv_type, rssi}; invoke_irq_handler(MP_BLUETOOTH_IRQ_SCAN_RESULT, args, 1, 2, addr, NULL_UUID, &data, &data_len, 1); } +#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT void mp_bluetooth_gattc_on_primary_service_result(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, mp_obj_bluetooth_uuid_t *service_uuid) { mp_int_t args[] = {conn_handle, start_handle, end_handle}; invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT, args, 3, 0, NULL_ADDR, service_uuid, NULL_DATA, NULL_DATA_LEN, 0); @@ -1325,7 +1329,7 @@ void mp_bluetooth_gattc_on_read_write_status(uint8_t event, uint16_t conn_handle invoke_irq_handler(event, args, 3, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0); } -#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT #else // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS // Callbacks are called in interrupt context (i.e. can't allocate), so we need to push the data @@ -1471,7 +1475,9 @@ void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, uin } schedule_ringbuf(atomic_state); } +#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT void mp_bluetooth_gattc_on_primary_service_result(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, mp_obj_bluetooth_uuid_t *service_uuid) { MICROPY_PY_BLUETOOTH_ENTER mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); @@ -1559,7 +1565,7 @@ void mp_bluetooth_gattc_on_read_write_status(uint8_t event, uint16_t conn_handle } schedule_ringbuf(atomic_state); } -#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT #endif // MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index c96427fcb4..d126ad6c11 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -43,6 +43,12 @@ #define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (0) #endif +#ifndef MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT +// Enable the client by default if we're enabling central mode. It's possible +// to enable client without central though. +#define MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT (MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE) +#endif + #ifndef MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS // This can be enabled if the BLE stack runs entirely in scheduler context // and therefore is able to call directly into the VM to run Python callbacks. @@ -365,7 +371,9 @@ int mp_bluetooth_gap_scan_stop(void); // Connect to a found peripheral. int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms); +#endif +#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT // Find all primary services on the connected peripheral. int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle, const mp_obj_bluetooth_uuid_t *uuid); @@ -383,7 +391,7 @@ int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const // Initiate MTU exchange for a specific connection using the preferred MTU. int mp_bluetooth_gattc_exchange_mtu(uint16_t conn_handle); -#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT #if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS int mp_bluetooth_l2cap_listen(uint16_t psm, uint16_t mtu); @@ -440,7 +448,9 @@ void mp_bluetooth_gap_on_scan_complete(void); // Notify modbluetooth of a scan result. void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, uint8_t adv_type, const int8_t rssi, const uint8_t *data, size_t data_len); +#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT // Notify modbluetooth that a service was found (either by discover-all, or discover-by-uuid). void mp_bluetooth_gattc_on_primary_service_result(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, mp_obj_bluetooth_uuid_t *service_uuid); @@ -458,14 +468,14 @@ void mp_bluetooth_gattc_on_data_available(uint8_t event, uint16_t conn_handle, u // Notify modbluetooth that a read or write operation has completed. void mp_bluetooth_gattc_on_read_write_status(uint8_t event, uint16_t conn_handle, uint16_t value_handle, uint16_t status); -#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT #if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS -mp_int_t mp_bluetooth_gattc_on_l2cap_accept(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu); -void mp_bluetooth_gattc_on_l2cap_connect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu); -void mp_bluetooth_gattc_on_l2cap_disconnect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t status); -void mp_bluetooth_gattc_on_l2cap_send_ready(uint16_t conn_handle, uint16_t cid, uint8_t status); -void mp_bluetooth_gattc_on_l2cap_recv(uint16_t conn_handle, uint16_t cid); +mp_int_t mp_bluetooth_on_l2cap_accept(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu); +void mp_bluetooth_on_l2cap_connect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu); +void mp_bluetooth_on_l2cap_disconnect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t status); +void mp_bluetooth_on_l2cap_send_ready(uint16_t conn_handle, uint16_t cid, uint8_t status); +void mp_bluetooth_on_l2cap_recv(uint16_t conn_handle, uint16_t cid); #endif // MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS // For stacks that don't manage attribute value data (currently all of them), helpers diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c index a0a3998c66..e3a2f872e5 100644 --- a/extmod/nimble/modbluetooth_nimble.c +++ b/extmod/nimble/modbluetooth_nimble.c @@ -80,6 +80,69 @@ STATIC int8_t ble_hs_err_to_errno_table[] = { [BLE_HS_EBADDATA] = MP_EINVAL, }; +STATIC int ble_hs_err_to_errno(int err); + +STATIC ble_uuid_t *create_nimble_uuid(const mp_obj_bluetooth_uuid_t *uuid, ble_uuid_any_t *storage); +STATIC void reverse_addr_byte_order(uint8_t *addr_out, const uint8_t *addr_in); + +#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +STATIC mp_obj_bluetooth_uuid_t create_mp_uuid(const ble_uuid_any_t *uuid); +STATIC ble_addr_t create_nimble_addr(uint8_t addr_type, const uint8_t *addr); +#endif + +STATIC void reset_cb(int reason); + +STATIC bool has_public_address(void); +STATIC void set_random_address(bool nrpa); + +#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING +STATIC int load_irk(void); +#endif + +STATIC void sync_cb(void); + +#if !MICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY +STATIC void ble_hs_shutdown_stop_cb(int status, void *arg); +#endif + +// Successfully registered service/char/desc handles. +STATIC void gatts_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg); + +// Events about a connected central (we're in peripheral role). +STATIC int central_gap_event_cb(struct ble_gap_event *event, void *arg); +#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +// Events about a connected peripheral (we're in central role). +STATIC int peripheral_gap_event_cb(struct ble_gap_event *event, void *arg); +#endif +// Used by both of the above. +STATIC int commmon_gap_event_cb(struct ble_gap_event *event, void *arg); + +#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +// Scan results. +STATIC int gap_scan_cb(struct ble_gap_event *event, void *arg); +#endif + +#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT +// Data available (either due to notify/indicate or successful read). +STATIC void gattc_on_data_available(uint8_t event, uint16_t conn_handle, uint16_t value_handle, const struct os_mbuf *om); + +// Client discovery callbacks. +STATIC int ble_gattc_service_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg); +STATIC int ble_gattc_characteristic_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *characteristic, void *arg); +STATIC int ble_gattc_descriptor_cb(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t characteristic_val_handle, const struct ble_gatt_dsc *descriptor, void *arg); + +// Client read/write handlers. +STATIC int ble_gattc_attr_read_cb(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg); +STATIC int ble_gattc_attr_write_cb(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg); +#endif + +#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING +// Bonding store. +STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, union ble_store_value *value); +STATIC int ble_store_ram_write(int obj_type, const union ble_store_value *val); +STATIC int ble_store_ram_delete(int obj_type, const union ble_store_key *key); +#endif + STATIC int ble_hs_err_to_errno(int err) { DEBUG_printf("ble_hs_err_to_errno: %d\n", err); if (!err) { @@ -334,8 +397,54 @@ STATIC void gatts_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) { } } -STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) { - DEBUG_printf("gap_event_cb: type=%d\n", event->type); +STATIC int commmon_gap_event_cb(struct ble_gap_event *event, void *arg) { + struct ble_gap_conn_desc desc; + + switch (event->type) { + #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT + case BLE_GAP_EVENT_NOTIFY_RX: { + uint16_t ev = event->notify_rx.indication == 0 ? MP_BLUETOOTH_IRQ_GATTC_NOTIFY : MP_BLUETOOTH_IRQ_GATTC_INDICATE; + gattc_on_data_available(ev, event->notify_rx.conn_handle, event->notify_rx.attr_handle, event->notify_rx.om); + return 0; + } + #endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT + + case BLE_GAP_EVENT_CONN_UPDATE: { + DEBUG_printf("commmon_gap_event_cb: connection update: status=%d\n", event->conn_update.status); + if (ble_gap_conn_find(event->conn_update.conn_handle, &desc) == 0) { + mp_bluetooth_gap_on_connection_update(event->conn_update.conn_handle, desc.conn_itvl, desc.conn_latency, desc.supervision_timeout, event->conn_update.status == 0 ? 0 : 1); + } + return 0; + } + + case BLE_GAP_EVENT_MTU: { + if (event->mtu.channel_id == BLE_L2CAP_CID_ATT) { + DEBUG_printf("commmon_gap_event_cb: mtu update: conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value); + mp_bluetooth_gatts_on_mtu_exchanged(event->mtu.conn_handle, event->mtu.value); + } + return 0; + } + + case BLE_GAP_EVENT_ENC_CHANGE: { + DEBUG_printf("commmon_gap_event_cb: enc change: status=%d\n", event->enc_change.status); + #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING + if (ble_gap_conn_find(event->enc_change.conn_handle, &desc) == 0) { + mp_bluetooth_gatts_on_encryption_update(event->conn_update.conn_handle, + desc.sec_state.encrypted, desc.sec_state.authenticated, + desc.sec_state.bonded, desc.sec_state.key_size); + } + #endif + return 0; + } + + default: + DEBUG_printf("commmon_gap_event_cb: unknown type %d\n", event->type); + return 0; + } +} + +STATIC int central_gap_event_cb(struct ble_gap_event *event, void *arg) { + DEBUG_printf("central_gap_event_cb: type=%d\n", event->type); if (!mp_bluetooth_is_active()) { return 0; } @@ -344,7 +453,7 @@ STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) { switch (event->type) { case BLE_GAP_EVENT_CONNECT: - DEBUG_printf("gap_event_cb: connect: status=%d\n", event->connect.status); + DEBUG_printf("central_gap_event_cb: connect: status=%d\n", event->connect.status); if (event->connect.status == 0) { // Connection established. ble_gap_conn_find(event->connect.conn_handle, &desc); @@ -354,60 +463,32 @@ STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) { // Connection failed. mp_bluetooth_gap_on_connected_disconnected(MP_BLUETOOTH_IRQ_CENTRAL_DISCONNECT, event->connect.conn_handle, 0xff, addr); } - break; + return 0; case BLE_GAP_EVENT_DISCONNECT: // Disconnect. - DEBUG_printf("gap_event_cb: disconnect: reason=%d\n", event->disconnect.reason); + DEBUG_printf("central_gap_event_cb: disconnect: reason=%d\n", event->disconnect.reason); reverse_addr_byte_order(addr, event->disconnect.conn.peer_id_addr.val); mp_bluetooth_gap_on_connected_disconnected(MP_BLUETOOTH_IRQ_CENTRAL_DISCONNECT, event->disconnect.conn.conn_handle, event->disconnect.conn.peer_id_addr.type, addr); - break; + return 0; case BLE_GAP_EVENT_NOTIFY_TX: { - DEBUG_printf("gap_event_cb: notify_tx: %d %d\n", event->notify_tx.indication, event->notify_tx.status); + DEBUG_printf("central_gap_event_cb: notify_tx: %d %d\n", event->notify_tx.indication, event->notify_tx.status); // This event corresponds to either a sent notify/indicate (status == 0), or an indication confirmation (status != 0). if (event->notify_tx.indication && event->notify_tx.status != 0) { // Map "done/ack" to 0, otherwise pass the status directly. mp_bluetooth_gatts_on_indicate_complete(event->notify_tx.conn_handle, event->notify_tx.attr_handle, event->notify_tx.status == BLE_HS_EDONE ? 0 : event->notify_tx.status); } - break; - } - - case BLE_GAP_EVENT_MTU: { - if (event->mtu.channel_id == BLE_L2CAP_CID_ATT) { - DEBUG_printf("gap_event_cb: mtu update: conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value); - mp_bluetooth_gatts_on_mtu_exchanged(event->mtu.conn_handle, event->mtu.value); - } - break; + return 0; } case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: - DEBUG_printf("gap_event_cb: phy update: %d\n", event->phy_updated.tx_phy); - break; - - case BLE_GAP_EVENT_CONN_UPDATE: { - DEBUG_printf("gap_event_cb: connection update: status=%d\n", event->conn_update.status); - if (ble_gap_conn_find(event->conn_update.conn_handle, &desc) == 0) { - mp_bluetooth_gap_on_connection_update(event->conn_update.conn_handle, desc.conn_itvl, desc.conn_latency, desc.supervision_timeout, event->conn_update.status == 0 ? 0 : 1); - } - break; - } - - case BLE_GAP_EVENT_ENC_CHANGE: { - DEBUG_printf("gap_event_cb: enc change: status=%d\n", event->enc_change.status); - #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING - if (ble_gap_conn_find(event->enc_change.conn_handle, &desc) == 0) { - mp_bluetooth_gatts_on_encryption_update(event->conn_update.conn_handle, - desc.sec_state.encrypted, desc.sec_state.authenticated, - desc.sec_state.bonded, desc.sec_state.key_size); - } - #endif - break; - } + DEBUG_printf("central_gap_event_cb: phy update: %d\n", event->phy_updated.tx_phy); + return 0; case BLE_GAP_EVENT_REPEAT_PAIRING: { // We recognized this peer but the peer doesn't recognize us. - DEBUG_printf("gap_event_cb: repeat pairing: conn_handle=%d\n", event->repeat_pairing.conn_handle); + DEBUG_printf("central_gap_event_cb: repeat pairing: conn_handle=%d\n", event->repeat_pairing.conn_handle); // TODO: Consider returning BLE_GAP_REPEAT_PAIRING_IGNORE (and // possibly an API to configure this). @@ -423,7 +504,7 @@ STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) { } case BLE_GAP_EVENT_PASSKEY_ACTION: { - DEBUG_printf("gap_event_cb: passkey action: conn_handle=%d action=%d num=" UINT_FMT "\n", event->passkey.conn_handle, event->passkey.params.action, (mp_uint_t)event->passkey.params.numcmp); + DEBUG_printf("central_gap_event_cb: passkey action: conn_handle=%d action=%d num=" UINT_FMT "\n", event->passkey.conn_handle, event->passkey.params.action, (mp_uint_t)event->passkey.params.numcmp); #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING mp_bluetooth_gap_on_passkey_action(event->passkey.conn_handle, event->passkey.params.action, event->passkey.params.numcmp); @@ -431,12 +512,9 @@ STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) { return 0; } - - default: - DEBUG_printf("gap_event_cb: unknown type %d\n", event->type); - break; } - return 0; + + return commmon_gap_event_cb(event, arg); } #if !MICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY @@ -738,7 +816,7 @@ int mp_bluetooth_gap_advertise_start(bool connectable, int32_t interval_us, cons .channel_map = 7, // all 3 channels. }; - ret = ble_gap_adv_start(nimble_address_mode, NULL, BLE_HS_FOREVER, &adv_params, gap_event_cb, NULL); + ret = ble_gap_adv_start(nimble_address_mode, NULL, BLE_HS_FOREVER, &adv_params, central_gap_event_cb, NULL); if (ret == 0) { return 0; } @@ -1025,38 +1103,6 @@ int mp_bluetooth_gap_passkey(uint16_t conn_handle, uint8_t action, mp_int_t pass #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE -STATIC void gattc_on_data_available(uint8_t event, uint16_t conn_handle, uint16_t value_handle, const struct os_mbuf *om) { - // When the HCI data for an ATT payload arrives, the L2CAP channel will - // buffer it into its receive buffer. We set BLE_L2CAP_JOIN_RX_FRAGS=1 in - // syscfg.h so it should be rare that the mbuf is fragmented, but we do need - // to be able to handle it. We pass all the fragments up to modbluetooth.c - // which will create a temporary buffer on the MicroPython heap if necessary - // to re-assemble them. - - // Count how many links are in the mbuf chain. - size_t n = 0; - const struct os_mbuf *elem = om; - while (elem) { - n += 1; - elem = SLIST_NEXT(elem, om_next); - } - - // Grab data pointers and lengths for each of the links. - const uint8_t **data = mp_local_alloc(sizeof(uint8_t *) * n); - uint16_t *data_len = mp_local_alloc(sizeof(uint16_t) * n); - for (size_t i = 0; i < n; ++i) { - data[i] = OS_MBUF_DATA(om, const uint8_t *); - data_len[i] = om->om_len; - om = SLIST_NEXT(om, om_next); - } - - // Pass all the fragments together. - mp_bluetooth_gattc_on_data_available(event, conn_handle, value_handle, data, data_len, n); - - mp_local_free(data_len); - mp_local_free(data); -} - STATIC int gap_scan_cb(struct ble_gap_event *event, void *arg) { DEBUG_printf("gap_scan_cb: event=%d type=%d\n", event->type, event->type == BLE_GAP_EVENT_DISC ? event->disc.event_type : -1); if (!mp_bluetooth_is_active()) { @@ -1135,56 +1181,17 @@ STATIC int peripheral_gap_event_cb(struct ble_gap_event *event, void *arg) { // Connection failed. mp_bluetooth_gap_on_connected_disconnected(MP_BLUETOOTH_IRQ_PERIPHERAL_DISCONNECT, event->connect.conn_handle, 0xff, addr); } - break; + return 0; case BLE_GAP_EVENT_DISCONNECT: // Disconnect. DEBUG_printf("peripheral_gap_event_cb: reason=%d\n", event->disconnect.reason); reverse_addr_byte_order(addr, event->disconnect.conn.peer_id_addr.val); mp_bluetooth_gap_on_connected_disconnected(MP_BLUETOOTH_IRQ_PERIPHERAL_DISCONNECT, event->disconnect.conn.conn_handle, event->disconnect.conn.peer_id_addr.type, addr); - - break; - - case BLE_GAP_EVENT_NOTIFY_RX: { - uint16_t ev = event->notify_rx.indication == 0 ? MP_BLUETOOTH_IRQ_GATTC_NOTIFY : MP_BLUETOOTH_IRQ_GATTC_INDICATE; - gattc_on_data_available(ev, event->notify_rx.conn_handle, event->notify_rx.attr_handle, event->notify_rx.om); - break; - } - - case BLE_GAP_EVENT_CONN_UPDATE: { - DEBUG_printf("peripheral_gap_event_cb: connection update: status=%d\n", event->conn_update.status); - if (ble_gap_conn_find(event->conn_update.conn_handle, &desc) == 0) { - mp_bluetooth_gap_on_connection_update(event->conn_update.conn_handle, desc.conn_itvl, desc.conn_latency, desc.supervision_timeout, event->conn_update.status == 0 ? 0 : 1); - } - break; - } - - case BLE_GAP_EVENT_MTU: { - if (event->mtu.channel_id == BLE_L2CAP_CID_ATT) { - DEBUG_printf("peripheral_gap_event_cb: mtu update: conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value); - mp_bluetooth_gatts_on_mtu_exchanged(event->mtu.conn_handle, event->mtu.value); - } - break; - } - - case BLE_GAP_EVENT_ENC_CHANGE: { - DEBUG_printf("peripheral_gap_event_cb: enc change: status=%d\n", event->enc_change.status); - #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING - if (ble_gap_conn_find(event->enc_change.conn_handle, &desc) == 0) { - mp_bluetooth_gatts_on_encryption_update(event->conn_update.conn_handle, - desc.sec_state.encrypted, desc.sec_state.authenticated, - desc.sec_state.bonded, desc.sec_state.key_size); - } - #endif - break; - } - - default: - DEBUG_printf("peripheral_gap_event_cb: unknown type %d\n", event->type); - break; + return 0; } - return 0; + return commmon_gap_event_cb(event, arg); } int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms) { @@ -1213,8 +1220,8 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, return ble_hs_err_to_errno(err); } -STATIC int peripheral_discover_service_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) { - DEBUG_printf("peripheral_discover_service_cb: conn_handle=%d status=%d start_handle=%d\n", conn_handle, error->status, service ? service->start_handle : -1); +STATIC int ble_gattc_service_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) { + DEBUG_printf("ble_gattc_service_cb: conn_handle=%d status=%d start_handle=%d\n", conn_handle, error->status, service ? service->start_handle : -1); if (!mp_bluetooth_is_active()) { return 0; } @@ -1227,6 +1234,42 @@ STATIC int peripheral_discover_service_cb(uint16_t conn_handle, const struct ble return 0; } +#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE + +#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT + +STATIC void gattc_on_data_available(uint8_t event, uint16_t conn_handle, uint16_t value_handle, const struct os_mbuf *om) { + // When the HCI data for an ATT payload arrives, the L2CAP channel will + // buffer it into its receive buffer. We set BLE_L2CAP_JOIN_RX_FRAGS=1 in + // syscfg.h so it should be rare that the mbuf is fragmented, but we do need + // to be able to handle it. We pass all the fragments up to modbluetooth.c + // which will create a temporary buffer on the MicroPython heap if necessary + // to re-assemble them. + + // Count how many links are in the mbuf chain. + size_t n = 0; + const struct os_mbuf *elem = om; + while (elem) { + n += 1; + elem = SLIST_NEXT(elem, om_next); + } + + // Grab data pointers and lengths for each of the links. + const uint8_t **data = mp_local_alloc(sizeof(uint8_t *) * n); + uint16_t *data_len = mp_local_alloc(sizeof(uint16_t) * n); + for (size_t i = 0; i < n; ++i) { + data[i] = OS_MBUF_DATA(om, const uint8_t *); + data_len[i] = om->om_len; + om = SLIST_NEXT(om, om_next); + } + + // Pass all the fragments together. + mp_bluetooth_gattc_on_data_available(event, conn_handle, value_handle, data, data_len, n); + + mp_local_free(data_len); + mp_local_free(data); +} + int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle, const mp_obj_bluetooth_uuid_t *uuid) { if (!mp_bluetooth_is_active()) { return ERRNO_BLUETOOTH_NOT_ACTIVE; @@ -1235,15 +1278,15 @@ int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle, const mp_ if (uuid) { ble_uuid_any_t nimble_uuid; create_nimble_uuid(uuid, &nimble_uuid); - err = ble_gattc_disc_svc_by_uuid(conn_handle, &nimble_uuid.u, &peripheral_discover_service_cb, NULL); + err = ble_gattc_disc_svc_by_uuid(conn_handle, &nimble_uuid.u, &ble_gattc_service_cb, NULL); } else { - err = ble_gattc_disc_all_svcs(conn_handle, &peripheral_discover_service_cb, NULL); + err = ble_gattc_disc_all_svcs(conn_handle, &ble_gattc_service_cb, NULL); } return ble_hs_err_to_errno(err); } -STATIC int ble_gatt_characteristic_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *characteristic, void *arg) { - DEBUG_printf("ble_gatt_characteristic_cb: conn_handle=%d status=%d def_handle=%d val_handle=%d\n", conn_handle, error->status, characteristic ? characteristic->def_handle : -1, characteristic ? characteristic->val_handle : -1); +STATIC int ble_gattc_characteristic_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *characteristic, void *arg) { + DEBUG_printf("ble_gattc_characteristic_cb: conn_handle=%d status=%d def_handle=%d val_handle=%d\n", conn_handle, error->status, characteristic ? characteristic->def_handle : -1, characteristic ? characteristic->val_handle : -1); if (!mp_bluetooth_is_active()) { return 0; } @@ -1264,15 +1307,15 @@ int mp_bluetooth_gattc_discover_characteristics(uint16_t conn_handle, uint16_t s if (uuid) { ble_uuid_any_t nimble_uuid; create_nimble_uuid(uuid, &nimble_uuid); - err = ble_gattc_disc_chrs_by_uuid(conn_handle, start_handle, end_handle, &nimble_uuid.u, &ble_gatt_characteristic_cb, NULL); + err = ble_gattc_disc_chrs_by_uuid(conn_handle, start_handle, end_handle, &nimble_uuid.u, &ble_gattc_characteristic_cb, NULL); } else { - err = ble_gattc_disc_all_chrs(conn_handle, start_handle, end_handle, &ble_gatt_characteristic_cb, NULL); + err = ble_gattc_disc_all_chrs(conn_handle, start_handle, end_handle, &ble_gattc_characteristic_cb, NULL); } return ble_hs_err_to_errno(err); } -STATIC int ble_gatt_descriptor_cb(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t characteristic_val_handle, const struct ble_gatt_dsc *descriptor, void *arg) { - DEBUG_printf("ble_gatt_descriptor_cb: conn_handle=%d status=%d chr_handle=%d dsc_handle=%d\n", conn_handle, error->status, characteristic_val_handle, descriptor ? descriptor->handle : -1); +STATIC int ble_gattc_descriptor_cb(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t characteristic_val_handle, const struct ble_gatt_dsc *descriptor, void *arg) { + DEBUG_printf("ble_gattc_descriptor_cb: conn_handle=%d status=%d chr_handle=%d dsc_handle=%d\n", conn_handle, error->status, characteristic_val_handle, descriptor ? descriptor->handle : -1); if (!mp_bluetooth_is_active()) { return 0; } @@ -1289,13 +1332,13 @@ int mp_bluetooth_gattc_discover_descriptors(uint16_t conn_handle, uint16_t start if (!mp_bluetooth_is_active()) { return ERRNO_BLUETOOTH_NOT_ACTIVE; } - int err = ble_gattc_disc_all_dscs(conn_handle, start_handle, end_handle, &ble_gatt_descriptor_cb, NULL); + int err = ble_gattc_disc_all_dscs(conn_handle, start_handle, end_handle, &ble_gattc_descriptor_cb, NULL); return ble_hs_err_to_errno(err); } -STATIC int ble_gatt_attr_read_cb(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { +STATIC int ble_gattc_attr_read_cb(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { uint16_t handle = attr ? attr->handle : (error ? error->att_handle : 0xffff); - DEBUG_printf("ble_gatt_attr_read_cb: conn_handle=%d status=%d handle=%d\n", conn_handle, error->status, handle); + DEBUG_printf("ble_gattc_attr_read_cb: conn_handle=%d status=%d handle=%d\n", conn_handle, error->status, handle); if (!mp_bluetooth_is_active()) { return 0; } @@ -1311,13 +1354,13 @@ int mp_bluetooth_gattc_read(uint16_t conn_handle, uint16_t value_handle) { if (!mp_bluetooth_is_active()) { return ERRNO_BLUETOOTH_NOT_ACTIVE; } - int err = ble_gattc_read(conn_handle, value_handle, &ble_gatt_attr_read_cb, NULL); + int err = ble_gattc_read(conn_handle, value_handle, &ble_gattc_attr_read_cb, NULL); return ble_hs_err_to_errno(err); } -STATIC int ble_gatt_attr_write_cb(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { +STATIC int ble_gattc_attr_write_cb(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { uint16_t handle = attr ? attr->handle : (error ? error->att_handle : 0xffff); - DEBUG_printf("ble_gatt_attr_write_cb: conn_handle=%d status=%d handle=%d\n", conn_handle, error->status, handle); + DEBUG_printf("ble_gattc_attr_write_cb: conn_handle=%d status=%d handle=%d\n", conn_handle, error->status, handle); if (!mp_bluetooth_is_active()) { return 0; } @@ -1334,7 +1377,7 @@ int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const if (mode == MP_BLUETOOTH_WRITE_MODE_NO_RESPONSE) { err = ble_gattc_write_no_rsp_flat(conn_handle, value_handle, value, *value_len); } else if (mode == MP_BLUETOOTH_WRITE_MODE_WITH_RESPONSE) { - err = ble_gattc_write_flat(conn_handle, value_handle, value, *value_len, &ble_gatt_attr_write_cb, NULL); + err = ble_gattc_write_flat(conn_handle, value_handle, value, *value_len, &ble_gattc_attr_write_cb, NULL); } else { err = BLE_HS_EINVAL; } @@ -1348,7 +1391,7 @@ int mp_bluetooth_gattc_exchange_mtu(uint16_t conn_handle) { return ble_hs_err_to_errno(ble_gattc_exchange_mtu(conn_handle, NULL, NULL)); } -#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT #if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS @@ -1375,6 +1418,11 @@ typedef struct _mp_bluetooth_nimble_l2cap_channel_t { os_membuf_t sdu_mem[]; } mp_bluetooth_nimble_l2cap_channel_t; +STATIC void destroy_l2cap_channel(); +STATIC int l2cap_channel_event(struct ble_l2cap_event *event, void *arg); +STATIC mp_bluetooth_nimble_l2cap_channel_t *get_l2cap_channel_for_conn_cid(uint16_t conn_handle, uint16_t cid); +STATIC int create_l2cap_channel(uint16_t mtu, mp_bluetooth_nimble_l2cap_channel_t **out); + STATIC void destroy_l2cap_channel() { // Only free the l2cap channel if we're the one that initiated the connection. // Listeners continue listening on the same channel. @@ -1395,9 +1443,9 @@ STATIC int l2cap_channel_event(struct ble_l2cap_event *event, void *arg) { ble_l2cap_get_chan_info(event->connect.chan, &info); if (event->connect.status == 0) { - mp_bluetooth_gattc_on_l2cap_connect(event->connect.conn_handle, info.scid, info.psm, info.our_coc_mtu, info.peer_coc_mtu); + mp_bluetooth_on_l2cap_connect(event->connect.conn_handle, info.scid, info.psm, info.our_coc_mtu, info.peer_coc_mtu); } else { - mp_bluetooth_gattc_on_l2cap_disconnect(event->connect.conn_handle, info.scid, info.psm, event->connect.status); + mp_bluetooth_on_l2cap_disconnect(event->connect.conn_handle, info.scid, info.psm, event->connect.status); destroy_l2cap_channel(); } break; @@ -1405,7 +1453,7 @@ STATIC int l2cap_channel_event(struct ble_l2cap_event *event, void *arg) { case BLE_L2CAP_EVENT_COC_DISCONNECTED: { DEBUG_printf("l2cap_channel_event: disconnect: conn_handle=%d\n", event->disconnect.conn_handle); ble_l2cap_get_chan_info(event->disconnect.chan, &info); - mp_bluetooth_gattc_on_l2cap_disconnect(event->disconnect.conn_handle, info.scid, info.psm, 0); + mp_bluetooth_on_l2cap_disconnect(event->disconnect.conn_handle, info.scid, info.psm, 0); destroy_l2cap_channel(); break; } @@ -1413,7 +1461,7 @@ STATIC int l2cap_channel_event(struct ble_l2cap_event *event, void *arg) { DEBUG_printf("l2cap_channel_event: accept: conn_handle=%d peer_sdu_size=%d\n", event->accept.conn_handle, event->accept.peer_sdu_size); chan->chan = event->accept.chan; ble_l2cap_get_chan_info(event->accept.chan, &info); - int ret = mp_bluetooth_gattc_on_l2cap_accept(event->accept.conn_handle, info.scid, info.psm, info.our_coc_mtu, info.peer_coc_mtu); + int ret = mp_bluetooth_on_l2cap_accept(event->accept.conn_handle, info.scid, info.psm, info.our_coc_mtu, info.peer_coc_mtu); if (ret != 0) { return ret; } @@ -1461,7 +1509,7 @@ STATIC int l2cap_channel_event(struct ble_l2cap_event *event, void *arg) { // Don't allow granting more credits until after the IRQ is handled. chan->irq_in_progress = true; - mp_bluetooth_gattc_on_l2cap_recv(event->receive.conn_handle, info.scid); + mp_bluetooth_on_l2cap_recv(event->receive.conn_handle, info.scid); chan->irq_in_progress = false; // If all data has been consumed by the IRQ handler, then now allow @@ -1480,7 +1528,7 @@ STATIC int l2cap_channel_event(struct ble_l2cap_event *event, void *arg) { DEBUG_printf("l2cap_channel_event: tx_unstalled: conn_handle=%d status=%d\n", event->tx_unstalled.conn_handle, event->tx_unstalled.status); ble_l2cap_get_chan_info(event->receive.chan, &info); // Map status to {0,1} (i.e. "sent everything", or "partial send"). - mp_bluetooth_gattc_on_l2cap_send_ready(event->tx_unstalled.conn_handle, info.scid, event->tx_unstalled.status == 0 ? 0 : 1); + mp_bluetooth_on_l2cap_send_ready(event->tx_unstalled.conn_handle, info.scid, event->tx_unstalled.status == 0 ? 0 : 1); break; } case BLE_L2CAP_EVENT_COC_RECONFIG_COMPLETED: { From 1342debb9b419f78566e173b55b67b15f0a89ee4 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 19 Feb 2021 16:21:05 +1100 Subject: [PATCH 074/174] tests/multi_bluetooth: Add basic performance tests. 1. Exchange GATT notifications. 2. Transmit a stream of data over L2CAP. Signed-off-by: Jim Mussared --- tests/multi_bluetooth/perf_gatt_notify.py | 133 ++++++++++++++++ tests/multi_bluetooth/perf_gatt_notify.py.exp | 0 tests/multi_bluetooth/perf_l2cap.py | 148 ++++++++++++++++++ tests/multi_bluetooth/perf_l2cap.py.exp | 0 4 files changed, 281 insertions(+) create mode 100644 tests/multi_bluetooth/perf_gatt_notify.py create mode 100644 tests/multi_bluetooth/perf_gatt_notify.py.exp create mode 100644 tests/multi_bluetooth/perf_l2cap.py create mode 100644 tests/multi_bluetooth/perf_l2cap.py.exp diff --git a/tests/multi_bluetooth/perf_gatt_notify.py b/tests/multi_bluetooth/perf_gatt_notify.py new file mode 100644 index 0000000000..88986dda3d --- /dev/null +++ b/tests/multi_bluetooth/perf_gatt_notify.py @@ -0,0 +1,133 @@ +# Ping-pong GATT notifications between two devices. + +from micropython import const +import time, machine, bluetooth + +TIMEOUT_MS = 2000 + +_IRQ_CENTRAL_CONNECT = const(1) +_IRQ_CENTRAL_DISCONNECT = const(2) +_IRQ_PERIPHERAL_CONNECT = const(7) +_IRQ_PERIPHERAL_DISCONNECT = const(8) +_IRQ_GATTC_CHARACTERISTIC_RESULT = const(11) +_IRQ_GATTC_CHARACTERISTIC_DONE = const(12) +_IRQ_GATTC_NOTIFY = const(18) + +# How long to run the test for. +_NUM_NOTIFICATIONS = const(50) + +SERVICE_UUID = bluetooth.UUID("A5A5A5A5-FFFF-9999-1111-5A5A5A5A5A5A") +CHAR_UUID = bluetooth.UUID("00000000-1111-2222-3333-444444444444") +CHAR = ( + CHAR_UUID, + bluetooth.FLAG_NOTIFY, +) +SERVICE = ( + SERVICE_UUID, + (CHAR,), +) +SERVICES = (SERVICE,) + +is_central = False + +waiting_events = {} + + +def irq(event, data): + if event == _IRQ_CENTRAL_CONNECT: + waiting_events[event] = data[0] + elif event == _IRQ_PERIPHERAL_CONNECT: + waiting_events[event] = data[0] + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + # conn_handle, def_handle, value_handle, properties, uuid = data + if data[-1] == CHAR_UUID: + waiting_events[event] = data[2] + else: + return + elif event == _IRQ_GATTC_NOTIFY: + if is_central: + conn_handle, value_handle, notify_data = data + ble.gatts_notify(conn_handle, value_handle, b"central" + notify_data) + + if event not in waiting_events: + waiting_events[event] = None + + +def wait_for_event(event, timeout_ms): + t0 = time.ticks_ms() + while time.ticks_diff(time.ticks_ms(), t0) < timeout_ms: + if event in waiting_events: + return waiting_events.pop(event) + machine.idle() + raise ValueError("Timeout waiting for {}".format(event)) + + +# Acting in peripheral role. +def instance0(): + multitest.globals(BDADDR=ble.config("mac")) + ((char_handle,),) = ble.gatts_register_services(SERVICES) + print("gap_advertise") + ble.gap_advertise(20_000, b"\x02\x01\x06\x04\xffMPY") + multitest.next() + try: + # Wait for central to connect to us. + conn_handle = wait_for_event(_IRQ_CENTRAL_CONNECT, TIMEOUT_MS) + + # Discover characteristics. + ble.gattc_discover_characteristics(conn_handle, 1, 65535) + value_handle = wait_for_event(_IRQ_GATTC_CHARACTERISTIC_RESULT, TIMEOUT_MS) + wait_for_event(_IRQ_GATTC_CHARACTERISTIC_DONE, TIMEOUT_MS) + + # Give the central enough time to discover chars. + time.sleep_ms(500) + + ticks_start = time.ticks_ms() + + for i in range(_NUM_NOTIFICATIONS): + # Send a notification and wait for a response. + ble.gatts_notify(conn_handle, value_handle, "peripheral" + str(i)) + wait_for_event(_IRQ_GATTC_NOTIFY, TIMEOUT_MS) + + ticks_end = time.ticks_ms() + ticks_total = time.ticks_diff(ticks_end, ticks_start) + print( + "Acknowledged {} notifications in {} ms. {} ms/notification.".format( + _NUM_NOTIFICATIONS, ticks_total, ticks_total // _NUM_NOTIFICATIONS + ) + ) + + # Disconnect the central. + print("gap_disconnect:", ble.gap_disconnect(conn_handle)) + wait_for_event(_IRQ_CENTRAL_DISCONNECT, TIMEOUT_MS) + finally: + ble.active(0) + + +# Acting in central role. +def instance1(): + global is_central + is_central = True + ((char_handle,),) = ble.gatts_register_services(SERVICES) + multitest.next() + try: + # Connect to peripheral and then disconnect. + print("gap_connect") + ble.gap_connect(*BDADDR) + conn_handle = wait_for_event(_IRQ_PERIPHERAL_CONNECT, TIMEOUT_MS) + + # Discover characteristics. + ble.gattc_discover_characteristics(conn_handle, 1, 65535) + value_handle = wait_for_event(_IRQ_GATTC_CHARACTERISTIC_RESULT, TIMEOUT_MS) + wait_for_event(_IRQ_GATTC_CHARACTERISTIC_DONE, TIMEOUT_MS) + + # The IRQ handler will respond to each notification. + + # Wait for the peripheral to disconnect us. + wait_for_event(_IRQ_PERIPHERAL_DISCONNECT, 20000) + finally: + ble.active(0) + + +ble = bluetooth.BLE() +ble.active(1) +ble.irq(irq) diff --git a/tests/multi_bluetooth/perf_gatt_notify.py.exp b/tests/multi_bluetooth/perf_gatt_notify.py.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/multi_bluetooth/perf_l2cap.py b/tests/multi_bluetooth/perf_l2cap.py new file mode 100644 index 0000000000..9b07bb1dce --- /dev/null +++ b/tests/multi_bluetooth/perf_l2cap.py @@ -0,0 +1,148 @@ +# Send L2CAP data as fast as possible and time it. + +from micropython import const +import time, machine, bluetooth, random + +TIMEOUT_MS = 1000 + +_IRQ_CENTRAL_CONNECT = const(1) +_IRQ_CENTRAL_DISCONNECT = const(2) +_IRQ_PERIPHERAL_CONNECT = const(7) +_IRQ_PERIPHERAL_DISCONNECT = const(8) +_IRQ_L2CAP_ACCEPT = const(22) +_IRQ_L2CAP_CONNECT = const(23) +_IRQ_L2CAP_DISCONNECT = const(24) +_IRQ_L2CAP_RECV = const(25) +_IRQ_L2CAP_SEND_READY = const(26) + +_L2CAP_PSM = const(22) +_L2CAP_MTU = const(512) + +_PAYLOAD_LEN = const(_L2CAP_MTU) +_NUM_PAYLOADS = const(20) + +_RANDOM_SEED = 22 + + +waiting_events = {} + + +def irq(event, data): + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + waiting_events[event] = conn_handle + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + waiting_events[event] = conn_handle + elif event == _IRQ_L2CAP_ACCEPT: + conn_handle, cid, psm, our_mtu, peer_mtu = data + waiting_events[event] = (conn_handle, cid, psm) + elif event == _IRQ_L2CAP_CONNECT: + conn_handle, cid, psm, our_mtu, peer_mtu = data + waiting_events[event] = (conn_handle, cid, psm, our_mtu, peer_mtu) + + if event not in waiting_events: + waiting_events[event] = None + + +def wait_for_event(event, timeout_ms): + t0 = time.ticks_ms() + while time.ticks_diff(time.ticks_ms(), t0) < timeout_ms: + if event in waiting_events: + return waiting_events.pop(event) + machine.idle() + raise ValueError("Timeout waiting for {}".format(event)) + + +def send_data(ble, conn_handle, cid): + buf = bytearray(_PAYLOAD_LEN) + for i in range(_NUM_PAYLOADS): + for j in range(_PAYLOAD_LEN): + buf[j] = random.randint(0, 255) + if not ble.l2cap_send(conn_handle, cid, buf): + wait_for_event(_IRQ_L2CAP_SEND_READY, TIMEOUT_MS) + + +def recv_data(ble, conn_handle, cid): + buf = bytearray(_PAYLOAD_LEN) + recv_bytes = 0 + recv_correct = 0 + expected_bytes = _PAYLOAD_LEN * _NUM_PAYLOADS + ticks_first_byte = 0 + while recv_bytes < expected_bytes: + wait_for_event(_IRQ_L2CAP_RECV, TIMEOUT_MS) + if not ticks_first_byte: + ticks_first_byte = time.ticks_ms() + while True: + n = ble.l2cap_recvinto(conn_handle, cid, buf) + if n == 0: + break + recv_bytes += n + for i in range(n): + if buf[i] == random.randint(0, 255): + recv_correct += 1 + ticks_end = time.ticks_ms() + return recv_bytes, recv_correct, time.ticks_diff(ticks_end, ticks_first_byte) + + +# Acting in peripheral role. +def instance0(): + multitest.globals(BDADDR=ble.config("mac")) + ble.gap_advertise(20_000, b"\x02\x01\x06\x04\xffMPY") + multitest.next() + try: + # Wait for central to connect to us. + conn_handle = wait_for_event(_IRQ_CENTRAL_CONNECT, TIMEOUT_MS) + + ble.l2cap_listen(_L2CAP_PSM, _L2CAP_MTU) + + conn_handle, cid, psm = wait_for_event(_IRQ_L2CAP_ACCEPT, TIMEOUT_MS) + conn_handle, cid, psm, our_mtu, peer_mtu = wait_for_event(_IRQ_L2CAP_CONNECT, TIMEOUT_MS) + + random.seed(_RANDOM_SEED) + + send_data(ble, conn_handle, cid) + + wait_for_event(_IRQ_L2CAP_DISCONNECT, TIMEOUT_MS) + + # Wait for the central to disconnect. + wait_for_event(_IRQ_CENTRAL_DISCONNECT, TIMEOUT_MS) + finally: + ble.active(0) + + +# Acting in central role. +def instance1(): + multitest.next() + try: + # Connect to peripheral and then disconnect. + ble.gap_connect(*BDADDR) + conn_handle = wait_for_event(_IRQ_PERIPHERAL_CONNECT, TIMEOUT_MS) + + ble.l2cap_connect(conn_handle, _L2CAP_PSM, _L2CAP_MTU) + conn_handle, cid, psm, our_mtu, peer_mtu = wait_for_event(_IRQ_L2CAP_CONNECT, TIMEOUT_MS) + + random.seed(_RANDOM_SEED) + + recv_bytes, recv_correct, total_ticks = recv_data(ble, conn_handle, cid) + + # Disconnect channel. + ble.l2cap_disconnect(conn_handle, cid) + wait_for_event(_IRQ_L2CAP_DISCONNECT, TIMEOUT_MS) + + print( + "Received {}/{} bytes in {} ms. {} B/s".format( + recv_bytes, recv_correct, total_ticks, recv_bytes * 1000 // total_ticks + ) + ) + + # Disconnect from peripheral. + ble.gap_disconnect(conn_handle) + wait_for_event(_IRQ_PERIPHERAL_DISCONNECT, TIMEOUT_MS) + finally: + ble.active(0) + + +ble = bluetooth.BLE() +ble.active(1) +ble.irq(irq) diff --git a/tests/multi_bluetooth/perf_l2cap.py.exp b/tests/multi_bluetooth/perf_l2cap.py.exp new file mode 100644 index 0000000000..e69de29bb2 From 9d674cf7ab8570637dfab23811800e3b98babad9 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Wed, 17 Feb 2021 11:07:34 +1100 Subject: [PATCH 075/174] stm32/uart: Add support for LPUART1 on L0, L4, H7 and WB MCUs. Add LPUART1 as a standard UART. No low power features are supported, yet. LPUART1 is enabled as the next available UART after the standard U(S)ARTs: STM32WB: LPUART1 = UART(2) STM32L0: LPUART1 = UART(6) STM32L4: LPUART1 = UART(6) STM32H7: LPUART1 = UART(9) On all ports: LPUART1 = machine.UART('LP1') LPUART1 is enabled by defining MICROPY_HW_LPUART1_TX and MICROPY_HW_LPUART1_RX in mpconfigboard.h. Signed-off-by: Chris Mason --- ports/stm32/boards/make-pins.py | 2 ++ ports/stm32/machine_uart.c | 29 ++++++++++++++++-- ports/stm32/mpconfigboard_common.h | 9 +++++- ports/stm32/mpconfigport.h | 2 +- ports/stm32/pin_defs_stm32.h | 5 ++++ ports/stm32/stm32_it.c | 18 ++++++++++++ ports/stm32/uart.c | 47 ++++++++++++++++++++++++++++-- ports/stm32/uart.h | 3 ++ 8 files changed, 108 insertions(+), 7 deletions(-) diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py index a91ed8a2c9..a195323318 100755 --- a/ports/stm32/boards/make-pins.py +++ b/ports/stm32/boards/make-pins.py @@ -14,6 +14,7 @@ SUPPORTED_FN = { "I2S": ["CK", "MCK", "SD", "WS", "EXTSD"], "USART": ["RX", "TX", "CTS", "RTS", "CK"], "UART": ["RX", "TX", "CTS", "RTS"], + "LPUART": ["RX", "TX", "CTS", "RTS"], "SPI": ["NSS", "SCK", "MISO", "MOSI"], "SDMMC": ["CK", "CMD", "D0", "D1", "D2", "D3"], "CAN": ["TX", "RX"], @@ -24,6 +25,7 @@ CONDITIONAL_VAR = { "I2S": "MICROPY_HW_ENABLE_I2S{num}", "SPI": "MICROPY_HW_SPI{num}_SCK", "UART": "MICROPY_HW_UART{num}_TX", + "LPUART": "MICROPY_HW_LPUART{num}_TX", "USART": "MICROPY_HW_UART{num}_TX", "SDMMC": "MICROPY_HW_SDMMC{num}_CK", "CAN": "MICROPY_HW_CAN{num}_TX", diff --git a/ports/stm32/machine_uart.c b/ports/stm32/machine_uart.c index 31e6a1789e..eceb5b6e7a 100644 --- a/ports/stm32/machine_uart.c +++ b/ports/stm32/machine_uart.c @@ -76,7 +76,14 @@ STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!self->is_enabled) { - mp_printf(print, "UART(%u)", self->uart_id); + #ifdef LPUART1 + if (self->uart_id == PYB_LPUART_1) { + mp_printf(print, "UART('LP1')"); + } else + #endif + { + mp_printf(print, "UART(%u)", self->uart_id); + } } else { mp_int_t bits; uint32_t cr1 = self->uartx->CR1; @@ -98,8 +105,16 @@ STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k if (cr1 & USART_CR1_PCE) { bits -= 1; } - mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=", - self->uart_id, uart_get_baudrate(self), bits); + #ifdef LPUART1 + if (self->uart_id == PYB_LPUART_1) { + mp_printf(print, "UART('LP1', baudrate=%u, bits=%u, parity=", + uart_get_baudrate(self), bits); + } else + #endif + { + mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=", + self->uart_id, uart_get_baudrate(self), bits); + } if (!(cr1 & USART_CR1_PCE)) { mp_print_str(print, "None"); } else if (!(cr1 & USART_CR1_PS)) { @@ -335,6 +350,14 @@ STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, size_t n_args, size } else if (strcmp(port, MICROPY_HW_UART10_NAME) == 0) { uart_id = PYB_UART_10; #endif + #ifdef MICROPY_HW_LPUART1_NAME + } else if (strcmp(port, MICROPY_HW_LPUART1_NAME) == 0) { + uart_id = PYB_LPUART_1; + #endif + #ifdef LPUART1 + } else if (strcmp(port, "LP1") == 0 && uart_exists(PYB_LPUART_1)) { + uart_id = PYB_LPUART_1; + #endif } else { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("UART(%s) doesn't exist"), port); } diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 615310e51b..ed30d17bdc 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -181,6 +181,7 @@ #define MICROPY_HW_MAX_I2C (2) #define MICROPY_HW_MAX_TIMER (17) #define MICROPY_HW_MAX_UART (8) +#define MICROPY_HW_MAX_LPUART (0) // Configuration for STM32F4 series #elif defined(STM32F4) @@ -200,6 +201,7 @@ #else #define MICROPY_HW_MAX_UART (6) #endif +#define MICROPY_HW_MAX_LPUART (0) // Configuration for STM32F7 series #elif defined(STM32F7) @@ -214,6 +216,7 @@ #define MICROPY_HW_MAX_I2C (4) #define MICROPY_HW_MAX_TIMER (17) #define MICROPY_HW_MAX_UART (8) +#define MICROPY_HW_MAX_LPUART (0) // Configuration for STM32H7 series #elif defined(STM32H7) @@ -223,6 +226,7 @@ #define MICROPY_HW_MAX_I2C (4) #define MICROPY_HW_MAX_TIMER (17) #define MICROPY_HW_MAX_UART (8) +#define MICROPY_HW_MAX_LPUART (1) // Configuration for STM32L0 series #elif defined(STM32L0) @@ -232,6 +236,7 @@ #define MICROPY_HW_MAX_I2C (3) #define MICROPY_HW_MAX_TIMER (22) #define MICROPY_HW_MAX_UART (5) +#define MICROPY_HW_MAX_LPUART (1) // Configuration for STM32L4 series #elif defined(STM32L4) @@ -240,7 +245,8 @@ #define PYB_EXTI_NUM_VECTORS (23) #define MICROPY_HW_MAX_I2C (4) #define MICROPY_HW_MAX_TIMER (17) -#define MICROPY_HW_MAX_UART (6) +#define MICROPY_HW_MAX_UART (5) +#define MICROPY_HW_MAX_LPUART (1) // Configuration for STM32WB series #elif defined(STM32WB) @@ -250,6 +256,7 @@ #define MICROPY_HW_MAX_I2C (3) #define MICROPY_HW_MAX_TIMER (17) #define MICROPY_HW_MAX_UART (1) +#define MICROPY_HW_MAX_LPUART (1) #ifndef MICROPY_HW_STM32WB_FLASH_SYNCRONISATION #define MICROPY_HW_STM32WB_FLASH_SYNCRONISATION (1) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 407a3e6c6a..5998cd9085 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -375,7 +375,7 @@ struct _mp_bluetooth_btstack_root_pointers_t; struct _pyb_uart_obj_t *pyb_stdio_uart; \ \ /* pointers to all UART objects (if they have been created) */ \ - struct _pyb_uart_obj_t *pyb_uart_obj_all[MICROPY_HW_MAX_UART]; \ + struct _pyb_uart_obj_t *pyb_uart_obj_all[MICROPY_HW_MAX_UART + MICROPY_HW_MAX_LPUART]; \ \ /* pointers to all CAN objects (if they have been created) */ \ struct _pyb_can_obj_t *pyb_can_obj_all[MICROPY_HW_MAX_CAN]; \ diff --git a/ports/stm32/pin_defs_stm32.h b/ports/stm32/pin_defs_stm32.h index 33a1790807..9285c190a6 100644 --- a/ports/stm32/pin_defs_stm32.h +++ b/ports/stm32/pin_defs_stm32.h @@ -47,6 +47,7 @@ enum { AF_FN_I2C, AF_FN_USART, AF_FN_UART = AF_FN_USART, + AF_FN_LPUART, AF_FN_SPI, AF_FN_I2S, AF_FN_SDMMC, @@ -77,6 +78,10 @@ enum { AF_PIN_TYPE_UART_RX = AF_PIN_TYPE_USART_RX, AF_PIN_TYPE_UART_CTS = AF_PIN_TYPE_USART_CTS, AF_PIN_TYPE_UART_RTS = AF_PIN_TYPE_USART_RTS, + AF_PIN_TYPE_LPUART_TX = AF_PIN_TYPE_USART_TX, + AF_PIN_TYPE_LPUART_RX = AF_PIN_TYPE_USART_RX, + AF_PIN_TYPE_LPUART_CTS = AF_PIN_TYPE_USART_CTS, + AF_PIN_TYPE_LPUART_RTS = AF_PIN_TYPE_USART_RTS, AF_PIN_TYPE_SPI_MOSI = 0, AF_PIN_TYPE_SPI_MISO, diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 8e96da177b..dc96e2dd6c 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -742,11 +742,13 @@ void USART1_IRQHandler(void) { IRQ_EXIT(USART1_IRQn); } +#if defined(USART2) void USART2_IRQHandler(void) { IRQ_ENTER(USART2_IRQn); uart_irq_handler(2); IRQ_EXIT(USART2_IRQn); } +#endif #if defined(STM32F0) @@ -772,29 +774,37 @@ void USART4_5_IRQHandler(void) { #else +#if defined(USART3) void USART3_IRQHandler(void) { IRQ_ENTER(USART3_IRQn); uart_irq_handler(3); IRQ_EXIT(USART3_IRQn); } +#endif +#if defined(UART4) void UART4_IRQHandler(void) { IRQ_ENTER(UART4_IRQn); uart_irq_handler(4); IRQ_EXIT(UART4_IRQn); } +#endif +#if defined(UART5) void UART5_IRQHandler(void) { IRQ_ENTER(UART5_IRQn); uart_irq_handler(5); IRQ_EXIT(UART5_IRQn); } +#endif +#if defined(USART6) void USART6_IRQHandler(void) { IRQ_ENTER(USART6_IRQn); uart_irq_handler(6); IRQ_EXIT(USART6_IRQn); } +#endif #if defined(UART7) void UART7_IRQHandler(void) { @@ -830,6 +840,14 @@ void UART10_IRQHandler(void) { #endif +#if defined(LPUART1) +void LPUART1_IRQHandler(void) { + IRQ_ENTER(LPUART1_IRQn); + uart_irq_handler(PYB_LPUART_1); + IRQ_EXIT(LPUART1_IRQn); +} +#endif + #if MICROPY_PY_PYB_LEGACY #if defined(MICROPY_HW_I2C1_SCL) diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 8091ba05f9..d40a883c52 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -201,6 +201,11 @@ bool uart_exists(int uart_id) { return true; #endif + #if defined(MICROPY_HW_LPUART1_TX) && defined(MICROPY_HW_LPUART1_RX) + case PYB_LPUART_1: + return true; + #endif + default: return false; } @@ -211,6 +216,7 @@ bool uart_init(pyb_uart_obj_t *uart_obj, uint32_t baudrate, uint32_t bits, uint32_t parity, uint32_t stop, uint32_t flow) { USART_TypeDef *UARTx; IRQn_Type irqn; + uint8_t uart_fn = AF_FN_UART; int uart_unit; const pin_obj_t *pins[4] = {0}; @@ -406,6 +412,28 @@ bool uart_init(pyb_uart_obj_t *uart_obj, break; #endif + #if defined(MICROPY_HW_LPUART1_TX) && defined(MICROPY_HW_LPUART1_RX) + case PYB_LPUART_1: + uart_fn = AF_FN_LPUART; + uart_unit = 1; + UARTx = LPUART1; + irqn = LPUART1_IRQn; + pins[0] = MICROPY_HW_LPUART1_TX; + pins[1] = MICROPY_HW_LPUART1_RX; + #if defined(MICROPY_HW_LPUART1_RTS) + if (flow & UART_HWCONTROL_RTS) { + pins[2] = MICROPY_HW_LPUART1_RTS; + } + #endif + #if defined(MICROPY_HW_LPUART1_CTS) + if (flow & UART_HWCONTROL_CTS) { + pins[3] = MICROPY_HW_LPUART1_CTS; + } + #endif + __HAL_RCC_LPUART1_CLK_ENABLE(); + break; + #endif + default: // UART does not exist or is not configured for this board return false; @@ -416,7 +444,7 @@ bool uart_init(pyb_uart_obj_t *uart_obj, for (uint i = 0; i < 4; i++) { if (pins[i] != NULL) { - bool ret = mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_UART, uart_unit); + bool ret = mp_hal_pin_config_alt(pins[i], mode, pull, uart_fn, uart_unit); if (!ret) { return false; } @@ -596,6 +624,13 @@ void uart_deinit(pyb_uart_obj_t *self) { __HAL_RCC_UART10_RELEASE_RESET(); __HAL_RCC_UART10_CLK_DISABLE(); #endif + #if defined(LPUART1) + } else if (self->uart_id == PYB_LPUART_1) { + HAL_NVIC_DisableIRQ(LPUART1_IRQn); + __HAL_RCC_LPUART1_FORCE_RESET(); + __HAL_RCC_LPUART1_RELEASE_RESET(); + __HAL_RCC_LPUART1_CLK_DISABLE(); + #endif } } @@ -677,7 +712,15 @@ uint32_t uart_get_source_freq(pyb_uart_obj_t *self) { uint32_t uart_get_baudrate(pyb_uart_obj_t *self) { // This formula assumes UART_OVERSAMPLING_16 - return uart_get_source_freq(self) / self->uartx->BRR; + uint32_t source_freq = uart_get_source_freq(self); + #if defined(LPUART1) + if (self->uart_id == PYB_LPUART_1) { + return source_freq / (self->uartx->BRR >> 8); + } else + #endif + { + return source_freq / self->uartx->BRR; + } } void uart_set_baudrate(pyb_uart_obj_t *self, uint32_t baudrate) { diff --git a/ports/stm32/uart.h b/ports/stm32/uart.h index 570a79c932..0490a617f6 100644 --- a/ports/stm32/uart.h +++ b/ports/stm32/uart.h @@ -40,6 +40,9 @@ typedef enum { PYB_UART_8 = 8, PYB_UART_9 = 9, PYB_UART_10 = 10, + #ifdef LPUART1 + PYB_LPUART_1 = MICROPY_HW_MAX_UART + 1, + #endif } pyb_uart_t; #define CHAR_WIDTH_8BIT (0) From 03a64f20771cd0582af61de31811294456fa695e Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 21 Feb 2021 15:24:38 +1100 Subject: [PATCH 076/174] stm32/boards/NUCLEO_WB55: Enable LPUART1 on PA2/PA3. Signed-off-by: Damien George --- ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h index 2061349417..179369d943 100644 --- a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h @@ -22,6 +22,8 @@ // UART buses #define MICROPY_HW_UART1_TX (pin_B6) #define MICROPY_HW_UART1_RX (pin_B7) +#define MICROPY_HW_LPUART1_TX (pin_A2) +#define MICROPY_HW_LPUART1_RX (pin_A3) // USART 1 is connected to the virtual com port on the ST-LINK #define MICROPY_HW_UART_REPL PYB_UART_1 #define MICROPY_HW_UART_REPL_BAUD 115200 From d334d781e1ec66dfdd1d165dfb481916639dccaf Mon Sep 17 00:00:00 2001 From: iTitou Date: Sun, 31 Jan 2021 17:56:52 +0100 Subject: [PATCH 077/174] tools/verifygitlog.py: Show required format regexp in error message. Signed-off-by: iTitou --- tools/verifygitlog.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/verifygitlog.py b/tools/verifygitlog.py index 0080b96bfa..cc4b80f4a9 100755 --- a/tools/verifygitlog.py +++ b/tools/verifygitlog.py @@ -57,8 +57,9 @@ def verify(sha): # Subject line. subject_line = raw_body[0] very_verbose("subject_line", subject_line) - if not re.match(r"^[^!]+: [A-Z]+.+ .+\.$", subject_line): - error("Subject line should contain ': ' and end in '.': " + subject_line) + subject_line_format = r"^[^!]+: [A-Z]+.+ .+\.$" + if not re.match(subject_line_format, subject_line): + error("Subject line should match " + repr(subject_line_format) + ": " + subject_line) if len(subject_line) >= 73: error("Subject line should be 72 or less characters: " + subject_line) From d867d20d9a7d15b6506b89f5e1e638367f843894 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 21 Feb 2021 11:30:12 +1100 Subject: [PATCH 078/174] py/mkrules.cmake: Rename QSTR_DEFS variables to QSTRDEFS. And also MICROPY_PY_QSTRDEFS to MICROPY_QSTRDEFS_PY. These variables are all related. Signed-off-by: Damien George --- py/mkrules.cmake | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/py/mkrules.cmake b/py/mkrules.cmake index e05dcb836a..304f2be558 100644 --- a/py/mkrules.cmake +++ b/py/mkrules.cmake @@ -1,14 +1,14 @@ # CMake fragment for MicroPython rules -set(MICROPY_PY_QSTRDEFS "${MICROPY_PY_DIR}/qstrdefs.h") set(MICROPY_GENHDR_DIR "${CMAKE_BINARY_DIR}/genhdr") set(MICROPY_MPVERSION "${MICROPY_GENHDR_DIR}/mpversion.h") set(MICROPY_MODULEDEFS "${MICROPY_GENHDR_DIR}/moduledefs.h") -set(MICROPY_QSTR_DEFS_LAST "${MICROPY_GENHDR_DIR}/qstr.i.last") -set(MICROPY_QSTR_DEFS_SPLIT "${MICROPY_GENHDR_DIR}/qstr.split") -set(MICROPY_QSTR_DEFS_COLLECTED "${MICROPY_GENHDR_DIR}/qstrdefs.collected.h") -set(MICROPY_QSTR_DEFS_PREPROCESSED "${MICROPY_GENHDR_DIR}/qstrdefs.preprocessed.h") -set(MICROPY_QSTR_DEFS_GENERATED "${MICROPY_GENHDR_DIR}/qstrdefs.generated.h") +set(MICROPY_QSTRDEFS_PY "${MICROPY_PY_DIR}/qstrdefs.h") +set(MICROPY_QSTRDEFS_LAST "${MICROPY_GENHDR_DIR}/qstr.i.last") +set(MICROPY_QSTRDEFS_SPLIT "${MICROPY_GENHDR_DIR}/qstr.split") +set(MICROPY_QSTRDEFS_COLLECTED "${MICROPY_GENHDR_DIR}/qstrdefs.collected.h") +set(MICROPY_QSTRDEFS_PREPROCESSED "${MICROPY_GENHDR_DIR}/qstrdefs.preprocessed.h") +set(MICROPY_QSTRDEFS_GENERATED "${MICROPY_GENHDR_DIR}/qstrdefs.generated.h") # Provide defaults for preprocessor flags if not already defined if(NOT MICROPY_CPP_FLAGS) @@ -33,7 +33,7 @@ find_package(Python3 REQUIRED COMPONENTS Interpreter) target_sources(${MICROPY_TARGET} PRIVATE ${MICROPY_MPVERSION} - ${MICROPY_QSTR_DEFS_GENERATED} + ${MICROPY_QSTRDEFS_GENERATED} ) # Command to force the build of another command @@ -68,7 +68,7 @@ add_custom_command( # It only needs to be passed the list of MICROPY_SOURCE_QSTR files that have changed since # it was last run, but it looks like it's not possible to specify that with cmake. add_custom_command( - OUTPUT ${MICROPY_QSTR_DEFS_LAST} + OUTPUT ${MICROPY_QSTRDEFS_LAST} COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py pp ${CMAKE_C_COMPILER} -E output ${MICROPY_GENHDR_DIR}/qstr.i.last cflags ${MICROPY_CPP_FLAGS} -DNO_QSTR sources ${MICROPY_SOURCE_QSTR} DEPENDS ${MICROPY_MODULEDEFS} ${MICROPY_SOURCE_QSTR} @@ -77,34 +77,34 @@ add_custom_command( ) add_custom_command( - OUTPUT ${MICROPY_QSTR_DEFS_SPLIT} + OUTPUT ${MICROPY_QSTRDEFS_SPLIT} COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py split qstr ${MICROPY_GENHDR_DIR}/qstr.i.last ${MICROPY_GENHDR_DIR}/qstr _ - COMMAND touch ${MICROPY_QSTR_DEFS_SPLIT} - DEPENDS ${MICROPY_QSTR_DEFS_LAST} + COMMAND touch ${MICROPY_QSTRDEFS_SPLIT} + DEPENDS ${MICROPY_QSTRDEFS_LAST} VERBATIM COMMAND_EXPAND_LISTS ) add_custom_command( - OUTPUT ${MICROPY_QSTR_DEFS_COLLECTED} - COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py cat qstr _ ${MICROPY_GENHDR_DIR}/qstr ${MICROPY_QSTR_DEFS_COLLECTED} - DEPENDS ${MICROPY_QSTR_DEFS_SPLIT} + OUTPUT ${MICROPY_QSTRDEFS_COLLECTED} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py cat qstr _ ${MICROPY_GENHDR_DIR}/qstr ${MICROPY_QSTRDEFS_COLLECTED} + DEPENDS ${MICROPY_QSTRDEFS_SPLIT} VERBATIM COMMAND_EXPAND_LISTS ) add_custom_command( - OUTPUT ${MICROPY_QSTR_DEFS_PREPROCESSED} - COMMAND cat ${MICROPY_PY_QSTRDEFS} ${MICROPY_QSTR_DEFS_COLLECTED} | sed "s/^Q(.*)/\"&\"/" | ${CMAKE_C_COMPILER} -E ${MICROPY_CPP_FLAGS} - | sed "s/^\\\"\\(Q(.*)\\)\\\"/\\1/" > ${MICROPY_QSTR_DEFS_PREPROCESSED} - DEPENDS ${MICROPY_QSTR_DEFS_COLLECTED} + OUTPUT ${MICROPY_QSTRDEFS_PREPROCESSED} + COMMAND cat ${MICROPY_QSTRDEFS_PY} ${MICROPY_QSTRDEFS_COLLECTED} | sed "s/^Q(.*)/\"&\"/" | ${CMAKE_C_COMPILER} -E ${MICROPY_CPP_FLAGS} - | sed "s/^\\\"\\(Q(.*)\\)\\\"/\\1/" > ${MICROPY_QSTRDEFS_PREPROCESSED} + DEPENDS ${MICROPY_QSTRDEFS_COLLECTED} VERBATIM COMMAND_EXPAND_LISTS ) add_custom_command( - OUTPUT ${MICROPY_QSTR_DEFS_GENERATED} - COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdata.py ${MICROPY_QSTR_DEFS_PREPROCESSED} > ${MICROPY_QSTR_DEFS_GENERATED} - DEPENDS ${MICROPY_QSTR_DEFS_PREPROCESSED} + OUTPUT ${MICROPY_QSTRDEFS_GENERATED} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdata.py ${MICROPY_QSTRDEFS_PREPROCESSED} > ${MICROPY_QSTRDEFS_GENERATED} + DEPENDS ${MICROPY_QSTRDEFS_PREPROCESSED} VERBATIM COMMAND_EXPAND_LISTS ) @@ -127,7 +127,7 @@ if(MICROPY_FROZEN_MANIFEST) OUTPUT ${MICROPY_FROZEN_CONTENT} COMMAND ${Python3_EXECUTABLE} ${MICROPY_DIR}/tools/makemanifest.py -o ${MICROPY_FROZEN_CONTENT} -v "MPY_DIR=${MICROPY_DIR}" -v "PORT_DIR=${MICROPY_PORT_DIR}" -b "${CMAKE_BINARY_DIR}" -f${MICROPY_CROSS_FLAGS} ${MICROPY_FROZEN_MANIFEST} DEPENDS MICROPY_FORCE_BUILD - ${MICROPY_QSTR_DEFS_GENERATED} + ${MICROPY_QSTRDEFS_GENERATED} VERBATIM ) endif() From 2adf20c5f28e4d36f7832412f4502be664ccdb23 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 21 Feb 2021 11:32:00 +1100 Subject: [PATCH 079/174] py/mkrules.cmake: Add MICROPY_QSTRDEFS_PORT to qstr build process. This allows a port to specify a custom qstrdefsport.h file, the same as the QSTR_DEFS variable in a Makefile. Signed-off-by: Damien George --- py/mkrules.cmake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/py/mkrules.cmake b/py/mkrules.cmake index 304f2be558..9c4c4afabe 100644 --- a/py/mkrules.cmake +++ b/py/mkrules.cmake @@ -95,8 +95,10 @@ add_custom_command( add_custom_command( OUTPUT ${MICROPY_QSTRDEFS_PREPROCESSED} - COMMAND cat ${MICROPY_QSTRDEFS_PY} ${MICROPY_QSTRDEFS_COLLECTED} | sed "s/^Q(.*)/\"&\"/" | ${CMAKE_C_COMPILER} -E ${MICROPY_CPP_FLAGS} - | sed "s/^\\\"\\(Q(.*)\\)\\\"/\\1/" > ${MICROPY_QSTRDEFS_PREPROCESSED} - DEPENDS ${MICROPY_QSTRDEFS_COLLECTED} + COMMAND cat ${MICROPY_QSTRDEFS_PY} ${MICROPY_QSTRDEFS_PORT} ${MICROPY_QSTRDEFS_COLLECTED} | sed "s/^Q(.*)/\"&\"/" | ${CMAKE_C_COMPILER} -E ${MICROPY_CPP_FLAGS} - | sed "s/^\\\"\\(Q(.*)\\)\\\"/\\1/" > ${MICROPY_QSTRDEFS_PREPROCESSED} + DEPENDS ${MICROPY_QSTRDEFS_PY} + ${MICROPY_QSTRDEFS_PORT} + ${MICROPY_QSTRDEFS_COLLECTED} VERBATIM COMMAND_EXPAND_LISTS ) From 75db0b907942f4b2e7306d2ce90d2f014cd5a414 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 21 Feb 2021 11:33:15 +1100 Subject: [PATCH 080/174] esp32: Define MICROPY_QSTRDEFS_PORT to include special qstrs. Fixes issue #6942. Signed-off-by: Damien George --- ports/esp32/main/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index 9fb48a9041..bd25d76ee4 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -5,6 +5,10 @@ get_filename_component(MICROPY_DIR ${PROJECT_DIR}/../.. ABSOLUTE) include(${MICROPY_DIR}/py/py.cmake) include(${MICROPY_DIR}/extmod/extmod.cmake) +set(MICROPY_QSTRDEFS_PORT + ${PROJECT_DIR}/qstrdefsport.h +) + set(MICROPY_SOURCE_EXTMOD_EXTRA ${MICROPY_DIR}/extmod/modonewire.c ) From 53f5bb05a9cdf59cc2deaf216c25c0c275e6dce7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 23 Feb 2021 09:49:12 +1100 Subject: [PATCH 081/174] rp2,stm32: Enable MICROPY_PY_UBINASCII_CRC32 to get ubinascii.crc32(). These ports already have uzlib enabled so this additional ubinascii.crc32 function only costs about 90 bytes of flash. Signed-off-by: Damien George --- ports/rp2/mpconfigport.h | 1 + ports/stm32/mpconfigport.h | 1 + 2 files changed, 2 insertions(+) diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index 9ba381030b..b3214acfc2 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -102,6 +102,7 @@ #define MICROPY_PY_URE_SUB (1) #define MICROPY_PY_UHASHLIB (1) #define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UBINASCII_CRC32 (1) #define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_URANDOM (1) #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 5998cd9085..174ef22f24 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -165,6 +165,7 @@ #define MICROPY_PY_UCRYPTOLIB (MICROPY_PY_USSL) #ifndef MICROPY_PY_UBINASCII #define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UBINASCII_CRC32 (1) #endif #ifndef MICROPY_PY_UOS #define MICROPY_PY_UOS (1) From cdaec0dcaffbfcb58e190738cf6e9d34541464f0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 23 Feb 2021 14:33:31 +1100 Subject: [PATCH 082/174] tools/pydfu.py: Support DFU files with elements of zero size. Instead of raising a ZeroDivisionError, this tool now just skips any elements in the DFU file that have zero size. Signed-off-by: Damien George --- tools/pydfu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pydfu.py b/tools/pydfu.py index 030f56bf85..42b4fa2da6 100755 --- a/tools/pydfu.py +++ b/tools/pydfu.py @@ -521,7 +521,7 @@ def write_elements(elements, mass_erase_used, progress=None): data = elem["data"] elem_size = size elem_addr = addr - if progress: + if progress and elem_size: progress(elem_addr, 0, elem_size) while size > 0: write_size = size From 680ce45323248df288ee8ebd055a4caacb3e46f3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 2 Mar 2021 12:14:54 +1100 Subject: [PATCH 083/174] stm32/rfcore: Allow BLE settings to be changed by a board. Two of the defaults have also changed in this commit: - MICROPY_HW_RFCORE_BLE_LSE_SOURCE changed from 1 to 0, which configures the LsSource to be LSE (needed due to errata 2.2.1). - MICROPY_HW_RFCORE_BLE_VITERBI_MODE changed from 0 to 1, which enables Viterbi mode, following all the ST examples. Signed-off-by: Damien George --- ports/stm32/mpconfigboard_common.h | 20 ++++++++++++++++ ports/stm32/rfcore.c | 38 +++++++++++++++--------------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index ed30d17bdc..948897b215 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -262,6 +262,26 @@ #define MICROPY_HW_STM32WB_FLASH_SYNCRONISATION (1) #endif +// RF core BLE configuration (a board should define +// MICROPY_HW_RFCORE_BLE_NUM_GATT_ATTRIBUTES to override all values) +#ifndef MICROPY_HW_RFCORE_BLE_NUM_GATT_ATTRIBUTES +#define MICROPY_HW_RFCORE_BLE_NUM_GATT_ATTRIBUTES (0) +#define MICROPY_HW_RFCORE_BLE_NUM_GATT_SERVICES (0) +#define MICROPY_HW_RFCORE_BLE_ATT_VALUE_ARRAY_SIZE (0) +#define MICROPY_HW_RFCORE_BLE_NUM_LINK (1) +#define MICROPY_HW_RFCORE_BLE_DATA_LENGTH_EXTENSION (1) +#define MICROPY_HW_RFCORE_BLE_PREPARE_WRITE_LIST_SIZE (0) +#define MICROPY_HW_RFCORE_BLE_MBLOCK_COUNT (0x79) +#define MICROPY_HW_RFCORE_BLE_MAX_ATT_MTU (0) +#define MICROPY_HW_RFCORE_BLE_SLAVE_SCA (0) +#define MICROPY_HW_RFCORE_BLE_MASTER_SCA (0) +#define MICROPY_HW_RFCORE_BLE_LSE_SOURCE (0) // use LSE to clock the rfcore (see errata 2.2.1) +#define MICROPY_HW_RFCORE_BLE_MAX_CONN_EVENT_LENGTH (0xffffffff) +#define MICROPY_HW_RFCORE_BLE_HSE_STARTUP_TIME (0x148) +#define MICROPY_HW_RFCORE_BLE_VITERBI_MODE (1) +#define MICROPY_HW_RFCORE_BLE_LL_ONLY (1) // use LL only, we provide the rest of the BLE stack +#endif + #else #error Unsupported MCU series #endif diff --git a/ports/stm32/rfcore.c b/ports/stm32/rfcore.c index b11c4f2022..55fc229dd0 100644 --- a/ports/stm32/rfcore.c +++ b/ports/stm32/rfcore.c @@ -548,30 +548,30 @@ static const struct { uint16_t AttMtu; uint16_t SlaveSca; uint8_t MasterSca; - uint8_t LsSource; // 0=LSE 1=internal RO + uint8_t LsSource; uint32_t MaxConnEventLength; uint16_t HsStartupTime; uint8_t ViterbiEnable; - uint8_t LlOnly; // 0=LL+Host, 1=LL only + uint8_t LlOnly; uint8_t HwVersion; } ble_init_params = { - 0, - 0, - 0, // NumAttrRecord - 0, // NumAttrServ - 0, // AttrValueArrSize - 1, // NumOfLinks - 1, // ExtendedPacketLengthEnable - 0, // PrWriteListSize - 0x79, // MblockCount - 0, // AttMtu - 0, // SlaveSca - 0, // MasterSca - 1, // LsSource - 0xffffffff, // MaxConnEventLength - 0x148, // HsStartupTime - 0, // ViterbiEnable - 1, // LlOnly + 0, // pBleBufferAddress + 0, // BleBufferSize + MICROPY_HW_RFCORE_BLE_NUM_GATT_ATTRIBUTES, + MICROPY_HW_RFCORE_BLE_NUM_GATT_SERVICES, + MICROPY_HW_RFCORE_BLE_ATT_VALUE_ARRAY_SIZE, + MICROPY_HW_RFCORE_BLE_NUM_LINK, + MICROPY_HW_RFCORE_BLE_DATA_LENGTH_EXTENSION, + MICROPY_HW_RFCORE_BLE_PREPARE_WRITE_LIST_SIZE, + MICROPY_HW_RFCORE_BLE_MBLOCK_COUNT, + MICROPY_HW_RFCORE_BLE_MAX_ATT_MTU, + MICROPY_HW_RFCORE_BLE_SLAVE_SCA, + MICROPY_HW_RFCORE_BLE_MASTER_SCA, + MICROPY_HW_RFCORE_BLE_LSE_SOURCE, + MICROPY_HW_RFCORE_BLE_MAX_CONN_EVENT_LENGTH, + MICROPY_HW_RFCORE_BLE_HSE_STARTUP_TIME, + MICROPY_HW_RFCORE_BLE_VITERBI_MODE, + MICROPY_HW_RFCORE_BLE_LL_ONLY, 0, // HwVersion }; From 59a129f22f096d992496111c498b3ea97e637115 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Fri, 5 Mar 2021 09:46:14 +1100 Subject: [PATCH 084/174] stm32/storage: Prevent attempts to read/write invalid block addresses. A corrupt filesystem may lead to a request for a block which is out of range of the block device limits. Return an error instead of passing the request down to the lower layer. --- ports/stm32/storage.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 6581860ff3..a71c4a3ea7 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -340,8 +340,12 @@ STATIC mp_obj_t pyb_flash_readblocks(size_t n_args, const mp_obj_t *args) { else if (self != &pyb_flash_obj) { // Extended block read on a sub-section of the flash storage uint32_t offset = mp_obj_get_int(args[3]); - block_num += self->start / PYB_FLASH_NATIVE_BLOCK_SIZE; - ret = MICROPY_HW_BDEV_READBLOCKS_EXT(bufinfo.buf, block_num, offset, bufinfo.len); + if ((block_num * PYB_FLASH_NATIVE_BLOCK_SIZE) >= self->len) { + ret = -MP_EFAULT; // Bad address + } else { + block_num += self->start / PYB_FLASH_NATIVE_BLOCK_SIZE; + ret = MICROPY_HW_BDEV_READBLOCKS_EXT(bufinfo.buf, block_num, offset, bufinfo.len); + } } #endif return MP_OBJ_NEW_SMALL_INT(ret); @@ -363,8 +367,12 @@ STATIC mp_obj_t pyb_flash_writeblocks(size_t n_args, const mp_obj_t *args) { else if (self != &pyb_flash_obj) { // Extended block write on a sub-section of the flash storage uint32_t offset = mp_obj_get_int(args[3]); - block_num += self->start / PYB_FLASH_NATIVE_BLOCK_SIZE; - ret = MICROPY_HW_BDEV_WRITEBLOCKS_EXT(bufinfo.buf, block_num, offset, bufinfo.len); + if ((block_num * PYB_FLASH_NATIVE_BLOCK_SIZE) >= self->len) { + ret = -MP_EFAULT; // Bad address + } else { + block_num += self->start / PYB_FLASH_NATIVE_BLOCK_SIZE; + ret = MICROPY_HW_BDEV_WRITEBLOCKS_EXT(bufinfo.buf, block_num, offset, bufinfo.len); + } } #endif return MP_OBJ_NEW_SMALL_INT(ret); From 35c602d3b8e1ee2d06715c75fa0b4ca7a353372e Mon Sep 17 00:00:00 2001 From: Herwin Grobben Date: Fri, 5 Mar 2021 10:05:19 +0100 Subject: [PATCH 085/174] stm32/make-stmconst.py: Allow "[]" chars when parsing source comments. For STM32WB MCUs, EXTI offset addresses were not parsed due to the appearance of "[31:0]" in a comment in the .h file. --- ports/stm32/make-stmconst.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/make-stmconst.py b/ports/stm32/make-stmconst.py index ac5c56f5c7..602bdc6c19 100644 --- a/ports/stm32/make-stmconst.py +++ b/ports/stm32/make-stmconst.py @@ -46,7 +46,7 @@ class LexerError(Exception): class Lexer: re_io_reg = r"__IO uint(?P8|16|32)_t +(?P[A-Z0-9]+)" - re_comment = r"(?P[A-Za-z0-9 \-/_()&:]+)" + re_comment = r"(?P[A-Za-z0-9 \-/_()&:\[\]]+)" re_addr_offset = r"Address offset: (?P0x[0-9A-Z]{2,3})" regexs = ( ( From 85ea4ac0e56faca680aa03c41eb4009464401f07 Mon Sep 17 00:00:00 2001 From: Braiden Kindt Date: Sun, 14 Feb 2021 23:42:57 -0500 Subject: [PATCH 086/174] stm32/main: Fix passing state.reset_mode to init_flash_fs. state.reset_mode is updated by `MICROPY_BOARD_BEFORE_SOFT_RESET_LOOP` but not passed to `init_flash_fs`, and so factory reset is not executed on boards that do not have a bootloader. This bug was introduced by 4c3976bbcaf58266fdcaab264fee5b7a94a682e5 Fixes #6903. --- ports/stm32/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 38710e2651..bdf7328f68 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -531,7 +531,7 @@ soft_reset: // Create it if needed, mount in on /flash, and set it as current dir. bool mounted_flash = false; #if MICROPY_HW_FLASH_MOUNT_AT_BOOT - mounted_flash = init_flash_fs(reset_mode); + mounted_flash = init_flash_fs(state.reset_mode); #endif bool mounted_sdcard = false; From 0facd891e7b4e226e7a905309f917dc271c1860b Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Sun, 27 Sep 2020 08:42:52 +0100 Subject: [PATCH 087/174] stm32/powerctrl: Save and restore EWUP state when configuring standby. This allows the user to enable wake-up sources using the EWUP bits, on F7 MCUs. Disabling the wake-up sources while clearing the wake-up flags follows the reference manual and ST examples. --- ports/stm32/powerctrl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index bf8be647f4..a579713b6f 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -712,10 +712,14 @@ void powerctrl_enter_standby_mode(void) { RTC->ISR &= ~ISR_BITS; #if defined(STM32F7) + // Save EWUP state + uint32_t csr2_ewup = PWR->CSR2 & (PWR_CSR2_EWUP6 | PWR_CSR2_EWUP5 | PWR_CSR2_EWUP4 | PWR_CSR2_EWUP3 | PWR_CSR2_EWUP2 | PWR_CSR2_EWUP1); // disable wake-up flags PWR->CSR2 &= ~(PWR_CSR2_EWUP6 | PWR_CSR2_EWUP5 | PWR_CSR2_EWUP4 | PWR_CSR2_EWUP3 | PWR_CSR2_EWUP2 | PWR_CSR2_EWUP1); // clear global wake-up flag PWR->CR2 |= PWR_CR2_CWUPF6 | PWR_CR2_CWUPF5 | PWR_CR2_CWUPF4 | PWR_CR2_CWUPF3 | PWR_CR2_CWUPF2 | PWR_CR2_CWUPF1; + // Restore EWUP state + PWR->CSR2 |= csr2_ewup; #elif defined(STM32H7) EXTI_D1->PR1 = 0x3fffff; PWR->WKUPCR |= PWR_WAKEUP_FLAG1 | PWR_WAKEUP_FLAG2 | PWR_WAKEUP_FLAG3 | PWR_WAKEUP_FLAG4 | PWR_WAKEUP_FLAG5 | PWR_WAKEUP_FLAG6; From 79c186f5c962b514cde21415d7a262cfdbddbd97 Mon Sep 17 00:00:00 2001 From: Reinhard Feger <47209718+rf-eng@users.noreply.github.com> Date: Sat, 22 Aug 2020 18:48:21 +0200 Subject: [PATCH 088/174] stm32/spi: Fix baudrate calculation for H7 series. Fixes issue #6342. --- ports/stm32/spi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index 07374d7a38..f8ab791898 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -633,7 +633,11 @@ void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy) { if (spi->State != HAL_SPI_STATE_RESET) { if (spi->Init.Mode == SPI_MODE_MASTER) { // compute baudrate + #if defined(STM32H7) + uint log_prescaler = (spi->Init.BaudRatePrescaler >> 28) + 1; + #else uint log_prescaler = (spi->Init.BaudRatePrescaler >> 3) + 1; + #endif uint baudrate = spi_get_source_freq(spi) >> log_prescaler; if (legacy) { mp_printf(print, ", SPI.MASTER"); From c33c749f64fc664e46529885d84e499ea2c3d461 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 11 Mar 2021 09:04:36 +1100 Subject: [PATCH 089/174] stm32/boardctrl: Add MICROPY_BOARD_STARTUP hook. Signed-off-by: Damien George --- ports/stm32/boardctrl.h | 4 ++++ ports/stm32/main.c | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boardctrl.h b/ports/stm32/boardctrl.h index 6f79dfb890..f1cbc3b955 100644 --- a/ports/stm32/boardctrl.h +++ b/ports/stm32/boardctrl.h @@ -28,6 +28,10 @@ #include "py/mpconfig.h" +#ifndef MICROPY_BOARD_STARTUP +#define MICROPY_BOARD_STARTUP powerctrl_check_enter_bootloader +#endif + #ifndef MICROPY_BOARD_EARLY_INIT #define MICROPY_BOARD_EARLY_INIT() #endif diff --git a/ports/stm32/main.c b/ports/stm32/main.c index bdf7328f68..888b20513c 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -313,8 +313,9 @@ void stm32_main(uint32_t reset_mode) { // Enable 8-byte stack alignment for IRQ handlers, in accord with EABI SCB->CCR |= SCB_CCR_STKALIGN_Msk; - // Check if bootloader should be entered instead of main application - powerctrl_check_enter_bootloader(); + // Hook for a board to run code at start up, for example check if a + // bootloader should be entered instead of the main application. + MICROPY_BOARD_STARTUP(); // Enable caches and prefetch buffers From 7d73b9ff9975261bd2ff3544b09e9ec494775435 Mon Sep 17 00:00:00 2001 From: Mirko Vogt Date: Tue, 9 Feb 2021 18:28:36 +0000 Subject: [PATCH 090/174] lib/mbedtls: Switch to currently latest commit of LTS branch v2.16. From a version numbering point of view this is a downgrade (2.17.0 -> 2.16.x). However the latest commit for version 2.17.0 is from March 2019 and no further minor release happened after 2.17.0. This version is EOL. 2.16.x though is still actively maintained as a long term release, hence security and stability fixes are still being backported, including compatibility with upcoming compiler releases. --- lib/mbedtls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mbedtls b/lib/mbedtls index 3f8d78411a..1b6a24f759 160000 --- a/lib/mbedtls +++ b/lib/mbedtls @@ -1 +1 @@ -Subproject commit 3f8d78411a26e833db18d9fbde0e2f0baeda87f0 +Subproject commit 1b6a24f759cefbb4a69ae9476885d7f42a847e3d From 2d5cece5ac3fc467055dd3e27378ad497adcee00 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Thu, 18 Feb 2021 01:28:42 +0200 Subject: [PATCH 091/174] py/nlr: Implement NLR for AArch64. --- py/nlr.h | 4 +++ py/nlraarch64.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ py/py.mk | 1 + 3 files changed, 79 insertions(+) create mode 100644 py/nlraarch64.c diff --git a/py/nlr.h b/py/nlr.h index f9fbf56e54..9f12ede9cd 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -39,6 +39,7 @@ #define MICROPY_NLR_NUM_REGS_X64_WIN (10) #define MICROPY_NLR_NUM_REGS_ARM_THUMB (10) #define MICROPY_NLR_NUM_REGS_ARM_THUMB_FP (10 + 6) +#define MICROPY_NLR_NUM_REGS_AARCH64 (13) #define MICROPY_NLR_NUM_REGS_XTENSA (10) #define MICROPY_NLR_NUM_REGS_XTENSAWIN (17) @@ -72,6 +73,9 @@ // so only save/restore those as an optimisation. #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_ARM_THUMB_FP) #endif +#elif defined(__aarch64__) + #define MICROPY_NLR_AARCH64 (1) + #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_AARCH64) #elif defined(__xtensa__) #define MICROPY_NLR_XTENSA (1) #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_XTENSA) diff --git a/py/nlraarch64.c b/py/nlraarch64.c new file mode 100644 index 0000000000..2df0dc9c85 --- /dev/null +++ b/py/nlraarch64.c @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Yonatan Goldschmidt + * + * 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 "py/mpstate.h" // needed for NLR defs + +#if MICROPY_NLR_AARCH64 + +// AArch64 callee-saved registers are x19-x29. +// https://en.wikipedia.org/wiki/Calling_convention#ARM_(A64) + +// Implemented purely as inline assembly; inside a function, we have to deal with undoing the prologue, restoring +// SP and LR. This way, we don't. +__asm( + "nlr_push: \n" + ".global nlr_push \n" + "mov x9, sp \n" + "stp lr, x9, [x0, #16]\n" // 16 == offsetof(nlr_buf_t, regs) + "stp x19, x20, [x0, #32]\n" + "stp x21, x22, [x0, #48]\n" + "stp x23, x24, [x0, #64]\n" + "stp x25, x26, [x0, #80]\n" + "stp x27, x28, [x0, #96]\n" + "str x29, [x0, #112]\n" + "b nlr_push_tail \n" // do the rest in C + ); + +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) + + MP_STATIC_ASSERT(offsetof(nlr_buf_t, regs) == 16); // asm assumes it + + __asm volatile ( + "ldr x29, [%0, #112]\n" + "ldp x27, x28, [%0, #96]\n" + "ldp x25, x26, [%0, #80]\n" + "ldp x23, x24, [%0, #64]\n" + "ldp x21, x22, [%0, #48]\n" + "ldp x19, x20, [%0, #32]\n" + "ldp lr, x9, [%0, #16]\n" // 16 == offsetof(nlr_buf_t, regs) + "mov sp, x9 \n" + "mov x0, #1 \n" // non-local return + "ret \n" + : + : "r" (top) + : + ); + + MP_UNREACHABLE +} + +#endif // MICROPY_NLR_AARCH64 diff --git a/py/py.mk b/py/py.mk index bac38f0741..59abc8f503 100644 --- a/py/py.mk +++ b/py/py.mk @@ -57,6 +57,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ nlrx86.o \ nlrx64.o \ nlrthumb.o \ + nlraarch64.o \ nlrpowerpc.o \ nlrxtensa.o \ nlrsetjmp.o \ From e196cb762e5a946bee0404b043acd673178c162d Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Thu, 18 Feb 2021 01:28:09 +0200 Subject: [PATCH 092/174] py/nlrx64: Fix typo in comment. --- py/nlrx64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/nlrx64.c b/py/nlrx64.c index eb39dadce7..f5d02afbdb 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -89,7 +89,7 @@ NORETURN void nlr_jump(void *val) { "movq %0, %%rcx \n" // %rcx points to nlr_buf #if MICROPY_NLR_OS_WINDOWS "movq 88(%%rcx), %%rsi \n" // load saved %rsi - "movq 80(%%rcx), %%rdi \n" // load saved %rdr + "movq 80(%%rcx), %%rdi \n" // load saved %rdi #endif "movq 72(%%rcx), %%r15 \n" // load saved %r15 "movq 64(%%rcx), %%r14 \n" // load saved %r14 From 098ac11bb0cb912909af801015ac07bd2bf01ce7 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sun, 21 Feb 2021 02:05:40 +0200 Subject: [PATCH 093/174] lib/utils/gchelper_generic: Implement AArch64 support. --- lib/utils/gchelper.h | 2 ++ lib/utils/gchelper_generic.c | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/lib/utils/gchelper.h b/lib/utils/gchelper.h index 4b6ead6ba6..645ee837f5 100644 --- a/lib/utils/gchelper.h +++ b/lib/utils/gchelper.h @@ -39,6 +39,8 @@ typedef uintptr_t gc_helper_regs_t[6]; typedef uintptr_t gc_helper_regs_t[4]; #elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) typedef uintptr_t gc_helper_regs_t[10]; +#elif defined(__aarch64__) +typedef uintptr_t gc_helper_regs_t[11]; // x19-x29 #endif #endif diff --git a/lib/utils/gchelper_generic.c b/lib/utils/gchelper_generic.c index 9750e8b0c8..3e7e33ab18 100644 --- a/lib/utils/gchelper_generic.c +++ b/lib/utils/gchelper_generic.c @@ -123,6 +123,33 @@ STATIC void gc_helper_get_regs(gc_helper_regs_t arr) { arr[9] = r13; } +#elif defined(__aarch64__) + +STATIC void gc_helper_get_regs(gc_helper_regs_t arr) { + const register long x19 asm ("x19"); + const register long x20 asm ("x20"); + const register long x21 asm ("x21"); + const register long x22 asm ("x22"); + const register long x23 asm ("x23"); + const register long x24 asm ("x24"); + const register long x25 asm ("x25"); + const register long x26 asm ("x26"); + const register long x27 asm ("x27"); + const register long x28 asm ("x28"); + const register long x29 asm ("x29"); + arr[0] = x19; + arr[1] = x20; + arr[2] = x21; + arr[3] = x22; + arr[4] = x23; + arr[5] = x24; + arr[6] = x25; + arr[7] = x26; + arr[8] = x27; + arr[9] = x28; + arr[10] = x29; +} + #else #error "Architecture not supported for gc_helper_get_regs. Set MICROPY_GCREGS_SETJMP to use the fallback implementation." From 8785acac22a25d376d11c7dda5d0556432818ac2 Mon Sep 17 00:00:00 2001 From: Mike Causer Date: Fri, 26 Feb 2021 09:36:48 +1100 Subject: [PATCH 094/174] esp32/Makefile: Specify port and baud on erase_flash command. --- ports/esp32/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 1249795993..9a3a15d6ee 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -37,7 +37,7 @@ deploy: idf.py $(IDFPY_FLAGS) -p $(PORT) -b $(BAUD) flash erase: - idf.py $(IDFPY_FLAGS) erase_flash + idf.py $(IDFPY_FLAGS) -p $(PORT) -b $(BAUD) erase_flash submodules: git submodule update --init $(addprefix ../../,$(GIT_SUBMODULES)) From 23ce25a7c3175e2251af9af34a6c5eafa871bfcd Mon Sep 17 00:00:00 2001 From: svetelna Date: Mon, 7 Dec 2020 13:00:09 +0100 Subject: [PATCH 095/174] mimxrt/boards: Add MIMXRT1050_EVK board, based on MIMXRT1060_EVK. --- .../evkmimxrt1050_flexspi_nor_config.h | 267 ++++++++++++++++++ .../boards/MIMXRT1050_EVK/flash_config.c | 56 ++++ .../boards/MIMXRT1050_EVK/mpconfigboard.h | 9 + .../boards/MIMXRT1050_EVK/mpconfigboard.mk | 7 + ports/mimxrt/boards/MIMXRT1050_EVK/pins.c | 33 +++ ports/mimxrt/boards/MIMXRT1050_EVK/pins.h | 30 ++ ports/mimxrt/boards/MIMXRT1052.ld | 7 + 7 files changed, 409 insertions(+) create mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/evkmimxrt1050_flexspi_nor_config.h create mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/flash_config.c create mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h create mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk create mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/pins.c create mode 100644 ports/mimxrt/boards/MIMXRT1050_EVK/pins.h create mode 100644 ports/mimxrt/boards/MIMXRT1052.ld diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/evkmimxrt1050_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1050_EVK/evkmimxrt1050_flexspi_nor_config.h new file mode 100644 index 0000000000..d8e842452e --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/evkmimxrt1050_flexspi_nor_config.h @@ -0,0 +1,267 @@ +/* + * Copyright 2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__ +#define __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__ + +#include +#include +#include "fsl_common.h" + +/*! @name Driver version */ +/*@{*/ +/*! @brief XIP_BOARD driver version 2.0.0. */ +#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) +/*@}*/ + +/* FLEXSPI memory config block related defintions */ +#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian +#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0 +#define FLEXSPI_CFG_BLK_SIZE (512) + +/* FLEXSPI Feature related definitions */ +#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1 + +/* Lookup table related defintions */ +#define CMD_INDEX_READ 0 +#define CMD_INDEX_READSTATUS 1 +#define CMD_INDEX_WRITEENABLE 2 +#define CMD_INDEX_WRITE 4 + +#define CMD_LUT_SEQ_IDX_READ 0 +#define CMD_LUT_SEQ_IDX_READSTATUS 1 +#define CMD_LUT_SEQ_IDX_WRITEENABLE 3 +#define CMD_LUT_SEQ_IDX_WRITE 9 + +#define CMD_SDR 0x01 +#define CMD_DDR 0x21 +#define RADDR_SDR 0x02 +#define RADDR_DDR 0x22 +#define CADDR_SDR 0x03 +#define CADDR_DDR 0x23 +#define MODE1_SDR 0x04 +#define MODE1_DDR 0x24 +#define MODE2_SDR 0x05 +#define MODE2_DDR 0x25 +#define MODE4_SDR 0x06 +#define MODE4_DDR 0x26 +#define MODE8_SDR 0x07 +#define MODE8_DDR 0x27 +#define WRITE_SDR 0x08 +#define WRITE_DDR 0x28 +#define READ_SDR 0x09 +#define READ_DDR 0x29 +#define LEARN_SDR 0x0A +#define LEARN_DDR 0x2A +#define DATSZ_SDR 0x0B +#define DATSZ_DDR 0x2B +#define DUMMY_SDR 0x0C +#define DUMMY_DDR 0x2C +#define DUMMY_RWDS_SDR 0x0D +#define DUMMY_RWDS_DDR 0x2D +#define JMP_ON_CS 0x1F +#define STOP 0 + +#define FLEXSPI_1PAD 0 +#define FLEXSPI_2PAD 1 +#define FLEXSPI_4PAD 2 +#define FLEXSPI_8PAD 3 + +#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ + (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ + FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) + +//!@brief Definitions for FlexSPI Serial Clock Frequency +typedef enum _FlexSpiSerialClockFreq +{ + kFlexSpiSerialClk_30MHz = 1, + kFlexSpiSerialClk_50MHz = 2, + kFlexSpiSerialClk_60MHz = 3, + kFlexSpiSerialClk_75MHz = 4, + kFlexSpiSerialClk_80MHz = 5, + kFlexSpiSerialClk_100MHz = 6, + kFlexSpiSerialClk_133MHz = 7, + kFlexSpiSerialClk_166MHz = 8, +} flexspi_serial_clk_freq_t; + +//!@brief FlexSPI clock configuration type +enum +{ + kFlexSpiClk_SDR, //!< Clock configure for SDR mode + kFlexSpiClk_DDR, //!< Clock configurat for DDR mode +}; + +//!@brief FlexSPI Read Sample Clock Source definition +typedef enum _FlashReadSampleClkSource +{ + kFlexSPIReadSampleClk_LoopbackInternally = 0, + kFlexSPIReadSampleClk_LoopbackFromDqsPad = 1, + kFlexSPIReadSampleClk_LoopbackFromSckPad = 2, + kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3, +} flexspi_read_sample_clk_t; + +//!@brief Misc feature bit definitions +enum +{ + kFlexSpiMiscOffset_DiffClkEnable = 0, //!< Bit for Differential clock enable + kFlexSpiMiscOffset_Ck2Enable = 1, //!< Bit for CK2 enable + kFlexSpiMiscOffset_ParallelEnable = 2, //!< Bit for Parallel mode enable + kFlexSpiMiscOffset_WordAddressableEnable = 3, //!< Bit for Word Addressable enable + kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, //!< Bit for Safe Configuration Frequency enable + kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable + kFlexSpiMiscOffset_DdrModeEnable = 6, //!< Bit for DDR clock confiuration indication. +}; + +//!@brief Flash Type Definition +enum +{ + kFlexSpiDeviceType_SerialNOR = 1, //!< Flash devices are Serial NOR + kFlexSpiDeviceType_SerialNAND = 2, //!< Flash devices are Serial NAND + kFlexSpiDeviceType_SerialRAM = 3, //!< Flash devices are Serial RAM/HyperFLASH + kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND + kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs +}; + +//!@brief Flash Pad Definitions +enum +{ + kSerialFlash_1Pad = 1, + kSerialFlash_2Pads = 2, + kSerialFlash_4Pads = 4, + kSerialFlash_8Pads = 8, +}; + +//!@brief FlexSPI LUT Sequence structure +typedef struct _lut_sequence +{ + uint8_t seqNum; //!< Sequence Number, valid number: 1-16 + uint8_t seqId; //!< Sequence Index, valid number: 0-15 + uint16_t reserved; +} flexspi_lut_seq_t; + +//!@brief Flash Configuration Command Type +enum +{ + kDeviceConfigCmdType_Generic, //!< Generic command, for example: configure dummy cycles, drive strength, etc + kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command + kDeviceConfigCmdType_Spi2Xpi, //!< Switch from SPI to DPI/QPI/OPI mode + kDeviceConfigCmdType_Xpi2Spi, //!< Switch from DPI/QPI/OPI to SPI mode + kDeviceConfigCmdType_Spi2NoCmd, //!< Switch to 0-4-4/0-8-8 mode + kDeviceConfigCmdType_Reset, //!< Reset device command +}; + +//!@brief FlexSPI Memory Configuration Block +typedef struct _FlexSPIConfig +{ + uint32_t tag; //!< [0x000-0x003] Tag, fixed value 0x42464346UL + uint32_t version; //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix + uint32_t reserved0; //!< [0x008-0x00b] Reserved for future use + uint8_t readSampleClkSrc; //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3 + uint8_t csHoldTime; //!< [0x00d-0x00d] CS hold time, default value: 3 + uint8_t csSetupTime; //!< [0x00e-0x00e] CS setup time, default value: 3 + uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For + //! Serial NAND, need to refer to datasheet + uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable + uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch, + //! Generic configuration, etc. + uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for + //! DPI/QPI/OPI switch or reset command + flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt + //! sequence number, [31:16] Reserved + uint32_t deviceModeArg; //!< [0x018-0x01b] Argument/Parameter for device configuration + uint8_t configCmdEnable; //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable + uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe + flexspi_lut_seq_t + configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq + uint32_t reserved1; //!< [0x02c-0x02f] Reserved for future use + uint32_t configCmdArgs[3]; //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands + uint32_t reserved2; //!< [0x03c-0x03f] Reserved for future use + uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more + //! details + uint8_t deviceType; //!< [0x044-0x044] Device Type: See Flash Type Definition for more details + uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal + uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot + //! Chapter for more details + uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot + //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH + uint32_t reserved3[2]; //!< [0x048-0x04f] Reserved for future use + uint32_t sflashA1Size; //!< [0x050-0x053] Size of Flash connected to A1 + uint32_t sflashA2Size; //!< [0x054-0x057] Size of Flash connected to A2 + uint32_t sflashB1Size; //!< [0x058-0x05b] Size of Flash connected to B1 + uint32_t sflashB2Size; //!< [0x05c-0x05f] Size of Flash connected to B2 + uint32_t csPadSettingOverride; //!< [0x060-0x063] CS pad setting override value + uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value + uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value + uint32_t dqsPadSettingOverride; //!< [0x06c-0x06f] DQS pad setting override value + uint32_t timeoutInMs; //!< [0x070-0x073] Timeout threshold for read status command + uint32_t commandInterval; //!< [0x074-0x077] CS deselect interval between two commands + uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns + uint16_t busyOffset; //!< [0x07c-0x07d] Busy offset, valid value: 0-31 + uint16_t busyBitPolarity; //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 - + //! busy flag is 0 when flash device is busy + uint32_t lookupTable[64]; //!< [0x080-0x17f] Lookup table holds Flash command sequences + flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences + uint32_t reserved4[4]; //!< [0x1b0-0x1bf] Reserved for future use +} flexspi_mem_config_t; + +/* */ +#define NOR_CMD_INDEX_READ CMD_INDEX_READ //!< 0 +#define NOR_CMD_INDEX_READSTATUS CMD_INDEX_READSTATUS //!< 1 +#define NOR_CMD_INDEX_WRITEENABLE CMD_INDEX_WRITEENABLE //!< 2 +#define NOR_CMD_INDEX_ERASESECTOR 3 //!< 3 +#define NOR_CMD_INDEX_PAGEPROGRAM CMD_INDEX_WRITE //!< 4 +#define NOR_CMD_INDEX_CHIPERASE 5 //!< 5 +#define NOR_CMD_INDEX_DUMMY 6 //!< 6 +#define NOR_CMD_INDEX_ERASEBLOCK 7 //!< 7 + +#define NOR_CMD_LUT_SEQ_IDX_READ CMD_LUT_SEQ_IDX_READ //!< 0 READ LUT sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_READSTATUS \ + CMD_LUT_SEQ_IDX_READSTATUS //!< 1 Read Status LUT sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI \ + 2 //!< 2 Read status DPI/QPI/OPI sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE \ + CMD_LUT_SEQ_IDX_WRITEENABLE //!< 3 Write Enable sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE_XPI \ + 4 //!< 4 Write Enable DPI/QPI/OPI sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5 //!< 5 Erase Sector sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_ERASEBLOCK 8 //!< 8 Erase Block sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM \ + CMD_LUT_SEQ_IDX_WRITE //!< 9 Program sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11 //!< 11 Chip Erase sequence in lookupTable id stored in config block +#define NOR_CMD_LUT_SEQ_IDX_READ_SFDP 13 //!< 13 Read SFDP sequence in lookupTable id stored in config block +#define NOR_CMD_LUT_SEQ_IDX_RESTORE_NOCMD \ + 14 //!< 14 Restore 0-4-4/0-8-8 mode sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_EXIT_NOCMD \ + 15 //!< 15 Exit 0-4-4/0-8-8 mode sequence id in lookupTable stored in config blobk + +/* + * Serial NOR configuration block + */ +typedef struct _flexspi_nor_config +{ + flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI + uint32_t pageSize; //!< Page size of Serial NOR + uint32_t sectorSize; //!< Sector size of Serial NOR + uint8_t ipcmdSerialClkFreq; //!< Clock frequency for IP command + uint8_t isUniformBlockSize; //!< Sector/Block size is the same + uint8_t reserved0[2]; //!< Reserved for future use + uint8_t serialNorType; //!< Serial NOR Flash type: 0/1/2/3 + uint8_t needExitNoCmdMode; //!< Need to exit NoCmd mode before other IP command + uint8_t halfClkForNonReadCmd; //!< Half the Serial Clock for non-read command: true/false + uint8_t needRestoreNoCmdMode; //!< Need to Restore NoCmd mode after IP commmand execution + uint32_t blockSize; //!< Block size + uint32_t reserve2[11]; //!< Reserved for future use +} flexspi_nor_config_t; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif +#endif /* __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__ */ diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/flash_config.c b/ports/mimxrt/boards/MIMXRT1050_EVK/flash_config.c new file mode 100644 index 0000000000..8203f4811a --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/flash_config.c @@ -0,0 +1,56 @@ +/* + * Copyright 2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "evkmimxrt1050_flexspi_nor_config.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.xip_board" +#endif + +/******************************************************************************* + * Code + ******************************************************************************/ +#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1) +#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__) +__attribute__((section(".boot_hdr.conf"))) +#elif defined(__ICCARM__) +#pragma location = ".boot_hdr.conf" +#endif + +const flexspi_nor_config_t qspiflash_config = { + .memConfig = + { + .tag = FLEXSPI_CFG_BLK_TAG, + .version = FLEXSPI_CFG_BLK_VERSION, + .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad, + .csHoldTime = 3u, + .csSetupTime = 3u, + .columnAddressWidth = 3u, + // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock + .controllerMiscOption = + (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) | + (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable), + .sflashPadType = kSerialFlash_8Pads, + .serialClkFreq = kFlexSpiSerialClk_133MHz, + .sflashA1Size = 64u * 1024u * 1024u, + .dataValidTime = {16u, 16u}, + .lookupTable = + { + // Read LUTs + FLEXSPI_LUT_SEQ(CMD_DDR, FLEXSPI_8PAD, 0xA0, RADDR_DDR, FLEXSPI_8PAD, 0x18), + FLEXSPI_LUT_SEQ(CADDR_DDR, FLEXSPI_8PAD, 0x10, DUMMY_DDR, FLEXSPI_8PAD, 0x06), + FLEXSPI_LUT_SEQ(READ_DDR, FLEXSPI_8PAD, 0x04, STOP, FLEXSPI_1PAD, 0x0), + }, + }, + .pageSize = 512u, + .sectorSize = 256u * 1024u, + .blockSize = 256u * 1024u, + .isUniformBlockSize = true, +}; + +#endif /* XIP_BOOT_HEADER_ENABLE */ diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h new file mode 100644 index 0000000000..5a733bbd97 --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h @@ -0,0 +1,9 @@ +#define MICROPY_HW_BOARD_NAME "i.MX RT1050 EVK" +#define MICROPY_HW_MCU_NAME "MIMXRT1052DVL6B" + +#define BOARD_FLASH_SIZE (64 * 1024 * 1024) + +// MIMXRT1050_EVK has 1 user LED +#define MICROPY_HW_LED1_PIN (GPIO_AD_B0_09) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk new file mode 100644 index 0000000000..61cca4d63f --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = MIMXRT1052 +MCU_VARIANT = MIMXRT1052DVL6B + +JLINK_PATH ?= /media/RT1050-EVK/ + +deploy: $(BUILD)/firmware.bin + cp $< $(JLINK_PATH) diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/pins.c b/ports/mimxrt/boards/MIMXRT1050_EVK/pins.c new file mode 100644 index 0000000000..d5da9c6f99 --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/pins.c @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 NXP + * + * 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 "pin.h" + +static pin_af_obj_t GPIO_AD_B0_09_af[] = { + PIN_AF(GPIO1_IO09, PIN_AF_MODE_ALT5, GPIO1, 0x10B0U), +}; + +pin_obj_t GPIO_AD_B0_09 = PIN(GPIO_AD_B0_09, GPIO1, 9, GPIO_AD_B0_09_af); diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/pins.h b/ports/mimxrt/boards/MIMXRT1050_EVK/pins.h new file mode 100644 index 0000000000..baef51c6c8 --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/pins.h @@ -0,0 +1,30 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 NXP + * + * 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. + */ + +// NOTE: pins.h shall only be included in in pin.h +// hence no include guards are needed since they will be provided by pin.h + +extern pin_obj_t GPIO_AD_B0_09; diff --git a/ports/mimxrt/boards/MIMXRT1052.ld b/ports/mimxrt/boards/MIMXRT1052.ld new file mode 100644 index 0000000000..836a119e5e --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1052.ld @@ -0,0 +1,7 @@ +__stack_size__ = 0x6000; +_estack = __StackTop; +_sstack = __StackLimit; + +/* Use second OCRAM bank for GC heap. */ +_gc_heap_start = ORIGIN(m_data2); +_gc_heap_end = ORIGIN(m_data2) + LENGTH(m_data2); From 8610bababed3703f52c57f7e7b575c9d50be38a4 Mon Sep 17 00:00:00 2001 From: StereoRocker Date: Wed, 3 Feb 2021 22:59:36 +0000 Subject: [PATCH 096/174] rp2: Enable VfsFat class for FAT filesystem support. Allows interfacing with SD cards, for example. --- ports/rp2/CMakeLists.txt | 1 + ports/rp2/fatfs_port.c | 34 ++++++++++++++++++++++++++++++++++ ports/rp2/mpconfigport.h | 6 ++++++ 3 files changed, 41 insertions(+) create mode 100644 ports/rp2/fatfs_port.c diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index bd58d8f707..cf20245a3c 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -51,6 +51,7 @@ set(SOURCE_DRIVERS ) set(SOURCE_PORT + fatfs_port.c machine_adc.c machine_i2c.c machine_pin.c diff --git a/ports/rp2/fatfs_port.c b/ports/rp2/fatfs_port.c new file mode 100644 index 0000000000..3821d6586c --- /dev/null +++ b/ports/rp2/fatfs_port.c @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 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 "lib/oofatfs/ff.h" +#include "hardware/rtc.h" + +MP_WEAK DWORD get_fattime(void) { + datetime_t t; + rtc_get_datetime(&t); + return ((2000 + t.year - 1980) << 25) | ((t.month) << 21) | ((t.day) << 16) | ((t.hour) << 11) | ((t.min) << 5) | (t.sec / 2); +} diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index b3214acfc2..69db4449d1 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -118,6 +118,12 @@ #define MICROPY_PY_FRAMEBUF (1) #define MICROPY_VFS (1) #define MICROPY_VFS_LFS2 (1) +#define MICROPY_VFS_FAT (1) + +// fatfs configuration +#define MICROPY_FATFS_ENABLE_LFN (1) +#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define MICROPY_FATFS_RPATH (2) // Use VfsLfs2's types for fileio/textio #define mp_type_fileio mp_type_vfs_lfs2_fileio From 8ade163fffe9cca620ebe945dec8d25c54dc877d Mon Sep 17 00:00:00 2001 From: robert-hh Date: Tue, 9 Feb 2021 15:50:21 +0100 Subject: [PATCH 097/174] rp2/machine_uart: Add timeout/timeout_char to read and write. --- ports/rp2/machine_uart.c | 59 +++++++++++++++++++++++++++++++++++----- ports/rp2/mpconfigport.h | 1 + 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/ports/rp2/machine_uart.c b/ports/rp2/machine_uart.c index 30446e688d..6693cf73bf 100644 --- a/ports/rp2/machine_uart.c +++ b/ports/rp2/machine_uart.c @@ -54,6 +54,8 @@ typedef struct _machine_uart_obj_t { uint8_t stop; uint8_t tx; uint8_t rx; + uint16_t timeout; // timeout waiting for first char (in ms) + uint16_t timeout_char; // timeout waiting between chars (in ms) } machine_uart_obj_t; STATIC machine_uart_obj_t machine_uart_obj[] = { @@ -68,13 +70,13 @@ STATIC const char *_parity_name[] = {"None", "0", "1"}; STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d)", + mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, timeout=%u, timeout_char=%u)", self->uart_id, self->baudrate, self->bits, _parity_name[self->parity], - self->stop, self->tx, self->rx); + self->stop, self->tx, self->rx, self->timeout, self->timeout_char); } STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_id, ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx }; + enum { ARG_id, ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_timeout, ARG_timeout_char }; static const mp_arg_t allowed_args[] = { { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} }, @@ -83,6 +85,8 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, { MP_QSTR_stop, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, }; // Parse args. @@ -140,11 +144,28 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, self->rx = rx; } + // Set timeout if configured. + if (args[ARG_timeout].u_int >= 0) { + self->timeout = args[ARG_timeout].u_int; + } + + // Set timeout_char if configured. + if (args[ARG_timeout_char].u_int >= 0) { + self->timeout_char = args[ARG_timeout_char].u_int; + } + // Initialise the UART peripheral if any arguments given, or it was not initialised previously. if (n_args > 1 || n_kw > 0 || self->baudrate == 0) { if (self->baudrate == 0) { self->baudrate = DEFAULT_UART_BAUDRATE; } + + // Make sure timeout_char is at least as long as a whole character (13 bits to be safe). + uint32_t min_timeout_char = 13000 / self->baudrate + 1; + if (self->timeout_char < min_timeout_char) { + self->timeout_char = min_timeout_char; + } + uart_init(self->uart, self->baudrate); uart_set_format(self->uart, self->bits, self->stop, self->parity); uart_set_fifo_enabled(self->uart, true); @@ -184,26 +205,50 @@ STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_t STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - // TODO support timeout + uint64_t t = time_us_64() + (uint64_t)self->timeout * 1000; + uint64_t timeout_char_us = (uint64_t)self->timeout_char * 1000; uint8_t *dest = buf_in; - for (size_t i = 0; i < size; ++i) { + + for (size_t i = 0; i < size; i++) { + // Wait for the first/next character while (!uart_is_readable(self->uart)) { + if (time_us_64() > t) { // timed out + if (i <= 0) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } else { + return i; + } + } MICROPY_EVENT_POLL_HOOK } *dest++ = uart_get_hw(self->uart)->dr; + t = time_us_64() + timeout_char_us; } return size; } STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - // TODO support timeout + uint64_t t = time_us_64() + (uint64_t)self->timeout * 1000; + uint64_t timeout_char_us = (uint64_t)self->timeout_char * 1000; const uint8_t *src = buf_in; - for (size_t i = 0; i < size; ++i) { + + for (size_t i = 0; i < size; i++) { + // wait for the first/next character while (!uart_is_writable(self->uart)) { + if (time_us_64() > t) { // timed out + if (i <= 0) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } else { + return i; + } + } MICROPY_EVENT_POLL_HOOK } uart_get_hw(self->uart)->dr = *src++; + t = time_us_64() + timeout_char_us; } return size; } diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index 69db4449d1..91d0c29b3a 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -62,6 +62,7 @@ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_STREAMS_NON_BLOCK (1) #define MICROPY_MODULE_BUILTIN_INIT (1) #define MICROPY_MODULE_WEAK_LINKS (1) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) From da85cb014afcf843bd0dfe99a1e232c271d3d5e8 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Wed, 10 Feb 2021 14:07:18 +0100 Subject: [PATCH 098/174] rp2/machine_uart: Add support for inverted TX and RX lines. Usage as in the other ports: keyword "invert" constants: INV_TX and INV_RX Sample: uart = UART(1, invert=UART.INV_TX | UART.INV_RX) --- ports/rp2/machine_uart.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/ports/rp2/machine_uart.c b/ports/rp2/machine_uart.c index 6693cf73bf..936b9a93e9 100644 --- a/ports/rp2/machine_uart.c +++ b/ports/rp2/machine_uart.c @@ -44,6 +44,10 @@ #define IS_VALID_TX(uart, pin) (((pin) & 3) == 0 && IS_VALID_PERIPH(uart, pin)) #define IS_VALID_RX(uart, pin) (((pin) & 3) == 1 && IS_VALID_PERIPH(uart, pin)) +#define UART_INVERT_TX (1) +#define UART_INVERT_RX (2) +#define UART_INVERT_MASK (UART_INVERT_TX | UART_INVERT_RX) + typedef struct _machine_uart_obj_t { mp_obj_base_t base; uart_inst_t *const uart; @@ -56,27 +60,29 @@ typedef struct _machine_uart_obj_t { uint8_t rx; uint16_t timeout; // timeout waiting for first char (in ms) uint16_t timeout_char; // timeout waiting between chars (in ms) + uint8_t invert; } machine_uart_obj_t; STATIC machine_uart_obj_t machine_uart_obj[] = { - {{&machine_uart_type}, uart0, 0, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP, DEFAULT_UART0_TX, DEFAULT_UART0_RX}, - {{&machine_uart_type}, uart1, 1, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP, DEFAULT_UART1_TX, DEFAULT_UART1_RX}, + {{&machine_uart_type}, uart0, 0, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP, DEFAULT_UART0_TX, DEFAULT_UART0_RX, 0, 0, 0}, + {{&machine_uart_type}, uart1, 1, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP, DEFAULT_UART1_TX, DEFAULT_UART1_RX, 0, 0, 0}, }; STATIC const char *_parity_name[] = {"None", "0", "1"}; +STATIC const char *_invert_name[] = {"None", "INV_TX", "INV_RX", "INV_TX|INV_RX"}; /******************************************************************************/ // MicroPython bindings for UART STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, timeout=%u, timeout_char=%u)", + mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, timeout=%u, timeout_char=%u, invert=%s)", self->uart_id, self->baudrate, self->bits, _parity_name[self->parity], - self->stop, self->tx, self->rx, self->timeout, self->timeout_char); + self->stop, self->tx, self->rx, self->timeout, self->timeout_char, _invert_name[self->invert]); } STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_id, ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_timeout, ARG_timeout_char }; + enum { ARG_id, ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_timeout, ARG_timeout_char, ARG_invert }; static const mp_arg_t allowed_args[] = { { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} }, @@ -87,6 +93,7 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, { MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_invert, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, }; // Parse args. @@ -154,6 +161,14 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, self->timeout_char = args[ARG_timeout_char].u_int; } + // Set line inversion if configured. + if (args[ARG_invert].u_int >= 0) { + if (args[ARG_invert].u_int & ~UART_INVERT_MASK) { + mp_raise_ValueError(MP_ERROR_TEXT("bad inversion mask")); + } + self->invert = args[ARG_invert].u_int; + } + // Initialise the UART peripheral if any arguments given, or it was not initialised previously. if (n_args > 1 || n_kw > 0 || self->baudrate == 0) { if (self->baudrate == 0) { @@ -171,6 +186,12 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, uart_set_fifo_enabled(self->uart, true); gpio_set_function(self->tx, GPIO_FUNC_UART); gpio_set_function(self->rx, GPIO_FUNC_UART); + if (self->invert & UART_INVERT_RX) { + gpio_set_inover(self->rx, GPIO_OVERRIDE_INVERT); + } + if (self->invert & UART_INVERT_TX) { + gpio_set_outover(self->tx, GPIO_OVERRIDE_INVERT); + } } return MP_OBJ_FROM_PTR(self); @@ -200,6 +221,10 @@ STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&machine_uart_sendbreak_obj) }, + + { MP_ROM_QSTR(MP_QSTR_INV_TX), MP_ROM_INT(UART_INVERT_TX) }, + { MP_ROM_QSTR(MP_QSTR_INV_RX), MP_ROM_INT(UART_INVERT_RX) }, + }; STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table); From a075e0b7d87a66a4b2ee9f75bcf70887157c7ae2 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Fri, 19 Feb 2021 17:11:04 +0100 Subject: [PATCH 099/174] rp2/rp2_pio: Allow more than 8 consecutive pins for PIO out/set/sideset. The bitmasks supplied for initialization of out/set/sideset were only 8 bit instead of 32. This resulted in an error, that not more than 8 consecutive pins would get initialized. Fixes issue #6933. --- ports/rp2/rp2_pio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c index 7d8921d0c3..6101164a15 100644 --- a/ports/rp2/rp2_pio.c +++ b/ports/rp2/rp2_pio.c @@ -139,8 +139,8 @@ enum { typedef struct _asm_pio_config_t { int8_t base; uint8_t count; - uint8_t pindirs; - uint8_t pinvals; + uint32_t pindirs; + uint32_t pinvals; } asm_pio_config_t; STATIC void asm_pio_override_shiftctrl(mp_obj_t arg, uint32_t bits, uint32_t lsb, pio_sm_config *config) { From 046164098337cc79dd0f6c710f49bdf6765aa711 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Wed, 3 Mar 2021 08:44:38 +0100 Subject: [PATCH 100/174] rp2/rp2_pio: Fix sm.get(buf) to not wait after getting last item. sm.get(buf) was waiting for one item more than the length of the supplied buffer. Even if this item was not stored, sm_get would block trying to get an item from the RX fifo. As part of the fix, the edge case for a zero length buffer was moved up to the section where the function arguments are handled. In case of a zero length buffer, sm.get() now returns immediately that buffer. --- ports/rp2/rp2_pio.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c index 6101164a15..9786e569d6 100644 --- a/ports/rp2/rp2_pio.c +++ b/ports/rp2/rp2_pio.c @@ -608,6 +608,9 @@ STATIC mp_obj_t rp2_state_machine_get(size_t n_args, const mp_obj_t *args) { } else { bufinfo.typecode |= 0x20; // make lowercase to support upper and lower } + if (bufinfo.len == 0) { // edge case: buffer of zero length supplied + return args[1]; + } } if (n_args > 2) { shift = mp_obj_get_int(args[2]); @@ -625,9 +628,6 @@ STATIC mp_obj_t rp2_state_machine_get(size_t n_args, const mp_obj_t *args) { if (dest == NULL) { return mp_obj_new_int_from_uint(value); } - if (dest >= dest_top) { - return args[1]; - } if (bufinfo.typecode == 'b') { *(uint8_t *)dest = value; dest += sizeof(uint8_t); @@ -640,6 +640,9 @@ STATIC mp_obj_t rp2_state_machine_get(size_t n_args, const mp_obj_t *args) { } else { mp_raise_ValueError("unsupported buffer type"); } + if (dest >= dest_top) { + return args[1]; + } } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2_state_machine_get_obj, 1, 3, rp2_state_machine_get); From 11cf742524202fa5fc062f3e6e3040a82f49b190 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Sat, 20 Feb 2021 11:11:24 +0100 Subject: [PATCH 101/174] rp2/modmachine: Allow changing CPU clock frequency. Using the standard machine.freq(). The safe ranges tested were 10 and 12-270MHz, at which USB REPL still worked. Requested settings can be checked with the script: pico-sdk/src/rp2_common/hardware_clocks/scripts/vcocalc.py. At frequencies like 300MHz the script still signaled OK, but USB did not work any more. --- ports/rp2/modmachine.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c index dbaafabe86..1393092818 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -36,6 +36,7 @@ #include "hardware/clocks.h" #include "hardware/watchdog.h" #include "pico/bootrom.h" +#include "pico/stdlib.h" #include "pico/unique_id.h" #define RP2_RESET_PWRON (1) @@ -80,10 +81,18 @@ STATIC mp_obj_t machine_bootloader(void) { } MP_DEFINE_CONST_FUN_OBJ_0(machine_bootloader_obj, machine_bootloader); -STATIC mp_obj_t machine_freq(void) { - return MP_OBJ_NEW_SMALL_INT(clock_get_hz(clk_sys)); +STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + return MP_OBJ_NEW_SMALL_INT(clock_get_hz(clk_sys)); + } else { + mp_int_t freq = mp_obj_get_int(args[0]); + if (!set_sys_clock_khz(freq / 1000, false)) { + mp_raise_ValueError(MP_ERROR_TEXT("cannot change frequency")); + } + return mp_const_none; + } } -MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 1, machine_freq); STATIC mp_obj_t machine_idle(void) { best_effort_wfe_or_timeout(make_timeout_time_ms(1)); From c675452566ffcae1a49121b84a0233ed164b2152 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Thu, 4 Mar 2021 20:57:16 +0100 Subject: [PATCH 102/174] rp2/modmachine: Re-init UART for REPL on frequency change. When UART is used for REPL and the MCU frequency is changed, the UART has to be re-initialised. Besides that the UART may have to be recreated after a frequency change, but with USB REPL this is not a problem. Thanks to @HermannSW for spotting and providing the change. --- ports/rp2/modmachine.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c index 1393092818..bf5033adba 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -33,6 +33,7 @@ #include "extmod/machine_spi.h" #include "modmachine.h" +#include "uart.h" #include "hardware/clocks.h" #include "hardware/watchdog.h" #include "pico/bootrom.h" @@ -89,6 +90,10 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { if (!set_sys_clock_khz(freq / 1000, false)) { mp_raise_ValueError(MP_ERROR_TEXT("cannot change frequency")); } + #if MICROPY_HW_ENABLE_UART_REPL + setup_default_uart(); + mp_uart_init(); + #endif return mp_const_none; } } From b6489425c631bf4d6551c352dc17836923c9157b Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Thu, 11 Mar 2021 10:31:03 +0000 Subject: [PATCH 103/174] rp2/rp2_flash: Prevent MICROPY_HW_FLASH_STORAGE_BASE being set negative. --- ports/rp2/rp2_flash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/rp2/rp2_flash.c b/ports/rp2/rp2_flash.c index cd1bc65489..b89cb6fd89 100644 --- a/ports/rp2/rp2_flash.c +++ b/ports/rp2/rp2_flash.c @@ -42,6 +42,7 @@ #define MICROPY_HW_FLASH_STORAGE_BASE (PICO_FLASH_SIZE_BYTES - MICROPY_HW_FLASH_STORAGE_BYTES) #endif +static_assert(MICROPY_HW_FLASH_STORAGE_BYTES <= PICO_FLASH_SIZE_BYTES, "MICROPY_HW_FLASH_STORAGE_BYTES too big"); static_assert(MICROPY_HW_FLASH_STORAGE_BASE + MICROPY_HW_FLASH_STORAGE_BYTES <= PICO_FLASH_SIZE_BYTES, "MICROPY_HW_FLASH_STORAGE_BYTES too big"); typedef struct _rp2_flash_obj_t { From a62e791978a66948637538d1a0a363fe35fa88e4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 11 Mar 2021 18:34:33 +1100 Subject: [PATCH 104/174] lib/pico-sdk: Update to latest version 1.1.0. Signed-off-by: Damien George --- lib/pico-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pico-sdk b/lib/pico-sdk index 2d5789eca8..fc10a97c38 160000 --- a/lib/pico-sdk +++ b/lib/pico-sdk @@ -1 +1 @@ -Subproject commit 2d5789eca89658a7f0a01e2d6010c0f254605d72 +Subproject commit fc10a97c386f65c1a44c68684fe52a56aaf50df0 From b24fcd7aec4b34064e9d9016d417d4ca3cc925cc Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 11 Mar 2021 13:32:00 +1100 Subject: [PATCH 105/174] esp32/machine_hw_spi: Use default pins when making SPI if none given. The default pins can be optionally configured by a board. Fixes issue #6974. Signed-off-by: Damien George --- docs/esp32/quickref.rst | 1 + ports/esp32/machine_hw_spi.c | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index 79e61a10b6..30c9b3b95a 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -302,6 +302,7 @@ has the same methods as software SPI above:: from machine import Pin, SPI + hspi = SPI(1, 10000000) hspi = SPI(1, 10000000, sck=Pin(14), mosi=Pin(13), miso=Pin(12)) vspi = SPI(2, baudrate=80000000, polarity=0, phase=0, bits=8, firstbit=0, sck=Pin(18), mosi=Pin(23), miso=Pin(19)) diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c index 3790b4e0cf..d59f2c750e 100644 --- a/ports/esp32/machine_hw_spi.c +++ b/ports/esp32/machine_hw_spi.c @@ -36,9 +36,29 @@ #include "driver/spi_master.h" +// Default pins for SPI(1), can be overridden by a board +#ifndef MICROPY_HW_SPI1_SCK +#define MICROPY_HW_SPI1_SCK (14) +#define MICROPY_HW_SPI1_MOSI (13) +#define MICROPY_HW_SPI1_MISO (12) +#endif + +// Default pins for SPI(2), can be overridden by a board +#ifndef MICROPY_HW_SPI2_SCK +#define MICROPY_HW_SPI2_SCK (18) +#define MICROPY_HW_SPI2_MOSI (23) +#define MICROPY_HW_SPI2_MISO (19) +#endif + #define MP_HW_SPI_MAX_XFER_BYTES (4092) #define MP_HW_SPI_MAX_XFER_BITS (MP_HW_SPI_MAX_XFER_BYTES * 8) // Has to be an even multiple of 8 +typedef struct _machine_hw_spi_default_pins_t { + int8_t sck; + int8_t mosi; + int8_t miso; +} machine_hw_spi_default_pins_t; + typedef struct _machine_hw_spi_obj_t { mp_obj_base_t base; spi_host_device_t host; @@ -58,6 +78,12 @@ typedef struct _machine_hw_spi_obj_t { } state; } machine_hw_spi_obj_t; +// Default pin mappings for the hardware SPI instances +STATIC const machine_hw_spi_default_pins_t machine_hw_spi_default_pins[2] = { + { .sck = MICROPY_HW_SPI1_SCK, .mosi = MICROPY_HW_SPI1_MOSI, .miso = MICROPY_HW_SPI1_MISO }, + { .sck = MICROPY_HW_SPI2_SCK, .mosi = MICROPY_HW_SPI2_MOSI, .miso = MICROPY_HW_SPI2_MISO }, +}; + // Static objects mapping to HSPI and VSPI hardware peripherals STATIC machine_hw_spi_obj_t machine_hw_spi_obj[2]; @@ -369,10 +395,13 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); machine_hw_spi_obj_t *self; + const machine_hw_spi_default_pins_t *default_pins; if (args[ARG_id].u_int == HSPI_HOST) { self = &machine_hw_spi_obj[0]; + default_pins = &machine_hw_spi_default_pins[0]; } else { self = &machine_hw_spi_obj[1]; + default_pins = &machine_hw_spi_default_pins[1]; } self->base.type = &machine_hw_spi_type; @@ -384,9 +413,9 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_ args[ARG_phase].u_int, args[ARG_bits].u_int, args[ARG_firstbit].u_int, - args[ARG_sck].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_sck].u_obj), - args[ARG_mosi].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_mosi].u_obj), - args[ARG_miso].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_miso].u_obj)); + args[ARG_sck].u_obj == MP_OBJ_NULL ? default_pins->sck : machine_pin_get_id(args[ARG_sck].u_obj), + args[ARG_mosi].u_obj == MP_OBJ_NULL ? default_pins->mosi : machine_pin_get_id(args[ARG_mosi].u_obj), + args[ARG_miso].u_obj == MP_OBJ_NULL ? default_pins->miso : machine_pin_get_id(args[ARG_miso].u_obj)); return MP_OBJ_FROM_PTR(self); } From 6129b8e401c36cc68e0f7ba8180da27a40d17621 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 11 Mar 2021 16:09:27 +1100 Subject: [PATCH 106/174] tests: Rename run-tests to run-tests.py for consistency. Signed-off-by: Damien George --- .github/workflows/ports_unix.yml | 22 +++++++++++----------- docs/develop/gettingstarted.rst | 2 +- docs/develop/writingtests.rst | 12 ++++++------ ports/cc3200/tools/smoke.py | 2 +- ports/javascript/Makefile | 4 ++-- ports/qemu-arm/Makefile.test | 2 +- ports/unix/Makefile | 16 ++++++++-------- ports/windows/.appveyor.yml | 14 +++++++------- ports/windows/README.md | 4 ++-- ports/zephyr/make-bin-testsuite | 4 ++-- tests/README | 6 +++--- tests/esp32/partition_ota.py | 2 +- tests/feature_check/README | 2 +- tests/jni/README | 2 +- tests/net_hosted/README | 2 +- tests/net_inet/README | 2 +- tests/run-internalbench.py | 2 +- tests/run-tests-exp.py | 4 ++-- tests/run-tests-exp.sh | 4 ++-- tests/{run-tests => run-tests.py} | 12 ++++++------ tools/ci.sh | 4 ++-- 21 files changed, 62 insertions(+), 62 deletions(-) rename tests/{run-tests => run-tests.py} (98%) diff --git a/.github/workflows/ports_unix.yml b/.github/workflows/ports_unix.yml index eb1416045c..aa4b8abdc9 100644 --- a/.github/workflows/ports_unix.yml +++ b/.github/workflows/ports_unix.yml @@ -24,7 +24,7 @@ jobs: run: source tools/ci.sh && ci_unix_minimal_run_tests - name: Print failures if: failure() - run: tests/run-tests --print-failures + run: tests/run-tests.py --print-failures reproducible: runs-on: ubuntu-latest @@ -49,7 +49,7 @@ jobs: run: source tools/ci.sh && ci_unix_standard_run_perfbench - name: Print failures if: failure() - run: tests/run-tests --print-failures + run: tests/run-tests.py --print-failures coverage: runs-on: ubuntu-latest @@ -76,7 +76,7 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} - name: Print failures if: failure() - run: tests/run-tests --print-failures + run: tests/run-tests.py --print-failures coverage_32bit: runs-on: ubuntu-latest @@ -94,7 +94,7 @@ jobs: run: source tools/ci.sh && ci_unix_coverage_32bit_run_native_mpy_tests - name: Print failures if: failure() - run: tests/run-tests --print-failures + run: tests/run-tests.py --print-failures nanbox: runs-on: ubuntu-latest @@ -108,7 +108,7 @@ jobs: run: source tools/ci.sh && ci_unix_nanbox_run_tests - name: Print failures if: failure() - run: tests/run-tests --print-failures + run: tests/run-tests.py --print-failures float: runs-on: ubuntu-latest @@ -120,7 +120,7 @@ jobs: run: source tools/ci.sh && ci_unix_float_run_tests - name: Print failures if: failure() - run: tests/run-tests --print-failures + run: tests/run-tests.py --print-failures stackless_clang: runs-on: ubuntu-20.04 @@ -134,7 +134,7 @@ jobs: run: source tools/ci.sh && ci_unix_stackless_clang_run_tests - name: Print failures if: failure() - run: tests/run-tests --print-failures + run: tests/run-tests.py --print-failures float_clang: runs-on: ubuntu-20.04 @@ -148,7 +148,7 @@ jobs: run: source tools/ci.sh && ci_unix_float_clang_run_tests - name: Print failures if: failure() - run: tests/run-tests --print-failures + run: tests/run-tests.py --print-failures settrace: runs-on: ubuntu-latest @@ -160,7 +160,7 @@ jobs: run: source tools/ci.sh && ci_unix_settrace_run_tests - name: Print failures if: failure() - run: tests/run-tests --print-failures + run: tests/run-tests.py --print-failures settrace_stackless: runs-on: ubuntu-latest @@ -172,7 +172,7 @@ jobs: run: source tools/ci.sh && ci_unix_settrace_stackless_run_tests - name: Print failures if: failure() - run: tests/run-tests --print-failures + run: tests/run-tests.py --print-failures macos: runs-on: macos-11.0 @@ -185,4 +185,4 @@ jobs: run: source tools/ci.sh && ci_unix_macos_run_tests - name: Print failures if: failure() - run: tests/run-tests --print-failures + run: tests/run-tests.py --print-failures diff --git a/docs/develop/gettingstarted.rst b/docs/develop/gettingstarted.rst index 3dd00a579a..32435ebe1c 100644 --- a/docs/develop/gettingstarted.rst +++ b/docs/develop/gettingstarted.rst @@ -273,7 +273,7 @@ To run a selection of tests on a board/device connected over USB use: .. code-block:: bash $ cd tests - $ ./run-tests --target minimal --device /dev/ttyACM0 + $ ./run-tests.py --target minimal --device /dev/ttyACM0 See also :ref:`writingtests`. diff --git a/docs/develop/writingtests.rst b/docs/develop/writingtests.rst index 4bdf4dd7a6..9bb5178f55 100644 --- a/docs/develop/writingtests.rst +++ b/docs/develop/writingtests.rst @@ -4,7 +4,7 @@ Writing tests ============= Tests in MicroPython are located at the path ``tests/``. The following is a listing of -key directories and the run-tests runner script: +key directories and the run-tests.py runner script: .. code-block:: bash @@ -13,7 +13,7 @@ key directories and the run-tests runner script: ├── extmod ├── float ├── micropython - ├── run-tests + ├── run-tests.py ... There are subfolders maintained to categorize the tests. Add a test by creating a new file in one of the @@ -54,17 +54,17 @@ The other way to run tests, which is useful when running on targets other than t .. code-block:: bash $ cd tests - $ ./run-tests + $ ./run-tests.py Then to run on a board: .. code-block:: bash - $ ./run-tests --target minimal --device /dev/ttyACM0 + $ ./run-tests.py --target minimal --device /dev/ttyACM0 And to run only a certain set of tests (eg a directory): .. code-block:: bash - $ ./run-tests -d basics - $ ./run-tests float/builtin*.py + $ ./run-tests.py -d basics + $ ./run-tests.py float/builtin*.py diff --git a/ports/cc3200/tools/smoke.py b/ports/cc3200/tools/smoke.py index 4ccc700c6c..463a485c4d 100644 --- a/ports/cc3200/tools/smoke.py +++ b/ports/cc3200/tools/smoke.py @@ -6,7 +6,7 @@ import os """ Execute it like this: -python3 run-tests --target wipy --device 192.168.1.1 ../cc3200/tools/smoke.py +python3 run-tests.py --target wipy --device 192.168.1.1 ../cc3200/tools/smoke.py """ pin_map = [23, 24, 11, 12, 13, 14, 15, 16, 17, 22, 28, 10, 9, 8, 7, 6, 30, 31, 3, 0, 4, 5] diff --git a/ports/javascript/Makefile b/ports/javascript/Makefile index 4f9dd444be..3962e93f5f 100644 --- a/ports/javascript/Makefile +++ b/ports/javascript/Makefile @@ -63,8 +63,8 @@ $(BUILD)/micropython.js: $(OBJ) library.js wrapper.js min: $(BUILD)/micropython.js uglifyjs $< -c -o $(BUILD)/micropython.min.js -test: $(BUILD)/micropython.js $(TOP)/tests/run-tests +test: $(BUILD)/micropython.js $(TOP)/tests/run-tests.py $(eval DIRNAME=ports/$(notdir $(CURDIR))) - cd $(TOP)/tests && MICROPY_MICROPYTHON=../ports/javascript/node_run.sh ./run-tests + cd $(TOP)/tests && MICROPY_MICROPYTHON=../ports/javascript/node_run.sh ./run-tests.py include $(TOP)/py/mkrules.mk diff --git a/ports/qemu-arm/Makefile.test b/ports/qemu-arm/Makefile.test index 340e1c3b90..6b7f1dc7ab 100644 --- a/ports/qemu-arm/Makefile.test +++ b/ports/qemu-arm/Makefile.test @@ -10,7 +10,7 @@ CFLAGS += -DTEST $(BUILD)/test_main.o: $(BUILD)/genhdr/tests.h $(BUILD)/genhdr/tests.h: - (cd $(TOP)/tests; ./run-tests --target=qemu-arm --write-exp) + (cd $(TOP)/tests; ./run-tests.py --target=qemu-arm --write-exp) $(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py) > $@ $(BUILD)/lib/tinytest/tinytest.o: CFLAGS += -DNO_FORKING diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 6a936a2425..fe86018aa0 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -292,17 +292,17 @@ include $(TOP)/py/mkrules.mk .PHONY: test test_full -test: $(PROG) $(TOP)/tests/run-tests +test: $(PROG) $(TOP)/tests/run-tests.py $(eval DIRNAME=ports/$(notdir $(CURDIR))) - cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests.py -test_full: $(PROG) $(TOP)/tests/run-tests +test_full: $(PROG) $(TOP)/tests/run-tests.py $(eval DIRNAME=ports/$(notdir $(CURDIR))) - cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests - cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests -d thread - cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests --emit native - cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests --via-mpy $(RUN_TESTS_MPY_CROSS_FLAGS) -d basics float micropython - cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests --via-mpy $(RUN_TESTS_MPY_CROSS_FLAGS) --emit native -d basics float micropython + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests.py + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests.py -d thread + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests.py --emit native + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests.py --via-mpy $(RUN_TESTS_MPY_CROSS_FLAGS) -d basics float micropython + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests.py --via-mpy $(RUN_TESTS_MPY_CROSS_FLAGS) --emit native -d basics float micropython cat $(TOP)/tests/basics/0prelim.py | ./$(PROG) | grep -q 'abc' test_gcov: test_full diff --git a/ports/windows/.appveyor.yml b/ports/windows/.appveyor.yml index 4d2d6bd11d..1ec72bbb38 100644 --- a/ports/windows/.appveyor.yml +++ b/ports/windows/.appveyor.yml @@ -37,14 +37,14 @@ build: test_script: - ps: | cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'tests') - & $env:MICROPY_CPYTHON3 run-tests + & $env:MICROPY_CPYTHON3 run-tests.py if ($LASTEXITCODE -ne 0) { - & $env:MICROPY_CPYTHON3 run-tests --print-failures + & $env:MICROPY_CPYTHON3 run-tests.py --print-failures throw "Test failure" } - & $env:MICROPY_CPYTHON3 run-tests --via-mpy -d basics float micropython + & $env:MICROPY_CPYTHON3 run-tests.py --via-mpy -d basics float micropython if ($LASTEXITCODE -ne 0) { - & $env:MICROPY_CPYTHON3 run-tests --print-failures + & $env:MICROPY_CPYTHON3 run-tests.py --print-failures throw "Test failure" } @@ -71,17 +71,17 @@ after_test: throw "$env:MSYSTEM mpy_cross build exited with code $LASTEXITCODE" } cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'tests') - $testArgs = @('run-tests') + $testArgs = @('run-tests.py') foreach ($skipTest in @('math_fun', 'float2int_double', 'float_parse', 'math_domain_special')) { $testArgs = $testArgs + '-e' + $skipTest } & $env:MICROPY_CPYTHON3 $testArgs if ($LASTEXITCODE -ne 0) { - & $env:MICROPY_CPYTHON3 run-tests --print-failures + & $env:MICROPY_CPYTHON3 run-tests.py --print-failures throw "Test failure" } & $env:MICROPY_CPYTHON3 ($testArgs + @('--via-mpy', '-d', 'basics', 'float', 'micropython')) if ($LASTEXITCODE -ne 0) { - & $env:MICROPY_CPYTHON3 run-tests --print-failures + & $env:MICROPY_CPYTHON3 run-tests.py --print-failures throw "Test failure" } diff --git a/ports/windows/README.md b/ports/windows/README.md index 1b904f8f5e..553e87513e 100644 --- a/ports/windows/README.md +++ b/ports/windows/README.md @@ -90,11 +90,11 @@ Running the tests This is similar for all ports: cd ../../tests - python ./run-tests + python ./run-tests.py Though when running on Cygwin and using Cygwin's Python installation you'll need: - python3 ./run-tests + python3 ./run-tests.py Depending on the combination of platform and Python version used it might be needed to first set the MICROPY_MICROPYTHON environment variable to diff --git a/ports/zephyr/make-bin-testsuite b/ports/zephyr/make-bin-testsuite index f6aeb83f8a..9a8c329772 100755 --- a/ports/zephyr/make-bin-testsuite +++ b/ports/zephyr/make-bin-testsuite @@ -8,8 +8,8 @@ # ./make-bin-testsuite BOARD=qemu_cortex_m3 run # -(cd ../../tests; ./run-tests --write-exp) -(cd ../../tests; ./run-tests --list-tests --target=minimal \ +(cd ../../tests; ./run-tests.py --write-exp) +(cd ../../tests; ./run-tests.py --list-tests --target=minimal \ -e async -e intbig -e int_big -e builtin_help -e memstats -e bytes_compare3 -e class_reverse_op \ -e /set -e frozenset -e complex -e const -e native -e viper \ -e 'float_divmod\.' -e float_parse_doubleprec -e float/true_value -e float/types \ diff --git a/tests/README b/tests/README index f2cd89bb93..8794202e15 100644 --- a/tests/README +++ b/tests/README @@ -1,15 +1,15 @@ This directory contains tests for various functionality areas of MicroPython. -To run all stable tests, run "run-tests" script in this directory. +To run all stable tests, run "run-tests.py" script in this directory. Tests of capabilities not supported on all platforms should be written to check for the capability being present. If it is not, the test should merely output 'SKIP' followed by the line terminator, and call sys.exit() to raise SystemExit, instead of attempting to test the -missing capability. The testing framework (run-tests in this +missing capability. The testing framework (run-tests.py in this directory, test_main.c in qemu_arm) recognizes this as a skipped test. There are a few features for which this mechanism cannot be used to -condition a test. The run-tests script uses small scripts in the +condition a test. The run-tests.py script uses small scripts in the feature_check directory to check whether each such feature is present, and skips the relevant tests if not. diff --git a/tests/esp32/partition_ota.py b/tests/esp32/partition_ota.py index 765630c8ce..212fcf0338 100644 --- a/tests/esp32/partition_ota.py +++ b/tests/esp32/partition_ota.py @@ -95,7 +95,7 @@ def copy_partition(src, dest): if sz - addr < 4096: blk = blk[: sz - addr] if addr & 0xFFFF == 0: - # need to show progress to run-tests else it times out + # need to show progress to run-tests.py else it times out print(" ... 0x{:06x}".format(addr)) src.readblocks(addr >> 12, blk) dest.writeblocks(addr >> 12, blk) diff --git a/tests/feature_check/README b/tests/feature_check/README index d062020f7b..3b7b6cba41 100644 --- a/tests/feature_check/README +++ b/tests/feature_check/README @@ -1,4 +1,4 @@ This directory doesn't contain real tests, but code snippets to detect various interpreter features, which can't be/inconvenient to detecte by -other means. Scripts here are executed by run-tests at the beginning of +other means. Scripts here are executed by run-tests.py at the beginning of testsuite to decide what other test groups to run/exclude. diff --git a/tests/jni/README b/tests/jni/README index 8418bb84f4..f1e1b0eca0 100644 --- a/tests/jni/README +++ b/tests/jni/README @@ -8,5 +8,5 @@ of JVM. For example, for OpenJDK 7 on x86_64, following may work: -LD_LIBRARY_PATH=/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server ./run-tests jni/*.py +LD_LIBRARY_PATH=/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server ./run-tests.py jni/*.py diff --git a/tests/net_hosted/README b/tests/net_hosted/README index 724dd61584..709ed50ce3 100644 --- a/tests/net_hosted/README +++ b/tests/net_hosted/README @@ -8,4 +8,4 @@ not yet fully correspond to the functional specification above. So far, these tests are not run as part of the main testsuite and need to be run seperately (from the main test/ directory): - ./run-tests net_hosted/*.py + ./run-tests.py net_hosted/*.py diff --git a/tests/net_inet/README b/tests/net_inet/README index 9a5614efa6..1d6e15b174 100644 --- a/tests/net_inet/README +++ b/tests/net_inet/README @@ -2,4 +2,4 @@ This directory contains network tests which require Internet connection. Note that these tests are not run as part of the main testsuite and need to be run seperately (from the main test/ directory): - ./run-tests net_inet/*.py + ./run-tests.py net_inet/*.py diff --git a/tests/run-internalbench.py b/tests/run-internalbench.py index 63392814a8..606fc3b772 100755 --- a/tests/run-internalbench.py +++ b/tests/run-internalbench.py @@ -67,7 +67,7 @@ def main(): cmd_parser.add_argument("files", nargs="*", help="input test files") args = cmd_parser.parse_args() - # Note pyboard support is copied over from run-tests, not testes, and likely needs revamping + # Note pyboard support is copied over from run-tests.py, not tests, and likely needs revamping if args.pyboard: import pyboard diff --git a/tests/run-tests-exp.py b/tests/run-tests-exp.py index ac32fe9869..21b6645336 100644 --- a/tests/run-tests-exp.py +++ b/tests/run-tests-exp.py @@ -1,6 +1,6 @@ # -# This is minimal MicroPython variant of run-tests script, which uses -# .exp files as generated by run-tests --write-exp. It is useful to run +# This is minimal MicroPython variant of run-tests.py script, which uses +# .exp files as generated by run-tests.py --write-exp. It is useful to run # testsuite on systems which have neither CPython3 nor unix shell. # This script is intended to be run by the same interpreter executable # which is to be tested, so should use minimal language functionality. diff --git a/tests/run-tests-exp.sh b/tests/run-tests-exp.sh index 8f81b96d2f..177090cd8d 100755 --- a/tests/run-tests-exp.sh +++ b/tests/run-tests-exp.sh @@ -1,7 +1,7 @@ #!/bin/sh # -# This is plain shell variant of run-tests script, which uses .exp files -# as generated by run-tests --write-exp. It is useful to run testsuite +# This is plain shell variant of run-tests.py script, which uses .exp files +# as generated by run-tests.py --write-exp. It is useful to run testsuite # on embedded systems which don't have CPython3. # diff --git a/tests/run-tests b/tests/run-tests.py similarity index 98% rename from tests/run-tests rename to tests/run-tests.py index b733d8a9fc..5863b23b41 100755 --- a/tests/run-tests +++ b/tests/run-tests.py @@ -258,7 +258,7 @@ def run_tests(pyb, tests, args, result_dir): if not (args.list_tests or args.write_exp): # Even if we run completely different tests in a different directory, # we need to access feature_checks from the same directory as the - # run-tests script itself so use base_path. + # run-tests.py script itself so use base_path. # Check if micropython.native is supported, and skip such tests if it's not output = run_feature_check(pyb, args, base_path, 'native_check.py') @@ -582,19 +582,19 @@ Tests are discovered by scanning test directories for .py files or using the specified test files. If test files nor directories are specified, the script expects to be ran in the tests directory (where this file is located) and the builtin tests suitable for the target platform are ran. -When running tests, run-tests compares the MicroPython output of the test with the output +When running tests, run-tests.py compares the MicroPython output of the test with the output produced by running the test through CPython unless a .exp file is found, in which case it is used as comparison. -If a test fails, run-tests produces a pair of .out and .exp files in the result +If a test fails, run-tests.py produces a pair of .out and .exp files in the result directory with the MicroPython output and the expectations, respectively. ''', epilog='''\ Options -i and -e can be multiple and processed in the order given. Regex "search" (vs "match") operation is used. An action (include/exclude) of the last matching regex is used: - run-tests -i async - exclude all, then include tests containing "async" anywhere - run-tests -e '/big.+int' - include all, then exclude by regex - run-tests -e async -i async_foo - include all, exclude async, yet still include async_foo + run-tests.py -i async - exclude all, then include tests containing "async" anywhere + run-tests.py -e '/big.+int' - include all, then exclude by regex + run-tests.py -e async -i async_foo - include all, exclude async, yet still include async_foo ''') cmd_parser.add_argument('--target', default='unix', help='the target platform') cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device or the IP address of the pyboard') diff --git a/tools/ci.sh b/tools/ci.sh index a815e9483e..53cf7f878b 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -306,7 +306,7 @@ function ci_unix_minimal_build { } function ci_unix_minimal_run_tests { - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-minimal ./run-tests -e exception_chain -e self_type_check -e subclass_native_init -d basics) + (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-minimal ./run-tests.py -e exception_chain -e self_type_check -e subclass_native_init -d basics) } function ci_unix_standard_build { @@ -441,7 +441,7 @@ function ci_unix_macos_run_tests { # - OSX has poor time resolution and these uasyncio tests do not have correct output # - import_pkg7 has a problem with relative imports # - urandom_basic has a problem with getrandbits(0) - (cd tests && ./run-tests --exclude 'uasyncio_(basic|heaplock|lock|wait_task)' --exclude 'import_pkg7.py' --exclude 'urandom_basic.py') + (cd tests && ./run-tests.py --exclude 'uasyncio_(basic|heaplock|lock|wait_task)' --exclude 'import_pkg7.py' --exclude 'urandom_basic.py') } ######################################################################################## From 2a38d7103672580882fb621a5b76e8d26805d593 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 11 Mar 2021 16:11:27 +1100 Subject: [PATCH 107/174] tests/run-tests.py: Reformat with Black. Signed-off-by: Damien George --- tests/run-tests.py | 580 +++++++++++++++++++++++++++------------------ 1 file changed, 351 insertions(+), 229 deletions(-) diff --git a/tests/run-tests.py b/tests/run-tests.py index 5863b23b41..3ab6194b62 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -13,31 +13,34 @@ from glob import glob # are guaranteed to always work, this one should though. BASEPATH = os.path.dirname(os.path.abspath(inspect.getsourcefile(lambda: None))) + def base_path(*p): - return os.path.abspath(os.path.join(BASEPATH, *p)).replace('\\', '/') + return os.path.abspath(os.path.join(BASEPATH, *p)).replace("\\", "/") + # Tests require at least CPython 3.3. If your default python3 executable # is of lower version, you can point MICROPY_CPYTHON3 environment var # to the correct executable. -if os.name == 'nt': - CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python') - MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', base_path('../ports/windows/micropython.exe')) +if os.name == "nt": + CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python") + MICROPYTHON = os.getenv("MICROPY_MICROPYTHON", base_path("../ports/windows/micropython.exe")) else: - CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3') - MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', base_path('../ports/unix/micropython')) + CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python3") + MICROPYTHON = os.getenv("MICROPY_MICROPYTHON", base_path("../ports/unix/micropython")) # Use CPython options to not save .pyc files, to only access the core standard library # (not site packages which may clash with u-module names), and improve start up time. CPYTHON3_CMD = [CPYTHON3, "-BS"] # mpy-cross is only needed if --via-mpy command-line arg is passed -MPYCROSS = os.getenv('MICROPY_MPYCROSS', base_path('../mpy-cross/mpy-cross')) +MPYCROSS = os.getenv("MICROPY_MPYCROSS", base_path("../mpy-cross/mpy-cross")) # For diff'ing test output -DIFF = os.getenv('MICROPY_DIFF', 'diff -u') +DIFF = os.getenv("MICROPY_DIFF", "diff -u") # Set PYTHONIOENCODING so that CPython will use utf-8 on systems which set another encoding in the locale -os.environ['PYTHONIOENCODING'] = 'utf-8' +os.environ["PYTHONIOENCODING"] = "utf-8" + def rm_f(fname): if os.path.exists(fname): @@ -48,57 +51,62 @@ def rm_f(fname): def convert_regex_escapes(line): cs = [] escape = False - for c in str(line, 'utf8'): + for c in str(line, "utf8"): if escape: escape = False cs.append(c) - elif c == '\\': + elif c == "\\": escape = True - elif c in ('(', ')', '[', ']', '{', '}', '.', '*', '+', '^', '$'): - cs.append('\\' + c) + elif c in ("(", ")", "[", "]", "{", "}", ".", "*", "+", "^", "$"): + cs.append("\\" + c) else: cs.append(c) # accept carriage-return(s) before final newline - if cs[-1] == '\n': - cs[-1] = '\r*\n' - return bytes(''.join(cs), 'utf8') + if cs[-1] == "\n": + cs[-1] = "\r*\n" + return bytes("".join(cs), "utf8") def run_micropython(pyb, args, test_file, is_special=False): special_tests = ( - 'micropython/meminfo.py', 'basics/bytes_compare3.py', - 'basics/builtin_help.py', 'thread/thread_exc2.py', - 'esp32/partition_ota.py', + "micropython/meminfo.py", + "basics/bytes_compare3.py", + "basics/builtin_help.py", + "thread/thread_exc2.py", + "esp32/partition_ota.py", ) had_crash = False if pyb is None: # run on PC - if test_file.startswith(('cmdline/', base_path('feature_check/'))) or test_file in special_tests: + if ( + test_file.startswith(("cmdline/", base_path("feature_check/"))) + or test_file in special_tests + ): # special handling for tests of the unix cmdline program is_special = True if is_special: # check for any cmdline options needed for this test args = [MICROPYTHON] - with open(test_file, 'rb') as f: + with open(test_file, "rb") as f: line = f.readline() - if line.startswith(b'# cmdline:'): + if line.startswith(b"# cmdline:"): # subprocess.check_output on Windows only accepts strings, not bytes - args += [str(c, 'utf-8') for c in line[10:].strip().split()] + args += [str(c, "utf-8") for c in line[10:].strip().split()] # run the test, possibly with redirected input try: - if 'repl_' in test_file: + if "repl_" in test_file: # Need to use a PTY to test command line editing try: import pty except ImportError: # in case pty module is not available, like on Windows - return b'SKIP\n' + return b"SKIP\n" import select def get(required=False): - rv = b'' + rv = b"" while True: ready = select.select([master], [], [], 0.02) if ready[0] == [master]: @@ -111,14 +119,15 @@ def run_micropython(pyb, args, test_file, is_special=False): os.write(master, what) return get() - with open(test_file, 'rb') as f: + with open(test_file, "rb") as f: # instead of: output_mupy = subprocess.check_output(args, stdin=f) master, slave = pty.openpty() - p = subprocess.Popen(args, stdin=slave, stdout=slave, - stderr=subprocess.STDOUT, bufsize=0) + p = subprocess.Popen( + args, stdin=slave, stdout=slave, stderr=subprocess.STDOUT, bufsize=0 + ) banner = get(True) - output_mupy = banner + b''.join(send_get(line) for line in f) - send_get(b'\x04') # exit the REPL, so coverage info is saved + output_mupy = banner + b"".join(send_get(line) for line in f) + send_get(b"\x04") # exit the REPL, so coverage info is saved # At this point the process might have exited already, but trying to # kill it 'again' normally doesn't result in exceptions as Python and/or # the OS seem to try to handle this nicely. When running Linux on WSL @@ -132,22 +141,28 @@ def run_micropython(pyb, args, test_file, is_special=False): os.close(master) os.close(slave) else: - output_mupy = subprocess.check_output(args + [test_file], stderr=subprocess.STDOUT) + output_mupy = subprocess.check_output( + args + [test_file], stderr=subprocess.STDOUT + ) except subprocess.CalledProcessError: - return b'CRASH' + return b"CRASH" else: # a standard test run on PC # create system command - cmdlist = [MICROPYTHON, '-X', 'emit=' + args.emit] + cmdlist = [MICROPYTHON, "-X", "emit=" + args.emit] if args.heapsize is not None: - cmdlist.extend(['-X', 'heapsize=' + args.heapsize]) + cmdlist.extend(["-X", "heapsize=" + args.heapsize]) # if running via .mpy, first compile the .py file if args.via_mpy: - subprocess.check_output([MPYCROSS] + args.mpy_cross_flags.split() + ['-o', 'mpytest.mpy', '-X', 'emit=' + args.emit, test_file]) - cmdlist.extend(['-m', 'mpytest']) + subprocess.check_output( + [MPYCROSS] + + args.mpy_cross_flags.split() + + ["-o", "mpytest.mpy", "-X", "emit=" + args.emit, test_file] + ) + cmdlist.extend(["-m", "mpytest"]) else: cmdlist.append(test_file) @@ -156,11 +171,11 @@ def run_micropython(pyb, args, test_file, is_special=False): output_mupy = subprocess.check_output(cmdlist, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as er: had_crash = True - output_mupy = er.output + b'CRASH' + output_mupy = er.output + b"CRASH" # clean up if we had an intermediate .mpy file if args.via_mpy: - rm_f('mpytest.mpy') + rm_f("mpytest.mpy") else: # run on pyboard @@ -169,56 +184,58 @@ def run_micropython(pyb, args, test_file, is_special=False): output_mupy = pyb.execfile(test_file) except pyboard.PyboardError as e: had_crash = True - if not is_special and e.args[0] == 'exception': - output_mupy = e.args[1] + e.args[2] + b'CRASH' + if not is_special and e.args[0] == "exception": + output_mupy = e.args[1] + e.args[2] + b"CRASH" else: - output_mupy = b'CRASH' + output_mupy = b"CRASH" # canonical form for all ports/platforms is to use \n for end-of-line - output_mupy = output_mupy.replace(b'\r\n', b'\n') + output_mupy = output_mupy.replace(b"\r\n", b"\n") # don't try to convert the output if we should skip this test - if had_crash or output_mupy in (b'SKIP\n', b'CRASH'): + if had_crash or output_mupy in (b"SKIP\n", b"CRASH"): return output_mupy if is_special or test_file in special_tests: # convert parts of the output that are not stable across runs - with open(test_file + '.exp', 'rb') as f: + with open(test_file + ".exp", "rb") as f: lines_exp = [] for line in f.readlines(): - if line == b'########\n': + if line == b"########\n": line = (line,) else: line = (line, re.compile(convert_regex_escapes(line))) lines_exp.append(line) - lines_mupy = [line + b'\n' for line in output_mupy.split(b'\n')] - if output_mupy.endswith(b'\n'): - lines_mupy = lines_mupy[:-1] # remove erroneous last empty line + lines_mupy = [line + b"\n" for line in output_mupy.split(b"\n")] + if output_mupy.endswith(b"\n"): + lines_mupy = lines_mupy[:-1] # remove erroneous last empty line i_mupy = 0 for i in range(len(lines_exp)): - if lines_exp[i][0] == b'########\n': + if lines_exp[i][0] == b"########\n": # 8x #'s means match 0 or more whole lines line_exp = lines_exp[i + 1] skip = 0 - while i_mupy + skip < len(lines_mupy) and not line_exp[1].match(lines_mupy[i_mupy + skip]): + while i_mupy + skip < len(lines_mupy) and not line_exp[1].match( + lines_mupy[i_mupy + skip] + ): skip += 1 if i_mupy + skip >= len(lines_mupy): - lines_mupy[i_mupy] = b'######## FAIL\n' + lines_mupy[i_mupy] = b"######## FAIL\n" break - del lines_mupy[i_mupy:i_mupy + skip] - lines_mupy.insert(i_mupy, b'########\n') + del lines_mupy[i_mupy : i_mupy + skip] + lines_mupy.insert(i_mupy, b"########\n") i_mupy += 1 else: # a regex if lines_exp[i][1].match(lines_mupy[i_mupy]): lines_mupy[i_mupy] = lines_exp[i][0] else: - #print("don't match: %r %s" % (lines_exp[i][1], lines_mupy[i_mupy])) # DEBUG + # print("don't match: %r %s" % (lines_exp[i][1], lines_mupy[i_mupy])) # DEBUG pass i_mupy += 1 if i_mupy >= len(lines_mupy): break - output_mupy = b''.join(lines_mupy) + output_mupy = b"".join(lines_mupy) return output_mupy @@ -261,193 +278,220 @@ def run_tests(pyb, tests, args, result_dir): # run-tests.py script itself so use base_path. # Check if micropython.native is supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'native_check.py') - if output == b'CRASH': + output = run_feature_check(pyb, args, base_path, "native_check.py") + if output == b"CRASH": skip_native = True # Check if arbitrary-precision integers are supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'int_big.py') - if output != b'1000000000000000000000000000000000000000000000\n': + output = run_feature_check(pyb, args, base_path, "int_big.py") + if output != b"1000000000000000000000000000000000000000000000\n": skip_int_big = True # Check if bytearray is supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'bytearray.py') - if output != b'bytearray\n': + output = run_feature_check(pyb, args, base_path, "bytearray.py") + if output != b"bytearray\n": skip_bytearray = True # Check if set type (and set literals) is supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'set_check.py') - if output == b'CRASH': + output = run_feature_check(pyb, args, base_path, "set_check.py") + if output == b"CRASH": skip_set_type = True # Check if slice is supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'slice.py') - if output != b'slice\n': + output = run_feature_check(pyb, args, base_path, "slice.py") + if output != b"slice\n": skip_slice = True # Check if async/await keywords are supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'async_check.py') - if output == b'CRASH': + output = run_feature_check(pyb, args, base_path, "async_check.py") + if output == b"CRASH": skip_async = True # Check if const keyword (MicroPython extension) is supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'const.py') - if output == b'CRASH': + output = run_feature_check(pyb, args, base_path, "const.py") + if output == b"CRASH": skip_const = True # Check if __rOP__ special methods are supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'reverse_ops.py') - if output == b'TypeError\n': + output = run_feature_check(pyb, args, base_path, "reverse_ops.py") + if output == b"TypeError\n": skip_revops = True # Check if uio module exists, and skip such tests if it doesn't - output = run_feature_check(pyb, args, base_path, 'uio_module.py') - if output != b'uio\n': + output = run_feature_check(pyb, args, base_path, "uio_module.py") + if output != b"uio\n": skip_io_module = True # Check if emacs repl is supported, and skip such tests if it's not - t = run_feature_check(pyb, args, base_path, 'repl_emacs_check.py') - if 'True' not in str(t, 'ascii'): - skip_tests.add('cmdline/repl_emacs_keys.py') + t = run_feature_check(pyb, args, base_path, "repl_emacs_check.py") + if "True" not in str(t, "ascii"): + skip_tests.add("cmdline/repl_emacs_keys.py") # Check if words movement in repl is supported, and skip such tests if it's not - t = run_feature_check(pyb, args, base_path, 'repl_words_move_check.py') - if 'True' not in str(t, 'ascii'): - skip_tests.add('cmdline/repl_words_move.py') + t = run_feature_check(pyb, args, base_path, "repl_words_move_check.py") + if "True" not in str(t, "ascii"): + skip_tests.add("cmdline/repl_words_move.py") - upy_byteorder = run_feature_check(pyb, args, base_path, 'byteorder.py') - upy_float_precision = run_feature_check(pyb, args, base_path, 'float.py') - if upy_float_precision == b'CRASH': + upy_byteorder = run_feature_check(pyb, args, base_path, "byteorder.py") + upy_float_precision = run_feature_check(pyb, args, base_path, "float.py") + if upy_float_precision == b"CRASH": upy_float_precision = 0 else: upy_float_precision = int(upy_float_precision) - has_complex = run_feature_check(pyb, args, base_path, 'complex.py') == b'complex\n' - has_coverage = run_feature_check(pyb, args, base_path, 'coverage.py') == b'coverage\n' - cpy_byteorder = subprocess.check_output(CPYTHON3_CMD + [base_path('feature_check/byteorder.py')]) - skip_endian = (upy_byteorder != cpy_byteorder) + has_complex = run_feature_check(pyb, args, base_path, "complex.py") == b"complex\n" + has_coverage = run_feature_check(pyb, args, base_path, "coverage.py") == b"coverage\n" + cpy_byteorder = subprocess.check_output( + CPYTHON3_CMD + [base_path("feature_check/byteorder.py")] + ) + skip_endian = upy_byteorder != cpy_byteorder # These tests don't test slice explicitly but rather use it to perform the test misc_slice_tests = ( - 'builtin_range', - 'class_super', - 'containment', - 'errno1', - 'fun_str', - 'generator1', - 'globals_del', - 'memoryview1', - 'memoryview_gc', - 'object1', - 'python34', - 'struct_endian', + "builtin_range", + "class_super", + "containment", + "errno1", + "fun_str", + "generator1", + "globals_del", + "memoryview1", + "memoryview_gc", + "object1", + "python34", + "struct_endian", ) # Some tests shouldn't be run on GitHub Actions - if os.getenv('GITHUB_ACTIONS') == 'true': - skip_tests.add('thread/stress_schedule.py') # has reliability issues + if os.getenv("GITHUB_ACTIONS") == "true": + skip_tests.add("thread/stress_schedule.py") # has reliability issues if upy_float_precision == 0: - skip_tests.add('extmod/uctypes_le_float.py') - skip_tests.add('extmod/uctypes_native_float.py') - skip_tests.add('extmod/uctypes_sizeof_float.py') - skip_tests.add('extmod/ujson_dumps_float.py') - skip_tests.add('extmod/ujson_loads_float.py') - skip_tests.add('extmod/urandom_extra_float.py') - skip_tests.add('misc/rge_sm.py') + skip_tests.add("extmod/uctypes_le_float.py") + skip_tests.add("extmod/uctypes_native_float.py") + skip_tests.add("extmod/uctypes_sizeof_float.py") + skip_tests.add("extmod/ujson_dumps_float.py") + skip_tests.add("extmod/ujson_loads_float.py") + skip_tests.add("extmod/urandom_extra_float.py") + skip_tests.add("misc/rge_sm.py") if upy_float_precision < 32: - skip_tests.add('float/float2int_intbig.py') # requires fp32, there's float2int_fp30_intbig.py instead - skip_tests.add('float/string_format.py') # requires fp32, there's string_format_fp30.py instead - skip_tests.add('float/bytes_construct.py') # requires fp32 - skip_tests.add('float/bytearray_construct.py') # requires fp32 + skip_tests.add( + "float/float2int_intbig.py" + ) # requires fp32, there's float2int_fp30_intbig.py instead + skip_tests.add( + "float/string_format.py" + ) # requires fp32, there's string_format_fp30.py instead + skip_tests.add("float/bytes_construct.py") # requires fp32 + skip_tests.add("float/bytearray_construct.py") # requires fp32 if upy_float_precision < 64: - skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead - skip_tests.add('float/float2int_doubleprec_intbig.py') - skip_tests.add('float/float_parse_doubleprec.py') + skip_tests.add("float/float_divmod.py") # tested by float/float_divmod_relaxed.py instead + skip_tests.add("float/float2int_doubleprec_intbig.py") + skip_tests.add("float/float_parse_doubleprec.py") if not has_complex: - skip_tests.add('float/complex1.py') - skip_tests.add('float/complex1_intbig.py') - skip_tests.add('float/complex_special_methods.py') - skip_tests.add('float/int_big_float.py') - skip_tests.add('float/true_value.py') - skip_tests.add('float/types.py') + skip_tests.add("float/complex1.py") + skip_tests.add("float/complex1_intbig.py") + skip_tests.add("float/complex_special_methods.py") + skip_tests.add("float/int_big_float.py") + skip_tests.add("float/true_value.py") + skip_tests.add("float/types.py") if not has_coverage: - skip_tests.add('cmdline/cmd_parsetree.py') + skip_tests.add("cmdline/cmd_parsetree.py") # Some tests shouldn't be run on a PC - if args.target == 'unix': + if args.target == "unix": # unix build does not have the GIL so can't run thread mutation tests for t in tests: - if t.startswith('thread/mutate_'): + if t.startswith("thread/mutate_"): skip_tests.add(t) # Some tests shouldn't be run on pyboard - if args.target != 'unix': - skip_tests.add('basics/exception_chain.py') # warning is not printed - skip_tests.add('micropython/meminfo.py') # output is very different to PC output - skip_tests.add('extmod/machine_mem.py') # raw memory access not supported + if args.target != "unix": + skip_tests.add("basics/exception_chain.py") # warning is not printed + skip_tests.add("micropython/meminfo.py") # output is very different to PC output + skip_tests.add("extmod/machine_mem.py") # raw memory access not supported - if args.target == 'wipy': - skip_tests.add('misc/print_exception.py') # requires error reporting full - skip_tests.update({'extmod/uctypes_%s.py' % t for t in 'bytearray le native_le ptr_le ptr_native_le sizeof sizeof_native array_assign_le array_assign_native_le'.split()}) # requires uctypes - skip_tests.add('extmod/zlibd_decompress.py') # requires zlib - skip_tests.add('extmod/uheapq1.py') # uheapq not supported by WiPy - skip_tests.add('extmod/urandom_basic.py') # requires urandom - skip_tests.add('extmod/urandom_extra.py') # requires urandom - elif args.target == 'esp8266': - skip_tests.add('misc/rge_sm.py') # too large - elif args.target == 'minimal': - skip_tests.add('basics/class_inplace_op.py') # all special methods not supported - skip_tests.add('basics/subclass_native_init.py')# native subclassing corner cases not support - skip_tests.add('misc/rge_sm.py') # too large - skip_tests.add('micropython/opt_level.py') # don't assume line numbers are stored - elif args.target == 'nrf': - skip_tests.add('basics/memoryview1.py') # no item assignment for memoryview - skip_tests.add('extmod/urandom_basic.py') # unimplemented: urandom.seed - skip_tests.add('micropython/opt_level.py') # no support for line numbers - skip_tests.add('misc/non_compliant.py') # no item assignment for bytearray + if args.target == "wipy": + skip_tests.add("misc/print_exception.py") # requires error reporting full + skip_tests.update( + { + "extmod/uctypes_%s.py" % t + for t in "bytearray le native_le ptr_le ptr_native_le sizeof sizeof_native array_assign_le array_assign_native_le".split() + } + ) # requires uctypes + skip_tests.add("extmod/zlibd_decompress.py") # requires zlib + skip_tests.add("extmod/uheapq1.py") # uheapq not supported by WiPy + skip_tests.add("extmod/urandom_basic.py") # requires urandom + skip_tests.add("extmod/urandom_extra.py") # requires urandom + elif args.target == "esp8266": + skip_tests.add("misc/rge_sm.py") # too large + elif args.target == "minimal": + skip_tests.add("basics/class_inplace_op.py") # all special methods not supported + skip_tests.add( + "basics/subclass_native_init.py" + ) # native subclassing corner cases not support + skip_tests.add("misc/rge_sm.py") # too large + skip_tests.add("micropython/opt_level.py") # don't assume line numbers are stored + elif args.target == "nrf": + skip_tests.add("basics/memoryview1.py") # no item assignment for memoryview + skip_tests.add("extmod/urandom_basic.py") # unimplemented: urandom.seed + skip_tests.add("micropython/opt_level.py") # no support for line numbers + skip_tests.add("misc/non_compliant.py") # no item assignment for bytearray for t in tests: - if t.startswith('basics/io_'): + if t.startswith("basics/io_"): skip_tests.add(t) - elif args.target == 'qemu-arm': - skip_tests.add('misc/print_exception.py') # requires sys stdfiles + elif args.target == "qemu-arm": + skip_tests.add("misc/print_exception.py") # requires sys stdfiles # Some tests are known to fail on 64-bit machines - if pyb is None and platform.architecture()[0] == '64bit': + if pyb is None and platform.architecture()[0] == "64bit": pass # Some tests use unsupported features on Windows - if os.name == 'nt': - skip_tests.add('import/import_file.py') # works but CPython prints forward slashes + if os.name == "nt": + skip_tests.add("import/import_file.py") # works but CPython prints forward slashes # Some tests are known to fail with native emitter # Remove them from the below when they work - if args.emit == 'native': - skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from_close generator_name'.split()}) # require raise_varargs, generator name - skip_tests.update({'basics/async_%s.py' % t for t in 'with with2 with_break with_return'.split()}) # require async_with - skip_tests.update({'basics/%s.py' % t for t in 'try_reraise try_reraise2'.split()}) # require raise_varargs - skip_tests.add('basics/annotate_var.py') # requires checking for unbound local - skip_tests.add('basics/del_deref.py') # requires checking for unbound local - skip_tests.add('basics/del_local.py') # requires checking for unbound local - skip_tests.add('basics/exception_chain.py') # raise from is not supported - skip_tests.add('basics/scope_implicit.py') # requires checking for unbound local - skip_tests.add('basics/try_finally_return2.py') # requires raise_varargs - skip_tests.add('basics/unboundlocal.py') # requires checking for unbound local - skip_tests.add('extmod/uasyncio_event.py') # unknown issue - skip_tests.add('extmod/uasyncio_lock.py') # requires async with - skip_tests.add('extmod/uasyncio_micropython.py') # unknown issue - skip_tests.add('extmod/uasyncio_wait_for.py') # unknown issue - skip_tests.add('misc/features.py') # requires raise_varargs - skip_tests.add('misc/print_exception.py') # because native doesn't have proper traceback info - skip_tests.add('misc/sys_exc_info.py') # sys.exc_info() is not supported for native - skip_tests.add('micropython/emg_exc.py') # because native doesn't have proper traceback info - skip_tests.add('micropython/heapalloc_traceback.py') # because native doesn't have proper traceback info - skip_tests.add('micropython/opt_level_lineno.py') # native doesn't have proper traceback info - skip_tests.add('micropython/schedule.py') # native code doesn't check pending events + if args.emit == "native": + skip_tests.update( + {"basics/%s.py" % t for t in "gen_yield_from_close generator_name".split()} + ) # require raise_varargs, generator name + skip_tests.update( + {"basics/async_%s.py" % t for t in "with with2 with_break with_return".split()} + ) # require async_with + skip_tests.update( + {"basics/%s.py" % t for t in "try_reraise try_reraise2".split()} + ) # require raise_varargs + skip_tests.add("basics/annotate_var.py") # requires checking for unbound local + skip_tests.add("basics/del_deref.py") # requires checking for unbound local + skip_tests.add("basics/del_local.py") # requires checking for unbound local + skip_tests.add("basics/exception_chain.py") # raise from is not supported + skip_tests.add("basics/scope_implicit.py") # requires checking for unbound local + skip_tests.add("basics/try_finally_return2.py") # requires raise_varargs + skip_tests.add("basics/unboundlocal.py") # requires checking for unbound local + skip_tests.add("extmod/uasyncio_event.py") # unknown issue + skip_tests.add("extmod/uasyncio_lock.py") # requires async with + skip_tests.add("extmod/uasyncio_micropython.py") # unknown issue + skip_tests.add("extmod/uasyncio_wait_for.py") # unknown issue + skip_tests.add("misc/features.py") # requires raise_varargs + skip_tests.add( + "misc/print_exception.py" + ) # because native doesn't have proper traceback info + skip_tests.add("misc/sys_exc_info.py") # sys.exc_info() is not supported for native + skip_tests.add( + "micropython/emg_exc.py" + ) # because native doesn't have proper traceback info + skip_tests.add( + "micropython/heapalloc_traceback.py" + ) # because native doesn't have proper traceback info + skip_tests.add( + "micropython/opt_level_lineno.py" + ) # native doesn't have proper traceback info + skip_tests.add("micropython/schedule.py") # native code doesn't check pending events for test_file in tests: - test_file = test_file.replace('\\', '/') + test_file = test_file.replace("\\", "/") if args.filters: # Default verdict is the opposit of the first action @@ -458,9 +502,13 @@ def run_tests(pyb, tests, args, result_dir): if verdict == "exclude": continue - test_basename = test_file.replace('..', '_').replace('./', '').replace('/', '_') + test_basename = test_file.replace("..", "_").replace("./", "").replace("/", "_") test_name = os.path.splitext(os.path.basename(test_file))[0] - is_native = test_name.startswith("native_") or test_name.startswith("viper_") or args.emit == "native" + is_native = ( + test_name.startswith("native_") + or test_name.startswith("viper_") + or args.emit == "native" + ) is_endian = test_name.endswith("_endian") is_int_big = test_name.startswith("int_big") or test_name.endswith("_intbig") is_bytearray = test_name.startswith("bytearray") or test_name.endswith("_bytearray") @@ -493,23 +541,23 @@ def run_tests(pyb, tests, args, result_dir): continue # get expected output - test_file_expected = test_file + '.exp' + test_file_expected = test_file + ".exp" if os.path.isfile(test_file_expected): # expected output given by a file, so read that in - with open(test_file_expected, 'rb') as f: + with open(test_file_expected, "rb") as f: output_expected = f.read() else: # run CPython to work out expected output try: output_expected = subprocess.check_output(CPYTHON3_CMD + [test_file]) if args.write_exp: - with open(test_file_expected, 'wb') as f: + with open(test_file_expected, "wb") as f: f.write(output_expected) except subprocess.CalledProcessError: - output_expected = b'CPYTHON3 CRASH' + output_expected = b"CPYTHON3 CRASH" # canonical form for all host platforms is to use \n for end-of-line - output_expected = output_expected.replace(b'\r\n', b'\n') + output_expected = output_expected.replace(b"\r\n", b"\n") if args.write_exp: continue @@ -517,7 +565,7 @@ def run_tests(pyb, tests, args, result_dir): # run MicroPython output_mupy = run_micropython(pyb, args, test_file) - if output_mupy == b'SKIP\n': + if output_mupy == b"SKIP\n": print("skip ", test_file) skipped_tests.append(test_name) continue @@ -549,9 +597,9 @@ def run_tests(pyb, tests, args, result_dir): print("{} tests passed".format(passed_count)) if len(skipped_tests) > 0: - print("{} tests skipped: {}".format(len(skipped_tests), ' '.join(skipped_tests))) + print("{} tests skipped: {}".format(len(skipped_tests), " ".join(skipped_tests))) if len(failed_tests) > 0: - print("{} tests failed: {}".format(len(failed_tests), ' '.join(failed_tests))) + print("{} tests failed: {}".format(len(failed_tests), " ".join(failed_tests))) return False # all tests succeeded @@ -559,7 +607,6 @@ def run_tests(pyb, tests, args, result_dir): class append_filter(argparse.Action): - def __init__(self, option_strings, dest, **kwargs): super().__init__(option_strings, dest, default=[], **kwargs) @@ -576,7 +623,7 @@ class append_filter(argparse.Action): def main(): cmd_parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, - description='''Run and manage tests for MicroPython. + description="""Run and manage tests for MicroPython. Tests are discovered by scanning test directories for .py files or using the specified test files. If test files nor directories are specified, the script @@ -587,34 +634,81 @@ produced by running the test through CPython unless a .exp file is found, case it is used as comparison. If a test fails, run-tests.py produces a pair of .out and .exp files in the result directory with the MicroPython output and the expectations, respectively. -''', - epilog='''\ +""", + epilog="""\ Options -i and -e can be multiple and processed in the order given. Regex "search" (vs "match") operation is used. An action (include/exclude) of the last matching regex is used: run-tests.py -i async - exclude all, then include tests containing "async" anywhere run-tests.py -e '/big.+int' - include all, then exclude by regex run-tests.py -e async -i async_foo - include all, exclude async, yet still include async_foo -''') - cmd_parser.add_argument('--target', default='unix', help='the target platform') - cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device or the IP address of the pyboard') - cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device') - cmd_parser.add_argument('-u', '--user', default='micro', help='the telnet login username') - cmd_parser.add_argument('-p', '--password', default='python', help='the telnet login password') - cmd_parser.add_argument('-d', '--test-dirs', nargs='*', help='input test directories (if no files given)') - cmd_parser.add_argument('-r', '--result-dir', default=base_path('results'), help='directory for test results') - cmd_parser.add_argument('-e', '--exclude', action=append_filter, metavar='REGEX', dest='filters', help='exclude test by regex on path/name.py') - cmd_parser.add_argument('-i', '--include', action=append_filter, metavar='REGEX', dest='filters', help='include test by regex on path/name.py') - cmd_parser.add_argument('--write-exp', action='store_true', help='use CPython to generate .exp files to run tests w/o CPython') - cmd_parser.add_argument('--list-tests', action='store_true', help='list tests instead of running them') - cmd_parser.add_argument('--emit', default='bytecode', help='MicroPython emitter to use (bytecode or native)') - cmd_parser.add_argument('--heapsize', help='heapsize to use (use default if not specified)') - cmd_parser.add_argument('--via-mpy', action='store_true', help='compile .py files to .mpy first') - cmd_parser.add_argument('--mpy-cross-flags', default='-mcache-lookup-bc', help='flags to pass to mpy-cross') - cmd_parser.add_argument('--keep-path', action='store_true', help='do not clear MICROPYPATH when running tests') - cmd_parser.add_argument('files', nargs='*', help='input test files') - cmd_parser.add_argument('--print-failures', action='store_true', help='print the diff of expected vs. actual output for failed tests and exit') - cmd_parser.add_argument('--clean-failures', action='store_true', help='delete the .exp and .out files from failed tests and exit') +""", + ) + cmd_parser.add_argument("--target", default="unix", help="the target platform") + cmd_parser.add_argument( + "--device", + default="/dev/ttyACM0", + help="the serial device or the IP address of the pyboard", + ) + cmd_parser.add_argument( + "-b", "--baudrate", default=115200, help="the baud rate of the serial device" + ) + cmd_parser.add_argument("-u", "--user", default="micro", help="the telnet login username") + cmd_parser.add_argument("-p", "--password", default="python", help="the telnet login password") + cmd_parser.add_argument( + "-d", "--test-dirs", nargs="*", help="input test directories (if no files given)" + ) + cmd_parser.add_argument( + "-r", "--result-dir", default=base_path("results"), help="directory for test results" + ) + cmd_parser.add_argument( + "-e", + "--exclude", + action=append_filter, + metavar="REGEX", + dest="filters", + help="exclude test by regex on path/name.py", + ) + cmd_parser.add_argument( + "-i", + "--include", + action=append_filter, + metavar="REGEX", + dest="filters", + help="include test by regex on path/name.py", + ) + cmd_parser.add_argument( + "--write-exp", + action="store_true", + help="use CPython to generate .exp files to run tests w/o CPython", + ) + cmd_parser.add_argument( + "--list-tests", action="store_true", help="list tests instead of running them" + ) + cmd_parser.add_argument( + "--emit", default="bytecode", help="MicroPython emitter to use (bytecode or native)" + ) + cmd_parser.add_argument("--heapsize", help="heapsize to use (use default if not specified)") + cmd_parser.add_argument( + "--via-mpy", action="store_true", help="compile .py files to .mpy first" + ) + cmd_parser.add_argument( + "--mpy-cross-flags", default="-mcache-lookup-bc", help="flags to pass to mpy-cross" + ) + cmd_parser.add_argument( + "--keep-path", action="store_true", help="do not clear MICROPYPATH when running tests" + ) + cmd_parser.add_argument("files", nargs="*", help="input test files") + cmd_parser.add_argument( + "--print-failures", + action="store_true", + help="print the diff of expected vs. actual output for failed tests and exit", + ) + cmd_parser.add_argument( + "--clean-failures", + action="store_true", + help="delete the .exp and .out files from failed tests and exit", + ) args = cmd_parser.parse_args() if args.print_failures: @@ -627,55 +721,82 @@ the last matching regex is used: sys.exit(0) if args.clean_failures: - for f in glob(os.path.join(args.result_dir, "*.exp")) + glob(os.path.join(args.result_dir, "*.out")): + for f in glob(os.path.join(args.result_dir, "*.exp")) + glob( + os.path.join(args.result_dir, "*.out") + ): os.remove(f) sys.exit(0) - LOCAL_TARGETS = ('unix', 'qemu-arm',) - EXTERNAL_TARGETS = ('pyboard', 'wipy', 'esp8266', 'esp32', 'minimal', 'nrf') + LOCAL_TARGETS = ( + "unix", + "qemu-arm", + ) + EXTERNAL_TARGETS = ("pyboard", "wipy", "esp8266", "esp32", "minimal", "nrf") if args.target in LOCAL_TARGETS or args.list_tests: pyb = None elif args.target in EXTERNAL_TARGETS: global pyboard - sys.path.append(base_path('../tools')) + sys.path.append(base_path("../tools")) import pyboard + pyb = pyboard.Pyboard(args.device, args.baudrate, args.user, args.password) pyb.enter_raw_repl() else: - raise ValueError('target must be one of %s' % ", ".join(LOCAL_TARGETS + EXTERNAL_TARGETS)) + raise ValueError("target must be one of %s" % ", ".join(LOCAL_TARGETS + EXTERNAL_TARGETS)) if len(args.files) == 0: if args.test_dirs is None: - test_dirs = ('basics', 'micropython', 'misc', 'extmod',) - if args.target == 'pyboard': + test_dirs = ( + "basics", + "micropython", + "misc", + "extmod", + ) + if args.target == "pyboard": # run pyboard tests - test_dirs += ('float', 'stress', 'pyb', 'pybnative', 'inlineasm') - elif args.target in ('esp8266', 'esp32', 'minimal', 'nrf'): - test_dirs += ('float',) - elif args.target == 'wipy': + test_dirs += ("float", "stress", "pyb", "pybnative", "inlineasm") + elif args.target in ("esp8266", "esp32", "minimal", "nrf"): + test_dirs += ("float",) + elif args.target == "wipy": # run WiPy tests - test_dirs += ('wipy',) - elif args.target == 'unix': + test_dirs += ("wipy",) + elif args.target == "unix": # run PC tests - test_dirs += ('float', 'import', 'io', 'stress', 'unicode', 'unix', 'cmdline',) - elif args.target == 'qemu-arm': + test_dirs += ( + "float", + "import", + "io", + "stress", + "unicode", + "unix", + "cmdline", + ) + elif args.target == "qemu-arm": if not args.write_exp: - raise ValueError('--target=qemu-arm must be used with --write-exp') + raise ValueError("--target=qemu-arm must be used with --write-exp") # Generate expected output files for qemu run. # This list should match the test_dirs tuple in tinytest-codegen.py. - test_dirs += ('float', 'inlineasm', 'qemu-arm',) + test_dirs += ( + "float", + "inlineasm", + "qemu-arm", + ) else: # run tests from these directories test_dirs = args.test_dirs - tests = sorted(test_file for test_files in (glob('{}/*.py'.format(dir)) for dir in test_dirs) for test_file in test_files) + tests = sorted( + test_file + for test_files in (glob("{}/*.py".format(dir)) for dir in test_dirs) + for test_file in test_files + ) else: # tests explicitly given tests = args.files if not args.keep_path: # clear search path to make sure tests use only builtin modules and those in extmod - os.environ['MICROPYPATH'] = os.pathsep + base_path('../extmod') + os.environ["MICROPYPATH"] = os.pathsep + base_path("../extmod") try: os.makedirs(args.result_dir, exist_ok=True) @@ -687,5 +808,6 @@ the last matching regex is used: if not res: sys.exit(1) + if __name__ == "__main__": main() From e98ff3f08e966595fd84d83296f84962ee3d8d94 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 12 Mar 2021 19:50:13 +1100 Subject: [PATCH 108/174] tests/multi_bluetooth: Skip tests when BLE features are unsupported. Signed-off-by: Damien George --- tests/multi_bluetooth/ble_gap_pair.py | 4 ++++ tests/multi_bluetooth/ble_gap_pair_bond.py | 4 ++++ tests/multi_bluetooth/ble_l2cap.py | 4 ++++ tests/multi_bluetooth/perf_l2cap.py | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/tests/multi_bluetooth/ble_gap_pair.py b/tests/multi_bluetooth/ble_gap_pair.py index 728513405e..f10fa37074 100644 --- a/tests/multi_bluetooth/ble_gap_pair.py +++ b/tests/multi_bluetooth/ble_gap_pair.py @@ -4,6 +4,10 @@ from micropython import const import time, machine, bluetooth +if not hasattr(bluetooth.BLE, "gap_pair"): + print("SKIP") + raise SystemExit + TIMEOUT_MS = 4000 _IRQ_CENTRAL_CONNECT = const(1) diff --git a/tests/multi_bluetooth/ble_gap_pair_bond.py b/tests/multi_bluetooth/ble_gap_pair_bond.py index a29c217887..d7224cc127 100644 --- a/tests/multi_bluetooth/ble_gap_pair_bond.py +++ b/tests/multi_bluetooth/ble_gap_pair_bond.py @@ -5,6 +5,10 @@ from micropython import const import time, machine, bluetooth +if not hasattr(bluetooth.BLE, "gap_pair"): + print("SKIP") + raise SystemExit + TIMEOUT_MS = 4000 _IRQ_CENTRAL_CONNECT = const(1) diff --git a/tests/multi_bluetooth/ble_l2cap.py b/tests/multi_bluetooth/ble_l2cap.py index a26f59b3ef..b14eeffcc5 100644 --- a/tests/multi_bluetooth/ble_l2cap.py +++ b/tests/multi_bluetooth/ble_l2cap.py @@ -7,6 +7,10 @@ from micropython import const import time, machine, bluetooth, random +if not hasattr(bluetooth.BLE, "l2cap_connect"): + print("SKIP") + raise SystemExit + TIMEOUT_MS = 1000 _IRQ_CENTRAL_CONNECT = const(1) diff --git a/tests/multi_bluetooth/perf_l2cap.py b/tests/multi_bluetooth/perf_l2cap.py index 9b07bb1dce..0603a02a81 100644 --- a/tests/multi_bluetooth/perf_l2cap.py +++ b/tests/multi_bluetooth/perf_l2cap.py @@ -3,6 +3,10 @@ from micropython import const import time, machine, bluetooth, random +if not hasattr(bluetooth.BLE, "l2cap_connect"): + print("SKIP") + raise SystemExit + TIMEOUT_MS = 1000 _IRQ_CENTRAL_CONNECT = const(1) From af45d511f190454159fe39ba50c477d7bbd6bb5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20K=C3=B6ck?= Date: Sat, 13 Mar 2021 09:17:02 +0100 Subject: [PATCH 109/174] rp2: Enable uerrno module. Fixes #6991. --- ports/rp2/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index 91d0c29b3a..35d1645522 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -88,6 +88,7 @@ #define MICROPY_PY_SYS_STDFILES (1) #define MICROPY_PY_SYS_STDIO_BUFFER (1) #define MICROPY_PY_SYS_PLATFORM "rp2" +#define MICROPY_PY_UERRNO (1) #define MICROPY_PY_THREAD (1) #define MICROPY_PY_THREAD_GIL (0) From 8010b15968dece822aa5318888cb6d969f36ef3b Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 14 Mar 2021 00:17:22 +1100 Subject: [PATCH 110/174] rp2: Enabled more core Python features. This brings the port's configuration closer to the stm32 and esp32 ports. Signed-off-by: Damien George --- ports/rp2/mpconfigport.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index 35d1645522..13db589ec0 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -71,17 +71,33 @@ // Fine control over Python builtins, classes, modules, etc #define MICROPY_PY_FUNCTION_ATTRS (1) +#define MICROPY_PY_DESCRIPTORS (1) +#define MICROPY_PY_DELATTR_SETATTR (1) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) +#define MICROPY_PY_BUILTINS_STR_CENTER (1) +#define MICROPY_PY_BUILTINS_STR_PARTITION (1) +#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) #define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_BUILTINS_SLICE_INDICES (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_BUILTINS_ROUND_INT (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_COMPILE (1) #define MICROPY_PY_BUILTINS_INPUT (1) +#define MICROPY_PY_BUILTINS_POW3 (1) #define MICROPY_PY_BUILTINS_HELP (1) #define MICROPY_PY_BUILTINS_HELP_TEXT rp2_help_text #define MICROPY_PY_BUILTINS_HELP_MODULES (1) -#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) -#define MICROPY_PY___FILE__ (0) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) +#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) +#define MICROPY_PY_MATH_FACTORIAL (1) +#define MICROPY_PY_MATH_ISCLOSE (1) +#define MICROPY_PY_CMATH (1) #define MICROPY_PY_IO_IOBASE (1) #define MICROPY_PY_IO_FILEIO (1) #define MICROPY_PY_SYS_MAXSIZE (1) From dcaf702578045299d5bc007d81669fe1ba640654 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 14 Mar 2021 00:18:18 +1100 Subject: [PATCH 111/174] rp2/modmachine: Enable machine.Signal class. Fixes issue #6863. Signed-off-by: Damien George --- ports/rp2/modmachine.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c index bf5033adba..cd7dcaade5 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -30,6 +30,7 @@ #include "extmod/machine_i2c.h" #include "extmod/machine_mem.h" #include "extmod/machine_pulse.h" +#include "extmod/machine_signal.h" #include "extmod/machine_spi.h" #include "modmachine.h" @@ -163,6 +164,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SoftI2C), MP_ROM_PTR(&mp_machine_soft_i2c_type) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) }, + { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) }, { MP_ROM_QSTR(MP_QSTR_SoftSPI), MP_ROM_PTR(&mp_machine_soft_spi_type) }, { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, From eccd73a403aef5b41368752b1d11d95e005bdc4b Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 14 Mar 2021 15:51:28 +1100 Subject: [PATCH 112/174] extmod/extmod.cmake: Add modonewire.c to MICROPY_SOURCE_EXTMOD list. Signed-off-by: Damien George --- extmod/extmod.cmake | 1 + ports/esp32/main/CMakeLists.txt | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/extmod/extmod.cmake b/extmod/extmod.cmake index 6668a2d8aa..691c3ce9b3 100644 --- a/extmod/extmod.cmake +++ b/extmod/extmod.cmake @@ -12,6 +12,7 @@ set(MICROPY_SOURCE_EXTMOD ${MICROPY_EXTMOD_DIR}/modbluetooth.c ${MICROPY_EXTMOD_DIR}/modbtree.c ${MICROPY_EXTMOD_DIR}/modframebuf.c + ${MICROPY_EXTMOD_DIR}/modonewire.c ${MICROPY_EXTMOD_DIR}/moduasyncio.c ${MICROPY_EXTMOD_DIR}/modubinascii.c ${MICROPY_EXTMOD_DIR}/moducryptolib.c diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index bd25d76ee4..b6bccdde3c 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -9,10 +9,6 @@ set(MICROPY_QSTRDEFS_PORT ${PROJECT_DIR}/qstrdefsport.h ) -set(MICROPY_SOURCE_EXTMOD_EXTRA - ${MICROPY_DIR}/extmod/modonewire.c -) - set(MICROPY_SOURCE_LIB ${MICROPY_DIR}/lib/littlefs/lfs1.c ${MICROPY_DIR}/lib/littlefs/lfs1_util.c @@ -75,7 +71,6 @@ set(MICROPY_SOURCE_PORT set(MICROPY_SOURCE_QSTR ${MICROPY_SOURCE_PY} ${MICROPY_SOURCE_EXTMOD} - ${MICROPY_SOURCE_EXTMOD_EXTRA} ${MICROPY_SOURCE_LIB} ${MICROPY_SOURCE_PORT} ) @@ -129,7 +124,6 @@ idf_component_register( SRCS ${MICROPY_SOURCE_PY} ${MICROPY_SOURCE_EXTMOD} - ${MICROPY_SOURCE_EXTMOD_EXTRA} ${MICROPY_SOURCE_LIB} ${MICROPY_SOURCE_DRIVERS} ${MICROPY_SOURCE_PORT} From a9140ab09b7f2b878972a86dabc12d00ddaa463e Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 14 Mar 2021 15:52:33 +1100 Subject: [PATCH 113/174] rp2: Use core-provided cmake fragments instead of custom ones. Signed-off-by: Damien George --- ports/rp2/CMakeLists.txt | 190 +++++++++++++++++++++------------ ports/rp2/micropy_extmod.cmake | 40 ------- ports/rp2/micropy_py.cmake | 134 ----------------------- ports/rp2/micropy_rules.cmake | 90 ---------------- 4 files changed, 119 insertions(+), 335 deletions(-) delete mode 100644 ports/rp2/micropy_extmod.cmake delete mode 100644 ports/rp2/micropy_py.cmake delete mode 100644 ports/rp2/micropy_rules.cmake diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index cf20245a3c..3968194dcb 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -6,8 +6,8 @@ if(NOT CMAKE_BUILD_TYPE) endif() # Set main target and component locations -set(MICROPYTHON_TARGET firmware) -get_filename_component(MPY_DIR "../.." ABSOLUTE) +set(MICROPY_TARGET firmware) +get_filename_component(MICROPY_DIR "../.." ABSOLUTE) if (PICO_SDK_PATH_OVERRIDE) set(PICO_SDK_PATH ${PICO_SDK_PATH_OVERRIDE}) else() @@ -15,42 +15,46 @@ else() endif() # Use the local tinyusb instead of the one in pico-sdk -set(PICO_TINYUSB_PATH ${MPY_DIR}/lib/tinyusb) +set(PICO_TINYUSB_PATH ${MICROPY_DIR}/lib/tinyusb) # Include component cmake fragments -include(micropy_py.cmake) -include(micropy_extmod.cmake) +include(${MICROPY_DIR}/py/py.cmake) +include(${MICROPY_DIR}/extmod/extmod.cmake) include(${PICO_SDK_PATH}/pico_sdk_init.cmake) # Define the top-level project -project(${MICROPYTHON_TARGET}) +project(${MICROPY_TARGET}) pico_sdk_init() -add_executable(${MICROPYTHON_TARGET}) +add_executable(${MICROPY_TARGET}) -set(SOURCE_LIB - ${MPY_DIR}/lib/littlefs/lfs1.c - ${MPY_DIR}/lib/littlefs/lfs1_util.c - ${MPY_DIR}/lib/littlefs/lfs2.c - ${MPY_DIR}/lib/littlefs/lfs2_util.c - ${MPY_DIR}/lib/mp-readline/readline.c - ${MPY_DIR}/lib/oofatfs/ff.c - ${MPY_DIR}/lib/oofatfs/ffunicode.c - ${MPY_DIR}/lib/timeutils/timeutils.c - ${MPY_DIR}/lib/utils/gchelper_m0.s - ${MPY_DIR}/lib/utils/gchelper_native.c - ${MPY_DIR}/lib/utils/mpirq.c - ${MPY_DIR}/lib/utils/stdout_helpers.c - ${MPY_DIR}/lib/utils/sys_stdio_mphal.c - ${MPY_DIR}/lib/utils/pyexec.c +set(MICROPY_QSTRDEFS_PORT + ${PROJECT_SOURCE_DIR}/qstrdefsport.h ) -set(SOURCE_DRIVERS - ${MPY_DIR}/drivers/bus/softspi.c +set(MICROPY_SOURCE_LIB + ${MICROPY_DIR}/lib/littlefs/lfs1.c + ${MICROPY_DIR}/lib/littlefs/lfs1_util.c + ${MICROPY_DIR}/lib/littlefs/lfs2.c + ${MICROPY_DIR}/lib/littlefs/lfs2_util.c + ${MICROPY_DIR}/lib/mp-readline/readline.c + ${MICROPY_DIR}/lib/oofatfs/ff.c + ${MICROPY_DIR}/lib/oofatfs/ffunicode.c + ${MICROPY_DIR}/lib/timeutils/timeutils.c + ${MICROPY_DIR}/lib/utils/gchelper_m0.s + ${MICROPY_DIR}/lib/utils/gchelper_native.c + ${MICROPY_DIR}/lib/utils/mpirq.c + ${MICROPY_DIR}/lib/utils/pyexec.c + ${MICROPY_DIR}/lib/utils/stdout_helpers.c + ${MICROPY_DIR}/lib/utils/sys_stdio_mphal.c ) -set(SOURCE_PORT +set(MICROPY_SOURCE_DRIVERS + ${MICROPY_DIR}/drivers/bus/softspi.c +) + +set(MICROPY_SOURCE_PORT fatfs_port.c machine_adc.c machine_i2c.c @@ -73,11 +77,11 @@ set(SOURCE_PORT uart.c ) -set(SOURCE_QSTR - ${SOURCE_PY} - ${SOURCE_EXTMOD} - ${MPY_DIR}/lib/utils/mpirq.c - ${MPY_DIR}/lib/utils/sys_stdio_mphal.c +set(MICROPY_SOURCE_QSTR + ${MICROPY_SOURCE_PY} + ${MICROPY_SOURCE_EXTMOD} + ${MICROPY_DIR}/lib/utils/mpirq.c + ${MICROPY_DIR}/lib/utils/sys_stdio_mphal.c ${PROJECT_SOURCE_DIR}/machine_adc.c ${PROJECT_SOURCE_DIR}/machine_i2c.c ${PROJECT_SOURCE_DIR}/machine_pin.c @@ -94,37 +98,65 @@ set(SOURCE_QSTR ${PROJECT_SOURCE_DIR}/rp2_pio.c ) -set(MPY_QSTR_DEFS ${PROJECT_SOURCE_DIR}/qstrdefsport.h) +set(PICO_SDK_COMPONENTS + hardware_adc + hardware_base + hardware_clocks + hardware_dma + hardware_flash + hardware_gpio + hardware_i2c + hardware_irq + hardware_pio + hardware_pwm + hardware_regs + hardware_rtc + hardware_spi + hardware_structs + hardware_sync + hardware_timer + hardware_uart + hardware_watchdog + pico_base_headers + pico_binary_info + pico_bootrom + pico_multicore + pico_platform + pico_stdio + pico_stdlib + pico_sync + pico_time + pico_unique_id + tinyusb_device +) # Define mpy-cross flags and frozen manifest -set(MPY_CROSS_FLAGS -march=armv7m) -set(FROZEN_MANIFEST ${PROJECT_SOURCE_DIR}/manifest.py) +set(MICROPY_CROSS_FLAGS -march=armv7m) +set(MICROPY_FROZEN_MANIFEST ${PROJECT_SOURCE_DIR}/manifest.py) -include(micropy_rules.cmake) - -target_sources(${MICROPYTHON_TARGET} PRIVATE - ${SOURCE_PY} - ${SOURCE_EXTMOD} - ${SOURCE_LIB} - ${SOURCE_DRIVERS} - ${SOURCE_PORT} +target_sources(${MICROPY_TARGET} PRIVATE + ${MICROPY_SOURCE_PY} + ${MICROPY_SOURCE_EXTMOD} + ${MICROPY_SOURCE_LIB} + ${MICROPY_SOURCE_DRIVERS} + ${MICROPY_SOURCE_PORT} ) -target_include_directories(${MICROPYTHON_TARGET} PRIVATE - "${PROJECT_SOURCE_DIR}" - "${MPY_DIR}" - "${CMAKE_BINARY_DIR}" - ) +target_include_directories(${MICROPY_TARGET} PRIVATE + "${PROJECT_SOURCE_DIR}" + "${MICROPY_DIR}" + "${CMAKE_BINARY_DIR}" +) -target_compile_options(${MICROPYTHON_TARGET} PRIVATE +target_compile_options(${MICROPY_TARGET} PRIVATE -Wall - #-Werror - -DFFCONF_H=\"${MPY_DIR}/lib/oofatfs/ffconf.h\" - -DLFS1_NO_MALLOC -DLFS1_NO_DEBUG -DLFS1_NO_WARN -DLFS1_NO_ERROR -DLFS1_NO_ASSERT - -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT + -Werror ) -target_compile_definitions(${MICROPYTHON_TARGET} PRIVATE +target_compile_definitions(${MICROPY_TARGET} PRIVATE + FFCONF_H=\"${MICROPY_OOFATFS_DIR}/ffconf.h\" + LFS1_NO_MALLOC LFS1_NO_DEBUG LFS1_NO_WARN LFS1_NO_ERROR LFS1_NO_ASSERT + LFS2_NO_MALLOC LFS2_NO_DEBUG LFS2_NO_WARN LFS2_NO_ERROR LFS2_NO_ASSERT PICO_FLOAT_PROPAGATE_NANS=1 PICO_STACK_SIZE=0x2000 PICO_CORE1_STACK_SIZE=0 @@ -134,34 +166,50 @@ target_compile_definitions(${MICROPYTHON_TARGET} PRIVATE PICO_NO_BI_STDIO_UART=1 # we call it UART REPL ) -target_link_libraries(${MICROPYTHON_TARGET} - hardware_adc - hardware_dma - hardware_flash - hardware_i2c - hardware_pio - hardware_pwm - hardware_rtc - hardware_spi - hardware_sync - pico_multicore - pico_stdlib_headers - pico_stdlib - pico_unique_id - tinyusb_device +target_link_libraries(${MICROPY_TARGET} + ${PICO_SDK_COMPONENTS} ) # todo this is a bit brittle, but we want to move a few source files into RAM (which requires # a linker script modification) until we explicitly add macro calls around the function # defs to move them into RAM. if (PICO_ON_DEVICE AND NOT PICO_NO_FLASH AND NOT PICO_COPY_TO_RAM) - pico_set_linker_script(${MICROPYTHON_TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_mp.ld) + pico_set_linker_script(${MICROPY_TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_mp.ld) endif() -pico_add_extra_outputs(${MICROPYTHON_TARGET}) +pico_add_extra_outputs(${MICROPY_TARGET}) -add_custom_command(TARGET ${MICROPYTHON_TARGET} +add_custom_command(TARGET ${MICROPY_TARGET} POST_BUILD - COMMAND arm-none-eabi-size --format=berkeley ${PROJECT_BINARY_DIR}/${MICROPYTHON_TARGET}.elf + COMMAND arm-none-eabi-size --format=berkeley ${PROJECT_BINARY_DIR}/${MICROPY_TARGET}.elf VERBATIM ) + +# Collect all the include directories and compile definitions for the pico-sdk components. +macro(_process_target targ) + if(TARGET ${targ}) + get_target_property(type ${targ} TYPE) + set(_inc OFF) + set(_def OFF) + if(${type} STREQUAL STATIC_LIBRARY) + get_target_property(_inc ${targ} INCLUDE_DIRECTORIES) + get_target_property(_def ${targ} COMPILE_DEFINITIONS) + elseif(${type} STREQUAL INTERFACE_LIBRARY) + get_target_property(_inc ${targ} INTERFACE_INCLUDE_DIRECTORIES) + get_target_property(_def ${targ} INTERFACE_COMPILE_DEFINITIONS) + endif() + if(_inc) + list(APPEND MICROPY_CPP_INC_EXTRA ${_inc}) + endif() + if(_def) + list(APPEND MICROPY_CPP_DEF_EXTRA ${_def}) + endif() + endif() +endmacro() +foreach(comp ${PICO_SDK_COMPONENTS}) + _process_target(${comp}) + _process_target(${comp}_headers) +endforeach() + +# Include the main MicroPython cmake rules. +include(${MICROPY_DIR}/py/mkrules.cmake) diff --git a/ports/rp2/micropy_extmod.cmake b/ports/rp2/micropy_extmod.cmake deleted file mode 100644 index 1e968bef63..0000000000 --- a/ports/rp2/micropy_extmod.cmake +++ /dev/null @@ -1,40 +0,0 @@ -# CMake fragment for MicroPython extmod component - -set(SOURCE_EXTMOD - ${MPY_DIR}/extmod/machine_i2c.c - ${MPY_DIR}/extmod/machine_mem.c - ${MPY_DIR}/extmod/machine_pulse.c - ${MPY_DIR}/extmod/machine_signal.c - ${MPY_DIR}/extmod/machine_spi.c - ${MPY_DIR}/extmod/modbtree.c - ${MPY_DIR}/extmod/modframebuf.c - ${MPY_DIR}/extmod/modonewire.c - ${MPY_DIR}/extmod/moduasyncio.c - ${MPY_DIR}/extmod/modubinascii.c - ${MPY_DIR}/extmod/moducryptolib.c - ${MPY_DIR}/extmod/moductypes.c - ${MPY_DIR}/extmod/moduhashlib.c - ${MPY_DIR}/extmod/moduheapq.c - ${MPY_DIR}/extmod/modujson.c - ${MPY_DIR}/extmod/modurandom.c - ${MPY_DIR}/extmod/modure.c - ${MPY_DIR}/extmod/moduselect.c - ${MPY_DIR}/extmod/modussl_axtls.c - ${MPY_DIR}/extmod/modussl_mbedtls.c - ${MPY_DIR}/extmod/modutimeq.c - ${MPY_DIR}/extmod/moduwebsocket.c - ${MPY_DIR}/extmod/moduzlib.c - ${MPY_DIR}/extmod/modwebrepl.c - ${MPY_DIR}/extmod/uos_dupterm.c - ${MPY_DIR}/extmod/utime_mphal.c - ${MPY_DIR}/extmod/vfs.c - ${MPY_DIR}/extmod/vfs_blockdev.c - ${MPY_DIR}/extmod/vfs_fat.c - ${MPY_DIR}/extmod/vfs_fat_diskio.c - ${MPY_DIR}/extmod/vfs_fat_file.c - ${MPY_DIR}/extmod/vfs_lfs.c - ${MPY_DIR}/extmod/vfs_posix.c - ${MPY_DIR}/extmod/vfs_posix_file.c - ${MPY_DIR}/extmod/vfs_reader.c - ${MPY_DIR}/extmod/virtpin.c -) diff --git a/ports/rp2/micropy_py.cmake b/ports/rp2/micropy_py.cmake deleted file mode 100644 index aeb7e2b9b5..0000000000 --- a/ports/rp2/micropy_py.cmake +++ /dev/null @@ -1,134 +0,0 @@ -# CMake fragment for MicroPython core py component - -set(MPY_PY_DIR "${MPY_DIR}/py") -set(MPY_PY_QSTRDEFS "${MPY_PY_DIR}/qstrdefs.h") -set(MPY_GENHDR_DIR "${CMAKE_BINARY_DIR}/genhdr") -set(MPY_MPVERSION "${MPY_GENHDR_DIR}/mpversion.h") -set(MPY_MODULEDEFS "${MPY_GENHDR_DIR}/moduledefs.h") -set(MPY_QSTR_DEFS_LAST "${MPY_GENHDR_DIR}/qstr.i.last") -set(MPY_QSTR_DEFS_SPLIT "${MPY_GENHDR_DIR}/qstr.split") -set(MPY_QSTR_DEFS_COLLECTED "${MPY_GENHDR_DIR}/qstrdefs.collected.h") -set(MPY_QSTR_DEFS_PREPROCESSED "${MPY_GENHDR_DIR}/qstrdefs.preprocessed.h") -set(MPY_QSTR_DEFS_GENERATED "${MPY_GENHDR_DIR}/qstrdefs.generated.h") -set(MPY_FROZEN_CONTENT "${CMAKE_BINARY_DIR}/frozen_content.c") - -# All py/ source files -set(SOURCE_PY - ${MPY_PY_DIR}/argcheck.c - ${MPY_PY_DIR}/asmarm.c - ${MPY_PY_DIR}/asmbase.c - ${MPY_PY_DIR}/asmthumb.c - ${MPY_PY_DIR}/asmx64.c - ${MPY_PY_DIR}/asmx86.c - ${MPY_PY_DIR}/asmxtensa.c - ${MPY_PY_DIR}/bc.c - ${MPY_PY_DIR}/binary.c - ${MPY_PY_DIR}/builtinevex.c - ${MPY_PY_DIR}/builtinhelp.c - ${MPY_PY_DIR}/builtinimport.c - ${MPY_PY_DIR}/compile.c - ${MPY_PY_DIR}/emitbc.c - ${MPY_PY_DIR}/emitcommon.c - ${MPY_PY_DIR}/emitglue.c - ${MPY_PY_DIR}/emitinlinethumb.c - ${MPY_PY_DIR}/emitinlinextensa.c - ${MPY_PY_DIR}/emitnarm.c - ${MPY_PY_DIR}/emitnthumb.c - ${MPY_PY_DIR}/emitnx64.c - ${MPY_PY_DIR}/emitnx86.c - ${MPY_PY_DIR}/emitnxtensa.c - ${MPY_PY_DIR}/emitnxtensawin.c - ${MPY_PY_DIR}/formatfloat.c - ${MPY_PY_DIR}/frozenmod.c - ${MPY_PY_DIR}/gc.c - ${MPY_PY_DIR}/lexer.c - ${MPY_PY_DIR}/malloc.c - ${MPY_PY_DIR}/map.c - ${MPY_PY_DIR}/modarray.c - ${MPY_PY_DIR}/modbuiltins.c - ${MPY_PY_DIR}/modcmath.c - ${MPY_PY_DIR}/modcollections.c - ${MPY_PY_DIR}/modgc.c - ${MPY_PY_DIR}/modio.c - ${MPY_PY_DIR}/modmath.c - ${MPY_PY_DIR}/modmicropython.c - ${MPY_PY_DIR}/modstruct.c - ${MPY_PY_DIR}/modsys.c - ${MPY_PY_DIR}/modthread.c - ${MPY_PY_DIR}/moduerrno.c - ${MPY_PY_DIR}/mpprint.c - ${MPY_PY_DIR}/mpstate.c - ${MPY_PY_DIR}/mpz.c - ${MPY_PY_DIR}/nativeglue.c - ${MPY_PY_DIR}/nlr.c - ${MPY_PY_DIR}/nlrpowerpc.c - ${MPY_PY_DIR}/nlrsetjmp.c - ${MPY_PY_DIR}/nlrthumb.c - ${MPY_PY_DIR}/nlrx64.c - ${MPY_PY_DIR}/nlrx86.c - ${MPY_PY_DIR}/nlrxtensa.c - ${MPY_PY_DIR}/obj.c - ${MPY_PY_DIR}/objarray.c - ${MPY_PY_DIR}/objattrtuple.c - ${MPY_PY_DIR}/objbool.c - ${MPY_PY_DIR}/objboundmeth.c - ${MPY_PY_DIR}/objcell.c - ${MPY_PY_DIR}/objclosure.c - ${MPY_PY_DIR}/objcomplex.c - ${MPY_PY_DIR}/objdeque.c - ${MPY_PY_DIR}/objdict.c - ${MPY_PY_DIR}/objenumerate.c - ${MPY_PY_DIR}/objexcept.c - ${MPY_PY_DIR}/objfilter.c - ${MPY_PY_DIR}/objfloat.c - ${MPY_PY_DIR}/objfun.c - ${MPY_PY_DIR}/objgenerator.c - ${MPY_PY_DIR}/objgetitemiter.c - ${MPY_PY_DIR}/objint.c - ${MPY_PY_DIR}/objint_longlong.c - ${MPY_PY_DIR}/objint_mpz.c - ${MPY_PY_DIR}/objlist.c - ${MPY_PY_DIR}/objmap.c - ${MPY_PY_DIR}/objmodule.c - ${MPY_PY_DIR}/objnamedtuple.c - ${MPY_PY_DIR}/objnone.c - ${MPY_PY_DIR}/objobject.c - ${MPY_PY_DIR}/objpolyiter.c - ${MPY_PY_DIR}/objproperty.c - ${MPY_PY_DIR}/objrange.c - ${MPY_PY_DIR}/objreversed.c - ${MPY_PY_DIR}/objset.c - ${MPY_PY_DIR}/objsingleton.c - ${MPY_PY_DIR}/objslice.c - ${MPY_PY_DIR}/objstr.c - ${MPY_PY_DIR}/objstringio.c - ${MPY_PY_DIR}/objstrunicode.c - ${MPY_PY_DIR}/objtuple.c - ${MPY_PY_DIR}/objtype.c - ${MPY_PY_DIR}/objzip.c - ${MPY_PY_DIR}/opmethods.c - ${MPY_PY_DIR}/pairheap.c - ${MPY_PY_DIR}/parse.c - ${MPY_PY_DIR}/parsenum.c - ${MPY_PY_DIR}/parsenumbase.c - ${MPY_PY_DIR}/persistentcode.c - ${MPY_PY_DIR}/profile.c - ${MPY_PY_DIR}/pystack.c - ${MPY_PY_DIR}/qstr.c - ${MPY_PY_DIR}/reader.c - ${MPY_PY_DIR}/repl.c - ${MPY_PY_DIR}/ringbuf.c - ${MPY_PY_DIR}/runtime.c - ${MPY_PY_DIR}/runtime_utils.c - ${MPY_PY_DIR}/scheduler.c - ${MPY_PY_DIR}/scope.c - ${MPY_PY_DIR}/sequence.c - ${MPY_PY_DIR}/showbc.c - ${MPY_PY_DIR}/smallint.c - ${MPY_PY_DIR}/stackctrl.c - ${MPY_PY_DIR}/stream.c - ${MPY_PY_DIR}/unicode.c - ${MPY_PY_DIR}/vm.c - ${MPY_PY_DIR}/vstr.c - ${MPY_PY_DIR}/warning.c -) diff --git a/ports/rp2/micropy_rules.cmake b/ports/rp2/micropy_rules.cmake deleted file mode 100644 index 9eee4ac14d..0000000000 --- a/ports/rp2/micropy_rules.cmake +++ /dev/null @@ -1,90 +0,0 @@ -# CMake fragment for MicroPython rules - -target_sources(${MICROPYTHON_TARGET} PRIVATE - ${MPY_MPVERSION} - ${MPY_QSTR_DEFS_GENERATED} - ${MPY_FROZEN_CONTENT} -) - -# Command to force the build of another command - -add_custom_command( - OUTPUT FORCE_BUILD - COMMENT "" - COMMAND echo -n -) - -# Generate mpversion.h - -add_custom_command( - OUTPUT ${MPY_MPVERSION} - COMMAND ${CMAKE_COMMAND} -E make_directory ${MPY_GENHDR_DIR} - COMMAND python3 ${MPY_DIR}/py/makeversionhdr.py ${MPY_MPVERSION} - DEPENDS FORCE_BUILD -) - -# Generate moduledefs.h - -add_custom_command( - OUTPUT ${MPY_MODULEDEFS} - COMMAND python3 ${MPY_PY_DIR}/makemoduledefs.py --vpath="/" ${SOURCE_QSTR} > ${MPY_MODULEDEFS} - DEPENDS ${MPY_MPVERSION} - ${SOURCE_QSTR} -) - -# Generate qstrs - -# If any of the dependencies in this rule change then the C-preprocessor step must be run. -# It only needs to be passed the list of SOURCE_QSTR files that have changed since it was -# last run, but it looks like it's not possible to specify that with cmake. -add_custom_command( - OUTPUT ${MPY_QSTR_DEFS_LAST} - COMMAND ${CMAKE_C_COMPILER} -E \$\(C_INCLUDES\) \$\(C_FLAGS\) -DNO_QSTR ${SOURCE_QSTR} > ${MPY_GENHDR_DIR}/qstr.i.last - DEPENDS ${MPY_MODULEDEFS} - ${SOURCE_QSTR} - VERBATIM -) - -add_custom_command( - OUTPUT ${MPY_QSTR_DEFS_SPLIT} - COMMAND python3 ${MPY_DIR}/py/makeqstrdefs.py split qstr ${MPY_GENHDR_DIR}/qstr.i.last ${MPY_GENHDR_DIR}/qstr _ - COMMAND touch ${MPY_QSTR_DEFS_SPLIT} - DEPENDS ${MPY_QSTR_DEFS_LAST} - VERBATIM -) - -add_custom_command( - OUTPUT ${MPY_QSTR_DEFS_COLLECTED} - COMMAND python3 ${MPY_DIR}/py/makeqstrdefs.py cat qstr _ ${MPY_GENHDR_DIR}/qstr ${MPY_QSTR_DEFS_COLLECTED} - DEPENDS ${MPY_QSTR_DEFS_SPLIT} - VERBATIM -) - -add_custom_command( - OUTPUT ${MPY_QSTR_DEFS_PREPROCESSED} - COMMAND cat ${MPY_PY_QSTRDEFS} ${MPY_QSTR_DEFS} ${MPY_QSTR_DEFS_COLLECTED} | sed "s/^Q(.*)/\"&\"/" | ${CMAKE_C_COMPILER} -E \$\(C_INCLUDES\) \$\(C_FLAGS\) - | sed "s/^\\\"\\(Q(.*)\\)\\\"/\\1/" > ${MPY_QSTR_DEFS_PREPROCESSED} - DEPENDS ${MPY_PY_QSTRDEFS} ${MPY_QSTR_DEFS} ${MPY_QSTR_DEFS_COLLECTED} - VERBATIM -) - -add_custom_command( - OUTPUT ${MPY_QSTR_DEFS_GENERATED} - COMMAND python3 ${MPY_PY_DIR}/makeqstrdata.py ${MPY_QSTR_DEFS_PREPROCESSED} > ${MPY_QSTR_DEFS_GENERATED} - DEPENDS ${MPY_QSTR_DEFS_PREPROCESSED} - VERBATIM -) - -# Build frozen code - -target_compile_options(${MICROPYTHON_TARGET} PUBLIC - -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool - -DMICROPY_MODULE_FROZEN_MPY=\(1\) -) - -add_custom_command( - OUTPUT ${MPY_FROZEN_CONTENT} - COMMAND python3 ${MPY_DIR}/tools/makemanifest.py -o ${MPY_FROZEN_CONTENT} -v "MPY_DIR=${MPY_DIR}" -v "PORT_DIR=${PROJECT_SOURCE_DIR}" -b "${CMAKE_BINARY_DIR}" -f${MPY_CROSS_FLAGS} ${FROZEN_MANIFEST} - DEPENDS FORCE_BUILD - ${MPY_QSTR_DEFS_GENERATED} - VERBATIM -) From 914380cb89d7cf5e9c186055753ff12bbcf6296a Mon Sep 17 00:00:00 2001 From: stijn Date: Mon, 15 Mar 2021 10:29:17 +0100 Subject: [PATCH 114/174] all: Add .git-blame-ignore-revs for fixing up git blame output. Add most formatting-only commits to this file so that when used with git blame, these commits are excluded and the output shows only the interesting bits. --- .git-blame-ignore-revs | 32 ++++++++++++++++++++++++++++++++ docs/develop/gettingstarted.rst | 5 +++++ 2 files changed, 37 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000000..83726922a5 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,32 @@ +# tests/run-tests.py: Reformat with Black. +2a38d7103672580882fb621a5b76e8d26805d593 + +# all: Update Python code to conform to latest black formatting. +06659077a81b85882254cf0953c33b27614e018e + +# tools/uncrustify: Enable more opts to remove space between func and '('. +77ed6f69ac35c1663a5633a8ee1d8a2446542204 + +# tools/codeformat.py: Include extmod/{btstack,nimble} in code formatting. +026fda605e03113d6e753290d65fed774418bc53 + +# all: Format code to add space after C++-style comment start. +84fa3312cfa7d2237d4b56952f2cd6e3591210c4 + +# tests: Format all Python code with black, except tests in basics subdir. +3dc324d3f1312e40d3a8ed87e7244966bb756f26 + +# all: Remove spaces inside and around parenthesis. +1a3e386c67e03a79eb768cb6e9f6777e002d6660 + +# all: Remove spaces between nested paren and inside function arg paren. +feb25775851ba0c04b8d1013716f442258879d9c + +# all: Reformat C and Python source code with tools/codeformat.py. +69661f3343bedf86e514337cff63d96cc42f8859 + +# stm32/usbdev: Convert files to unix line endings. +abde0fa2267f9062b28c3c015d7662a550125cc6 + +# all: Remove trailing spaces, per coding conventions. +761e4c7ff62896c7d8f8c3dfc3cc98a4cc4f2f6f diff --git a/docs/develop/gettingstarted.rst b/docs/develop/gettingstarted.rst index 32435ebe1c..30b26071ea 100644 --- a/docs/develop/gettingstarted.rst +++ b/docs/develop/gettingstarted.rst @@ -21,6 +21,11 @@ of Git for your operating system to follow through the rest of the steps. Learn about the basic git commands in this `Git Handbook `_ or any other sources on the internet. +.. note:: + A .git-blame-ignore-revs file is included which avoids the output of git blame getting cluttered + by commits which are only for formatting code but have no functional changes. See `git blame documentation + `_ on how to use this. + Get the code ------------ From d53a6d58b04e524e4ec5ee937a15cc3932f8ee2f Mon Sep 17 00:00:00 2001 From: stijn Date: Mon, 15 Mar 2021 09:30:46 +0100 Subject: [PATCH 115/174] stm32/Makefile: Fix C++ linker flags when toolchain has spaces in path. The GNU Make dir command uses spaces as item separator so it does not work for e.g building the STM32 port on Cygwin with a default Arm installation in "c:/program files (x86)/GNU Arm Embedded Toolchain". Fix by using POSIX dirname on a quoted path instead. --- ports/stm32/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 6e5fc15363..9a66d3c10b 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -145,7 +145,8 @@ endif CXXFLAGS += $(filter-out -Wmissing-prototypes -Wold-style-definition -std=gnu99,$(CFLAGS)) CXXFLAGS += $(CXXFLAGS_MOD) ifneq ($(SRC_CXX)$(SRC_MOD_CXX),) -LDFLAGS += -L$(dir $(shell $(CXX) $(CXXFLAGS) -print-file-name=libstdc++.a)) +LIBSTDCPP_FILE_NAME = "$(shell $(CXX) $(CXXFLAGS) -print-file-name=libstdc++.a)" +LDFLAGS += -L"$(shell dirname $(LIBSTDCPP_FILE_NAME))" endif # Options for mpy-cross From 2b888aa2f346b52b16fbefbea6a2d9d8085d8ff1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 16 Mar 2021 12:40:16 +1100 Subject: [PATCH 116/174] extmod/modbluetooth: Free temp arrays in gatts register services. This helps to reduce memory fragmentation, by freeing the heap data as soon as it is not needed. It also helps the compiler keeps a reference to the beginning of both arrays, which need to be traceable by the GC (otherwise some compilers may optimise this reference to something else). Signed-off-by: Damien George --- extmod/modbluetooth.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 269493f0a9..e379a8c6a3 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -619,6 +619,11 @@ STATIC mp_obj_t bluetooth_ble_gatts_register_services(mp_obj_t self_in, mp_obj_t } result->items[i] = MP_OBJ_FROM_PTR(service_handles); } + + // Free temporary arrays. + m_del(uint16_t *, handles, len); + m_del(size_t, num_handles, len); + return MP_OBJ_FROM_PTR(result); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gatts_register_services_obj, bluetooth_ble_gatts_register_services); From a79d97cb76cf6ec3794c357b706dd24970317c4a Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 16 Mar 2021 12:45:39 +1100 Subject: [PATCH 117/174] tests/extmod/vfs_fat_fileio2.py: Close test file at end of test. Otherwise it can lead to inconsistent results running subsequent tests. Signed-off-by: Damien George --- tests/extmod/vfs_fat_fileio2.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/extmod/vfs_fat_fileio2.py b/tests/extmod/vfs_fat_fileio2.py index a9cea2bed8..531dd91f94 100644 --- a/tests/extmod/vfs_fat_fileio2.py +++ b/tests/extmod/vfs_fat_fileio2.py @@ -112,3 +112,4 @@ try: f.write(bytearray(bsize * free)) except OSError as e: print("ENOSPC:", e.args[0] == 28) # uerrno.ENOSPC +f.close() From cb68a5741aba5d4935428674234a9d643f97405f Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 16 Mar 2021 12:46:49 +1100 Subject: [PATCH 118/174] tests/run-tests.py: Provide more info if script run via pyboard crashes. Signed-off-by: Damien George --- tests/run-tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-tests.py b/tests/run-tests.py index 3ab6194b62..ae63f9a29a 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -187,7 +187,7 @@ def run_micropython(pyb, args, test_file, is_special=False): if not is_special and e.args[0] == "exception": output_mupy = e.args[1] + e.args[2] + b"CRASH" else: - output_mupy = b"CRASH" + output_mupy = bytes(e.args[0], "ascii") + b"\nCRASH" # canonical form for all ports/platforms is to use \n for end-of-line output_mupy = output_mupy.replace(b"\r\n", b"\n") From 6e5aea08a9916c5acc6893e4829bba25fbab32ba Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Mar 2021 10:25:16 +1100 Subject: [PATCH 119/174] stm32/Makefile: Allow QSTR_DEFS,QSTR_GLOBAL_DEPENDENCIES to be extended. So a board can provide custom qstr definitions if needed. Signed-off-by: Damien George --- ports/stm32/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 9a66d3c10b..6c71f27573 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -18,8 +18,8 @@ include $(BOARD_DIR)/mpconfigboard.mk QSTR_GENERATED_HEADERS = $(BUILD)/pins_qstr.h $(BUILD)/modstm_qstr.h # qstr definitions (must come before including py.mk) -QSTR_DEFS = qstrdefsport.h $(QSTR_GENERATED_HEADERS) -QSTR_GLOBAL_DEPENDENCIES = mpconfigboard_common.h $(BOARD_DIR)/mpconfigboard.h $(QSTR_GENERATED_HEADERS) +QSTR_DEFS += qstrdefsport.h $(QSTR_GENERATED_HEADERS) +QSTR_GLOBAL_DEPENDENCIES += mpconfigboard_common.h $(BOARD_DIR)/mpconfigboard.h $(QSTR_GENERATED_HEADERS) # MicroPython feature configurations MICROPY_ROM_TEXT_COMPRESSION ?= 1 From 42cf77f48bcb24b0515b4ce604736f10267d87bd Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Mar 2021 10:22:03 +1100 Subject: [PATCH 120/174] py/vm: For tracing use mp_printf, and print state when thread enabled. mp_printf should be used to print the prefix because it's also used in mp_bytecode_print2 (otherwise, depending on the system, different output streams may be used). Also print the current thread state when threading is enabled to easily see which thread executes what opcode. Signed-off-by: Damien George --- py/vm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/py/vm.c b/py/vm.c index 393a2bbbd6..c97070b78b 100644 --- a/py/vm.c +++ b/py/vm.c @@ -39,7 +39,12 @@ // *FORMAT-OFF* #if 0 -#define TRACE(ip) printf("sp=%d ", (int)(sp - &code_state->state[0] + 1)); mp_bytecode_print2(&mp_plat_print, ip, 1, code_state->fun_bc->const_table); +#if MICROPY_PY_THREAD +#define TRACE_PREFIX mp_printf(&mp_plat_print, "ts=%p sp=%d ", mp_thread_get_state(), (int)(sp - &code_state->state[0] + 1)) +#else +#define TRACE_PREFIX mp_printf(&mp_plat_print, "sp=%d ", (int)(sp - &code_state->state[0] + 1)) +#endif +#define TRACE(ip) TRACE_PREFIX; mp_bytecode_print2(&mp_plat_print, ip, 1, code_state->fun_bc->const_table); #else #define TRACE(ip) #endif From 4fc2866f45692b05829d71b636724e690b786307 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 12 Mar 2021 21:03:03 +1100 Subject: [PATCH 121/174] bare-arm: Clean up the code, make it run on an F405, and add a README. This commit simplifies and cleans up the bare-arm port, and adds just enough system and library code to make it execute on an STM32F405 MCU. The mpconfigport.h configuration is simplified to just specify those configuration values that are different from the defaults. And the addition of -fdata-sections and -ffunction-sections means the final firmware is smaller than it previously was, by about 4200 bytes. A README is also added. Signed-off-by: Damien George --- ports/bare-arm/Makefile | 69 ++++++++------- ports/bare-arm/README.md | 21 +++++ ports/bare-arm/lib.c | 128 +++++++++++++++++++++++++++ ports/bare-arm/main.c | 157 +++++++++++----------------------- ports/bare-arm/mpconfigport.h | 118 ++++++++++++------------- ports/bare-arm/qstrdefsport.h | 2 - ports/bare-arm/stm32f405.ld | 93 ++++---------------- ports/bare-arm/system.c | 142 ++++++++++++++++++++++++++++++ 8 files changed, 454 insertions(+), 276 deletions(-) create mode 100644 ports/bare-arm/README.md create mode 100644 ports/bare-arm/lib.c delete mode 100644 ports/bare-arm/qstrdefsport.h create mode 100644 ports/bare-arm/system.c diff --git a/ports/bare-arm/Makefile b/ports/bare-arm/Makefile index 72d5f1a277..455a9dc5ac 100644 --- a/ports/bare-arm/Makefile +++ b/ports/bare-arm/Makefile @@ -1,52 +1,59 @@ +# Include the core environment definitions; this will set $(TOP). include ../../py/mkenv.mk -# qstr definitions (must come before including py.mk) -QSTR_DEFS = qstrdefsport.h - -# MicroPython feature configurations -MICROPY_ROM_TEXT_COMPRESSION ?= 1 - -# include py core make definitions +# Include py core make definitions. include $(TOP)/py/py.mk +# Set makefile-level MicroPython feature configurations. +MICROPY_ROM_TEXT_COMPRESSION ?= 1 + +# Define toolchain and other tools. CROSS_COMPILE ?= arm-none-eabi- +DFU ?= $(TOP)/tools/dfu.py +PYDFU ?= $(TOP)/tools/pydfu.py -INC += -I. -INC += -I$(TOP) -INC += -I$(BUILD) +# Set CFLAGS. +CFLAGS += -I. -I$(TOP) -I$(BUILD) +CFLAGS += -Wall -Werror -std=c99 -nostdlib +CFLAGS += -mthumb -mtune=cortex-m4 -mcpu=cortex-m4 -msoft-float +CSUPEROPT = -Os # save some code space for performance-critical code -CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion -CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT) -CSUPEROPT = -Os # save some code space - -#Debugging/Optimization +# Select debugging or optimisation build. ifeq ($(DEBUG), 1) -CFLAGS += -O0 -ggdb +CFLAGS += -Og else CFLAGS += -Os -DNDEBUG +CFLAGS += -fdata-sections -ffunction-sections endif -LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref -LIBS = +# Set linker flags. +LDFLAGS += -nostdlib -T stm32f405.ld --gc-sections -SRC_C = \ - main.c \ -# printf.c \ - string0.c \ - malloc0.c \ - gccollect.c \ +# Define the required source files. +SRC_C += lib.c main.c system.c -SRC_S = \ -# startup_stm32f40xx.s \ - gchelper.s \ +# Define the required object files. +OBJ += $(PY_CORE_O) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) -OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o)) - -all: $(BUILD)/firmware.elf +# Define the top-level target, the main firmware. +all: $(BUILD)/firmware.dfu $(BUILD)/firmware.elf: $(OBJ) $(ECHO) "LINK $@" - $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(Q)$(SIZE) $@ +$(BUILD)/firmware.bin: $(BUILD)/firmware.elf + $(ECHO) "Create $@" + $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $@ + +$(BUILD)/firmware.dfu: $(BUILD)/firmware.bin + $(ECHO) "Create $@" + $(Q)$(PYTHON) $(DFU) -b 0x08000000:$^ $@ + +deploy: $(BUILD)/firmware.dfu + $(Q)$(PYTHON) $(PYDFU) -u $^ + +# Include remaining core make rules. include $(TOP)/py/mkrules.mk diff --git a/ports/bare-arm/README.md b/ports/bare-arm/README.md new file mode 100644 index 0000000000..496ee9c755 --- /dev/null +++ b/ports/bare-arm/README.md @@ -0,0 +1,21 @@ +The bare-arm port +================= + +This port is intended to be the bare-minimum amount of code and configuration +required to get MicroPython compiling and running on a bare-metal ARM-based +target. No external dependencies or libraries are needed for this build and +it shows exactly what hardware and system functionality MicroPython needs to +run. + +To build, simply run `make` in this directory. The output will be +`build/firmware.elf` (and also corresponding `.bin` and `.dfu` files). This +firmware can run on an STM32F405-based board (eg a PYBv1.x) and `make deploy` +will program it to such an MCU when put in USB DFU mode. The output is a UART +at 115200 baud, with TX on PA0. + +There are some simple demonstration code strings (see `main.c`) which are +compiled and executed when the firmware starts. They produce output on the +system's stdout. + +The size of the firmware (the machine code that is programmed to the +microcontroller's flash/ROM) is currently around 61200 bytes. diff --git a/ports/bare-arm/lib.c b/ports/bare-arm/lib.c new file mode 100644 index 0000000000..ee7c1d765e --- /dev/null +++ b/ports/bare-arm/lib.c @@ -0,0 +1,128 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 + +// These memory functions are needed when the garbage collector is disabled. +// A full implementation should be provided, or the garbage collector enabled. +// The functions here are very simple. + +extern char _heap_start; + +void *malloc(size_t n) { + static char *cur_heap = NULL; + if (cur_heap == NULL) { + cur_heap = &_heap_start; + } + void *ptr = cur_heap; + cur_heap += (n + 7) & ~7; + return ptr; +} + +void *realloc(void *ptr, size_t size) { + void *ptr2 = malloc(size); + if (ptr && size) { + memcpy(ptr2, ptr, size); // size may be greater than ptr's region, do copy anyway + } + return ptr2; +} + +void free(void *p) { +} + +// These standard string functions are needed by the runtime, and can be +// provided either by the system or lib/libc/string0.c. The implementations +// here are very simple. + +int memcmp(const void *s1, const void *s2, size_t n) { + const unsigned char *ss1 = s1, *ss2 = s2; + while (n--) { + int c = *ss1++ - *ss2++; + if (c) { + return c; + } + } + return 0; +} + +void *memcpy(void *dest, const void *src, size_t n) { + return memmove(dest, src, n); +} + +void *memmove(void *dest, const void *src, size_t n) { + unsigned char *d = dest; + const unsigned char *s = src; + if (s < d && d < s + n) { + // Need to copy backwards. + d += n - 1; + s += n - 1; + while (n--) { + *d-- = *s--; + } + } else { + // Can copy forwards. + while (n--) { + *d++ = *s++; + } + } + return dest; +} + +void *memset(void *s, int c, size_t n) { + unsigned char *ss = s; + while (n--) { + *ss++ = c; + } + return s; +} + +char *strchr(const char *s, int c) { + while (*s) { + if (*s == c) { + return (char *)s; + } + ++s; + } + return NULL; +} + +int strcmp(const char *s1, const char *s2) { + while (*s1 && *s2) { + int c = *s1++ - *s2++; + if (c) { + return c; + } + } + return *s1 - *s2; +} + +size_t strlen(const char *s) { + const char *ss = s; + while (*ss) { + ++ss; + } + return ss - s; +} diff --git a/ports/bare-arm/main.c b/ports/bare-arm/main.c index df66c04eff..82c27bd097 100644 --- a/ports/bare-arm/main.c +++ b/ports/bare-arm/main.c @@ -1,15 +1,48 @@ -#include -#include -#include +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2021 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 "py/compile.h" #include "py/runtime.h" -#include "py/repl.h" -#include "py/mperrno.h" -void do_str(const char *src, mp_parse_input_kind_t input_kind) { +static const char *demo_single_input = + "print('hello world!', list(x + 1 for x in range(10)), end='eol\\n')"; + +static const char *demo_file_input = + "import micropython\n" + "\n" + "print(dir(micropython))\n" + "\n" + "for i in range(10):\n" + " print('iter {:08}'.format(i))"; + +static void do_str(const char *src, mp_parse_input_kind_t input_kind) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { + // Compile, parse and execute the given string. mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); @@ -17,121 +50,29 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) { mp_call_function_0(module_fun); nlr_pop(); } else { - // uncaught exception + // Uncaught exception: print it out. mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); } } -int main(int argc, char **argv) { +// Main entry point: initialise the runtime and execute demo strings. +void bare_main(void) { mp_init(); - do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')", MP_PARSE_SINGLE_INPUT); - do_str("for i in range(10):\n print(i)", MP_PARSE_FILE_INPUT); + do_str(demo_single_input, MP_PARSE_SINGLE_INPUT); + do_str(demo_file_input, MP_PARSE_FILE_INPUT); mp_deinit(); - return 0; } -mp_lexer_t *mp_lexer_new_from_file(const char *filename) { - mp_raise_OSError(MP_ENOENT); -} - -mp_import_stat_t mp_import_stat(const char *path) { - return MP_IMPORT_STAT_NO_EXIST; -} - -mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); - +// Called if an exception is raised outside all C exception-catching handlers. void nlr_jump_fail(void *val) { - while (1) { - ; - } -} - -void NORETURN __fatal_error(const char *msg) { - while (1) { - ; + for (;;) { } } #ifndef NDEBUG +// Used when debugging is enabled. void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { - printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); - __fatal_error("Assertion failed"); + for (;;) { + } } #endif - -/* -int _lseek() {return 0;} -int _read() {return 0;} -int _write() {return 0;} -int _close() {return 0;} -void _exit(int x) {for(;;){}} -int _sbrk() {return 0;} -int _kill() {return 0;} -int _getpid() {return 0;} -int _fstat() {return 0;} -int _isatty() {return 0;} -*/ - -void *malloc(size_t n) { - return NULL; -} -void *calloc(size_t nmemb, size_t size) { - return NULL; -} -void *realloc(void *ptr, size_t size) { - return NULL; -} -void free(void *p) { -} -int printf(const char *m, ...) { - return 0; -} -void *memcpy(void *dest, const void *src, size_t n) { - return NULL; -} -int memcmp(const void *s1, const void *s2, size_t n) { - return 0; -} -void *memmove(void *dest, const void *src, size_t n) { - return NULL; -} -void *memset(void *s, int c, size_t n) { - return NULL; -} -int strcmp(const char *s1, const char *s2) { - return 0; -} -int strncmp(const char *s1, const char *s2, size_t n) { - return 0; -} -size_t strlen(const char *s) { - return 0; -} -char *strcat(char *dest, const char *src) { - return NULL; -} -char *strchr(const char *dest, int c) { - return NULL; -} -#include -int vprintf(const char *format, va_list ap) { - return 0; -} -int vsnprintf(char *str, size_t size, const char *format, va_list ap) { - return 0; -} - -#undef putchar -int putchar(int c) { - return 0; -} -int puts(const char *s) { - return 0; -} - -void _start(void) { - main(0, NULL); -} diff --git a/ports/bare-arm/mpconfigport.h b/ports/bare-arm/mpconfigport.h index 7fd236bfba..41b6ee71a3 100644 --- a/ports/bare-arm/mpconfigport.h +++ b/ports/bare-arm/mpconfigport.h @@ -1,71 +1,71 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2021 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 -// options to control how MicroPython is built +// Options to control how MicroPython is built -#define MICROPY_QSTR_BYTES_IN_HASH (1) -#define MICROPY_ALLOC_PATH_MAX (512) -#define MICROPY_EMIT_X64 (0) -#define MICROPY_EMIT_THUMB (0) -#define MICROPY_EMIT_INLINE_THUMB (0) -#define MICROPY_COMP_MODULE_CONST (0) -#define MICROPY_COMP_CONST (0) -#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) -#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) -#define MICROPY_MEM_STATS (0) -#define MICROPY_DEBUG_PRINTERS (0) -#define MICROPY_ENABLE_GC (0) -#define MICROPY_HELPER_REPL (0) -#define MICROPY_HELPER_LEXER_UNIX (0) -#define MICROPY_ENABLE_SOURCE_LINE (0) -#define MICROPY_ENABLE_DOC_STRING (0) -#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) -#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0) -#define MICROPY_PY_ASYNC_AWAIT (0) -#define MICROPY_PY_ASSIGN_EXPR (0) -#define MICROPY_PY_BUILTINS_BYTEARRAY (0) -#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (0) -#define MICROPY_PY_BUILTINS_MEMORYVIEW (0) -#define MICROPY_PY_BUILTINS_ENUMERATE (0) -#define MICROPY_PY_BUILTINS_FROZENSET (0) -#define MICROPY_PY_BUILTINS_REVERSED (0) -#define MICROPY_PY_BUILTINS_SET (0) -#define MICROPY_PY_BUILTINS_SLICE (0) -#define MICROPY_PY_BUILTINS_PROPERTY (0) -#define MICROPY_PY_BUILTINS_STR_COUNT (0) -#define MICROPY_PY_BUILTINS_STR_OP_MODULO (0) -#define MICROPY_PY___FILE__ (0) -#define MICROPY_PY_GC (0) -#define MICROPY_PY_ARRAY (0) -#define MICROPY_PY_ATTRTUPLE (0) -#define MICROPY_PY_COLLECTIONS (0) -#define MICROPY_PY_MATH (0) -#define MICROPY_PY_CMATH (0) -#define MICROPY_PY_IO (0) -#define MICROPY_PY_STRUCT (0) -#define MICROPY_PY_SYS (0) -#define MICROPY_CPYTHON_COMPAT (0) -#define MICROPY_MODULE_GETATTR (0) -#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) -#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) -#define MICROPY_USE_INTERNAL_PRINTF (0) +// Memory allocation policy +#define MICROPY_QSTR_BYTES_IN_HASH (1) -// type definitions for the specific machine +// Compiler configuration +#define MICROPY_COMP_CONST (0) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) -#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1)) +// Python internal features +#define MICROPY_ENABLE_EXTERNAL_IMPORT (0) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_MODULE_GETATTR (0) +#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0) -#define UINT_FMT "%lu" -#define INT_FMT "%ld" +// Fine control over Python builtins, classes, modules, etc +#define MICROPY_PY_ASYNC_AWAIT (0) +#define MICROPY_PY_ASSIGN_EXPR (0) +#define MICROPY_PY_BUILTINS_STR_COUNT (0) +#define MICROPY_PY_BUILTINS_STR_OP_MODULO (0) +#define MICROPY_PY_BUILTINS_BYTEARRAY (0) +#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (0) +#define MICROPY_PY_BUILTINS_SET (0) +#define MICROPY_PY_BUILTINS_SLICE (0) +#define MICROPY_PY_BUILTINS_PROPERTY (0) +#define MICROPY_PY_BUILTINS_ENUMERATE (0) +#define MICROPY_PY_BUILTINS_REVERSED (0) +#define MICROPY_PY___FILE__ (0) +#define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_STRUCT (0) +#define MICROPY_PY_SYS (0) + +// Type definitions for the specific machine typedef int32_t mp_int_t; // must be pointer size typedef uint32_t mp_uint_t; // must be pointer size typedef long mp_off_t; -// dummy print -#define MP_PLAT_PRINT_STRN(str, len) (void)0 - -// extra built in names to add to the global namespace -#define MICROPY_PORT_BUILTINS \ - { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, - -// We need to provide a declaration/definition of alloca() +// Need to provide a declaration/definition of alloca() #include diff --git a/ports/bare-arm/qstrdefsport.h b/ports/bare-arm/qstrdefsport.h deleted file mode 100644 index 00d3e2ae3c..0000000000 --- a/ports/bare-arm/qstrdefsport.h +++ /dev/null @@ -1,2 +0,0 @@ -// qstrs specific to this port -// *FORMAT-OFF* diff --git a/ports/bare-arm/stm32f405.ld b/ports/bare-arm/stm32f405.ld index dd688a0246..33a5502d60 100644 --- a/ports/bare-arm/stm32f405.ld +++ b/ports/bare-arm/stm32f405.ld @@ -1,117 +1,58 @@ -/* - GNU linker script for STM32F405 -*/ +/* GNU linker script for STM32F405 */ -/* Specify the memory areas */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x100000 /* entire flash, 1 MiB */ - FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 0x004000 /* sector 0, 16 KiB */ - FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 0x080000 /* sectors 5,6,7,8, 4*128KiB = 512 KiB (could increase it more) */ - CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 0x010000 /* 64 KiB */ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x020000 /* 128 KiB */ } -/* top end of the stack */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* RAM extents for the garbage collector */ -_ram_end = ORIGIN(RAM) + LENGTH(RAM); -_heap_end = 0x2001c000; /* tunable */ - -/* define output sections */ SECTIONS { - /* The startup code goes first into FLASH */ .isr_vector : { . = ALIGN(4); - KEEP(*(.isr_vector)) /* Startup code */ - + KEEP(*(.isr_vector)) . = ALIGN(4); - } >FLASH_ISR + } >FLASH - /* The program code and other data goes into FLASH */ .text : { . = ALIGN(4); - *(.text) /* .text sections (code) */ - *(.text*) /* .text* sections (code) */ - *(.rodata) /* .rodata sections (constants, strings, etc.) */ - *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ - /* *(.glue_7) */ /* glue arm to thumb code */ - /* *(.glue_7t) */ /* glue thumb to arm code */ - + *(.text) + *(.text*) + *(.rodata) + *(.rodata*) . = ALIGN(4); - _etext = .; /* define a global symbol at end of code */ - _sidata = _etext; /* This is used by the startup in order to initialize the .data secion */ - } >FLASH_TEXT - - /* - .ARM.extab : - { - *(.ARM.extab* .gnu.linkonce.armextab.*) + _etext = .; + _sidata = _etext; } >FLASH - .ARM : - { - __exidx_start = .; - *(.ARM.exidx*) - __exidx_end = .; - } >FLASH - */ - - /* This is the initialized data section - The program executes knowing that the data is in the RAM - but the loader puts the initial values in the FLASH (inidata). - It is one task of the startup to copy the initial values from FLASH to RAM. */ .data : AT ( _sidata ) { . = ALIGN(4); - _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ - _ram_start = .; /* create a global symbol at ram start for garbage collector */ - *(.data) /* .data sections */ - *(.data*) /* .data* sections */ - + _sdata = .; + *(.data) + *(.data*) . = ALIGN(4); - _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ + _edata = .; } >RAM - /* Uninitialized data section */ .bss : { . = ALIGN(4); - _sbss = .; /* define a global symbol at bss start; used by startup code */ + _sbss = .; *(.bss) *(.bss*) *(COMMON) - . = ALIGN(4); - _ebss = .; /* define a global symbol at bss end; used by startup code */ + _ebss = .; } >RAM - /* this is to define the start of the heap, and make sure we have a minimum size */ .heap : { - . = ALIGN(4); - _heap_start = .; /* define a global symbol at heap start */ + . = ALIGN(8); + _heap_start = .; } >RAM - - /* this just checks there is enough RAM for the stack */ - .stack : - { - . = ALIGN(4); - } >RAM - - /* Remove information from the standard libraries */ - /* - /DISCARD/ : - { - libc.a ( * ) - libm.a ( * ) - libgcc.a ( * ) - } - */ - - .ARM.attributes 0 : { *(.ARM.attributes) } } diff --git a/ports/bare-arm/system.c b/ports/bare-arm/system.c new file mode 100644 index 0000000000..f66dd2d80a --- /dev/null +++ b/ports/bare-arm/system.c @@ -0,0 +1,142 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 + +#define RCC ((periph_rcc_t *)0x40023800) +#define GPIOA ((periph_gpio_t *)0x40020000) +#define UART4 ((periph_uart_t *)0x40004C00) + +typedef struct { + volatile uint32_t CR; + volatile uint32_t PLLCFGR; + volatile uint32_t CFGR; + volatile uint32_t CIR; + uint32_t _1[8]; + volatile uint32_t AHB1ENR; + volatile uint32_t AHB2ENR; + volatile uint32_t AHB3ENR; + uint32_t _2; + volatile uint32_t APB1ENR; + volatile uint32_t APB2ENR; +} periph_rcc_t; + +typedef struct { + volatile uint32_t MODER; + volatile uint32_t OTYPER; + volatile uint32_t OSPEEDR; + volatile uint32_t PUPDR; + volatile uint32_t IDR; + volatile uint32_t ODR; + volatile uint16_t BSRRL; + volatile uint16_t BSRRH; + volatile uint32_t LCKR; + volatile uint32_t AFR[2]; +} periph_gpio_t; + +typedef struct { + volatile uint32_t SR; + volatile uint32_t DR; + volatile uint32_t BRR; + volatile uint32_t CR1; +} periph_uart_t; + +extern uint32_t _estack, _sidata, _sdata, _edata, _sbss, _ebss; + +void Reset_Handler(void) __attribute__((naked)); +void bare_main(void); + +static void stm32_init(void); +static void gpio_init_alt(periph_gpio_t *gpio, int pin, int alt); + +// Very simple ARM vector table. +const uint32_t isr_vector[] __attribute__((section(".isr_vector"))) = { + (uint32_t)&_estack, + (uint32_t)&Reset_Handler, +}; + +// The CPU runs this function after a reset. +void Reset_Handler(void) { + // Set stack pointer. + __asm volatile ("ldr sp, =_estack"); + + // Copy .data section from flash to RAM. + memcpy(&_sdata, &_sidata, (char *)&_edata - (char *)&_sdata); + + // Zero out .bss section. + memset(&_sbss, 0, (char *)&_ebss - (char *)&_sbss); + + // SCB->CCR: enable 8-byte stack alignment for IRQ handlers, in accord with EABI. + *((volatile uint32_t *)0xe000ed14) |= 1 << 9; + + // Initialise the cpu and peripherals. + stm32_init(); + + // Now that there is a basic system up and running, call the main application code. + bare_main(); + + // This function must not return. + for (;;) { + } +} + +// Set up the STM32 MCU. +static void stm32_init(void) { + // Note: default clock is internal 16MHz. + RCC->AHB1ENR |= 1 << 0; // GPIOAEN + RCC->APB1ENR |= 1 << 19; // UART4EN + gpio_init_alt(GPIOA, 0, 8); + UART4->BRR = (8 << 4) | 11; // 16MHz/(16*8.6875) = 115107 baud + UART4->CR1 = 0x00002008; // USART enable, tx enable, rx enable +} + +// Configure a GPIO pin in alternate-function mode. +static void gpio_init_alt(periph_gpio_t *gpio, int pin, int alt) { + gpio->MODER = (gpio->MODER & ~(3 << (2 * pin))) | (2 << (2 * pin)); + // OTYPER is left as default push-pull + // OSPEEDR is left as default low speed + // PUPDR is left as default no-pull + gpio->AFR[pin >> 3] = (gpio->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7))); +} + +// Write a character out to the UART. +static inline void uart_write_char(int c) { + // Wait for TXE, then write the character. + while ((UART4->SR & (1 << 7)) == 0) { + } + UART4->DR = c; +} + +// Send string of given length to stdout, converting \n to \r\n. +void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { + while (len--) { + if (*str == '\n') { + uart_write_char('\r'); + } + uart_write_char(*str++); + } +} From 9fef1c0bde2f9642d383bd56aa112447384a84ba Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 26 Mar 2021 13:48:34 +1100 Subject: [PATCH 122/174] py: Rename remaining object types to be of the form mp_type_xxx. For consistency with all other object types in the core. Signed-off-by: Damien George --- py/modio.c | 4 ++-- py/objarray.c | 4 ++-- py/objclosure.c | 4 ++-- py/objdict.c | 20 ++++++++++---------- py/objgetitemiter.c | 4 ++-- py/objrange.c | 4 ++-- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/py/modio.c b/py/modio.c index 8a18357e24..7f0d13cdfa 100644 --- a/py/modio.c +++ b/py/modio.c @@ -195,7 +195,7 @@ STATIC const mp_stream_p_t bufwriter_stream_p = { .write = bufwriter_write, }; -STATIC const mp_obj_type_t bufwriter_type = { +STATIC const mp_obj_type_t mp_type_bufwriter = { { &mp_type_type }, .name = MP_QSTR_BufferedWriter, .make_new = bufwriter_make_new, @@ -270,7 +270,7 @@ STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_BytesIO), MP_ROM_PTR(&mp_type_bytesio) }, #endif #if MICROPY_PY_IO_BUFFEREDWRITER - { MP_ROM_QSTR(MP_QSTR_BufferedWriter), MP_ROM_PTR(&bufwriter_type) }, + { MP_ROM_QSTR(MP_QSTR_BufferedWriter), MP_ROM_PTR(&mp_type_bufwriter) }, #endif }; diff --git a/py/objarray.c b/py/objarray.c index 4947f75905..c27366d720 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -634,7 +634,7 @@ STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) { } } -STATIC const mp_obj_type_t array_it_type = { +STATIC const mp_obj_type_t mp_type_array_it = { { &mp_type_type }, .name = MP_QSTR_iterator, .getiter = mp_identity_getiter, @@ -645,7 +645,7 @@ STATIC mp_obj_t array_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_bu assert(sizeof(mp_obj_array_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_array_t *array = MP_OBJ_TO_PTR(array_in); mp_obj_array_it_t *o = (mp_obj_array_it_t *)iter_buf; - o->base.type = &array_it_type; + o->base.type = &mp_type_array_it; o->array = array; o->offset = 0; o->cur = 0; diff --git a/py/objclosure.c b/py/objclosure.c index 9a8c7631c2..054b657896 100644 --- a/py/objclosure.c +++ b/py/objclosure.c @@ -78,7 +78,7 @@ STATIC void closure_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_ } #endif -const mp_obj_type_t closure_type = { +const mp_obj_type_t mp_type_closure = { { &mp_type_type }, .flags = MP_TYPE_FLAG_BINDS_SELF, .name = MP_QSTR_closure, @@ -90,7 +90,7 @@ const mp_obj_type_t closure_type = { mp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed_over, const mp_obj_t *closed) { mp_obj_closure_t *o = m_new_obj_var(mp_obj_closure_t, mp_obj_t, n_closed_over); - o->base.type = &closure_type; + o->base.type = &mp_type_closure; o->fun = fun; o->n_closed = n_closed_over; memcpy(o->closed, closed, n_closed_over * sizeof(mp_obj_t)); diff --git a/py/objdict.c b/py/objdict.c index 4e51f259e7..aea5952d3d 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -408,8 +408,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dict_update_obj, 1, dict_update); /******************************************************************************/ /* dict views */ -STATIC const mp_obj_type_t dict_view_type; -STATIC const mp_obj_type_t dict_view_it_type; +STATIC const mp_obj_type_t mp_type_dict_view; +STATIC const mp_obj_type_t mp_type_dict_view_it; typedef enum _mp_dict_view_kind_t { MP_DICT_VIEW_ITEMS, @@ -433,7 +433,7 @@ typedef struct _mp_obj_dict_view_t { } mp_obj_dict_view_t; STATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) { - mp_check_self(mp_obj_is_type(self_in, &dict_view_it_type)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_dict_view_it)); mp_obj_dict_view_it_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *next = dict_iter_next(MP_OBJ_TO_PTR(self->dict), &self->cur); @@ -454,7 +454,7 @@ STATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) { } } -STATIC const mp_obj_type_t dict_view_it_type = { +STATIC const mp_obj_type_t mp_type_dict_view_it = { { &mp_type_type }, .name = MP_QSTR_iterator, .getiter = mp_identity_getiter, @@ -463,10 +463,10 @@ STATIC const mp_obj_type_t dict_view_it_type = { STATIC mp_obj_t dict_view_getiter(mp_obj_t view_in, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t)); - mp_check_self(mp_obj_is_type(view_in, &dict_view_type)); + mp_check_self(mp_obj_is_type(view_in, &mp_type_dict_view)); mp_obj_dict_view_t *view = MP_OBJ_TO_PTR(view_in); mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t *)iter_buf; - o->base.type = &dict_view_it_type; + o->base.type = &mp_type_dict_view_it; o->kind = view->kind; o->dict = view->dict; o->cur = 0; @@ -475,7 +475,7 @@ STATIC mp_obj_t dict_view_getiter(mp_obj_t view_in, mp_obj_iter_buf_t *iter_buf) STATIC void dict_view_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; - mp_check_self(mp_obj_is_type(self_in, &dict_view_type)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_dict_view)); mp_obj_dict_view_t *self = MP_OBJ_TO_PTR(self_in); bool first = true; mp_print_str(print, mp_dict_view_names[self->kind]); @@ -505,7 +505,7 @@ STATIC mp_obj_t dict_view_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t return dict_binary_op(op, o->dict, rhs_in); } -STATIC const mp_obj_type_t dict_view_type = { +STATIC const mp_obj_type_t mp_type_dict_view = { { &mp_type_type }, .name = MP_QSTR_dict_view, .print = dict_view_print, @@ -515,7 +515,7 @@ STATIC const mp_obj_type_t dict_view_type = { STATIC mp_obj_t mp_obj_new_dict_view(mp_obj_t dict, mp_dict_view_kind_t kind) { mp_obj_dict_view_t *o = m_new_obj(mp_obj_dict_view_t); - o->base.type = &dict_view_type; + o->base.type = &mp_type_dict_view; o->dict = dict; o->kind = kind; return MP_OBJ_FROM_PTR(o); @@ -548,7 +548,7 @@ STATIC mp_obj_t dict_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t)); mp_check_self(mp_obj_is_dict_or_ordereddict(self_in)); mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t *)iter_buf; - o->base.type = &dict_view_it_type; + o->base.type = &mp_type_dict_view_it; o->kind = MP_DICT_VIEW_KEYS; o->dict = self_in; o->cur = 0; diff --git a/py/objgetitemiter.c b/py/objgetitemiter.c index 54e27b8f11..2670314ab2 100644 --- a/py/objgetitemiter.c +++ b/py/objgetitemiter.c @@ -57,7 +57,7 @@ STATIC mp_obj_t it_iternext(mp_obj_t self_in) { } } -STATIC const mp_obj_type_t it_type = { +STATIC const mp_obj_type_t mp_type_it = { { &mp_type_type }, .name = MP_QSTR_iterator, .getiter = mp_identity_getiter, @@ -68,7 +68,7 @@ STATIC const mp_obj_type_t it_type = { mp_obj_t mp_obj_new_getitem_iter(mp_obj_t *args, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_getitem_iter_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_getitem_iter_t *o = (mp_obj_getitem_iter_t *)iter_buf; - o->base.type = &it_type; + o->base.type = &mp_type_it; o->args[0] = args[0]; o->args[1] = args[1]; o->args[2] = MP_OBJ_NEW_SMALL_INT(0); diff --git a/py/objrange.c b/py/objrange.c index 4eed4b9410..1f028eb867 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -50,7 +50,7 @@ STATIC mp_obj_t range_it_iternext(mp_obj_t o_in) { } } -STATIC const mp_obj_type_t range_it_type = { +STATIC const mp_obj_type_t mp_type_range_it = { { &mp_type_type }, .name = MP_QSTR_iterator, .getiter = mp_identity_getiter, @@ -60,7 +60,7 @@ STATIC const mp_obj_type_t range_it_type = { STATIC mp_obj_t mp_obj_new_range_iterator(mp_int_t cur, mp_int_t stop, mp_int_t step, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_range_it_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_range_it_t *o = (mp_obj_range_it_t *)iter_buf; - o->base.type = &range_it_type; + o->base.type = &mp_type_range_it; o->cur = cur; o->stop = stop; o->step = step; From ccc388f157eacfea6b5c44e1b6049a2bbeb44734 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 23 Feb 2021 22:56:44 +0000 Subject: [PATCH 123/174] rp2/mpthreadport.h: Cast core_state to _mp_state_thread_t. Required for user C++ code to build successfully against ports/rp2. Signed-off-by: Phil Howard --- ports/rp2/mpthreadport.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/rp2/mpthreadport.h b/ports/rp2/mpthreadport.h index 4583f6f539..5eb0bff396 100644 --- a/ports/rp2/mpthreadport.h +++ b/ports/rp2/mpthreadport.h @@ -41,7 +41,7 @@ static inline void mp_thread_set_state(struct _mp_state_thread_t *state) { } static inline struct _mp_state_thread_t *mp_thread_get_state(void) { - return core_state[get_core_num()]; + return (struct _mp_state_thread_t *)core_state[get_core_num()]; } static inline void mp_thread_mutex_init(mp_thread_mutex_t *m) { From 0cf12dd59c9ddddbd602d4267410033cb5a9d265 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 23 Feb 2021 22:57:14 +0000 Subject: [PATCH 124/174] rp2: Add support for USER_C_MODULES to CMake build system. The parts that are generic are added to py/ so they can be used by other ports that use CMake. py/usermod.cmake: * Creates a usermod target to hang user C/CXX modules from. * Gathers sources from user C/CXX modules and libs for QSTR scan. ports/rp2/CMakeLists.txt: * Includes py/usermod.cmake. * Links the resulting usermod library to the MicroPython target. py/mkrules.cmake: Add cxxflags to qstr.i.last custom command for CXX modules: * MICROPY_CPP_FLAGS so CXX modules will find includes. * -DNO_QSTR to fix fatal error missing "genhdr/qstrdefs.generated.h". Usage: The rp2 port can be linked against user C modules by running: make USER_C_MODULES=/path/to/module/micropython.cmake CMake will print a list of included modules. Co-authored-by: Graham Sanderson Co-authored-by: Michael O'Cleirigh Signed-off-by: Phil Howard --- ports/rp2/CMakeLists.txt | 6 +++++ ports/rp2/Makefile | 8 ++++++- py/mkrules.cmake | 2 +- py/usermod.cmake | 52 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 py/usermod.cmake diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 3968194dcb..3db0e6b62a 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -27,6 +27,8 @@ project(${MICROPY_TARGET}) pico_sdk_init() +include(${MICROPY_DIR}/py/usermod.cmake) + add_executable(${MICROPY_TARGET}) set(MICROPY_QSTRDEFS_PORT @@ -80,6 +82,7 @@ set(MICROPY_SOURCE_PORT set(MICROPY_SOURCE_QSTR ${MICROPY_SOURCE_PY} ${MICROPY_SOURCE_EXTMOD} + ${MICROPY_SOURCE_USERMOD} ${MICROPY_DIR}/lib/utils/mpirq.c ${MICROPY_DIR}/lib/utils/sys_stdio_mphal.c ${PROJECT_SOURCE_DIR}/machine_adc.c @@ -142,7 +145,10 @@ target_sources(${MICROPY_TARGET} PRIVATE ${MICROPY_SOURCE_PORT} ) +target_link_libraries(${MICROPY_TARGET} usermod) + target_include_directories(${MICROPY_TARGET} PRIVATE + ${MICROPY_INC_USERMOD} "${PROJECT_SOURCE_DIR}" "${MICROPY_DIR}" "${CMAKE_BINARY_DIR}" diff --git a/ports/rp2/Makefile b/ports/rp2/Makefile index 08cd53dcca..3358c4ccae 100644 --- a/ports/rp2/Makefile +++ b/ports/rp2/Makefile @@ -6,8 +6,14 @@ BUILD = build $(VERBOSE)MAKESILENT = -s +CMAKE_ARGS = + +ifdef USER_C_MODULES +CMAKE_ARGS += -DUSER_C_MODULES=${USER_C_MODULES} +endif + all: - [ -d $(BUILD) ] || cmake -S . -B $(BUILD) -DPICO_BUILD_DOCS=0 + [ -d $(BUILD) ] || cmake -S . -B $(BUILD) -DPICO_BUILD_DOCS=0 ${CMAKE_ARGS} $(MAKE) $(MAKESILENT) -C $(BUILD) clean: diff --git a/py/mkrules.cmake b/py/mkrules.cmake index 9c4c4afabe..f20240c62b 100644 --- a/py/mkrules.cmake +++ b/py/mkrules.cmake @@ -69,7 +69,7 @@ add_custom_command( # it was last run, but it looks like it's not possible to specify that with cmake. add_custom_command( OUTPUT ${MICROPY_QSTRDEFS_LAST} - COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py pp ${CMAKE_C_COMPILER} -E output ${MICROPY_GENHDR_DIR}/qstr.i.last cflags ${MICROPY_CPP_FLAGS} -DNO_QSTR sources ${MICROPY_SOURCE_QSTR} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py pp ${CMAKE_C_COMPILER} -E output ${MICROPY_GENHDR_DIR}/qstr.i.last cflags ${MICROPY_CPP_FLAGS} -DNO_QSTR cxxflags ${MICROPY_CPP_FLAGS} -DNO_QSTR sources ${MICROPY_SOURCE_QSTR} DEPENDS ${MICROPY_MODULEDEFS} ${MICROPY_SOURCE_QSTR} VERBATIM diff --git a/py/usermod.cmake b/py/usermod.cmake new file mode 100644 index 0000000000..8532762837 --- /dev/null +++ b/py/usermod.cmake @@ -0,0 +1,52 @@ +# Create a target for all user modules to link against. +add_library(usermod INTERFACE) + +function(usermod_gather_sources SOURCES_VARNAME INCLUDE_DIRECTORIES_VARNAME INCLUDED_VARNAME LIB) + if (NOT ${LIB} IN_LIST ${INCLUDED_VARNAME}) + list(APPEND ${INCLUDED_VARNAME} ${LIB}) + + # Gather library sources + get_target_property(lib_sources ${LIB} INTERFACE_SOURCES) + if (lib_sources) + list(APPEND ${SOURCES_VARNAME} ${lib_sources}) + endif() + + # Gather library includes + get_target_property(lib_include_directories ${LIB} INTERFACE_INCLUDE_DIRECTORIES) + if (lib_include_directories) + list(APPEND ${INCLUDE_DIRECTORIES_VARNAME} ${lib_include_directories}) + endif() + + # Recurse linked libraries + get_target_property(trans_depend ${LIB} INTERFACE_LINK_LIBRARIES) + if (trans_depend) + foreach(SUB_LIB ${trans_depend}) + usermod_gather_sources( + ${SOURCES_VARNAME} + ${INCLUDE_DIRECTORIES_VARNAME} + ${INCLUDED_VARNAME} + ${SUB_LIB}) + endforeach() + endif() + + set(${SOURCES_VARNAME} ${${SOURCES_VARNAME}} PARENT_SCOPE) + set(${INCLUDE_DIRECTORIES_VARNAME} ${${INCLUDE_DIRECTORIES_VARNAME}} PARENT_SCOPE) + set(${INCLUDED_VARNAME} ${${INCLUDED_VARNAME}} PARENT_SCOPE) + endif() +endfunction() + +# Include CMake files for user modules. +if (USER_C_MODULES) + foreach(USER_C_MODULE_PATH ${USER_C_MODULES}) + message("Including User C Module(s) from ${USER_C_MODULE_PATH}") + include(${USER_C_MODULE_PATH}) + endforeach() +endif() + +# Recursively gather sources for QSTR scanning - doesn't support generator expressions. +usermod_gather_sources(MICROPY_SOURCE_USERMOD MICROPY_INC_USERMOD found_modules usermod) + +# Report found modules. +list(REMOVE_ITEM found_modules "usermod") +list(JOIN found_modules ", " found_modules) +message("Found User C Module(s): ${found_modules}") From cc497d4c6a7bbf491fbc57b9447632bddff8d566 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 23 Feb 2021 23:06:04 +0000 Subject: [PATCH 125/174] examples/usercmodule: Add micropython.cmake to the C and CPP examples. examples/usercmodule/micropython.cmake: Root micropython.cmake file is responsible for including modules. examples/usercmodule/cexample/micropython.cmake: examples/usercmodule/cppexample/micropython.cmake: Module micropython.cmake files define the target and link it to usermod. Signed-off-by: Phil Howard --- .../usercmodule/cexample/micropython.cmake | 21 ++++++++++++++++++ .../usercmodule/cppexample/micropython.cmake | 22 +++++++++++++++++++ examples/usercmodule/micropython.cmake | 11 ++++++++++ 3 files changed, 54 insertions(+) create mode 100644 examples/usercmodule/cexample/micropython.cmake create mode 100644 examples/usercmodule/cppexample/micropython.cmake create mode 100644 examples/usercmodule/micropython.cmake diff --git a/examples/usercmodule/cexample/micropython.cmake b/examples/usercmodule/cexample/micropython.cmake new file mode 100644 index 0000000000..371a3eefa4 --- /dev/null +++ b/examples/usercmodule/cexample/micropython.cmake @@ -0,0 +1,21 @@ +# Create an INTERFACE library for our C module. +add_library(usermod_cexample INTERFACE) + +# Add our source files to the lib +target_sources(usermod_cexample INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/examplemodule.c +) + +# Add the current directory as an include directory. +target_include_directories(usermod_cexample INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +# Enable the module automatically by adding the relevant compile definitions. +target_compile_definitions(usermod_cexample INTERFACE + MODULE_CEXAMPLE_ENABLED=1 +) + +# Link our INTERFACE library to the usermod target. +target_link_libraries(usermod INTERFACE usermod_cexample) + diff --git a/examples/usercmodule/cppexample/micropython.cmake b/examples/usercmodule/cppexample/micropython.cmake new file mode 100644 index 0000000000..43e8d887f5 --- /dev/null +++ b/examples/usercmodule/cppexample/micropython.cmake @@ -0,0 +1,22 @@ +# Create an INTERFACE library for our CPP module. +add_library(usermod_cppexample INTERFACE) + +# Add our source files to the library. +target_sources(usermod_cppexample INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/example.cpp + ${CMAKE_CURRENT_LIST_DIR}/examplemodule.c +) + +# Add the current directory as an include directory. +target_include_directories(usermod_cppexample INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +# Enable the module automatically by adding the relevant compile definitions. +target_compile_definitions(usermod_cppexample INTERFACE + MODULE_CPPEXAMPLE_ENABLED=1 +) + +# Link our INTERFACE library to the usermod target. +target_link_libraries(usermod INTERFACE usermod_cppexample) + diff --git a/examples/usercmodule/micropython.cmake b/examples/usercmodule/micropython.cmake new file mode 100644 index 0000000000..ad88d77806 --- /dev/null +++ b/examples/usercmodule/micropython.cmake @@ -0,0 +1,11 @@ +# This top-level micropython.cmake is responsible for listing +# the individual modules we want to include. +# Paths are absolute, and ${CMAKE_CURRENT_LIST_DIR} can be +# used to prefix subdirectories. + +# Add the C example. +include(${CMAKE_CURRENT_LIST_DIR}/cexample/micropython.cmake) + +# Add the CPP example. +include(${CMAKE_CURRENT_LIST_DIR}/cppexample/micropython.cmake) + From 8e5756e2b6d03805bf9f40cd1128c0cd6214e07c Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 24 Feb 2021 12:57:53 +0000 Subject: [PATCH 126/174] docs/develop/cmodules.rst: Document C-modules and micropython.cmake. Documents the micropython.cmake file required to make user C modules compatible with the CMake build system. Signed-off-by: Phil Howard --- docs/develop/cmodules.rst | 76 ++++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/docs/develop/cmodules.rst b/docs/develop/cmodules.rst index 2db1f65f2e..dd02f1439c 100644 --- a/docs/develop/cmodules.rst +++ b/docs/develop/cmodules.rst @@ -53,6 +53,30 @@ A MicroPython user C module is a directory with the following files: for header files), these should be added to ``CFLAGS_USERMOD`` for C code and to ``CXXFLAGS_USERMOD`` for C++ code. +* ``micropython.cmake`` contains the CMake configuration for this module. + + In ``micropython.cmake``, you may use ``${CMAKE_CURRENT_LIST_DIR}`` as the path to + the current module. + + Your ``micropython.cmake`` should define an ``INTERFACE`` library and associate + your source files, compile definitions and include directories with it. + The library should then be linked to the ``usermod`` target. + + .. code-block:: cmake + + add_library(usermod_cexample INTERFACE) + + target_sources(usermod_cexample INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/examplemodule.c + ) + + target_include_directories(usermod_cexample INTERFACE + ${CMAKE_CURRENT_LIST_DIR} + ) + + target_link_libraries(usermod INTERFACE usermod_cexample) + + See below for full usage example. @@ -70,9 +94,11 @@ and has a source file and a Makefile fragment with content as descibed above:: └──usercmodule/ └──cexample/ ├── examplemodule.c - └── micropython.mk + ├── micropython.mk + └── micropython.cmake -Refer to the comments in these 2 files for additional explanation. + +Refer to the comments in these files for additional explanation. Next to the ``cexample`` module there's also ``cppexample`` which works in the same way but shows one way of mixing C and C++ code in MicroPython. @@ -97,10 +123,13 @@ applying 2 modifications: ├── modules/ │ └──example1/ │ ├──example1.c - │ └──micropython.mk + │ ├──micropython.mk + │ └──micropython.cmake │ └──example2/ │ ├──example2.c - │ └──micropython.mk + │ ├──micropython.mk + │ └──micropython.cmake + │ └──micropython.cmake └── micropython/ ├──ports/ ... ├──stm32/ @@ -109,10 +138,21 @@ applying 2 modifications: with ``USER_C_MODULES`` set to the ``my_project/modules`` directory. -- all modules found in this directory will be compiled, but only those - which are explicitly enabled will be availabe for importing. Enabling a - module is done by setting the preprocessor define from its module - registration to 1. For example if the source code defines the module with + A top level ``micropython.cmake`` - found directly in the ``my_project/modules`` + directory - should ``include`` all of your modules. + + .. code-block:: cmake + + include(${CMAKE_CURRENT_LIST_DIR}/example1/micropython.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/example2/micropython.cmake) + + +- all modules found in this directory (or added via ``include`` in the top-level + ``micropython.cmake`` when using CMake) will be compiled, but only those which are + explicitly enabled will be available for importing. Enabling a module is done + by setting the preprocessor define from its module registration to 1. + + For example if the source code defines the module with .. code-block:: c @@ -149,6 +189,26 @@ The build output will show the modules found:: ... +For a CMake-based port such as rp2, this will look a little different: + +.. code-block:: bash + + cd micropython/ports/rp2 + make USER_C_MODULES=../../examples/usercmodule all + + +The CMake build output lists the modules by name:: + + ... + Including User C Module(s) from ../../examples/usercmodule/micropython.cmake + Found User C Module(s): usermod_cexample, usermod_cppexample + ... + + +Note that the ``micropython.cmake`` files define ``DMODULE__ENABLED=1`` automatically. +The top-level ``micropython.cmake`` can be used to control which modules are enabled. + + Or for your own project with a directory structure as shown above, including both modules and building the stm32 port for example: From 5976ea02a50ea76d72ada40db4cda186147fb412 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 23 Mar 2021 12:25:27 +0000 Subject: [PATCH 127/174] tools/ci.sh: Add CI for CMake USER_C_MODULE support. Builds the rp2 port against the example C and CXX modules. Signed-off-by: Phil Howard --- tools/ci.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/ci.sh b/tools/ci.sh index 53cf7f878b..0450611a10 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -181,6 +181,8 @@ function ci_rp2_build { make ${MAKEOPTS} -C mpy-cross git submodule update --init lib/pico-sdk lib/tinyusb make ${MAKEOPTS} -C ports/rp2 + make ${MAKEOPTS} -C ports/rp2 clean + make ${MAKEOPTS} -C ports/rp2 USER_C_MODULES=../../examples/usercmodule/micropython.cmake } ######################################################################################## From ca3d51f12206a88463f2b2a2d27756a1b519cb6a Mon Sep 17 00:00:00 2001 From: Liam Fraser Date: Tue, 30 Mar 2021 11:18:11 +0100 Subject: [PATCH 128/174] rp2: Don't advertise remote wakeup for USB serial. This USB feature is currently not supported. With this flag enabled (and the feature not implemented) the USB serial will stop working if there is a delay of more than about 2 seconds between messages, which can occur with USB autosuspend enabled. Fixes issue #6866. --- ports/rp2/tusb_port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/rp2/tusb_port.c b/ports/rp2/tusb_port.c index afb566bdb4..94856ab452 100644 --- a/ports/rp2/tusb_port.c +++ b/ports/rp2/tusb_port.c @@ -68,7 +68,7 @@ static const tusb_desc_device_t usbd_desc_device = { static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = { TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN, - TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA), + 0, USBD_MAX_POWER_MA), TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE), From 0ccd9e08aad95f955ded0006cff67e2a50778c84 Mon Sep 17 00:00:00 2001 From: Michael O'Cleirigh Date: Sat, 27 Mar 2021 17:10:39 -0400 Subject: [PATCH 129/174] esp32: Restore USER_C_MODULE support with new CMake build system. Support for User C and C++ modules was lost due to upgrading the esp32 to the latest CMake based IDF from the GNUMakefile build process. Restore the support for the esp32 port by integrating with the approach recently added for the rp2 port. Signed-off-by: Michael O'Cleirigh --- ports/esp32/Makefile | 8 +++++++- ports/esp32/main/CMakeLists.txt | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 9a3a15d6ee..39b740ffae 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -18,7 +18,13 @@ GIT_SUBMODULES = lib/berkeley-db-1.xx .PHONY: all clean deploy erase submodules FORCE -IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -B $(BUILD) +CMAKE_ARGS = + +ifdef USER_C_MODULES + CMAKE_ARGS += -DUSER_C_MODULES=${USER_C_MODULES} +endif + +IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -B $(BUILD) $(CMAKE_ARGS) all: idf.py $(IDFPY_FLAGS) build diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index b6bccdde3c..082410f4c0 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -5,6 +5,10 @@ get_filename_component(MICROPY_DIR ${PROJECT_DIR}/../.. ABSOLUTE) include(${MICROPY_DIR}/py/py.cmake) include(${MICROPY_DIR}/extmod/extmod.cmake) +if(NOT CMAKE_BUILD_EARLY_EXPANSION) + include(${MICROPY_DIR}/py/usermod.cmake) +endif() + set(MICROPY_QSTRDEFS_PORT ${PROJECT_DIR}/qstrdefsport.h ) @@ -71,6 +75,7 @@ set(MICROPY_SOURCE_PORT set(MICROPY_SOURCE_QSTR ${MICROPY_SOURCE_PY} ${MICROPY_SOURCE_EXTMOD} + ${MICROPY_SOURCE_USERMOD} ${MICROPY_SOURCE_LIB} ${MICROPY_SOURCE_PORT} ) @@ -129,6 +134,7 @@ idf_component_register( ${MICROPY_SOURCE_PORT} INCLUDE_DIRS ${MICROPY_DIR} + ${MICROPY_INC_USERMOD} ${MICROPY_PORT_DIR} ${MICROPY_BOARD_DIR} ${CMAKE_BINARY_DIR} @@ -159,6 +165,10 @@ target_compile_options(${MICROPY_TARGET} PUBLIC -Wno-missing-field-initializers ) +# add usermod +target_link_libraries(${MICROPY_TARGET} usermod) + + # Collect all of the include directories and compile definitions for the IDF components. foreach(comp ${IDF_COMPONENTS}) get_target_property(type __idf_${comp} TYPE) From 17b1f8212199ea6344e289e7fdea9585e30765d6 Mon Sep 17 00:00:00 2001 From: Michael O'Cleirigh Date: Sat, 27 Mar 2021 17:13:00 -0400 Subject: [PATCH 130/174] tools/ci.sh: Build user C modules for esp32. Builds the esp32 port against the example C and CXX modules. Signed-off-by: Michael O'Cleirigh --- tools/ci.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/ci.sh b/tools/ci.sh index 0450611a10..1a410632cd 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -100,6 +100,8 @@ function ci_esp32_build { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/esp32 submodules make ${MAKEOPTS} -C ports/esp32 + make ${MAKEOPTS} -C ports/esp32 clean + make ${MAKEOPTS} -C ports/esp32 USER_C_MODULES=../../../examples/usercmodule/micropython.cmake } ######################################################################################## From ec79e445027857d219d139cd31af578124a8e913 Mon Sep 17 00:00:00 2001 From: Michael O'Cleirigh Date: Tue, 30 Mar 2021 23:03:31 -0400 Subject: [PATCH 131/174] esp32: Fix multiple definition errors with mp_hal_stdout_tx functions. It was noticed that the esp32 port didn't build ulab correctly. The problem was a multiple defintion of the 'mp_hal_stdout_tx_str' and 'mp_hal_stdout_tx_strn_cooked' functions. They were defined in stdout_helpers.c but also in the ports/esp32/mphalport.c. Fixed by removing stdout_helpers.c from the build. Signed-off-by: Michael O'Cleirigh --- ports/esp32/main/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index 082410f4c0..d7d08ea663 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -25,7 +25,6 @@ set(MICROPY_SOURCE_LIB ${MICROPY_DIR}/lib/oofatfs/ffunicode.c ${MICROPY_DIR}/lib/timeutils/timeutils.c ${MICROPY_DIR}/lib/utils/interrupt_char.c - ${MICROPY_DIR}/lib/utils/stdout_helpers.c ${MICROPY_DIR}/lib/utils/sys_stdio_mphal.c ${MICROPY_DIR}/lib/utils/pyexec.c ) From d87f42b0e53829052f17955ba1e17f938ae486fb Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 31 Mar 2021 00:45:43 +1100 Subject: [PATCH 132/174] examples/usercmodules: Simplify user C module enabling. It's a bit of a pitfall with user C modules that including them in the build does not automatically enable them. This commit changes the docs and examples for user C modules to encourage writers of user C modules to enable them unconditionally. This makes things simpler and covers most use cases. See discussion in issue #6960, and also #7086. Signed-off-by: Damien George --- docs/develop/cmodules.rst | 20 +++++++++++-------- examples/usercmodule/cexample/examplemodule.c | 5 ++++- .../usercmodule/cexample/micropython.cmake | 6 ------ .../usercmodule/cppexample/examplemodule.c | 5 ++++- .../usercmodule/cppexample/micropython.cmake | 6 ------ .../unix/variants/coverage/mpconfigvariant.mk | 3 +-- tools/ci.sh | 2 +- 7 files changed, 22 insertions(+), 25 deletions(-) diff --git a/docs/develop/cmodules.rst b/docs/develop/cmodules.rst index dd02f1439c..be49485f2c 100644 --- a/docs/develop/cmodules.rst +++ b/docs/develop/cmodules.rst @@ -149,17 +149,23 @@ applying 2 modifications: - all modules found in this directory (or added via ``include`` in the top-level ``micropython.cmake`` when using CMake) will be compiled, but only those which are - explicitly enabled will be available for importing. Enabling a module is done - by setting the preprocessor define from its module registration to 1. + enabled will be available for importing. If a module is to always be enabled, + which is usually the case for custom modules and custom builds, then it is + enough to supply "1" as the third parameter to the registration macro, like: - For example if the source code defines the module with + .. code-block:: c + + MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, 1); + + Alternatively, to make the module disabled by default but selectable through + a preprocessor configuration option, use: .. code-block:: c MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, MODULE_CEXAMPLE_ENABLED); - then ``MODULE_CEXAMPLE_ENABLED`` has to be set to 1 to make the module available. + Then ``MODULE_CEXAMPLE_ENABLED`` has to be set to 1 to make the module available. This can be done by adding ``CFLAGS_EXTRA=-DMODULE_CEXAMPLE_ENABLED=1`` to the ``make`` command, or editing ``mpconfigport.h`` or ``mpconfigboard.h`` to add @@ -179,7 +185,7 @@ directory can be built for the unix port: .. code-block:: bash cd micropython/ports/unix - make USER_C_MODULES=../../examples/usercmodule CFLAGS_EXTRA=-DMODULE_CEXAMPLE_ENABLED=1 all + make USER_C_MODULES=../../examples/usercmodule all The build output will show the modules found:: @@ -205,7 +211,6 @@ The CMake build output lists the modules by name:: ... -Note that the ``micropython.cmake`` files define ``DMODULE__ENABLED=1`` automatically. The top-level ``micropython.cmake`` can be used to control which modules are enabled. @@ -215,8 +220,7 @@ including both modules and building the stm32 port for example: .. code-block:: bash cd my_project/micropython/ports/stm32 - make USER_C_MODULES=../../../modules \ - CFLAGS_EXTRA="-DMODULE_EXAMPLE1_ENABLED=1 -DMODULE_EXAMPLE2_ENABLED=1" all + make USER_C_MODULES=../../../modules all Module usage in MicroPython diff --git a/examples/usercmodule/cexample/examplemodule.c b/examples/usercmodule/cexample/examplemodule.c index f608823c9e..49ebc7aaaf 100644 --- a/examples/usercmodule/cexample/examplemodule.c +++ b/examples/usercmodule/cexample/examplemodule.c @@ -31,4 +31,7 @@ const mp_obj_module_t example_user_cmodule = { }; // Register the module to make it available in Python. -MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, MODULE_CEXAMPLE_ENABLED); +// Note: the "1" in the third argument means this module is always enabled. +// This "1" can be optionally replaced with a macro like MODULE_CEXAMPLE_ENABLED +// which can then be used to conditionally enable this module. +MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, 1); diff --git a/examples/usercmodule/cexample/micropython.cmake b/examples/usercmodule/cexample/micropython.cmake index 371a3eefa4..ba076a16b2 100644 --- a/examples/usercmodule/cexample/micropython.cmake +++ b/examples/usercmodule/cexample/micropython.cmake @@ -11,11 +11,5 @@ target_include_directories(usermod_cexample INTERFACE ${CMAKE_CURRENT_LIST_DIR} ) -# Enable the module automatically by adding the relevant compile definitions. -target_compile_definitions(usermod_cexample INTERFACE - MODULE_CEXAMPLE_ENABLED=1 -) - # Link our INTERFACE library to the usermod target. target_link_libraries(usermod INTERFACE usermod_cexample) - diff --git a/examples/usercmodule/cppexample/examplemodule.c b/examples/usercmodule/cppexample/examplemodule.c index ceb588bef6..dfb7856837 100644 --- a/examples/usercmodule/cppexample/examplemodule.c +++ b/examples/usercmodule/cppexample/examplemodule.c @@ -22,4 +22,7 @@ const mp_obj_module_t cppexample_user_cmodule = { }; // Register the module to make it available in Python. -MP_REGISTER_MODULE(MP_QSTR_cppexample, cppexample_user_cmodule, MODULE_CPPEXAMPLE_ENABLED); +// Note: the "1" in the third argument means this module is always enabled. +// This "1" can be optionally replaced with a macro like MODULE_CPPEXAMPLE_ENABLED +// which can then be used to conditionally enable this module. +MP_REGISTER_MODULE(MP_QSTR_cppexample, cppexample_user_cmodule, 1); diff --git a/examples/usercmodule/cppexample/micropython.cmake b/examples/usercmodule/cppexample/micropython.cmake index 43e8d887f5..6da972c94e 100644 --- a/examples/usercmodule/cppexample/micropython.cmake +++ b/examples/usercmodule/cppexample/micropython.cmake @@ -12,11 +12,5 @@ target_include_directories(usermod_cppexample INTERFACE ${CMAKE_CURRENT_LIST_DIR} ) -# Enable the module automatically by adding the relevant compile definitions. -target_compile_definitions(usermod_cppexample INTERFACE - MODULE_CPPEXAMPLE_ENABLED=1 -) - # Link our INTERFACE library to the usermod target. target_link_libraries(usermod INTERFACE usermod_cppexample) - diff --git a/ports/unix/variants/coverage/mpconfigvariant.mk b/ports/unix/variants/coverage/mpconfigvariant.mk index ef81975d9d..fac8c0d275 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.mk +++ b/ports/unix/variants/coverage/mpconfigvariant.mk @@ -7,8 +7,7 @@ CFLAGS += \ -fprofile-arcs -ftest-coverage \ -Wformat -Wmissing-declarations -Wmissing-prototypes \ -Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \ - -DMICROPY_UNIX_COVERAGE \ - -DMODULE_CEXAMPLE_ENABLED=1 -DMODULE_CPPEXAMPLE_ENABLED=1 + -DMICROPY_UNIX_COVERAGE LDFLAGS += -fprofile-arcs -ftest-coverage diff --git a/tools/ci.sh b/tools/ci.sh index 1a410632cd..3ce96a96a9 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -211,7 +211,7 @@ function ci_stm32_pyb_build { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/stm32 submodules git submodule update --init lib/btstack - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 USER_C_MODULES=../../examples/usercmodule CFLAGS_EXTRA="-DMODULE_CEXAMPLE_ENABLED=1 -DMODULE_CPPEXAMPLE_ENABLED=1" + make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 USER_C_MODULES=../../examples/usercmodule make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF2 make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF6 NANBOX=1 MICROPY_BLUETOOTH_NIMBLE=0 MICROPY_BLUETOOTH_BTSTACK=1 make ${MAKEOPTS} -C ports/stm32/mboot BOARD=PYBV10 CFLAGS_EXTRA='-DMBOOT_FSLOAD=1 -DMBOOT_VFS_LFS2=1' From f541b3673d272fbe9081a96776072a83ac5add9d Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Apr 2021 17:07:20 +1100 Subject: [PATCH 133/174] docs/develop: Improve user C modules to properly describe how to build. Make and CMake builds are slightly different and these changes help make it clear what to do in each case. Signed-off-by: Damien George --- docs/develop/cmodules.rst | 186 ++++++++++++++++++++++---------------- 1 file changed, 107 insertions(+), 79 deletions(-) diff --git a/docs/develop/cmodules.rst b/docs/develop/cmodules.rst index be49485f2c..346b3e0314 100644 --- a/docs/develop/cmodules.rst +++ b/docs/develop/cmodules.rst @@ -18,7 +18,11 @@ If however you're targeting obscure or proprietary systems it may make more sense to keep this external to the main MicroPython repository. This chapter describes how to compile such external modules into the -MicroPython executable or firmware image. +MicroPython executable or firmware image. Both Make and CMake build +tools are supported, and when writing an external module it's a good idea to +add the build files for both of these tools so the module can be used on all +ports. But when compiling a particular port you will only need to use one +method of building, either Make or CMake. An alternative approach is to use :ref:`natmod` which allows writing custom C code that is placed in a .mpy file, which can be imported dynamically in to @@ -111,116 +115,140 @@ To build such a module, compile MicroPython (see `getting started `_), applying 2 modifications: -- an extra ``make`` flag named ``USER_C_MODULES`` set to the directory - containing all modules you want included (not to the module itself). - For building the example modules which come with MicroPython, - set ``USER_C_MODULES`` to the ``examples/usercmodule`` directory. - For your own projects it's more convenient to keep custom code out of - the main source tree so a typical project directory structure will look - like this:: +1. Set the build-time flag ``USER_C_MODULES`` to point to the modules + you want to include. For ports that use Make this variable should be a + directory which is searched automatically for modules. For ports that + use CMake this variable should be a file which includes the modules to + build. See below for details. - my_project/ - ├── modules/ - │ └──example1/ - │ ├──example1.c - │ ├──micropython.mk - │ └──micropython.cmake - │ └──example2/ - │ ├──example2.c - │ ├──micropython.mk - │ └──micropython.cmake - │ └──micropython.cmake - └── micropython/ - ├──ports/ - ... ├──stm32/ - ... +2. Enable the modules by setting the corresponding C preprocessor macro to + 1. This is only needed if the modules you are building are not + automatically enabled. +For building the example modules which come with MicroPython, +set ``USER_C_MODULES`` to the ``examples/usercmodule`` directory for Make, +or to ``examples/usercmodule/micropython.cmake`` for CMake. - with ``USER_C_MODULES`` set to the ``my_project/modules`` directory. - - A top level ``micropython.cmake`` - found directly in the ``my_project/modules`` - directory - should ``include`` all of your modules. - - .. code-block:: cmake - - include(${CMAKE_CURRENT_LIST_DIR}/example1/micropython.cmake) - include(${CMAKE_CURRENT_LIST_DIR}/example2/micropython.cmake) - - -- all modules found in this directory (or added via ``include`` in the top-level - ``micropython.cmake`` when using CMake) will be compiled, but only those which are - enabled will be available for importing. If a module is to always be enabled, - which is usually the case for custom modules and custom builds, then it is - enough to supply "1" as the third parameter to the registration macro, like: - - .. code-block:: c - - MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, 1); - - Alternatively, to make the module disabled by default but selectable through - a preprocessor configuration option, use: - - .. code-block:: c - - MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, MODULE_CEXAMPLE_ENABLED); - - - Then ``MODULE_CEXAMPLE_ENABLED`` has to be set to 1 to make the module available. - This can be done by adding ``CFLAGS_EXTRA=-DMODULE_CEXAMPLE_ENABLED=1`` to - the ``make`` command, or editing ``mpconfigport.h`` or ``mpconfigboard.h`` - to add - - .. code-block:: c - - #define MODULE_CEXAMPLE_ENABLED (1) - - - Note that the exact method depends on the port as they have different - structures. If not done correctly it will compile but importing will - fail to find the module. - -To sum up, here's how the ``cexample`` module from the ``examples/usercmodule`` -directory can be built for the unix port: +For example, here's how the to build the unix port with the example modules: .. code-block:: bash cd micropython/ports/unix - make USER_C_MODULES=../../examples/usercmodule all + make USER_C_MODULES=../../examples/usercmodule -The build output will show the modules found:: +You may need to run ``make clean`` once at the start when including new +user modules in the build. The build output will show the modules found:: ... Including User C Module from ../../examples/usercmodule/cexample Including User C Module from ../../examples/usercmodule/cppexample ... - -For a CMake-based port such as rp2, this will look a little different: +For a CMake-based port such as rp2, this will look a little different (note +that CMake is actually invoked by ``make``): .. code-block:: bash cd micropython/ports/rp2 - make USER_C_MODULES=../../examples/usercmodule all + make USER_C_MODULES=../../examples/usercmodule/micropython.cmake - -The CMake build output lists the modules by name:: +Again, you may need to run ``make clean`` first for CMake to pick up the +user modules. The CMake build output lists the modules by name:: ... Including User C Module(s) from ../../examples/usercmodule/micropython.cmake Found User C Module(s): usermod_cexample, usermod_cppexample ... +The contents of the top-level ``micropython.cmake`` can be used to control which +modules are enabled. -The top-level ``micropython.cmake`` can be used to control which modules are enabled. +For your own projects it's more convenient to keep custom code out of the main +MicroPython source tree, so a typical project directory structure will look +like this:: + my_project/ + ├── modules/ + │ ├── example1/ + │ │ ├── example1.c + │ │ ├── micropython.mk + │ │ └── micropython.cmake + │ ├── example2/ + │ │ ├── example2.c + │ │ ├── micropython.mk + │ │ └── micropython.cmake + │ └── micropython.cmake + └── micropython/ + ├──ports/ + ... ├──stm32/ + ... -Or for your own project with a directory structure as shown above, -including both modules and building the stm32 port for example: +When building with Make set ``USER_C_MODULES`` to the ``my_project/modules`` +directory. For example, building the stm32 port: .. code-block:: bash cd my_project/micropython/ports/stm32 - make USER_C_MODULES=../../../modules all + make USER_C_MODULES=../../../modules + +When building with CMake the top level ``micropython.cmake`` -- found directly +in the ``my_project/modules`` directory -- should ``include`` all of the modules +you want to have available: + + .. code-block:: cmake + + include(${CMAKE_CURRENT_LIST_DIR}/example1/micropython.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/example2/micropython.cmake) + +Then build with: + +.. code-block:: bash + + cd my_project/micropython/ports/esp32 + make USER_C_MODULES=../../../../modules/micropython.cmake + +Note that the esp32 port needs the extra ``..`` for relative paths due to the +location of its main ``CMakeLists.txt`` file. You can also specify absolute +paths to ``USER_C_MODULES``. + +All modules specified by the ``USER_C_MODULES`` variable (either found in this +directory when using Make, or added via ``include`` when using CMake) will be +compiled, but only those which are enabled will be available for importing. +User modules are usually enabled by default (this is decided by the developer +of the module), in which case there is nothing more to do than set ``USER_C_MODULES`` +as described above. + +If a module is not enabled by default then the corresponding C preprocessor macro +must be enabled. This macro name can be found by searching for the ``MP_REGISTER_MODULE`` +line in the module's source code (it usually appears at the end of the main source file). +The third argument to ``MP_REGISTER_MODULE`` is the macro name, and this must be set +to 1 using ``CFLAGS_EXTRA`` to make the module available. If the third argument is just +the number 1 then the module is enabled by default. + +For example, the ``examples/usercmodule/cexample`` module is enabled by default so +has the following line in its source code: + + .. code-block:: c + + MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, 1); + +Alternatively, to make this module disabled by default but selectable through +a preprocessor configuration option, it would be: + + .. code-block:: c + + MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, MODULE_CEXAMPLE_ENABLED); + +In this case the module is enabled by adding ``CFLAGS_EXTRA=-DMODULE_CEXAMPLE_ENABLED=1`` +to the ``make`` command, or editing ``mpconfigport.h`` or ``mpconfigboard.h`` to add + + .. code-block:: c + + #define MODULE_CEXAMPLE_ENABLED (1) + +Note that the exact method depends on the port as they have different +structures. If not done correctly it will compile but importing will +fail to find the module. Module usage in MicroPython From 2d8aecd2ad43afeeb14fb8a21fcff29a1000c5c4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Apr 2021 13:36:26 +1100 Subject: [PATCH 134/174] rp2/CMakeLists.txt: Enable USB enumeration fix. This is a workaround for errata RP2040-E5, and is needed to make USB more reliable on certain USB ports. Signed-off-by: Damien George --- ports/rp2/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 3db0e6b62a..37b041279f 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -170,6 +170,7 @@ target_compile_definitions(${MICROPY_TARGET} PRIVATE PICO_NO_PROGRAM_VERSION_STRING=1 # do it ourselves in main.c MICROPY_BUILD_TYPE="${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION} ${CMAKE_BUILD_TYPE}" PICO_NO_BI_STDIO_UART=1 # we call it UART REPL + PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1 ) target_link_libraries(${MICROPY_TARGET} From 25ae169e6ec5ada4d80f6632b72b711c0b5e4c98 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 6 Apr 2021 12:11:15 +1000 Subject: [PATCH 135/174] stm32: Include .ARM section in firmware for C++ exception handling. Support for C++ was added in 97960dc7deb7a0e691fca5944402cd03386b744b but that commit didn't include the C++ exception handling table in the binary firmware image. This commit fixes that. Signed-off-by: Damien George --- ports/stm32/Makefile | 4 ++-- ports/stm32/boards/PYBD_SF2/mpconfigboard.mk | 2 +- ports/stm32/boards/PYBD_SF3/mpconfigboard.mk | 2 +- ports/stm32/boards/STM32F769DISC/mpconfigboard.mk | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 6c71f27573..9c22928a0c 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -643,7 +643,7 @@ TEXT0_ADDR ?= 0x08000000 ifeq ($(TEXT1_ADDR),) # No TEXT1_ADDR given so put all firmware at TEXT0_ADDR location -TEXT0_SECTIONS ?= .isr_vector .text .data +TEXT0_SECTIONS ?= .isr_vector .text .data .ARM deploy-stlink: $(BUILD)/firmware.bin $(call RUN_STLINK,$^,$(TEXT0_ADDR)) @@ -661,7 +661,7 @@ else # TEXT0_ADDR and TEXT1_ADDR are specified so split firmware between these locations TEXT0_SECTIONS ?= .isr_vector -TEXT1_SECTIONS ?= .text .data +TEXT1_SECTIONS ?= .text .data .ARM deploy-stlink: $(BUILD)/firmware0.bin $(BUILD)/firmware1.bin $(call RUN_STLINK,$(word 1,$^),$(TEXT0_ADDR)) diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk index ead8bb8c07..9917aa2c57 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk @@ -6,7 +6,7 @@ AF_FILE = boards/stm32f722_af.csv LD_FILES = boards/PYBD_SF2/f722_qspi.ld TEXT0_ADDR = 0x08008000 TEXT1_ADDR = 0x90000000 -TEXT0_SECTIONS = .isr_vector .text .data +TEXT0_SECTIONS = .isr_vector .text .data .ARM TEXT1_SECTIONS = .text_ext # MicroPython settings diff --git a/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk index abe3dcd862..6bcc68f4b1 100644 --- a/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk @@ -6,7 +6,7 @@ AF_FILE = boards/stm32f722_af.csv LD_FILES = boards/PYBD_SF2/f722_qspi.ld TEXT0_ADDR = 0x08008000 TEXT1_ADDR = 0x90000000 -TEXT0_SECTIONS = .isr_vector .text .data +TEXT0_SECTIONS = .isr_vector .text .data .ARM TEXT1_SECTIONS = .text_ext # MicroPython settings diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk index 81add8c88e..5d3d11a795 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk @@ -22,7 +22,7 @@ ifeq ($(USE_QSPI_XIP),1) LD_FILES = boards/STM32F769DISC/f769_qspi.ld TEXT0_ADDR = 0x08020000 TEXT1_ADDR = 0x90000000 -TEXT0_SECTIONS = .isr_vector .text .data +TEXT0_SECTIONS = .isr_vector .text .data .ARM TEXT1_SECTIONS = .text_qspi else From d35f12f5caf2f6eef08670b61dbe2a3a1b387042 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 6 Apr 2021 12:50:19 +1000 Subject: [PATCH 136/174] tools/metrics.py: Fix esp32 output filename due to move to CMake. Signed-off-by: Damien George --- tools/metrics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/metrics.py b/tools/metrics.py index 25acb30f51..98291e25a9 100755 --- a/tools/metrics.py +++ b/tools/metrics.py @@ -65,7 +65,7 @@ port_data = { "s": PortData("stm32", "stm32", "build-PYBV10/firmware.elf", "BOARD=PYBV10"), "c": PortData("cc3200", "cc3200", "build/WIPY/release/application.axf", "BTARGET=application"), "8": PortData("esp8266", "esp8266", "build-GENERIC/firmware.elf"), - "3": PortData("esp32", "esp32", "build-GENERIC/application.elf"), + "3": PortData("esp32", "esp32", "build-GENERIC/micropython.elf"), "r": PortData("nrf", "nrf", "build-pca10040/firmware.elf"), "d": PortData("samd", "samd", "build-ADAFRUIT_ITSYBITSY_M4_EXPRESS/firmware.elf"), } From 172fb5230a3943eeb6fbbb4de1dc56b16e2a7637 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 27 Mar 2021 19:19:51 -0500 Subject: [PATCH 137/174] extmod/re1.5: Check and report byte overflow errors in _compilecode. The generated regex code is limited in the range of jumps and counts, and this commit checks all cases which can overflow given the right kind of input regex, and returns an error in such a case. This change assumes that the results that overflow an int8_t do not overflow a platform int. Closes: #7078 Signed-off-by: Jeff Epler --- extmod/re1.5/compilecode.c | 31 ++++++++++++++++++++----------- tests/extmod/ure_limit.py | 34 ++++++++++++++++++++++++++++++++++ tests/extmod/ure_limit.py.exp | 7 +++++++ 3 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 tests/extmod/ure_limit.py create mode 100644 tests/extmod/ure_limit.py.exp diff --git a/extmod/re1.5/compilecode.c b/extmod/re1.5/compilecode.c index c4d12af87a..add4f6ac20 100644 --- a/extmod/re1.5/compilecode.c +++ b/extmod/re1.5/compilecode.c @@ -8,11 +8,20 @@ ((code ? memmove(code + at + num, code + at, pc - at) : 0), pc += num) #define REL(at, to) (to - at - 2) #define EMIT(at, byte) (code ? (code[at] = byte) : (at)) +#define EMIT_CHECKED(at, byte) (_emit_checked(at, code, byte, &err)) #define PC (prog->bytelen) +static void _emit_checked(int at, char *code, int val, bool *err) { + *err |= val != (int8_t)val; + if (code) { + code[at] = val; + } +} + static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) { char *code = sizecode ? NULL : prog->insts; + bool err = false; int start = PC; int term = PC; int alt_label = 0; @@ -64,7 +73,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) } EMIT(PC++, *re); } - EMIT(term + 1, cnt); + EMIT_CHECKED(term + 1, cnt); break; } case '(': { @@ -75,7 +84,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) if (capture) { sub = ++prog->sub; EMIT(PC++, Save); - EMIT(PC++, 2 * sub); + EMIT_CHECKED(PC++, 2 * sub); prog->len++; } else { re += 2; @@ -86,7 +95,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) if (capture) { EMIT(PC++, Save); - EMIT(PC++, 2 * sub + 1); + EMIT_CHECKED(PC++, 2 * sub + 1); prog->len++; } @@ -101,7 +110,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) } else { EMIT(term, Split); } - EMIT(term + 1, REL(term, PC)); + EMIT_CHECKED(term + 1, REL(term, PC)); prog->len++; term = PC; break; @@ -109,7 +118,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) if (PC == term) return NULL; // nothing to repeat INSERT_CODE(term, 2, PC); EMIT(PC, Jmp); - EMIT(PC + 1, REL(PC, term)); + EMIT_CHECKED(PC + 1, REL(PC, term)); PC += 2; if (re[1] == '?') { EMIT(term, RSplit); @@ -117,7 +126,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) } else { EMIT(term, Split); } - EMIT(term + 1, REL(term, PC)); + EMIT_CHECKED(term + 1, REL(term, PC)); prog->len += 2; term = PC; break; @@ -129,20 +138,20 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) } else { EMIT(PC, RSplit); } - EMIT(PC + 1, REL(PC, term)); + EMIT_CHECKED(PC + 1, REL(PC, term)); PC += 2; prog->len++; term = PC; break; case '|': if (alt_label) { - EMIT(alt_label, REL(alt_label, PC) + 1); + EMIT_CHECKED(alt_label, REL(alt_label, PC) + 1); } INSERT_CODE(start, 2, PC); EMIT(PC++, Jmp); alt_label = PC++; EMIT(start, Split); - EMIT(start + 1, REL(start, PC)); + EMIT_CHECKED(start + 1, REL(start, PC)); prog->len += 2; term = PC; break; @@ -160,9 +169,9 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) } if (alt_label) { - EMIT(alt_label, REL(alt_label, PC) + 1); + EMIT_CHECKED(alt_label, REL(alt_label, PC) + 1); } - return re; + return err ? NULL : re; } int re1_5_sizecode(const char *re) diff --git a/tests/extmod/ure_limit.py b/tests/extmod/ure_limit.py new file mode 100644 index 0000000000..99c6a818e8 --- /dev/null +++ b/tests/extmod/ure_limit.py @@ -0,0 +1,34 @@ +# Test overflow in ure.compile output code. + +try: + import ure as re +except ImportError: + print("SKIP") + raise SystemExit + + +def test_re(r): + try: + re.compile(r) + except: + print("Error") + + +# too many chars in [] +test_re("[" + "a" * 256 + "]") + +# too many groups +test_re("(a)" * 256) + +# jump too big for ? +test_re("(" + "a" * 62 + ")?") + +# jump too big for * +test_re("(" + "a" * 60 + ".)*") +test_re("(" + "a" * 60 + "..)*") + +# jump too big for + +test_re("(" + "a" * 62 + ")+") + +# jump too big for | +test_re("b" * 63 + "|a") diff --git a/tests/extmod/ure_limit.py.exp b/tests/extmod/ure_limit.py.exp new file mode 100644 index 0000000000..8353be536c --- /dev/null +++ b/tests/extmod/ure_limit.py.exp @@ -0,0 +1,7 @@ +Error +Error +Error +Error +Error +Error +Error From 4f53f462ca9dbec45771e06d2d1a84b61e01e61a Mon Sep 17 00:00:00 2001 From: Tim Radvan Date: Sat, 3 Apr 2021 12:20:48 +0100 Subject: [PATCH 138/174] rp2: Import uarray instead of array in rp2 module. Some forum users noticed that `sm.exec()` took longer the more was present on the flash filesystem connected to the RP2040. They traced this back to the `array` import inside `asm_pio()`, which is causing MicroPython to scan the filesystem. uarray is a built-in module, so importing it shouldn't require scanning the filesystem. We avoid moving the import to the top-level in order to keep the namespace clean; we don't want to accidentally expose `rp2.array`. --- ports/rp2/modules/rp2.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ports/rp2/modules/rp2.py b/ports/rp2/modules/rp2.py index a3adcdc512..17e35c73b7 100644 --- a/ports/rp2/modules/rp2.py +++ b/ports/rp2/modules/rp2.py @@ -33,7 +33,9 @@ class PIOASMEmit: push_thresh=32, pull_thresh=32 ): - from array import array + # uarray is a built-in module so importing it here won't require + # scanning the filesystem. + from uarray import array self.labels = {} execctrl = 0 From a66286f3a0f24985cae2648102e51de64b8a1871 Mon Sep 17 00:00:00 2001 From: stijn Date: Tue, 6 Apr 2021 20:40:31 +0200 Subject: [PATCH 139/174] unix: Improve command line argument processing. Per CPython everything which comes after the command, module or file argument is not an option for the interpreter itself. Hence the processing of options should stop when encountering those, and the remainder be passed as sys.argv. Note the latter was already the case for a module or file but not for a command. This fixes issues like 'micropython myfile.py -h' showing the help and exiting instead of passing '-h' as sys.argv[1], likewise for '-X ' being treated as a special option no matter where it occurs on the command line. --- ports/unix/main.c | 12 ++++++++---- tests/cmdline/repl_inspect.py | 2 +- tests/cmdline/repl_inspect.py.exp | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/ports/unix/main.c b/ports/unix/main.c index 07db8d22c6..129c6d3bb4 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -341,6 +341,9 @@ STATIC int invalid_args(void) { STATIC void pre_process_options(int argc, char **argv) { for (int a = 1; a < argc; a++) { if (argv[a][0] == '-') { + if (strcmp(argv[a], "-c") == 0 || strcmp(argv[a], "-m") == 0) { + break; // Everything after this is a command/module and arguments for it + } if (strcmp(argv[a], "-h") == 0) { print_help(argv); exit(0); @@ -400,6 +403,8 @@ STATIC void pre_process_options(int argc, char **argv) { } a++; } + } else { + break; // Not an option but a file } } } @@ -568,11 +573,10 @@ MP_NOINLINE int main_(int argc, char **argv) { if (a + 1 >= argc) { return invalid_args(); } + set_sys_argv(argv, a + 1, a); // The -c becomes first item of sys.argv, as in CPython + set_sys_argv(argv, argc, a + 2); // Then what comes after the command ret = do_str(argv[a + 1]); - if (ret & FORCED_EXIT) { - break; - } - a += 1; + break; } else if (strcmp(argv[a], "-m") == 0) { if (a + 1 >= argc) { return invalid_args(); diff --git a/tests/cmdline/repl_inspect.py b/tests/cmdline/repl_inspect.py index 5a7564a3c2..8c86f287d1 100644 --- a/tests/cmdline/repl_inspect.py +++ b/tests/cmdline/repl_inspect.py @@ -1,2 +1,2 @@ -# cmdline: -c print("test") -i +# cmdline: -i -c print("test") # -c option combined with -i option results in REPL diff --git a/tests/cmdline/repl_inspect.py.exp b/tests/cmdline/repl_inspect.py.exp index 59f734b2f6..051acfd153 100644 --- a/tests/cmdline/repl_inspect.py.exp +++ b/tests/cmdline/repl_inspect.py.exp @@ -1,6 +1,6 @@ test MicroPython \.\+ version Use \.\+ ->>> # cmdline: -c print("test") -i +>>> # cmdline: -i -c print("test") >>> # -c option combined with -i option results in REPL >>> From 00963a4e69207eca9f9ce106f533544774eddd1f Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Apr 2021 11:55:07 +1000 Subject: [PATCH 140/174] stm32/powerctrl: Allow a board to configure AHB and APB clock dividers. Signed-off-by: Damien George --- ports/stm32/mpconfigboard_common.h | 19 +++++++++++++++++ ports/stm32/powerctrl.c | 4 ++-- ports/stm32/system_stm32.c | 34 +++++++++++++++--------------- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 948897b215..6fb9289e00 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -310,6 +310,25 @@ #endif #endif +// Configure the default bus clock divider values +#ifndef MICROPY_HW_CLK_AHB_DIV +#if defined(STM32H7) +#define MICROPY_HW_CLK_AHB_DIV (RCC_HCLK_DIV2) +#define MICROPY_HW_CLK_APB1_DIV (RCC_APB1_DIV2) +#define MICROPY_HW_CLK_APB2_DIV (RCC_APB2_DIV2) +#define MICROPY_HW_CLK_APB3_DIV (RCC_APB3_DIV2) +#define MICROPY_HW_CLK_APB4_DIV (RCC_APB4_DIV2) +#elif defined(STM32L4) +#define MICROPY_HW_CLK_AHB_DIV (RCC_SYSCLK_DIV1) +#define MICROPY_HW_CLK_APB1_DIV (RCC_HCLK_DIV1) +#define MICROPY_HW_CLK_APB2_DIV (RCC_HCLK_DIV1) +#else +#define MICROPY_HW_CLK_AHB_DIV (RCC_SYSCLK_DIV1) +#define MICROPY_HW_CLK_APB1_DIV (RCC_HCLK_DIV4) +#define MICROPY_HW_CLK_APB2_DIV (RCC_HCLK_DIV2) +#endif +#endif + // If disabled then try normal (non-bypass) LSE first, with fallback to LSI. // If enabled first try LSE in bypass mode. If that fails to start, try non-bypass mode, with fallback to LSI. #ifndef MICROPY_HW_RTC_USE_BYPASS diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index a579713b6f..a34927798a 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -377,8 +377,8 @@ set_clk: RCC_ClkInitStruct.APB2CLKDivider = calc_apb2_div(ahb / apb2); #if defined(STM32H7) RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; - RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; + RCC_ClkInitStruct.APB3CLKDivider = MICROPY_HW_CLK_APB3_DIV; + RCC_ClkInitStruct.APB4CLKDivider = MICROPY_HW_CLK_APB4_DIV; #endif #if MICROPY_HW_CLK_LAST_FREQ diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index 2160e0ac99..72918bbc53 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -272,9 +272,9 @@ void SystemClock_Config(void) { n = MICROPY_HW_CLK_PLLN; p = MICROPY_HW_CLK_PLLP; q = MICROPY_HW_CLK_PLLQ; - h = RCC_SYSCLK_DIV1; - b1 = RCC_HCLK_DIV4; - b2 = RCC_HCLK_DIV2; + h = MICROPY_HW_CLK_AHB_DIV; + b1 = MICROPY_HW_CLK_APB1_DIV; + b2 = MICROPY_HW_CLK_APB2_DIV; } else { h <<= 4; b1 <<= 10; @@ -285,9 +285,9 @@ void SystemClock_Config(void) { RCC_OscInitStruct.PLL.PLLP = p; // MICROPY_HW_CLK_PLLP; RCC_OscInitStruct.PLL.PLLQ = q; // MICROPY_HW_CLK_PLLQ; - RCC_ClkInitStruct.AHBCLKDivider = h; // RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = b1; // RCC_HCLK_DIV4; - RCC_ClkInitStruct.APB2CLKDivider = b2; // RCC_HCLK_DIV2; + RCC_ClkInitStruct.AHBCLKDivider = h; + RCC_ClkInitStruct.APB1CLKDivider = b1; + RCC_ClkInitStruct.APB2CLKDivider = b2; #else // defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ RCC_OscInitStruct.PLL.PLLM = MICROPY_HW_CLK_PLLM; RCC_OscInitStruct.PLL.PLLN = MICROPY_HW_CLK_PLLN; @@ -304,20 +304,20 @@ void SystemClock_Config(void) { #endif #if defined(STM32F4) || defined(STM32F7) - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; + RCC_ClkInitStruct.AHBCLKDivider = MICROPY_HW_CLK_AHB_DIV; + RCC_ClkInitStruct.APB1CLKDivider = MICROPY_HW_CLK_APB1_DIV; + RCC_ClkInitStruct.APB2CLKDivider = MICROPY_HW_CLK_APB2_DIV; #elif defined(STM32L4) - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + RCC_ClkInitStruct.AHBCLKDivider = MICROPY_HW_CLK_AHB_DIV; + RCC_ClkInitStruct.APB1CLKDivider = MICROPY_HW_CLK_APB1_DIV; + RCC_ClkInitStruct.APB2CLKDivider = MICROPY_HW_CLK_APB2_DIV; #elif defined(STM32H7) RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; - RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; - RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; - RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; - RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; + RCC_ClkInitStruct.AHBCLKDivider = MICROPY_HW_CLK_AHB_DIV; + RCC_ClkInitStruct.APB3CLKDivider = MICROPY_HW_CLK_APB3_DIV; + RCC_ClkInitStruct.APB1CLKDivider = MICROPY_HW_CLK_APB1_DIV; + RCC_ClkInitStruct.APB2CLKDivider = MICROPY_HW_CLK_APB2_DIV; + RCC_ClkInitStruct.APB4CLKDivider = MICROPY_HW_CLK_APB4_DIV; #endif #endif From f4340b7e62e717d31d412f42364fa85a7d4728bc Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Apr 2021 11:58:36 +1000 Subject: [PATCH 141/174] stm32/powerctrl: Support using PLLI2C on STM32F413 as USB clock source. So SYSCLK can run at more varied frequencies, eg 100MHz. Signed-off-by: Damien George --- ports/stm32/powerctrl.c | 64 ++++++++++++++++++++++++++++---------- ports/stm32/system_stm32.c | 4 +-- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index a34927798a..573844063b 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -50,6 +50,22 @@ #define RCC_SR_RMVF RCC_CSR_RMVF #endif +// Whether this MCU has an independent PLL which can generate 48MHz for USB. +#if defined(STM32F413xx) +// STM32F413 uses PLLI2S as secondary PLL. +#define HAVE_PLL48 1 +#define RCC_CR_PLL48_ON RCC_CR_PLLI2SON +#define RCC_CR_PLL48_RDY RCC_CR_PLLI2SRDY +#elif defined(STM32F7) +// STM32F7 uses PLLSAI as secondary PLL. +#define HAVE_PLL48 1 +#define RCC_CR_PLL48_ON RCC_CR_PLLSAION +#define RCC_CR_PLL48_RDY RCC_CR_PLLSAIRDY +#else +// MCU does not have a secondary PLL. +#define HAVE_PLL48 0 +#endif + // Location in RAM of bootloader state (just after the top of the stack) extern uint32_t _estack[]; #define BL_STATE ((uint32_t *)&_estack) @@ -141,13 +157,24 @@ STATIC int powerctrl_config_vos(uint32_t sysclk_mhz) { } // Assumes that PLL is used as the SYSCLK source -int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pllsai) { +int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pll48) { uint32_t flash_latency; - #if defined(STM32F7) - if (need_pllsai) { - // Configure PLLSAI at 48MHz for those peripherals that need this freq - // (calculation assumes it can get an integral value of PLLSAIN) + #if HAVE_PLL48 + if (need_pll48) { + // Configure secondary PLL at 48MHz for those peripherals that need this freq + // (the calculation assumes it can get an integral value of PLL-N). + + #if defined(STM32F413xx) + const uint32_t plli2sm = HSE_VALUE / 1000000; + const uint32_t plli2sq = 2; + const uint32_t plli2sr = 2; + const uint32_t plli2sn = 48 * plli2sq; + RCC->PLLI2SCFGR = plli2sr << RCC_PLLI2SCFGR_PLLI2SR_Pos + | plli2sq << RCC_PLLI2SCFGR_PLLI2SQ_Pos + | plli2sn << RCC_PLLI2SCFGR_PLLI2SN_Pos + | plli2sm << RCC_PLLI2SCFGR_PLLI2SM_Pos; + #else const uint32_t pllm = (RCC->PLLCFGR >> RCC_PLLCFGR_PLLM_Pos) & 0x3f; const uint32_t pllsaip = 4; const uint32_t pllsaiq = 2; @@ -155,13 +182,18 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk RCC->PLLSAICFGR = pllsaiq << RCC_PLLSAICFGR_PLLSAIQ_Pos | (pllsaip / 2 - 1) << RCC_PLLSAICFGR_PLLSAIP_Pos | pllsain << RCC_PLLSAICFGR_PLLSAIN_Pos; - RCC->CR |= RCC_CR_PLLSAION; + #endif + + // Turn on the PLL and wait for it to be ready. + RCC->CR |= RCC_CR_PLL48_ON; uint32_t ticks = mp_hal_ticks_ms(); - while (!(RCC->CR & RCC_CR_PLLSAIRDY)) { + while (!(RCC->CR & RCC_CR_PLL48_RDY)) { if (mp_hal_ticks_ms() - ticks > 200) { return -MP_ETIMEDOUT; } } + + // Select the alternate 48MHz source. RCC->DCKCFGR2 |= RCC_DCKCFGR2_CK48MSEL; } #endif @@ -317,7 +349,7 @@ int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t // Default PLL parameters that give 48MHz on PLL48CK uint32_t m = MICROPY_HW_CLK_VALUE / 1000000, n = 336, p = 2, q = 7; uint32_t sysclk_source; - bool need_pllsai = false; + bool need_pll48 = false; // Search for a valid PLL configuration that keeps USB at 48MHz uint32_t sysclk_mhz = sysclk / 1000000; @@ -338,8 +370,8 @@ int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t uint32_t vco_out = sys * p; n = vco_out * m / (MICROPY_HW_CLK_VALUE / 1000000); q = vco_out / 48; - #if defined(STM32F7) - need_pllsai = vco_out % 48 != 0; + #if HAVE_PLL48 + need_pll48 = vco_out % 48 != 0; #endif } goto set_clk; @@ -393,11 +425,11 @@ set_clk: return -MP_EIO; } - #if defined(STM32F7) + #if HAVE_PLL48 // Deselect PLLSAI as 48MHz source if we were using it RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_CK48MSEL; // Turn PLLSAI off because we are changing PLLM (which drives PLLSAI) - RCC->CR &= ~RCC_CR_PLLSAION; + RCC->CR &= ~RCC_CR_PLL48_ON; #endif // Re-configure PLL @@ -440,7 +472,7 @@ set_clk: // Set PLL as system clock source if wanted if (sysclk_source == RCC_SYSCLKSOURCE_PLLCLK) { RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; - int ret = powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pllsai); + int ret = powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pll48); if (ret != 0) { return ret; } @@ -607,11 +639,11 @@ void powerctrl_enter_stop_mode(void) { powerctrl_disable_hsi_if_unused(); - #if defined(STM32F7) + #if HAVE_PLL48 if (RCC->DCKCFGR2 & RCC_DCKCFGR2_CK48MSEL) { // Enable PLLSAI if it is selected as 48MHz source - RCC->CR |= RCC_CR_PLLSAION; - while (!(RCC->CR & RCC_CR_PLLSAIRDY)) { + RCC->CR |= RCC_CR_PLL48_ON; + while (!(RCC->CR & RCC_CR_PLL48_RDY)) { } } #endif diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index 72918bbc53..4e89204bf6 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -351,8 +351,8 @@ void SystemClock_Config(void) { uint32_t vco_out = RCC_OscInitStruct.PLL.PLLN * (MICROPY_HW_CLK_VALUE / 1000000) / RCC_OscInitStruct.PLL.PLLM; uint32_t sysclk_mhz = vco_out / RCC_OscInitStruct.PLL.PLLP; - bool need_pllsai = vco_out % 48 != 0; - if (powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pllsai) != 0) { + bool need_pll48 = vco_out % 48 != 0; + if (powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pll48) != 0) { __fatal_error("HAL_RCC_ClockConfig"); } From cb396827f56f79741efeaa127b9c71c72bba3584 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Apr 2021 12:05:00 +1000 Subject: [PATCH 142/174] stm32/boards/pllvalues.py: Relax PLLQ constraints on STM32F413 MCUs. Signed-off-by: Damien George --- ports/stm32/Makefile | 2 +- ports/stm32/boards/pllvalues.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 9c22928a0c..e7a8f0aee6 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -750,7 +750,7 @@ CMSIS_MCU_HDR = $(CMSIS_DIR)/$(CMSIS_MCU_LOWER).h modmachine.c: $(GEN_PLLFREQTABLE_HDR) $(GEN_PLLFREQTABLE_HDR): $(PLLVALUES) | $(HEADER_BUILD) $(ECHO) "GEN $@" - $(Q)$(PYTHON) $(PLLVALUES) -c -m $(MCU_SERIES) file:$(BOARD_DIR)/stm32$(MCU_SERIES)xx_hal_conf.h > $@ + $(Q)$(PYTHON) $(PLLVALUES) -c -m $(CMSIS_MCU_LOWER) file:$(BOARD_DIR)/stm32$(MCU_SERIES)xx_hal_conf.h > $@ $(BUILD)/modstm.o: $(GEN_STMCONST_HDR) # Use a pattern rule here so that make will only call make-stmconst.py once to diff --git a/ports/stm32/boards/pllvalues.py b/ports/stm32/boards/pllvalues.py index 59d660364a..619146cd47 100644 --- a/ports/stm32/boards/pllvalues.py +++ b/ports/stm32/boards/pllvalues.py @@ -240,7 +240,7 @@ def main(): argv = sys.argv[1:] c_table = False - mcu_series = "f4" + mcu_series = "stm32f4" hse = None hsi = None @@ -271,13 +271,13 @@ def main(): hse = int(argv[0]) # Select MCU parameters - if mcu_series == "h7": + if mcu_series.startswith("stm32h7"): mcu = mcu_h7 else: mcu = mcu_default - # Relax constraight on PLLQ being 48MHz on F7 and H7 MCUs, which have separate PLLs for 48MHz - relax_pll48 = mcu_series in ("f7", "h7") + # Relax constraint on PLLQ being 48MHz on MCUs which have separate PLLs for 48MHz + relax_pll48 = mcu_series.startswith(("stm32f413", "stm32f7", "stm32h7")) hse_valid_plls = compute_pll_table(hse, relax_pll48) if hsi is not None: From 4d9e657f0ee881f4a41093ab89ec91d03613744d Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Apr 2021 17:00:26 +1000 Subject: [PATCH 143/174] stm32/mpconfigport.h: Add support for a board to specify root pointers. A board can now define MICROPY_BOARD_ROOT_POINTERS to specify any custom root pointers. Signed-off-by: Damien George --- ports/stm32/mpconfigport.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 174ef22f24..2888cac88c 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -353,6 +353,10 @@ struct _mp_bluetooth_btstack_root_pointers_t; #define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_BTSTACK #endif +#ifndef MICROPY_BOARD_ROOT_POINTERS +#define MICROPY_BOARD_ROOT_POINTERS +#endif + #define MICROPY_PORT_ROOT_POINTERS \ const char *readline_hist[8]; \ \ @@ -384,9 +388,13 @@ struct _mp_bluetooth_btstack_root_pointers_t; /* list of registered NICs */ \ mp_obj_list_t mod_network_nic_list; \ \ + /* root pointers for sub-systems */ \ MICROPY_PORT_ROOT_POINTER_MBEDTLS \ MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE \ - MICROPY_PORT_ROOT_POINTER_BLUETOOTH_BTSTACK \ + MICROPY_PORT_ROOT_POINTER_BLUETOOTH_BTSTACK \ + \ + /* root pointers defined by a board */ \ + MICROPY_BOARD_ROOT_POINTERS \ // type definitions for the specific machine From 7b41d7f187d0bbfdda66db06b523c8829f198998 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Apr 2021 21:11:24 +1000 Subject: [PATCH 144/174] stm32/boardctrl: Give boards control over execution of boot.py,main.py. This commit simplifies the customisation of the main MicroPython execution loop (4 macros are reduced to 2), and allows a board to have full control over the execution (or not) of boot.py and main.py. For boards that use the default start-up code, there is no functional change in this commit. Signed-off-by: Damien George --- ports/stm32/boardctrl.c | 50 +++++++++++++++++++++++++++++++---------- ports/stm32/boardctrl.h | 30 +++++++++---------------- ports/stm32/main.c | 38 ++++++------------------------- 3 files changed, 56 insertions(+), 62 deletions(-) diff --git a/ports/stm32/boardctrl.c b/ports/stm32/boardctrl.c index 188068d705..c82fefa97c 100644 --- a/ports/stm32/boardctrl.c +++ b/ports/stm32/boardctrl.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include "py/runtime.h" #include "py/mphal.h" #include "lib/utils/pyexec.h" #include "boardctrl.h" @@ -140,13 +141,21 @@ void boardctrl_top_soft_reset_loop(boardctrl_state_t *state) { led_state(4, 0); } -void boardctrl_before_boot_py(boardctrl_state_t *state) { - state->run_boot_py = state->reset_mode == 1 || state->reset_mode == 3; -} +int boardctrl_run_boot_py(boardctrl_state_t *state) { + bool run_boot_py = state->reset_mode == 1 || state->reset_mode == 3; -void boardctrl_after_boot_py(boardctrl_state_t *state) { - if (state->run_boot_py && !state->last_ret) { - flash_error(4); + if (run_boot_py) { + // Run boot.py, if it exists. + const char *boot_py = "boot.py"; + int ret = pyexec_file_if_exists(boot_py); + + // Take action based on the execution result. + if (ret & PYEXEC_FORCED_EXIT) { + return BOARDCTRL_GOTO_SOFT_RESET_EXIT; + } + if (!ret) { + flash_error(4); + } } // Turn boot-up LEDs off @@ -160,17 +169,34 @@ void boardctrl_after_boot_py(boardctrl_state_t *state) { led_state(2, 0); led_state(3, 0); led_state(4, 0); + + return BOARDCTRL_CONTINUE; } -void boardctrl_before_main_py(boardctrl_state_t *state) { - state->run_main_py = (state->reset_mode == 1 || state->reset_mode == 3) +int boardctrl_run_main_py(boardctrl_state_t *state) { + bool run_main_py = (state->reset_mode == 1 || state->reset_mode == 3) && pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL; -} -void boardctrl_after_main_py(boardctrl_state_t *state) { - if (state->run_main_py && !state->last_ret) { - flash_error(3); + if (run_main_py) { + // Run main.py (or what it was configured to be), if it exists. + const char *main_py; + if (MP_STATE_PORT(pyb_config_main) == MP_OBJ_NULL) { + main_py = "main.py"; + } else { + main_py = mp_obj_str_get_str(MP_STATE_PORT(pyb_config_main)); + } + int ret = pyexec_file_if_exists(main_py); + + // Take action based on the execution result. + if (ret & PYEXEC_FORCED_EXIT) { + return BOARDCTRL_GOTO_SOFT_RESET_EXIT; + } + if (!ret) { + flash_error(3); + } } + + return BOARDCTRL_CONTINUE; } void boardctrl_start_soft_reset(boardctrl_state_t *state) { diff --git a/ports/stm32/boardctrl.h b/ports/stm32/boardctrl.h index f1cbc3b955..33e71b65c9 100644 --- a/ports/stm32/boardctrl.h +++ b/ports/stm32/boardctrl.h @@ -44,20 +44,12 @@ #define MICROPY_BOARD_TOP_SOFT_RESET_LOOP boardctrl_top_soft_reset_loop #endif -#ifndef MICROPY_BOARD_BEFORE_BOOT_PY -#define MICROPY_BOARD_BEFORE_BOOT_PY boardctrl_before_boot_py +#ifndef MICROPY_BOARD_RUN_BOOT_PY +#define MICROPY_BOARD_RUN_BOOT_PY boardctrl_run_boot_py #endif -#ifndef MICROPY_BOARD_AFTER_BOOT_PY -#define MICROPY_BOARD_AFTER_BOOT_PY boardctrl_after_boot_py -#endif - -#ifndef MICROPY_BOARD_BEFORE_MAIN_PY -#define MICROPY_BOARD_BEFORE_MAIN_PY boardctrl_before_main_py -#endif - -#ifndef MICROPY_BOARD_AFTER_MAIN_PY -#define MICROPY_BOARD_AFTER_MAIN_PY boardctrl_after_main_py +#ifndef MICROPY_BOARD_RUN_MAIN_PY +#define MICROPY_BOARD_RUN_MAIN_PY boardctrl_run_main_py #endif #ifndef MICROPY_BOARD_START_SOFT_RESET @@ -68,20 +60,20 @@ #define MICROPY_BOARD_END_SOFT_RESET boardctrl_end_soft_reset #endif +enum { + BOARDCTRL_CONTINUE, + BOARDCTRL_GOTO_SOFT_RESET_EXIT, +}; + typedef struct _boardctrl_state_t { uint8_t reset_mode; - bool run_boot_py; - bool run_main_py; bool log_soft_reset; - int last_ret; } boardctrl_state_t; void boardctrl_before_soft_reset_loop(boardctrl_state_t *state); void boardctrl_top_soft_reset_loop(boardctrl_state_t *state); -void boardctrl_before_boot_py(boardctrl_state_t *state); -void boardctrl_after_boot_py(boardctrl_state_t *state); -void boardctrl_before_main_py(boardctrl_state_t *state); -void boardctrl_after_main_py(boardctrl_state_t *state); +int boardctrl_run_boot_py(boardctrl_state_t *state); +int boardctrl_run_main_py(boardctrl_state_t *state); void boardctrl_start_soft_reset(boardctrl_state_t *state); void boardctrl_end_soft_reset(boardctrl_state_t *state); diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 888b20513c..bc8e6f0691 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -469,9 +469,7 @@ void stm32_main(uint32_t reset_mode) { boardctrl_state_t state; state.reset_mode = reset_mode; - state.run_boot_py = false; - state.run_main_py = false; - state.last_ret = 0; + state.log_soft_reset = false; MICROPY_BOARD_BEFORE_SOFT_RESET_LOOP(&state); @@ -566,20 +564,11 @@ soft_reset: // reset config variables; they should be set by boot.py MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL; - MICROPY_BOARD_BEFORE_BOOT_PY(&state); - - // run boot.py, if it exists - // TODO perhaps have pyb.reboot([bootpy]) function to soft-reboot and execute custom boot.py - if (state.run_boot_py) { - const char *boot_py = "boot.py"; - state.last_ret = pyexec_file_if_exists(boot_py); - if (state.last_ret & PYEXEC_FORCED_EXIT) { - goto soft_reset_exit; - } + // Run boot.py (or whatever else a board configures at this stage). + if (MICROPY_BOARD_RUN_BOOT_PY(&state) == BOARDCTRL_GOTO_SOFT_RESET_EXIT) { + goto soft_reset_exit; } - MICROPY_BOARD_AFTER_BOOT_PY(&state); - // Now we initialise sub-systems that need configuration from boot.py, // or whose initialisation can be safely deferred until after running // boot.py. @@ -613,24 +602,11 @@ soft_reset: // At this point everything is fully configured and initialised. - MICROPY_BOARD_BEFORE_MAIN_PY(&state); - - // Run the main script from the current directory. - if (state.run_main_py) { - const char *main_py; - if (MP_STATE_PORT(pyb_config_main) == MP_OBJ_NULL) { - main_py = "main.py"; - } else { - main_py = mp_obj_str_get_str(MP_STATE_PORT(pyb_config_main)); - } - state.last_ret = pyexec_file_if_exists(main_py); - if (state.last_ret & PYEXEC_FORCED_EXIT) { - goto soft_reset_exit; - } + // Run main.py (or whatever else a board configures at this stage). + if (MICROPY_BOARD_RUN_MAIN_PY(&state) == BOARDCTRL_GOTO_SOFT_RESET_EXIT) { + goto soft_reset_exit; } - MICROPY_BOARD_AFTER_MAIN_PY(&state); - #if MICROPY_ENABLE_COMPILER // Main script is finished, so now go into REPL mode. // The REPL mode can change, or it can request a soft reset. From 0fabda31de33b38c6858925d9195731deba6f54a Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Apr 2021 23:42:22 +1000 Subject: [PATCH 145/174] py/py.cmake: Move qstr helper code to micropy_gather_target_properties. Signed-off-by: Damien George --- ports/esp32/main/CMakeLists.txt | 17 +---------------- ports/rp2/CMakeLists.txt | 24 ++---------------------- py/py.cmake | 22 ++++++++++++++++++++++ 3 files changed, 25 insertions(+), 38 deletions(-) diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index d7d08ea663..1f4bb3175b 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -170,22 +170,7 @@ target_link_libraries(${MICROPY_TARGET} usermod) # Collect all of the include directories and compile definitions for the IDF components. foreach(comp ${IDF_COMPONENTS}) - get_target_property(type __idf_${comp} TYPE) - set(_inc OFF) - set(_def OFF) - if(${type} STREQUAL STATIC_LIBRARY) - get_target_property(_inc __idf_${comp} INCLUDE_DIRECTORIES) - get_target_property(_def __idf_${comp} COMPILE_DEFINITIONS) - elseif(${type} STREQUAL INTERFACE_LIBRARY) - get_target_property(_inc __idf_${comp} INTERFACE_INCLUDE_DIRECTORIES) - get_target_property(_def __idf_${comp} INTERFACE_COMPILE_DEFINITIONS) - endif() - if(_inc) - list(APPEND MICROPY_CPP_INC_EXTRA ${_inc}) - endif() - if(_def) - list(APPEND MICROPY_CPP_DEF_EXTRA ${_def}) - endif() + micropy_gather_target_properties(__idf_${comp}) endforeach() if(IDF_VERSION_MINOR GREATER_EQUAL 2) diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 37b041279f..5f3cdebd87 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -193,29 +193,9 @@ add_custom_command(TARGET ${MICROPY_TARGET} ) # Collect all the include directories and compile definitions for the pico-sdk components. -macro(_process_target targ) - if(TARGET ${targ}) - get_target_property(type ${targ} TYPE) - set(_inc OFF) - set(_def OFF) - if(${type} STREQUAL STATIC_LIBRARY) - get_target_property(_inc ${targ} INCLUDE_DIRECTORIES) - get_target_property(_def ${targ} COMPILE_DEFINITIONS) - elseif(${type} STREQUAL INTERFACE_LIBRARY) - get_target_property(_inc ${targ} INTERFACE_INCLUDE_DIRECTORIES) - get_target_property(_def ${targ} INTERFACE_COMPILE_DEFINITIONS) - endif() - if(_inc) - list(APPEND MICROPY_CPP_INC_EXTRA ${_inc}) - endif() - if(_def) - list(APPEND MICROPY_CPP_DEF_EXTRA ${_def}) - endif() - endif() -endmacro() foreach(comp ${PICO_SDK_COMPONENTS}) - _process_target(${comp}) - _process_target(${comp}_headers) + micropy_gather_target_properties(${comp}) + micropy_gather_target_properties(${comp}_headers) endforeach() # Include the main MicroPython cmake rules. diff --git a/py/py.cmake b/py/py.cmake index 52baaa8efc..be5deca251 100644 --- a/py/py.cmake +++ b/py/py.cmake @@ -122,3 +122,25 @@ set(MICROPY_SOURCE_PY ${MICROPY_PY_DIR}/vstr.c ${MICROPY_PY_DIR}/warning.c ) + +# Helper macro to collect include directories and compile definitions for qstr processing. +macro(micropy_gather_target_properties targ) + if(TARGET ${targ}) + get_target_property(type ${targ} TYPE) + set(_inc OFF) + set(_def OFF) + if(${type} STREQUAL STATIC_LIBRARY) + get_target_property(_inc ${targ} INCLUDE_DIRECTORIES) + get_target_property(_def ${targ} COMPILE_DEFINITIONS) + elseif(${type} STREQUAL INTERFACE_LIBRARY) + get_target_property(_inc ${targ} INTERFACE_INCLUDE_DIRECTORIES) + get_target_property(_def ${targ} INTERFACE_COMPILE_DEFINITIONS) + endif() + if(_inc) + list(APPEND MICROPY_CPP_INC_EXTRA ${_inc}) + endif() + if(_def) + list(APPEND MICROPY_CPP_DEF_EXTRA ${_def}) + endif() + endif() +endmacro() From 5dcc9b3b16cf6a27acf01bdf8a7d23ae2aff56e3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Apr 2021 00:59:16 +1000 Subject: [PATCH 146/174] py/py.cmake: Introduce MICROPY_INC_CORE as a list with core includes. Signed-off-by: Damien George --- ports/esp32/main/CMakeLists.txt | 2 +- ports/rp2/CMakeLists.txt | 2 +- ports/zephyr/CMakeLists.txt | 2 +- py/py.cmake | 2 ++ 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index 1f4bb3175b..2bfc09558e 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -132,7 +132,7 @@ idf_component_register( ${MICROPY_SOURCE_DRIVERS} ${MICROPY_SOURCE_PORT} INCLUDE_DIRS - ${MICROPY_DIR} + ${MICROPY_INC_CORE} ${MICROPY_INC_USERMOD} ${MICROPY_PORT_DIR} ${MICROPY_BOARD_DIR} diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 5f3cdebd87..100a834090 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -148,9 +148,9 @@ target_sources(${MICROPY_TARGET} PRIVATE target_link_libraries(${MICROPY_TARGET} usermod) target_include_directories(${MICROPY_TARGET} PRIVATE + ${MICROPY_INC_CORE} ${MICROPY_INC_USERMOD} "${PROJECT_SOURCE_DIR}" - "${MICROPY_DIR}" "${CMAKE_BINARY_DIR}" ) diff --git a/ports/zephyr/CMakeLists.txt b/ports/zephyr/CMakeLists.txt index 08868d716d..716642979a 100644 --- a/ports/zephyr/CMakeLists.txt +++ b/ports/zephyr/CMakeLists.txt @@ -85,7 +85,7 @@ set(MICROPY_CPP_FLAGS_EXTRA ${includes} ${system_includes} ${definitions} ${opti zephyr_library_named(${MICROPY_TARGET}) zephyr_library_include_directories( - ${MICROPY_DIR} + ${MICROPY_INC_CORE} ${MICROPY_PORT_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) diff --git a/py/py.cmake b/py/py.cmake index be5deca251..2b5d437b57 100644 --- a/py/py.cmake +++ b/py/py.cmake @@ -2,6 +2,8 @@ set(MICROPY_PY_DIR "${MICROPY_DIR}/py") +list(APPEND MICROPY_INC_CORE "${MICROPY_DIR}") + # All py/ source files set(MICROPY_SOURCE_PY ${MICROPY_PY_DIR}/argcheck.c From 212fe7f33e7427899ee245cda5ab1776b38a79e2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Apr 2021 23:45:28 +1000 Subject: [PATCH 147/174] extmod/extmod.cmake: Add support to build btree module with CMake. Signed-off-by: Damien George --- extmod/extmod.cmake | 48 +++++++++++++++++++++++++++++++++ ports/esp32/main/CMakeLists.txt | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/extmod/extmod.cmake b/extmod/extmod.cmake index 691c3ce9b3..a54047519d 100644 --- a/extmod/extmod.cmake +++ b/extmod/extmod.cmake @@ -4,6 +4,8 @@ set(MICROPY_EXTMOD_DIR "${MICROPY_DIR}/extmod") set(MICROPY_OOFATFS_DIR "${MICROPY_DIR}/lib/oofatfs") set(MICROPY_SOURCE_EXTMOD + ${MICROPY_DIR}/lib/embed/abort_.c + ${MICROPY_DIR}/lib/utils/printf.c ${MICROPY_EXTMOD_DIR}/machine_i2c.c ${MICROPY_EXTMOD_DIR}/machine_mem.c ${MICROPY_EXTMOD_DIR}/machine_pulse.c @@ -43,3 +45,49 @@ set(MICROPY_SOURCE_EXTMOD ${MICROPY_EXTMOD_DIR}/virtpin.c ${MICROPY_EXTMOD_DIR}/nimble/modbluetooth_nimble.c ) + +# Library for btree module and associated code + +set(MICROPY_LIB_BERKELEY_DIR "${MICROPY_DIR}/lib/berkeley-db-1.xx") + +if(EXISTS "${MICROPY_LIB_BERKELEY_DIR}/btree/bt_close.c") + add_library(micropy_extmod_btree OBJECT + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_close.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_conv.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_debug.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_delete.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_get.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_open.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_overflow.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_page.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_put.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_search.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_seq.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_split.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_utils.c + ${MICROPY_LIB_BERKELEY_DIR}/mpool/mpool.c + ) + + target_include_directories(micropy_extmod_btree PRIVATE + ${MICROPY_LIB_BERKELEY_DIR}/PORT/include + ) + + target_compile_definitions(micropy_extmod_btree PRIVATE + __DBINTERFACE_PRIVATE=1 + mpool_error=printf + abort=abort_ + "virt_fd_t=void*" + ) + + # The include directories and compile definitions below are needed to build + # modbtree.c and should be added to the main MicroPython target. + + list(APPEND MICROPY_INC_CORE + "${MICROPY_LIB_BERKELEY_DIR}/PORT/include" + ) + + list(APPEND MICROPY_DEF_CORE + __DBINTERFACE_PRIVATE=1 + "virt_fd_t=void*" + ) +endif() diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index 2bfc09558e..2223ecd031 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -3,10 +3,10 @@ get_filename_component(MICROPY_DIR ${PROJECT_DIR}/../.. ABSOLUTE) # Include core source components. include(${MICROPY_DIR}/py/py.cmake) -include(${MICROPY_DIR}/extmod/extmod.cmake) if(NOT CMAKE_BUILD_EARLY_EXPANSION) include(${MICROPY_DIR}/py/usermod.cmake) + include(${MICROPY_DIR}/extmod/extmod.cmake) endif() set(MICROPY_QSTRDEFS_PORT From ab9d47e0230768f82a735343fa5b58e2029d8eda Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Apr 2021 23:56:28 +1000 Subject: [PATCH 148/174] esp32: Enable btree module. This was disabled with the move to CMake, and this commit reinstates it. Signed-off-by: Damien George --- ports/esp32/main/CMakeLists.txt | 4 +++- ports/esp32/mpconfigport.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index 2223ecd031..aacdd40d31 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -149,6 +149,7 @@ set(MICROPY_CROSS_FLAGS -march=xtensawin) # Set compile options for this port. target_compile_definitions(${MICROPY_TARGET} PUBLIC + ${MICROPY_DEF_CORE} MICROPY_ESP_IDF_4=1 MICROPY_VFS_FAT=1 MICROPY_VFS_LFS2=1 @@ -164,7 +165,8 @@ target_compile_options(${MICROPY_TARGET} PUBLIC -Wno-missing-field-initializers ) -# add usermod +# Add additional extmod and usermod components. +target_link_libraries(${MICROPY_TARGET} micropy_extmod_btree) target_link_libraries(${MICROPY_TARGET} usermod) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 392f8c749c..c9c4b6268b 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -162,6 +162,7 @@ #define MICROPY_PY_UWEBSOCKET (1) #define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_FRAMEBUF (1) +#define MICROPY_PY_BTREE (1) #define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL) #define MICROPY_PY_BLUETOOTH_RANDOM_ADDR (1) #define MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME ("ESP32") From 7546d3cf73608b7888583d5bdbcec059954ccfe8 Mon Sep 17 00:00:00 2001 From: aziubin Date: Sun, 21 Mar 2021 18:34:05 +0200 Subject: [PATCH 149/174] stm32/boards/NUCLEO_L476RG: Add 5 remaining UARTs. STM32L476RG MCU of NUCLEO_L476RG board has 6 UART/USART units in total (USART1, USART2, USART3, UART4, UART5 and LPUART1), but only UART2, connected to REPL, was defined and available in Python code. Defined are all 5 remaining UART/USART units including LPUART1. Signed-off-by: Alexander Ziubin aziubin@googlemail.com --- .../boards/NUCLEO_L476RG/mpconfigboard.h | 75 ++++++++++++------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h index 00b033006b..2899a97ace 100644 --- a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h @@ -9,45 +9,64 @@ #define MICROPY_HW_ENABLE_DAC (1) // MSI is used and is 4MHz -#define MICROPY_HW_CLK_PLLM (1) -#define MICROPY_HW_CLK_PLLN (40) -#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) -#define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2) -#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) +#define MICROPY_HW_CLK_PLLM (1) +#define MICROPY_HW_CLK_PLLN (40) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) +#define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2) +#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) + +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 // The board has an external 32kHz crystal #define MICROPY_HW_RTC_USE_LSE (1) -// UART config -#define MICROPY_HW_UART2_TX (pin_A2) -#define MICROPY_HW_UART2_RX (pin_A3) - +// USART1 config +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) +// USART2 config. Connected to ST-Link +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +// USART3 config +#define MICROPY_HW_UART3_TX (pin_C4) +#define MICROPY_HW_UART3_RX (pin_C5) +#define MICROPY_HW_UART3_RTS (pin_B14) +#define MICROPY_HW_UART3_CTS (pin_B13) +// UART4 config +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +// UART5 config +#define MICROPY_HW_UART5_TX (pin_C12) +#define MICROPY_HW_UART5_RX (pin_D2) +// LPUART config +#define MICROPY_HW_LPUART1_TX (pin_C1) +#define MICROPY_HW_LPUART1_RX (pin_C0) +// USART2 is connected to the virtual com port on the ST-Link #define MICROPY_HW_UART_REPL PYB_UART_2 #define MICROPY_HW_UART_REPL_BAUD 115200 -#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 - // I2C busses -#define MICROPY_HW_I2C1_SCL (pin_B8) -#define MICROPY_HW_I2C1_SDA (pin_B9) -#define MICROPY_HW_I2C2_SCL (pin_B10) -#define MICROPY_HW_I2C2_SDA (pin_B11) -#define MICROPY_HW_I2C3_SCL (pin_C0) -#define MICROPY_HW_I2C3_SDA (pin_C1) +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) +#define MICROPY_HW_I2C3_SCL (pin_C0) +#define MICROPY_HW_I2C3_SDA (pin_C1) // SPI busses -#define MICROPY_HW_SPI1_NSS (pin_A4) -#define MICROPY_HW_SPI1_SCK (pin_B3) -#define MICROPY_HW_SPI1_MISO (pin_B4) -#define MICROPY_HW_SPI1_MOSI (pin_B5) -#define MICROPY_HW_SPI2_NSS (pin_B12) -#define MICROPY_HW_SPI2_SCK (pin_B13) -#define MICROPY_HW_SPI2_MISO (pin_B14) -#define MICROPY_HW_SPI2_MOSI (pin_B15) +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_B3) +#define MICROPY_HW_SPI1_MISO (pin_B4) +#define MICROPY_HW_SPI1_MOSI (pin_B5) +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) // CAN bus -#define MICROPY_HW_CAN1_TX (pin_A12) -#define MICROPY_HW_CAN1_RX (pin_A11) +#define MICROPY_HW_CAN1_TX (pin_A12) +#define MICROPY_HW_CAN1_RX (pin_A11) // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_C13) @@ -61,4 +80,4 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config -#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_FS (1) From 42035e5eded531d41319ffde999fa5a97478c872 Mon Sep 17 00:00:00 2001 From: Santeri Paavolainen Date: Wed, 24 Feb 2021 10:33:26 +0200 Subject: [PATCH 150/174] examples/embedding: Fix example so it compiles again. There were a few changes that had broken this example, specifically 2cdf1d25f59409b6130c0e8b6cf50300aed2d7e6 removed file.c from ports/unix. And (at least for MacOS) mp_state_ctx must be placed in the BSS with -fno-common so it is visible to the linker. Signed-off-by: Santeri Paavolainen --- examples/embedding/Makefile.upylib | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/embedding/Makefile.upylib b/examples/embedding/Makefile.upylib index 0e388332e6..00def493d6 100644 --- a/examples/embedding/Makefile.upylib +++ b/examples/embedding/Makefile.upylib @@ -21,6 +21,9 @@ CWARN = -Wall -Werror CWARN += -Wpointer-arith -Wuninitialized CFLAGS = $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) +# Some systems (eg MacOS) need -fno-common so that mp_state_ctx is placed in the BSS. +CFLAGS += -fno-common + # Debugging/Optimization ifdef DEBUG CFLAGS += -g @@ -133,7 +136,6 @@ SRC_C = $(addprefix ports/unix/,\ gccollect.c \ unix_mphal.c \ input.c \ - file.c \ modmachine.c \ modos.c \ moduselect.c \ @@ -146,6 +148,7 @@ SRC_C = $(addprefix ports/unix/,\ LIB_SRC_C = $(addprefix lib/,\ $(LIB_SRC_C_EXTRA) \ utils/printf.c \ + utils/gchelper_generic.c \ timeutils/timeutils.c \ ) From 2c9af1c1d7398bb340f7c78601be6ed2d79ee0b8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 15 Mar 2021 16:42:58 +1100 Subject: [PATCH 151/174] rp2/rp2_pio: Validate state machine frequency in constructor. Fixes issue #7025. Signed-off-by: Damien George --- ports/rp2/rp2_pio.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c index 9786e569d6..bd3e10a06c 100644 --- a/ports/rp2/rp2_pio.c +++ b/ports/rp2/rp2_pio.c @@ -462,13 +462,24 @@ STATIC mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *sel } // Compute the clock divider. - float div; + uint16_t clkdiv_int; + uint8_t clkdiv_frac; if (args[ARG_freq].u_int < 0) { - div = 1; + // Default: run at CPU frequency. + clkdiv_int = 1; + clkdiv_frac = 0; } else if (args[ARG_freq].u_int == 0) { - div = 0; + // Special case of 0: set clkdiv to 0. + clkdiv_int = 0; + clkdiv_frac = 0; } else { - div = (float)clock_get_hz(clk_sys) / (float)args[ARG_freq].u_int; + // Frequency given in Hz, compute clkdiv from it. + uint64_t div = (uint64_t)clock_get_hz(clk_sys) * 256ULL / (uint64_t)args[ARG_freq].u_int; + if (!(div >= 1 * 256 && div <= 65536 * 256)) { + mp_raise_ValueError(MP_ERROR_TEXT("freq out of range")); + } + clkdiv_int = div / 256; + clkdiv_frac = div & 0xff; } // Disable and reset the state machine. @@ -476,7 +487,7 @@ STATIC mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *sel // Build the state machine config. pio_sm_config config = pio_get_default_sm_config(); - sm_config_set_clkdiv(&config, div); + sm_config_set_clkdiv_int_frac(&config, clkdiv_int, clkdiv_frac); config.execctrl = mp_obj_get_int_truncated(prog[PROG_EXECCTRL]); config.shiftctrl = mp_obj_get_int_truncated(prog[PROG_SHIFTCTRL]); From 6f06dcaee57cc6f36a4121b4797942200b2d7281 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Wed, 17 Mar 2021 07:57:27 +0100 Subject: [PATCH 152/174] rp2/moduos: Implement uos.urandom(). The implementation samples rosc.randombits at a frequency lower than the oscillator frequency. This gives better random values. In addition, for an 8-bit value 8 samples are taken and fed through a 8-bit CRC, distributing the sampling over the byte. The resulting sampling rate is about 120k/sec. The RNG does not include testing of error conditions, like the ROSC being in sync with the sampling or completely failing. Making the interim value static causes it to perform a little bit better in short sync or drop-out situations. The output of uos.urandom() performs well with the NIST800-22 test suite. In my trial it passed all tests of the sts 2.1.2 test suite. I also ran a test of the random data with the Common Criteria test suite AIS 31, and it passed all tests too. --- ports/rp2/main.c | 16 ++++++++++++++-- ports/rp2/moduos.c | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/ports/rp2/main.c b/ports/rp2/main.c index 64218f97c5..8fddeaa560 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -30,6 +30,7 @@ #include "py/runtime.h" #include "py/gc.h" #include "py/mperrno.h" +#include "py/mphal.h" #include "py/stackctrl.h" #include "lib/mp-readline/readline.h" #include "lib/utils/gchelper.h" @@ -168,10 +169,21 @@ void MP_WEAK __assert_func(const char *file, int line, const char *func, const c } #endif +#define POLY (0xD5) + +uint8_t rosc_random_u8(size_t cycles) { + static uint8_t r; + for (size_t i = 0; i < cycles; ++i) { + r = ((r << 1) | rosc_hw->randombit) ^ (r & 0x80 ? POLY : 0); + mp_hal_delay_us_fast(1); + } + return r; +} + uint32_t rosc_random_u32(void) { uint32_t value = 0; - for (size_t i = 0; i < 32; ++i) { - value = value << 1 | rosc_hw->randombit; + for (size_t i = 0; i < 4; ++i) { + value = value << 8 | rosc_random_u8(32); } return value; } diff --git a/ports/rp2/moduos.c b/ports/rp2/moduos.c index 7ee662b5a4..02f34eb960 100644 --- a/ports/rp2/moduos.c +++ b/ports/rp2/moduos.c @@ -31,6 +31,8 @@ #include "extmod/vfs_lfs.h" #include "genhdr/mpversion.h" +uint8_t rosc_random_u8(size_t cycles); + STATIC const qstr os_uname_info_fields[] = { MP_QSTR_sysname, MP_QSTR_nodename, MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine @@ -57,10 +59,22 @@ STATIC mp_obj_t os_uname(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); +STATIC mp_obj_t os_urandom(mp_obj_t num) { + mp_int_t n = mp_obj_get_int(num); + vstr_t vstr; + vstr_init_len(&vstr, n); + for (int i = 0; i < n; i++) { + vstr.buf[i] = rosc_random_u8(8); + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); + STATIC const mp_rom_map_elem_t os_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, + { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) }, #if MICROPY_VFS { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, From 22554cf8e21ab97c60137539536eab05d6a6cdcb Mon Sep 17 00:00:00 2001 From: robert-hh Date: Mon, 1 Mar 2021 14:23:45 +0100 Subject: [PATCH 153/174] rp2/rp2_pio: Add StateMachine restart,rx_fifo,tx_fifo helper functions. StateMachine.restart: Restarts the state machine StateMachine.rx_fifo: Return the number of RX FIFO items, 0 if empty StateMachine.tx_fifo: Return the number of TX FIFO items, 0 if empty restart() seems to be the most useful one, as it resets the state machine to the initial state without the need to re-initialise/re-create. It also makes PIO code easier, because then stalling as an error state can be unlocked. rx_fifo() is also useful, for MP code to check for data and timeout if no data arrived. Complex logic is easier handled in Python code than in PIO code. tx_fifo() can be useful to check states where data is not processed, and is mostly for symmetry. --- ports/rp2/rp2_pio.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c index bd3e10a06c..5f93f10c26 100644 --- a/ports/rp2/rp2_pio.c +++ b/ports/rp2/rp2_pio.c @@ -66,6 +66,7 @@ typedef struct _rp2_state_machine_irq_obj_t { } rp2_state_machine_irq_obj_t; STATIC const rp2_state_machine_obj_t rp2_state_machine_obj[8]; +STATIC uint8_t rp2_state_machine_initial_pc[8]; STATIC mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); @@ -459,6 +460,7 @@ STATIC mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *sel if (offset < 0) { rp2_pio_add_program(&rp2_pio_obj[PIO_NUM(self->pio)], args[ARG_prog].u_obj); offset = mp_obj_get_int(prog[PROG_OFFSET_PIO0 + PIO_NUM(self->pio)]); + rp2_state_machine_initial_pc[self->id] = offset; } // Compute the clock divider. @@ -592,6 +594,15 @@ STATIC mp_obj_t rp2_state_machine_active(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2_state_machine_active_obj, 1, 2, rp2_state_machine_active); +// StateMachine.restart() +STATIC mp_obj_t rp2_state_machine_restart(mp_obj_t self_in) { + rp2_state_machine_obj_t *self = MP_OBJ_TO_PTR(self_in); + pio_sm_restart(self->pio, self->sm); + pio_sm_exec(self->pio, self->sm, pio_encode_jmp(rp2_state_machine_initial_pc[self->id])); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(rp2_state_machine_restart_obj, rp2_state_machine_restart); + // StateMachine.exec(instr) STATIC mp_obj_t rp2_state_machine_exec(mp_obj_t self_in, mp_obj_t instr_in) { rp2_state_machine_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -700,6 +711,20 @@ STATIC mp_obj_t rp2_state_machine_put(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2_state_machine_put_obj, 2, 3, rp2_state_machine_put); +// StateMachine.rx_fifo() +STATIC mp_obj_t rp2_state_machine_rx_fifo(mp_obj_t self_in) { + rp2_state_machine_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(pio_sm_get_rx_fifo_level(self->pio, self->sm)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(rp2_state_machine_rx_fifo_obj, rp2_state_machine_rx_fifo); + +// StateMachine.tx_fifo() +STATIC mp_obj_t rp2_state_machine_tx_fifo(mp_obj_t self_in) { + rp2_state_machine_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(pio_sm_get_tx_fifo_level(self->pio, self->sm)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(rp2_state_machine_tx_fifo_obj, rp2_state_machine_tx_fifo); + // StateMachine.irq(handler=None, trigger=0|1, hard=False) STATIC mp_obj_t rp2_state_machine_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_handler, ARG_trigger, ARG_hard }; @@ -759,9 +784,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(rp2_state_machine_irq_obj, 1, rp2_state_machin STATIC const mp_rom_map_elem_t rp2_state_machine_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&rp2_state_machine_init_obj) }, { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&rp2_state_machine_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&rp2_state_machine_restart_obj) }, { MP_ROM_QSTR(MP_QSTR_exec), MP_ROM_PTR(&rp2_state_machine_exec_obj) }, { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&rp2_state_machine_get_obj) }, { MP_ROM_QSTR(MP_QSTR_put), MP_ROM_PTR(&rp2_state_machine_put_obj) }, + { MP_ROM_QSTR(MP_QSTR_rx_fifo), MP_ROM_PTR(&rp2_state_machine_rx_fifo_obj) }, + { MP_ROM_QSTR(MP_QSTR_tx_fifo), MP_ROM_PTR(&rp2_state_machine_tx_fifo_obj) }, { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&rp2_state_machine_irq_obj) }, }; STATIC MP_DEFINE_CONST_DICT(rp2_state_machine_locals_dict, rp2_state_machine_locals_dict_table); From 1be74b94b6f3263b8e360a0a012ae87301539f91 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Thu, 11 Mar 2021 08:36:16 +0100 Subject: [PATCH 154/174] rp2/machine_uart: Add buffered transfer of data with rxbuf/txbuf kwargs. Instantiation and init now support the rxbuf and txbuf keywords for setting the buffer size. The default size is 256 bytes. The minimum and maximum sizes are 32 and 32766 respectively. uart.write() still includes checks for timeout, even if it is very unlikely to happen due to a) lack of flow control support and b) the minimal timeout values being longer than the time it needs to send a byte. --- ports/rp2/machine_uart.c | 159 +++++++++++++++++++++++++++++++++++---- ports/rp2/mpconfigport.h | 2 + 2 files changed, 147 insertions(+), 14 deletions(-) diff --git a/ports/rp2/machine_uart.c b/ports/rp2/machine_uart.c index 936b9a93e9..2da3ab41f8 100644 --- a/ports/rp2/machine_uart.c +++ b/ports/rp2/machine_uart.c @@ -28,9 +28,12 @@ #include "py/stream.h" #include "py/mphal.h" #include "py/mperrno.h" +#include "py/ringbuf.h" #include "modmachine.h" +#include "hardware/irq.h" #include "hardware/uart.h" +#include "hardware/regs/uart.h" #define DEFAULT_UART_BAUDRATE (115200) #define DEFAULT_UART_BITS (8) @@ -39,6 +42,9 @@ #define DEFAULT_UART0_RX (1) #define DEFAULT_UART1_TX (4) #define DEFAULT_UART1_RX (5) +#define DEFAULT_BUFFER_SIZE (256) +#define MIN_BUFFER_SIZE (32) +#define MAX_BUFFER_SIZE (32766) #define IS_VALID_PERIPH(uart, pin) (((((pin) + 4) & 8) >> 3) == (uart)) #define IS_VALID_TX(uart, pin) (((pin) & 3) == 0 && IS_VALID_PERIPH(uart, pin)) @@ -61,28 +67,81 @@ typedef struct _machine_uart_obj_t { uint16_t timeout; // timeout waiting for first char (in ms) uint16_t timeout_char; // timeout waiting between chars (in ms) uint8_t invert; + ringbuf_t read_buffer; + bool read_lock; + ringbuf_t write_buffer; + bool write_lock; } machine_uart_obj_t; STATIC machine_uart_obj_t machine_uart_obj[] = { - {{&machine_uart_type}, uart0, 0, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP, DEFAULT_UART0_TX, DEFAULT_UART0_RX, 0, 0, 0}, - {{&machine_uart_type}, uart1, 1, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP, DEFAULT_UART1_TX, DEFAULT_UART1_RX, 0, 0, 0}, + {{&machine_uart_type}, uart0, 0, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP, + DEFAULT_UART0_TX, DEFAULT_UART0_RX, 0, 0, 0, {NULL, 1, 0, 0}, 0, {NULL, 1, 0, 0}, 0}, + {{&machine_uart_type}, uart1, 1, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP, + DEFAULT_UART1_TX, DEFAULT_UART1_RX, 0, 0, 0, {NULL, 1, 0, 0}, 0, {NULL, 1, 0, 0}, 0,}, }; STATIC const char *_parity_name[] = {"None", "0", "1"}; STATIC const char *_invert_name[] = {"None", "INV_TX", "INV_RX", "INV_TX|INV_RX"}; +/******************************************************************************/ +// IRQ and buffer handling + +// take all bytes from the fifo and store them, if possible, in the buffer +STATIC void uart_drain_rx_fifo(machine_uart_obj_t *self) { + while (uart_is_readable(self->uart)) { + // try to write the data, ignore the fail + ringbuf_put(&(self->read_buffer), uart_get_hw(self->uart)->dr); + } +} + +// take bytes from the buffer and put them into the UART FIFO +STATIC void uart_fill_tx_fifo(machine_uart_obj_t *self) { + while (uart_is_writable(self->uart) && ringbuf_avail(&self->write_buffer) > 0) { + // get a byte from the buffer and put it into the uart + uart_get_hw(self->uart)->dr = ringbuf_get(&(self->write_buffer)); + } +} + +STATIC inline void uart_service_interrupt(machine_uart_obj_t *self) { + if (uart_get_hw(self->uart)->mis & UART_UARTMIS_RXMIS_BITS) { // rx interrupt? + // clear all interrupt bits but tx + uart_get_hw(self->uart)->icr = UART_UARTICR_BITS & (~UART_UARTICR_TXIC_BITS); + if (!self->read_lock) { + uart_drain_rx_fifo(self); + } + } + if (uart_get_hw(self->uart)->mis & UART_UARTMIS_TXMIS_BITS) { // tx interrupt? + // clear all interrupt bits but rx + uart_get_hw(self->uart)->icr = UART_UARTICR_BITS & (~UART_UARTICR_RXIC_BITS); + if (!self->write_lock) { + uart_fill_tx_fifo(self); + } + } +} + +STATIC void uart0_irq_handler(void) { + uart_service_interrupt(&machine_uart_obj[0]); +} + +STATIC void uart1_irq_handler(void) { + uart_service_interrupt(&machine_uart_obj[1]); +} + /******************************************************************************/ // MicroPython bindings for UART STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, timeout=%u, timeout_char=%u, invert=%s)", + mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, " + "txbuf=%d, rxbuf=%d, timeout=%u, timeout_char=%u, invert=%s)", self->uart_id, self->baudrate, self->bits, _parity_name[self->parity], - self->stop, self->tx, self->rx, self->timeout, self->timeout_char, _invert_name[self->invert]); + self->stop, self->tx, self->rx, self->write_buffer.size - 1, self->read_buffer.size - 1, + self->timeout, self->timeout_char, _invert_name[self->invert]); } STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_id, ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_timeout, ARG_timeout_char, ARG_invert }; + enum { ARG_id, ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, + ARG_timeout, ARG_timeout_char, ARG_invert, ARG_txbuf, ARG_rxbuf}; static const mp_arg_t allowed_args[] = { { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} }, @@ -94,6 +153,8 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_invert, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_txbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, }; // Parse args. @@ -169,6 +230,30 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, self->invert = args[ARG_invert].u_int; } + self->read_lock = false; + + // Set the RX buffer size if configured. + size_t rxbuf_len = DEFAULT_BUFFER_SIZE; + if (args[ARG_rxbuf].u_int > 0) { + rxbuf_len = args[ARG_rxbuf].u_int; + if (rxbuf_len < MIN_BUFFER_SIZE) { + rxbuf_len = MIN_BUFFER_SIZE; + } else if (rxbuf_len > MAX_BUFFER_SIZE) { + mp_raise_ValueError(MP_ERROR_TEXT("rxbuf too large")); + } + } + + // Set the TX buffer size if configured. + size_t txbuf_len = DEFAULT_BUFFER_SIZE; + if (args[ARG_txbuf].u_int > 0) { + txbuf_len = args[ARG_txbuf].u_int; + if (txbuf_len < MIN_BUFFER_SIZE) { + txbuf_len = MIN_BUFFER_SIZE; + } else if (txbuf_len > MAX_BUFFER_SIZE) { + mp_raise_ValueError(MP_ERROR_TEXT("txbuf too large")); + } + } + // Initialise the UART peripheral if any arguments given, or it was not initialised previously. if (n_args > 1 || n_kw > 0 || self->baudrate == 0) { if (self->baudrate == 0) { @@ -192,6 +277,25 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, if (self->invert & UART_INVERT_TX) { gpio_set_outover(self->tx, GPIO_OVERRIDE_INVERT); } + + // Allocate the RX/TX buffers. + ringbuf_alloc(&(self->read_buffer), rxbuf_len + 1); + MP_STATE_PORT(rp2_uart_rx_buffer[uart_id]) = self->read_buffer.buf; + + ringbuf_alloc(&(self->write_buffer), txbuf_len + 1); + MP_STATE_PORT(rp2_uart_tx_buffer[uart_id]) = self->write_buffer.buf; + + // Set the irq handler. + if (self->uart_id == 0) { + irq_set_exclusive_handler(UART0_IRQ, uart0_irq_handler); + irq_set_enabled(UART0_IRQ, true); + } else { + irq_set_exclusive_handler(UART1_IRQ, uart1_irq_handler); + irq_set_enabled(UART1_IRQ, true); + } + + // Enable the uart irq; this macro sets the rx irq level to 4. + uart_set_irq_enables(self->uart, true, true); } return MP_OBJ_FROM_PTR(self); @@ -199,7 +303,11 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_SMALL_INT(uart_is_readable(self->uart)); + // get all bytes from the fifo first + self->read_lock = true; + uart_drain_rx_fifo(self); + self->read_lock = false; + return MP_OBJ_NEW_SMALL_INT(ringbuf_avail(&self->read_buffer)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any); @@ -236,7 +344,7 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz for (size_t i = 0; i < size; i++) { // Wait for the first/next character - while (!uart_is_readable(self->uart)) { + while (ringbuf_avail(&self->read_buffer) == 0) { if (time_us_64() > t) { // timed out if (i <= 0) { *errcode = MP_EAGAIN; @@ -246,8 +354,12 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz } } MICROPY_EVENT_POLL_HOOK + // Force a few incoming bytes to the buffer + self->read_lock = true; + uart_drain_rx_fifo(self); + self->read_lock = false; } - *dest++ = uart_get_hw(self->uart)->dr; + *dest++ = ringbuf_get(&(self->read_buffer)); t = time_us_64() + timeout_char_us; } return size; @@ -258,10 +370,23 @@ STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uin uint64_t t = time_us_64() + (uint64_t)self->timeout * 1000; uint64_t timeout_char_us = (uint64_t)self->timeout_char * 1000; const uint8_t *src = buf_in; + size_t i = 0; - for (size_t i = 0; i < size; i++) { - // wait for the first/next character - while (!uart_is_writable(self->uart)) { + // Put as many bytes as possible into the transmit buffer. + while (i < size && ringbuf_free(&(self->write_buffer)) > 0) { + ringbuf_put(&(self->write_buffer), *src++); + ++i; + } + + // Kickstart the UART transmit. + self->write_lock = true; + uart_fill_tx_fifo(self); + self->write_lock = false; + + // Send the next characters while busy waiting. + while (i < size) { + // Wait for the first/next character to be sent. + while (ringbuf_free(&(self->write_buffer)) == 0) { if (time_us_64() > t) { // timed out if (i <= 0) { *errcode = MP_EAGAIN; @@ -272,9 +397,15 @@ STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uin } MICROPY_EVENT_POLL_HOOK } - uart_get_hw(self->uart)->dr = *src++; + ringbuf_put(&(self->write_buffer), *src++); + ++i; t = time_us_64() + timeout_char_us; + self->write_lock = true; + uart_fill_tx_fifo(self); + self->write_lock = false; } + + // Just in case the fifo was drained during refill of the ringbuf. return size; } @@ -284,10 +415,10 @@ STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint if (request == MP_STREAM_POLL) { uintptr_t flags = arg; ret = 0; - if ((flags & MP_STREAM_POLL_RD) && uart_is_readable(self->uart)) { + if ((flags & MP_STREAM_POLL_RD) && ringbuf_avail(&self->read_buffer) > 0) { ret |= MP_STREAM_POLL_RD; } - if ((flags & MP_STREAM_POLL_WR) && uart_is_writable(self->uart)) { + if ((flags & MP_STREAM_POLL_WR) && ringbuf_free(&self->write_buffer) > 0) { ret |= MP_STREAM_POLL_WR; } } else { diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index 13db589ec0..6c82d18620 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -174,6 +174,8 @@ extern const struct _mp_obj_module_t mp_module_utime; void *machine_pin_irq_obj[30]; \ void *rp2_pio_irq_obj[2]; \ void *rp2_state_machine_irq_obj[8]; \ + void *rp2_uart_rx_buffer[2]; \ + void *rp2_uart_tx_buffer[2]; \ #define MP_STATE_PORT MP_STATE_VM From 7ca686684ea5bffb45764bc3782f54133855a3c9 Mon Sep 17 00:00:00 2001 From: jahr Date: Mon, 5 Apr 2021 22:57:18 +0200 Subject: [PATCH 155/174] rp2: Add support for building different board configurations. This change allows to build firmware for different rp2-based boards, following how it is done in other ports like stm32 and esp32. So far only the original Pico and Adafruit Feather RP2040 are added. Board names should match (sans case) those in pico-sdk/src/boards/include/boards/. Usage: Pico firmware can be build either using make as previously (it is the default board) or by `make BOARD=PICO`. Feather is built by `make BOARD=ADAFRUIT_FEATHER_RP2040`. Only the board name and flash drive size is set, pin definition is taken from the appropriate pico-sdk board definition. Firmware is saved in the directory build-BOARD_NAME. --- ports/rp2/CMakeLists.txt | 25 +++++++++++++++++++ ports/rp2/Makefile | 6 +++-- .../mpconfigboard.cmake | 1 + .../ADAFRUIT_FEATHER_RP2040/mpconfigboard.h | 3 +++ ports/rp2/boards/PICO/mpconfigboard.cmake | 1 + ports/rp2/boards/PICO/mpconfigboard.h | 3 +++ ports/rp2/mpconfigport.h | 3 ++- 7 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.cmake create mode 100644 ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.h create mode 100644 ports/rp2/boards/PICO/mpconfigboard.cmake create mode 100644 ports/rp2/boards/PICO/mpconfigboard.h diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 100a834090..bd3eb74384 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -17,6 +17,30 @@ endif() # Use the local tinyusb instead of the one in pico-sdk set(PICO_TINYUSB_PATH ${MICROPY_DIR}/lib/tinyusb) +# Set the location of this port's directory. +set(MICROPY_PORT_DIR ${CMAKE_SOURCE_DIR}) + +# Set the board if it's not already set. +if(NOT MICROPY_BOARD) + set(MICROPY_BOARD PICO) +endif() + +# Set the PICO_BOARD if it's not already set. +if(NOT PICO_BOARD) + string(TOLOWER ${MICROPY_BOARD} PICO_BOARD) +endif() + +# Set the board directory and check that it exists. +if(NOT MICROPY_BOARD_DIR) + set(MICROPY_BOARD_DIR ${MICROPY_PORT_DIR}/boards/${MICROPY_BOARD}) +endif() +if(NOT EXISTS ${MICROPY_BOARD_DIR}/mpconfigboard.cmake) + message(FATAL_ERROR "Invalid MICROPY_BOARD specified: ${MICROPY_BOARD}") +endif() + +# Include board config +include(${MICROPY_BOARD_DIR}/mpconfigboard.cmake) + # Include component cmake fragments include(${MICROPY_DIR}/py/py.cmake) include(${MICROPY_DIR}/extmod/extmod.cmake) @@ -150,6 +174,7 @@ target_link_libraries(${MICROPY_TARGET} usermod) target_include_directories(${MICROPY_TARGET} PRIVATE ${MICROPY_INC_CORE} ${MICROPY_INC_USERMOD} + ${MICROPY_BOARD_DIR} "${PROJECT_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" ) diff --git a/ports/rp2/Makefile b/ports/rp2/Makefile index 3358c4ccae..246f29dd09 100644 --- a/ports/rp2/Makefile +++ b/ports/rp2/Makefile @@ -2,11 +2,13 @@ # # This is a simple wrapper around cmake -BUILD = build +BOARD ?= PICO + +BUILD ?= build-$(BOARD) $(VERBOSE)MAKESILENT = -s -CMAKE_ARGS = +CMAKE_ARGS = -DMICROPY_BOARD=$(BOARD) ifdef USER_C_MODULES CMAKE_ARGS += -DUSER_C_MODULES=${USER_C_MODULES} diff --git a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.cmake b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.cmake new file mode 100644 index 0000000000..877efa6aba --- /dev/null +++ b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.cmake @@ -0,0 +1 @@ +# cmake file for Adafruit Feather RP2040 diff --git a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.h b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.h new file mode 100644 index 0000000000..5068d35541 --- /dev/null +++ b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.h @@ -0,0 +1,3 @@ +// Board and hardware specific configuration +#define MICROPY_HW_BOARD_NAME "Adafruit Feather RP2040" +#define MICROPY_HW_FLASH_STORAGE_BYTES (3072 * 1024) diff --git a/ports/rp2/boards/PICO/mpconfigboard.cmake b/ports/rp2/boards/PICO/mpconfigboard.cmake new file mode 100644 index 0000000000..3a40ca2871 --- /dev/null +++ b/ports/rp2/boards/PICO/mpconfigboard.cmake @@ -0,0 +1 @@ +# cmake file for Raspberry Pi Pico diff --git a/ports/rp2/boards/PICO/mpconfigboard.h b/ports/rp2/boards/PICO/mpconfigboard.h new file mode 100644 index 0000000000..e6623374d0 --- /dev/null +++ b/ports/rp2/boards/PICO/mpconfigboard.h @@ -0,0 +1,3 @@ +// Board and hardware specific configuration +#define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico" +#define MICROPY_HW_FLASH_STORAGE_BYTES (1408 * 1024) diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index 6c82d18620..218cd72752 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -31,8 +31,9 @@ #include "hardware/sync.h" #include "pico/binary_info.h" +#include "mpconfigboard.h" + // Board and hardware specific configuration -#define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico" #define MICROPY_HW_MCU_NAME "RP2040" #define MICROPY_HW_ENABLE_UART_REPL (0) // useful if there is no USB #define MICROPY_HW_ENABLE_USBDEV (1) From dd62c52a36e224cd0518d0361cc66a2f7e957f93 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 12 Apr 2021 16:21:54 +1000 Subject: [PATCH 156/174] stm32/rfcore: Fix race condition with C2 accessing free buffer list. Prior to this commit, if C2 was busy (eg lots of BLE activity) then it may not have had time to respond to the notification on the IPCC_CH_MM channel by the time additional memory was available to put on that buffer. In such a case C1 would modify the free buffer list while C2 was potentially accessing it, and this would eventually lead to lost memory buffers (or a corrupt linked list). If all buffers become lost then ACL packets (asynchronous events) can no longer be delivered from C2 to C1. This commit fixes this issue by waiting for C2 to indicate that it has finished using the free buffer list. Work done in collaboration with Jim Mussared aka @jimmo. Signed-off-by: Damien George --- ports/stm32/rfcore.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/stm32/rfcore.c b/ports/stm32/rfcore.c index 55fc229dd0..878d5e1f85 100644 --- a/ports/stm32/rfcore.c +++ b/ports/stm32/rfcore.c @@ -417,6 +417,12 @@ STATIC void tl_process_msg(volatile tl_list_node_t *head, unsigned int ch, parse // If this node is allocated from the memmgr event pool, then place it into the free buffer. if ((uint8_t *)cur >= ipcc_membuf_memmgr_evt_pool && (uint8_t *)cur < ipcc_membuf_memmgr_evt_pool + sizeof(ipcc_membuf_memmgr_evt_pool)) { + // Wait for C2 to indicate that it has finished using the free buffer, + // so that we can link the newly-freed memory in to this buffer. + // If waiting is needed then it is typically between 5 and 20 microseconds. + while (LL_C1_IPCC_IsActiveFlag_CHx(IPCC, IPCC_CH_MM)) { + } + // Place memory back in free pool. tl_list_append(&ipcc_mem_memmgr_free_buf_queue, cur); added_to_free_queue = true; From 2668337f36deef7fdd97f35e2efc68a5d2102192 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 12 Apr 2021 16:30:53 +1000 Subject: [PATCH 157/174] stm32/rfcore: Intercept addr-resolution HCI cmd to work around BLE bug. The STM32WB has a problem when address resolution is enabled: under certain conditions the MCU can get into a state where it draws an additional 10mA or so and eventually ends up with a broken BLE RX path in the silicon. A simple way to reproduce this is to enable address resolution (which is the default for NimBLE) and start the device advertising. If there is enough BLE activity in the vicinity then the device will at some point enter the bad state and, if left long enough, will have permanent BLE RX damage. STMicroelectronics are aware of this issue. The only known workaround at this stage is to not enable address resolution, which is implemented by this commit. Work done in collaboration with Jim Mussared aka @jimmo. Signed-off-by: Damien George --- ports/stm32/rfcore.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ports/stm32/rfcore.c b/ports/stm32/rfcore.c index 878d5e1f85..049f6bdc10 100644 --- a/ports/stm32/rfcore.c +++ b/ports/stm32/rfcore.c @@ -610,6 +610,24 @@ void rfcore_ble_hci_cmd(size_t len, const uint8_t *src) { tl_list_node_t *n; uint32_t ch; if (src[0] == HCI_KIND_BT_CMD) { + // The STM32WB has a problem when address resolution is enabled: under certain + // conditions the MCU can get into a state where it draws an additional 10mA + // or so and eventually ends up with a broken BLE RX path in the silicon. A + // simple way to reproduce this is to enable address resolution (which is the + // default for NimBLE) and start the device advertising. If there is enough + // BLE activity in the vicinity then the device will at some point enter the + // bad state and, if left long enough, will have permanent BLE RX damage. + // + // STMicroelectronics are aware of this issue. The only known workaround at + // this stage is to not enable address resolution. We do that here by + // intercepting any command that enables address resolution and convert it + // into a command that disables address resolution. + // + // OGF=0x08 OCF=0x002d HCI_LE_Set_Address_Resolution_Enable + if (len == 5 && memcmp(src + 1, "\x2d\x20\x01\x01", 4) == 0) { + src = (const uint8_t *)"\x01\x2d\x20\x01\x00"; + } + n = (tl_list_node_t *)&ipcc_membuf_ble_cmd_buf[0]; ch = IPCC_CH_BLE; } else if (src[0] == HCI_KIND_BT_ACL) { From b26def0644b7f4c01cf616a24b6fe18f0737ebb6 Mon Sep 17 00:00:00 2001 From: matejcik Date: Fri, 9 Apr 2021 15:28:14 +0200 Subject: [PATCH 158/174] py/profile: Resolve name collision with STATIC unset. When building with STATIC undefined (e.g., -DSTATIC=), there are two instances of mp_type_code that collide at link time: in profile.c and in builtinevex.c. This patch resolves the collision by renaming one of them. --- py/profile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/profile.c b/py/profile.c index 863b0068a0..9cf8c4b7ba 100644 --- a/py/profile.c +++ b/py/profile.c @@ -172,7 +172,7 @@ STATIC void code_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } } -const mp_obj_type_t mp_type_code = { +const mp_obj_type_t mp_type_settrace_codeobj = { { &mp_type_type }, .name = MP_QSTR_code, .print = code_print, @@ -185,7 +185,7 @@ mp_obj_t mp_obj_new_code(const mp_raw_code_t *rc) { if (o == NULL) { return MP_OBJ_NULL; } - o->base.type = &mp_type_code; + o->base.type = &mp_type_settrace_codeobj; o->rc = rc; o->dict_locals = mp_locals_get(); // this is a wrong! how to do this properly? o->lnotab = MP_OBJ_NULL; From 1a2ffda175bb5842617841362b2df40d7cfa97dd Mon Sep 17 00:00:00 2001 From: matejcik Date: Mon, 22 Mar 2021 11:20:22 +0100 Subject: [PATCH 159/174] py/runtime: Make sys.modules preallocate to a configurable size. This allows configuring the pre-allocated size of sys.modules dict, in order to prevent unwanted reallocations at run-time (3 sys-modules is really not quite enough for a larger project). --- py/mpconfig.h | 5 +++++ py/runtime.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/py/mpconfig.h b/py/mpconfig.h index 454fc12b7c..b26fa2137a 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -229,6 +229,11 @@ #define MICROPY_MODULE_DICT_SIZE (1) #endif +// Initial size of sys.modules dict +#ifndef MICROPY_LOADED_MODULES_DICT_SIZE +#define MICROPY_LOADED_MODULES_DICT_SIZE (3) +#endif + // Whether realloc/free should be passed allocated memory region size // You must enable this if MICROPY_MEM_STATS is enabled #ifndef MICROPY_MALLOC_USES_ALLOCATED_SIZE diff --git a/py/runtime.c b/py/runtime.c index 5d476a2764..0ce6854732 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -91,7 +91,7 @@ void mp_init(void) { #endif // init global module dict - mp_obj_dict_init(&MP_STATE_VM(mp_loaded_modules_dict), 3); + mp_obj_dict_init(&MP_STATE_VM(mp_loaded_modules_dict), MICROPY_LOADED_MODULES_DICT_SIZE); // initialise the __main__ module mp_obj_dict_init(&MP_STATE_VM(dict_main), 1); From 25c029ce9fb0c2c313bfbf933e17648c98a33afc Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Apr 2021 23:22:08 +1000 Subject: [PATCH 160/174] stm32/boards: Split UARTx_RTS_DE into UARTx_RTS/UARTx_DE in pin defs. So these alternate functions can be parsed by the build scripts and used in application code. Signed-off-by: Damien George --- ports/stm32/boards/stm32l072_af.csv | 24 ++++++++++++------------ ports/stm32/boards/stm32l452_af.csv | 2 +- ports/stm32/boards/stm32l476_af.csv | 2 +- ports/stm32/boards/stm32wb55_af.csv | 6 +++--- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/ports/stm32/boards/stm32l072_af.csv b/ports/stm32/boards/stm32l072_af.csv index 0b1115b164..c9155bd444 100644 --- a/ports/stm32/boards/stm32l072_af.csv +++ b/ports/stm32/boards/stm32l072_af.csv @@ -1,7 +1,7 @@ Port,Pin,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,, ,,SPI1/SPI2/I2S2/USART1/2/LPUART1/USB/LPTIM1/TSC/TIM2/21/22/EVENTOUT/SYS_AF,SPI1/SPI2/I2S2/I2C1/TIM2/21,SPI1/SPI2/I2S2/LPUART1/USART5/USB/LPTIM1/TIM2/3/EVENTOUT/SYS_AF,I2C1/TSC/EVENTOUT,I2C1/USART1/2/LPUART1/TIM3/22/EVENTOUT,SPI2/I2S2/I2C2/USART1/TIM2/21/22,I2C1/2/LPUART1/USART4/UASRT5/TIM21/EVENTOUT,I2C3/LPUART1/COMP1/2/TIM3,,ADC PortA,PA0,,,TIM2_CH1,TSC_G1_IO1,USART2_CTS,TIM2_ETR,USART4_TX,COMP1_OUT,,ADC_IN0 -PortA,PA1,EVENTOUT,,TIM2_CH2,TSC_G1_IO2,USART2_RTS_DE,TIM21_ETR,USART4_RX,,,ADC_IN1 +PortA,PA1,EVENTOUT,,TIM2_CH2,TSC_G1_IO2,USART2_RTS/USART2_DE,TIM21_ETR,USART4_RX,,,ADC_IN1 PortA,PA2,TIM21_CH1,,TIM2_CH3,TSC_G1_IO3,USART2_TX,,LPUART1_TX,COMP2_OUT,,ADC_IN2 PortA,PA3,TIM21_CH2,,TIM2_CH4,TSC_G1_IO4,USART2_RX,,LPUART1_RX,,,ADC_IN3 PortA,PA4,SPI1_NSS,,,TSC_G2_IO1,USART2_CK,TIM22_ETR,,,,ADC_IN4 @@ -12,25 +12,25 @@ PortA,PA8,MCO,,USB_CRS_SYNC,EVENTOUT,USART1_CK,,,I2C3_SCL,, PortA,PA9,MCO,,,TSC_G4_IO1,USART1_TX,,I2C1_SCL,I2C3_SMBA,, PortA,PA10,,,,TSC_G4_IO2,USART1_RX,,I2C1_SDA,,, PortA,PA11,SPI1_MISO,,EVENTOUT,TSC_G4_IO3,USART1_CTS,,,COMP1_OUT,, -PortA,PA12,SPI1_MOSI,,EVENTOUT,TSC_G4_IO4,USART1_RTS_DE,,,COMP2_OUT,, +PortA,PA12,SPI1_MOSI,,EVENTOUT,TSC_G4_IO4,USART1_RTS/USART1_DE,,,COMP2_OUT,, PortA,PA13,SWDIO,,USB_NOE,,,,LPUART1_RX,,, PortA,PA14,SWCLK,,,,USART2_TX,,LPUART1_TX,,, -PortA,PA15,SPI1_NSS,,TIM2_ETR,EVENTOUT,USART2_RX,TIM2_CH1,USART4_RTS_DE,,, +PortA,PA15,SPI1_NSS,,TIM2_ETR,EVENTOUT,USART2_RX,TIM2_CH1,USART4_RTS/USART4_DE,,, PortB,PB0,EVENTOUT,,TIM3_CH3,TSC_G3_IO2,,,,,,ADC_IN8 -PortB,PB1,,,TIM3_CH4,TSC_G3_IO3,LPUART1_RTS_DE,,,,,ADC_IN9 +PortB,PB1,,,TIM3_CH4,TSC_G3_IO3,LPUART1_RTS/LPUART1_DE,,,,,ADC_IN9 PortB,PB2,,,LPTIM1_OUT,TSC_G3_IO4,,,,I2C3_SMBA,, -PortB,PB3,SPI1_SCK,,TIM2_CH2,TSC_G5_IO1,EVENTOUT,USART1_RTS_DE,USART5_TX,,, +PortB,PB3,SPI1_SCK,,TIM2_CH2,TSC_G5_IO1,EVENTOUT,USART1_RTS/USART1_DE,USART5_TX,,, PortB,PB4,SPI1_MISO,,TIM3_CH1,TSC_G5_IO2,TIM22_CH1,USART1_CTS,USART5_RX,I2C3_SDA,, -PortB,PB5,SPI1_MOSI,,LPTIM1_IN1,I2C1_SMBA,TIM3_CH2/TIM22_CH2,USART1_CK,USART5_CK/USART5_RTS_DE,,, +PortB,PB5,SPI1_MOSI,,LPTIM1_IN1,I2C1_SMBA,TIM3_CH2/TIM22_CH2,USART1_CK,USART5_CK/USART5_RTS/USART5_DE,,, PortB,PB6,USART1_TX,I2C1_SCL,LPTIM1_ETR,TSC_G5_IO3,,,,,, PortB,PB7,USART1_RX,I2C1_SDA,LPTIM1_IN2,TSC_G5_IO4,,,USART4_CTS,,, PortB,PB8,,,,TSC_SYNC,I2C1_SCL,,,,, PortB,PB9,,,EVENTOUT,,I2C1_SDA,SPI2_NSS/I2S2_WS,,,, PortB,PB10,,,TIM2_CH3,TSC_SYNC,LPUART1_TX,SPI2_SCK,I2C2_SCL,LPUART1_RX,, PortB,PB11,EVENTOUT,,TIM2_CH4,TSC_G6_IO1,LPUART1_RX,,I2C2_SDA,LPUART1_TX,, -PortB,PB12,SPI2_NSS/I2S2_WS,,LPUART1_RTS_DE,TSC_G6_IO2,I2C2_SMBA,,EVENTOUT,,, +PortB,PB12,SPI2_NSS/I2S2_WS,,LPUART1_RTS/LPUART1_DE,TSC_G6_IO2,I2C2_SMBA,,EVENTOUT,,, PortB,PB13,SPI2_SCK/I2S2_CK,,MCO,TSC_G6_IO3,LPUART1_CTS,I2C2_SCL,TIM21_CH1,,, -PortB,PB14,SPI2_MISO/I2S2_MCK,,RTC_OUT,TSC_G6_IO4,LPUART1_RTS_DE,I2C2_SDA,TIM21_CH2,,, +PortB,PB14,SPI2_MISO/I2S2_MCK,,RTC_OUT,TSC_G6_IO4,LPUART1_RTS/LPUART1_DE,I2C2_SDA,TIM21_CH2,,, PortB,PB15,SPI2_MOSI/I2S2_SD,,RTC_REFIN,,,,,,, PortC,PC0,LPTIM1_IN1,,EVENTOUT,TSC_G7_IO1,,,LPUART1_RX,I2C3_SCL,,ADC_IN10 PortC,PC1,LPTIM1_OUT,,EVENTOUT,TSC_G7_IO2,,,LPUART1_TX,I2C3_SDA,,ADC_IN11 @@ -50,9 +50,9 @@ PortC,PC14,,,,,,,,,, PortC,PC15,,,,,,,,,, PortD,PD0,TIM21_CH1,SPI2_NSS/I2S2_WS,,,,,,,, PortD,PD1,,SPI2_SCK/I2S2_CK,,,,,,,, -PortD,PD2,LPUART1_RTS_DE,,TIM3_ETR,,,,USART5_RX,,, +PortD,PD2,LPUART1_RTS/LPUART1_DE,,TIM3_ETR,,,,USART5_RX,,, PortD,PD3,USART2_CTS,,SPI2_MISO/I2S2_MCK,,,,,,, -PortD,PD4,USART2_RTS_DE,SPI2_MOSI/I2S2_SD,,,,,,,, +PortD,PD4,USART2_RTS/USART2_DE,SPI2_MOSI/I2S2_SD,,,,,,,, PortD,PD5,USART2_TX,,,,,,,,, PortD,PD6,USART2_RX,,,,,,,,, PortD,PD7,USART2_CK,TIM21_CH2,,,,,,,, @@ -60,7 +60,7 @@ PortD,PD8,LPUART1_TX,,,,,,,,, PortD,PD9,LPUART1_RX,,,,,,,,, PortD,PD10,,,,,,,,,, PortD,PD11,LPUART1_CTS,,,,,,,,, -PortD,PD12,LPUART1_RTS_DE,,,,,,,,, +PortD,PD12,LPUART1_RTS/LPUART1_DE,,,,,,,,, PortD,PD13,,,,,,,,,, PortD,PD14,,,,,,,,,, PortD,PD15,USB_CRS_SYNC,,,,,,,,, @@ -71,7 +71,7 @@ PortE,PE3,TIM22_CH1,,TIM3_CH1,,,,,,, PortE,PE4,TIM22_CH2,,TIM3_CH2,,,,,,, PortE,PE5,TIM21_CH1,,TIM3_CH3,,,,,,, PortE,PE6,TIM21_CH2,,TIM3_CH4,,,,,,, -PortE,PE7,,,,,,,USART5_CK/USART5_RTS_DE,,, +PortE,PE7,,,,,,,USART5_CK/USART5_RTS/USART5_DE,,, PortE,PE8,,,,,,,USART4_TX,,, PortE,PE9,TIM2_CH1,,TIM2_ETR,,,,USART4_RX,,, PortE,PE10,TIM2_CH2,,,,,,USART5_TX,,, diff --git a/ports/stm32/boards/stm32l452_af.csv b/ports/stm32/boards/stm32l452_af.csv index f7170d1c65..1de5c211d2 100644 --- a/ports/stm32/boards/stm32l452_af.csv +++ b/ports/stm32/boards/stm32l452_af.csv @@ -30,7 +30,7 @@ PortB,PB10,,TIM2_CH3,,I2C4_SCL,I2C2_SCL,SPI2_SCK,,USART3_TX,LPUART1_RX,TSC_SYNC, PortB,PB11,,TIM2_CH4,,I2C4_SDA,I2C2_SDA,,,USART3_RX,LPUART1_TX,,QUADSPI_NCS,,COMP2_OUT,,,EVENTOUT,,, PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS/LPUART1_DE,TSC_G1_IO1,CAN1_RX,,,SAI1_FS_A,TIM15_BKIN,EVENTOUT,,, PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,CAN1_TX,,,SAI1_SCK_A,TIM15_CH1N,EVENTOUT,,, -PortB,PB14,,TIM1_CH2N,,,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS_DE,,TSC_G1_IO3,,,,SAI1_MCLK_A,TIM15_CH1,EVENTOUT,,, +PortB,PB14,,TIM1_CH2N,,,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS/USART3_DE,,TSC_G1_IO3,,,,SAI1_MCLK_A,TIM15_CH1,EVENTOUT,,, PortB,PB15,RTC_REFIN,TIM1_CH3N,,,,SPI2_MOSI,DFSDM_CKIN2,,,TSC_G1_IO4,,,,SAI1_SD_A,TIM15_CH2,EVENTOUT,,, PortC,PC0,,LPTIM1_IN1,I2C4_SCL,,I2C3_SCL,,,,LPUART1_RX,,,,,,LPTIM2_IN1,EVENTOUT,ADC123_IN1,, PortC,PC1,TRACED0,LPTIM1_OUT,I2C4_SDA,,I2C3_SDA,,,,LPUART1_TX,,,,,,,EVENTOUT,ADC123_IN2,, diff --git a/ports/stm32/boards/stm32l476_af.csv b/ports/stm32/boards/stm32l476_af.csv index 01db895725..df824ed708 100644 --- a/ports/stm32/boards/stm32l476_af.csv +++ b/ports/stm32/boards/stm32l476_af.csv @@ -30,7 +30,7 @@ PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK,DFSDM_DATIN7,USART3_TX,LPUART1_RX,,QUAD PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,LPUART1_TX,,QUADSPI_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT,, PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS/LPUART1_DE,TSC_G1_IO1,,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,, PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,,LCD_SEG13,SWPMI1_TX,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,, -PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS/USART3_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,, PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI,DFSDM_CKIN2,,,TSC_G1_IO4,,LCD_SEG15,SWPMI1_SUSPEND,SAI2_SD_A,TIM15_CH2,EVENTOUT,, PortC,PC0,,LPTIM1_IN1,,,I2C3_SCL,,DFSDM_DATIN4,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT,ADC123_IN1, PortC,PC1,,LPTIM1_OUT,,,I2C3_SDA,,DFSDM_CKIN4,,LPUART1_TX,,,LCD_SEG19,,,,EVENTOUT,ADC123_IN2, diff --git a/ports/stm32/boards/stm32wb55_af.csv b/ports/stm32/boards/stm32wb55_af.csv index 074c330892..d6e1c3f773 100644 --- a/ports/stm32/boards/stm32wb55_af.csv +++ b/ports/stm32/boards/stm32wb55_af.csv @@ -12,14 +12,14 @@ PortA,PA8,MCO,TIM1_CH1,,SAI1_PDM_CK2,,,,USART1_CK,,,,LCD_COM0,,SAI1_SCK_A,LPTIM2 PortA,PA9,,TIM1_CH2,,SAI1_PDM_DI2,I2C1_SCL,SPI2_SCK,,USART1_TX,,,,LCD_COM1,,SAI1_FS_A,,EVENTOUT,ADC1_IN16 PortA,PA10,,TIM1_CH3,,SAI1_PDM_DI1,I2C1_SDA,,,USART1_RX,,,USB_CRS_SYNC,LCD_COM2,,SAI1_SD_A,TIM17_BKIN,EVENTOUT, PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,SPI1_MISO,,USART1_CTS,,,USB_DM,,TIM1_BKIN2,,,EVENTOUT, -PortA,PA12,,TIM1_ETR,,,,SPI1_MOSI,,USART1_RTS_DE,LPUART1_RX,,USB_DP,,,,,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,SPI1_MOSI,,USART1_RTS/USART1_DE,LPUART1_RX,,USB_DP,,,,,EVENTOUT, PortA,PA13,JTMS/SWDIO,,,,,,,,IR_OUT,,USB_NOE,,,SAI1_SD_B,,EVENTOUT, PortA,PA14,JTCK/SWCLK,LPTIM1_OUT,,,I2C1_SMBA,,,,,,,LCD_SEG5,,SAI1_FS_B,,EVENTOUT, PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,,,,TSC_G3_IO1,,LCD_SEG17,,,,EVENTOUT, PortB,PB0,,,,,,,EXT_PA_TX,,,,,,COMP1_OUT,,,EVENTOUT, -PortB,PB1,,,,,,,,,LPUART1_RTS_DE,,,,,,LPTIM2_IN1,EVENTOUT, +PortB,PB1,,,,,,,,,LPUART1_RTS/LPUART1_DE,,,,,,LPTIM2_IN1,EVENTOUT, PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,SPI1_NSS,,,,,,LCD_VLCD,,SAI1_EXTCLK,,EVENTOUT, -PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,,USART1_RTS_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,,USART1_RTS/USART1_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT, PortB,PB4,NJTRST,,,,I2C3_SDA,SPI1_MISO,,USART1_CTS,,TSC_G2_IO1,,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT, PortB,PB5,,LPTIM1_IN1,,,I2C1_SMBA,SPI1_MOSI,,USART1_CK,LPUART1_TX,TSC_G2_IO2,,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT, PortB,PB6,MCO,LPTIM1_ETR,,,I2C1_SCL,,,USART1_TX,,TSC_G2_IO3,,LCD_SEG6,,SAI1_FS_B,TIM16_CH1N,EVENTOUT, From 2ac09c2694f89b11544f4abf10413c64eeec2b15 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Apr 2021 23:56:37 +1000 Subject: [PATCH 161/174] stm32/uart: Use LL_USART_GetBaudRate to compute baudrate. This function includes the UART prescaler in the calculation (if it has one, eg on H7 and WB MCUs). Signed-off-by: Damien George --- ports/stm32/uart.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index d40a883c52..36c59cee4a 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -711,16 +711,11 @@ uint32_t uart_get_source_freq(pyb_uart_obj_t *self) { } uint32_t uart_get_baudrate(pyb_uart_obj_t *self) { - // This formula assumes UART_OVERSAMPLING_16 - uint32_t source_freq = uart_get_source_freq(self); - #if defined(LPUART1) - if (self->uart_id == PYB_LPUART_1) { - return source_freq / (self->uartx->BRR >> 8); - } else - #endif - { - return source_freq / self->uartx->BRR; - } + return LL_USART_GetBaudRate(self->uartx, uart_get_source_freq(self), + #if defined(STM32H7) || defined(STM32WB) + self->uartx->PRESC, + #endif + LL_USART_OVERSAMPLING_16); } void uart_set_baudrate(pyb_uart_obj_t *self, uint32_t baudrate) { From 9c9bfe1968d4260924316353bd1c941fe7e8741d Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Tue, 30 Mar 2021 20:08:11 +0200 Subject: [PATCH 162/174] unix/main: Make static variable that's potentially clobbered by longjmp. This fixes `error: variable 'subpkg_tried' might be clobbered by 'longjmp' or 'vfork' [-Werror=clobbered]` when compiling on ppc64le and aarch64 (and possibly other architectures/toolchains). --- ports/unix/main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ports/unix/main.c b/ports/unix/main.c index 129c6d3bb4..e33c1742d8 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -596,7 +596,12 @@ MP_NOINLINE int main_(int argc, char **argv) { mp_obj_t mod; nlr_buf_t nlr; - bool subpkg_tried = false; + + // Allocating subpkg_tried on the stack can lead to compiler warnings about this + // variable being clobbered when nlr is implemented using setjmp/longjmp. Its + // value must be preserved across calls to setjmp/longjmp. + static bool subpkg_tried; + subpkg_tried = false; reimport: if (nlr_push(&nlr) == 0) { From fc6ea28d00ca733f3ed806cc660f94c606ded4fb Mon Sep 17 00:00:00 2001 From: 8bitgeek Date: Mon, 5 Apr 2021 06:55:39 -0400 Subject: [PATCH 163/174] stm32/sdram: Make MICROPY_HW_FMC_BA1,MICROPY_HW_FMC_A11 optional pins. This supports SDRAM having only 2 internal banks (using BA0 only), and only 11 (A0-A10) bits of address, such as IS42S16100H (512K x 16bit x 2bank). --- ports/stm32/sdram.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/stm32/sdram.c b/ports/stm32/sdram.c index e8892b5746..2791df277a 100644 --- a/ports/stm32/sdram.c +++ b/ports/stm32/sdram.c @@ -73,7 +73,9 @@ bool sdram_init(void) { mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_SDNRAS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_SDNRAS); mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_SDNWE, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_SDNWE); mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_BA0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_BA0); + #ifdef MICROPY_HW_FMC_BA1 mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_BA1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_BA1); + #endif mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_NBL0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_NBL0); mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_NBL1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_NBL1); #ifdef MICROPY_HW_FMC_NBL2 @@ -91,7 +93,9 @@ bool sdram_init(void) { mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A8, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A8); mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A9, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A9); mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A10, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A10); + #ifdef MICROPY_HW_FMC_A11 mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A11, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A11); + #endif #ifdef MICROPY_HW_FMC_A12 mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A12, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A12); #endif From d0e014aa41e32a80a7b591d4de6f2b1ed1298e4d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 14 Apr 2021 12:55:53 +1000 Subject: [PATCH 164/174] mimxrt: Enable CPYTHON_COMPAT, PY_ASYNC_AWAIT, PY_ATTRTUPLE options. This change allows running the tests in tests/basics/ without any failures (but some tests are still skipped). Signed-off-by: Damien George --- ports/mimxrt/mpconfigport.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index 68c7a89422..65b91675a5 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -46,11 +46,9 @@ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) -#define MICROPY_CPYTHON_COMPAT (0) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) // Control over Python builtins -#define MICROPY_PY_ASYNC_AWAIT (0) #define MICROPY_PY_BUILTINS_STR_COUNT (0) #define MICROPY_PY_BUILTINS_MEMORYVIEW (1) #define MICROPY_PY_BUILTINS_SET (1) @@ -63,7 +61,6 @@ #define MICROPY_PY___FILE__ (0) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) -#define MICROPY_PY_ATTRTUPLE (0) #define MICROPY_PY_COLLECTIONS (0) #define MICROPY_PY_SYS_MAXSIZE (1) From 7f366a2190825555c16f57f5dfd4d0d57efd7c1f Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 14 Apr 2021 14:55:55 +1000 Subject: [PATCH 165/174] esp32/modsocket: Correctly handle poll/read of unconnected TCP socket. For an unconnected TCP socket, poll should return WR|HUP and read should raise ENOTCONN. This is implemented by this commit and now the following tests pass on esp32: extmod/usocket_tcp_basic.py, net_hosted/connect_poll.py. Signed-off-by: Damien George --- ports/esp32/modsocket.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 5135e31631..67b1d7d6f0 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -59,13 +59,19 @@ #define MDNS_QUERY_TIMEOUT_MS (5000) #define MDNS_LOCAL_SUFFIX ".local" +enum { + SOCKET_STATE_NEW, + SOCKET_STATE_CONNECTED, + SOCKET_STATE_PEER_CLOSED, +}; + typedef struct _socket_obj_t { mp_obj_base_t base; int fd; uint8_t domain; uint8_t type; uint8_t proto; - bool peer_closed; + uint8_t state; unsigned int retries; #if MICROPY_PY_USOCKET_EVENTS mp_obj_t events_callback; @@ -254,7 +260,6 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, siz sock->domain = AF_INET; sock->type = SOCK_STREAM; sock->proto = 0; - sock->peer_closed = false; if (n_args > 0) { sock->domain = mp_obj_get_int(args[0]); if (n_args > 1) { @@ -265,6 +270,8 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, siz } } + sock->state = sock->type == SOCK_STREAM ? SOCKET_STATE_NEW : SOCKET_STATE_CONNECTED; + sock->fd = lwip_socket(sock->domain, sock->type, sock->proto); if (sock->fd < 0) { mp_raise_OSError(errno); @@ -278,6 +285,7 @@ STATIC mp_obj_t socket_bind(const mp_obj_t arg0, const mp_obj_t arg1) { socket_obj_t *self = MP_OBJ_TO_PTR(arg0); struct addrinfo *res; _socket_getaddrinfo(arg1, &res); + self->state = SOCKET_STATE_CONNECTED; int r = lwip_bind(self->fd, res->ai_addr, res->ai_addrlen); lwip_freeaddrinfo(res); if (r < 0) { @@ -290,6 +298,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); STATIC mp_obj_t socket_listen(const mp_obj_t arg0, const mp_obj_t arg1) { socket_obj_t *self = MP_OBJ_TO_PTR(arg0); int backlog = mp_obj_get_int(arg1); + self->state = SOCKET_STATE_CONNECTED; int r = lwip_listen(self->fd, backlog); if (r < 0) { mp_raise_OSError(errno); @@ -332,7 +341,7 @@ STATIC mp_obj_t socket_accept(const mp_obj_t arg0) { sock->domain = self->domain; sock->type = self->type; sock->proto = self->proto; - sock->peer_closed = false; + sock->state = SOCKET_STATE_CONNECTED; _socket_settimeout(sock, UINT64_MAX); // make the return value @@ -351,6 +360,7 @@ STATIC mp_obj_t socket_connect(const mp_obj_t arg0, const mp_obj_t arg1) { struct addrinfo *res; _socket_getaddrinfo(arg1, &res); MP_THREAD_GIL_EXIT(); + self->state = SOCKET_STATE_CONNECTED; int r = lwip_connect(self->fd, res->ai_addr, res->ai_addrlen); MP_THREAD_GIL_ENTER(); lwip_freeaddrinfo(res); @@ -471,11 +481,17 @@ STATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size, struct sockaddr *from, socklen_t *from_len, int *errcode) { socket_obj_t *sock = MP_OBJ_TO_PTR(self_in); + // A new socket cannot be read from. + if (sock->state == SOCKET_STATE_NEW) { + *errcode = MP_ENOTCONN; + return MP_STREAM_ERROR; + } + // If the peer closed the connection then the lwIP socket API will only return "0" once // from lwip_recvfrom and then block on subsequent calls. To emulate POSIX behaviour, // which continues to return "0" for each call on a closed socket, we set a flag when // the peer closed the socket. - if (sock->peer_closed) { + if (sock->state == SOCKET_STATE_PEER_CLOSED) { return 0; } @@ -500,7 +516,7 @@ STATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size, MP_THREAD_GIL_ENTER(); } if (r == 0) { - sock->peer_closed = true; + sock->state = SOCKET_STATE_PEER_CLOSED; } if (r >= 0) { return r; @@ -702,6 +718,12 @@ STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt if (FD_ISSET(socket->fd, &efds)) { ret |= MP_STREAM_POLL_HUP; } + + // New (unconnected) sockets are writable and have HUP set. + if (socket->state == SOCKET_STATE_NEW) { + ret |= (arg & MP_STREAM_POLL_WR) | MP_STREAM_POLL_HUP; + } + return ret; } else if (request == MP_STREAM_CLOSE) { if (socket->fd >= 0) { From 8459f538eb45fd8e1e4d614298449cf18de84d75 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Apr 2021 00:47:24 +1000 Subject: [PATCH 166/174] tests/feature_check: Check for lack of pass result rather than failure. Commit cb68a5741aba5d4935428674234a9d643f97405f broke automatic Python feature detection when running tests, because some detection relied on a crash of a feature script returning exactly b"CRASH". This commit fixes this and improves the situation by testing for the lack of a known pass result, rather than an exact failure result. Signed-off-by: Damien George --- tests/feature_check/async_check.py | 3 +++ tests/feature_check/const.py | 1 + tests/feature_check/native_check.py | 4 ++++ tests/feature_check/set_check.py | 2 +- tests/run-tests.py | 14 +++++++------- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/feature_check/async_check.py b/tests/feature_check/async_check.py index 0f6361cd12..727b7136a5 100644 --- a/tests/feature_check/async_check.py +++ b/tests/feature_check/async_check.py @@ -1,3 +1,6 @@ # check if async/await keywords are supported async def foo(): await 1 + + +print("async") diff --git a/tests/feature_check/const.py b/tests/feature_check/const.py index db32e8c69b..e5928f6d76 100644 --- a/tests/feature_check/const.py +++ b/tests/feature_check/const.py @@ -1 +1,2 @@ x = const(1) +print(x) diff --git a/tests/feature_check/native_check.py b/tests/feature_check/native_check.py index 3971d1355f..4dc9754d0c 100644 --- a/tests/feature_check/native_check.py +++ b/tests/feature_check/native_check.py @@ -2,3 +2,7 @@ @micropython.native def f(): pass + + +f() +print("native") diff --git a/tests/feature_check/set_check.py b/tests/feature_check/set_check.py index ec186cc5b9..0c7612843a 100644 --- a/tests/feature_check/set_check.py +++ b/tests/feature_check/set_check.py @@ -1,2 +1,2 @@ # check if set literal syntax is supported -{1} +print({1}) diff --git a/tests/run-tests.py b/tests/run-tests.py index ae63f9a29a..a5a9b60637 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -279,7 +279,7 @@ def run_tests(pyb, tests, args, result_dir): # Check if micropython.native is supported, and skip such tests if it's not output = run_feature_check(pyb, args, base_path, "native_check.py") - if output == b"CRASH": + if output != b"native\n": skip_native = True # Check if arbitrary-precision integers are supported, and skip such tests if it's not @@ -294,7 +294,7 @@ def run_tests(pyb, tests, args, result_dir): # Check if set type (and set literals) is supported, and skip such tests if it's not output = run_feature_check(pyb, args, base_path, "set_check.py") - if output == b"CRASH": + if output != b"{1}\n": skip_set_type = True # Check if slice is supported, and skip such tests if it's not @@ -304,12 +304,12 @@ def run_tests(pyb, tests, args, result_dir): # Check if async/await keywords are supported, and skip such tests if it's not output = run_feature_check(pyb, args, base_path, "async_check.py") - if output == b"CRASH": + if output != b"async\n": skip_async = True # Check if const keyword (MicroPython extension) is supported, and skip such tests if it's not output = run_feature_check(pyb, args, base_path, "const.py") - if output == b"CRASH": + if output != b"1\n": skip_const = True # Check if __rOP__ special methods are supported, and skip such tests if it's not @@ -334,10 +334,10 @@ def run_tests(pyb, tests, args, result_dir): upy_byteorder = run_feature_check(pyb, args, base_path, "byteorder.py") upy_float_precision = run_feature_check(pyb, args, base_path, "float.py") - if upy_float_precision == b"CRASH": - upy_float_precision = 0 - else: + try: upy_float_precision = int(upy_float_precision) + except ValueError: + upy_float_precision = 0 has_complex = run_feature_check(pyb, args, base_path, "complex.py") == b"complex\n" has_coverage = run_feature_check(pyb, args, base_path, "coverage.py") == b"coverage\n" cpy_byteorder = subprocess.check_output( From 66a86a061530eeee51191c3c667e9bc3cfcfda40 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 18 Feb 2021 21:24:34 +1100 Subject: [PATCH 167/174] esp32: Add initial support for ESP32S2 SoCs. Builds against IDF v4.3-beta2. Signed-off-by: Damien George --- ports/esp32/boards/sdkconfig.base | 1 - ports/esp32/esp32_ulp.c | 4 ++++ ports/esp32/machine_adc.c | 16 +++++++++++++++- ports/esp32/machine_dac.c | 5 +++++ ports/esp32/machine_hw_spi.c | 10 ++++++++-- ports/esp32/machine_i2c.c | 5 +++++ ports/esp32/machine_pin.c | 14 ++++++++++++++ ports/esp32/machine_pwm.c | 4 ++++ ports/esp32/machine_sdcard.c | 6 ++---- ports/esp32/machine_timer.c | 21 ++++++++++++++++++++- ports/esp32/machine_touchpad.c | 15 +++++++-------- ports/esp32/machine_uart.c | 2 ++ ports/esp32/main.c | 5 +++++ ports/esp32/main/CMakeLists.txt | 7 ++++++- ports/esp32/modesp32.c | 8 ++++++++ ports/esp32/modmachine.c | 16 ++++++++++++++-- ports/esp32/mpconfigport.h | 2 ++ ports/esp32/uart.c | 4 ++++ 18 files changed, 125 insertions(+), 20 deletions(-) diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index 91e68c7bf6..4d9e38077d 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -1,7 +1,6 @@ # MicroPython on ESP32, ESP IDF configuration # The following options override the defaults -CONFIG_IDF_TARGET="esp32" CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 # Compiler options: use -Os to reduce size, but keep full assertions diff --git a/ports/esp32/esp32_ulp.c b/ports/esp32/esp32_ulp.c index 50244cdf25..8e4ce9c5a4 100644 --- a/ports/esp32/esp32_ulp.c +++ b/ports/esp32/esp32_ulp.c @@ -26,6 +26,8 @@ #include "py/runtime.h" +#if CONFIG_IDF_TARGET_ESP32 + #include "esp32/ulp.h" #include "esp_err.h" @@ -95,3 +97,5 @@ const mp_obj_type_t esp32_ulp_type = { .make_new = esp32_ulp_make_new, .locals_dict = (mp_obj_t)&esp32_ulp_locals_dict, }; + +#endif // CONFIG_IDF_TARGET_ESP32 diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c index 811a208e6d..4c19d5992b 100644 --- a/ports/esp32/machine_adc.c +++ b/ports/esp32/machine_adc.c @@ -60,7 +60,11 @@ STATIC mp_obj_t madc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n static int initialized = 0; if (!initialized) { - adc1_config_width(ADC_WIDTH_12Bit); + #if CONFIG_IDF_TARGET_ESP32S2 + adc1_config_width(ADC_WIDTH_BIT_13); + #else + adc1_config_width(ADC_WIDTH_BIT_12); + #endif adc_bit_width = 12; initialized = 1; } @@ -128,6 +132,7 @@ STATIC mp_obj_t madc_width(mp_obj_t cls_in, mp_obj_t width_in) { mp_raise_ValueError(MP_ERROR_TEXT("parameter error")); } switch (width) { + #if CONFIG_IDF_TARGET_ESP32 case ADC_WIDTH_9Bit: adc_bit_width = 9; break; @@ -140,6 +145,11 @@ STATIC mp_obj_t madc_width(mp_obj_t cls_in, mp_obj_t width_in) { case ADC_WIDTH_12Bit: adc_bit_width = 12; break; + #elif CONFIG_IDF_TARGET_ESP32S2 + case ADC_WIDTH_BIT_13: + adc_bit_width = 13; + break; + #endif default: break; } @@ -160,10 +170,14 @@ STATIC const mp_rom_map_elem_t madc_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_ATTN_6DB), MP_ROM_INT(ADC_ATTEN_6db) }, { MP_ROM_QSTR(MP_QSTR_ATTN_11DB), MP_ROM_INT(ADC_ATTEN_11db) }, + #if CONFIG_IDF_TARGET_ESP32 { MP_ROM_QSTR(MP_QSTR_WIDTH_9BIT), MP_ROM_INT(ADC_WIDTH_9Bit) }, { MP_ROM_QSTR(MP_QSTR_WIDTH_10BIT), MP_ROM_INT(ADC_WIDTH_10Bit) }, { MP_ROM_QSTR(MP_QSTR_WIDTH_11BIT), MP_ROM_INT(ADC_WIDTH_11Bit) }, { MP_ROM_QSTR(MP_QSTR_WIDTH_12BIT), MP_ROM_INT(ADC_WIDTH_12Bit) }, + #elif CONFIG_IDF_TARGET_ESP32S2 + { MP_ROM_QSTR(MP_QSTR_WIDTH_13BIT), MP_ROM_INT(ADC_WIDTH_BIT_13) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(madc_locals_dict, madc_locals_dict_table); diff --git a/ports/esp32/machine_dac.c b/ports/esp32/machine_dac.c index 02855fcf80..146ef60aa8 100644 --- a/ports/esp32/machine_dac.c +++ b/ports/esp32/machine_dac.c @@ -43,8 +43,13 @@ typedef struct _mdac_obj_t { } mdac_obj_t; STATIC const mdac_obj_t mdac_obj[] = { + #if CONFIG_IDF_TARGET_ESP32 {{&machine_dac_type}, GPIO_NUM_25, DAC_CHANNEL_1}, {{&machine_dac_type}, GPIO_NUM_26, DAC_CHANNEL_2}, + #else + {{&machine_dac_type}, GPIO_NUM_17, DAC_CHANNEL_1}, + {{&machine_dac_type}, GPIO_NUM_18, DAC_CHANNEL_2}, + #endif }; STATIC mp_obj_t mdac_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c index d59f2c750e..a49a58035a 100644 --- a/ports/esp32/machine_hw_spi.c +++ b/ports/esp32/machine_hw_spi.c @@ -184,8 +184,12 @@ STATIC void machine_hw_spi_init_internal( changed = true; } - if (self->host != HSPI_HOST && self->host != VSPI_HOST) { - mp_raise_ValueError(MP_ERROR_TEXT("SPI ID must be either HSPI(1) or VSPI(2)")); + if (self->host != HSPI_HOST + #ifdef VSPI_HOST + && self->host != VSPI_HOST + #endif + ) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), self->host); } if (changed) { @@ -220,8 +224,10 @@ STATIC void machine_hw_spi_init_internal( int dma_chan = 0; if (self->host == HSPI_HOST) { dma_chan = 1; + #ifdef VSPI_HOST } else if (self->host == VSPI_HOST) { dma_chan = 2; + #endif } ret = spi_bus_initialize(self->host, &buscfg, dma_chan); diff --git a/ports/esp32/machine_i2c.c b/ports/esp32/machine_i2c.c index 3993c7b52b..fd5180b8d0 100644 --- a/ports/esp32/machine_i2c.c +++ b/ports/esp32/machine_i2c.c @@ -34,8 +34,13 @@ #define I2C_0_DEFAULT_SCL (GPIO_NUM_18) #define I2C_0_DEFAULT_SDA (GPIO_NUM_19) +#if CONFIG_IDF_TARGET_ESP32 #define I2C_1_DEFAULT_SCL (GPIO_NUM_25) #define I2C_1_DEFAULT_SDA (GPIO_NUM_26) +#else +#define I2C_1_DEFAULT_SCL (GPIO_NUM_9) +#define I2C_1_DEFAULT_SDA (GPIO_NUM_8) +#endif #define I2C_DEFAULT_TIMEOUT_US (10000) // 10ms diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c index dcdd53be92..8290c77a48 100644 --- a/ports/esp32/machine_pin.c +++ b/ports/esp32/machine_pin.c @@ -77,10 +77,17 @@ STATIC const machine_pin_obj_t machine_pin_obj[] = { {{&machine_pin_type}, GPIO_NUM_19}, {{NULL}, -1}, {{&machine_pin_type}, GPIO_NUM_21}, + #if CONFIG_IDF_TARGET_ESP32 {{&machine_pin_type}, GPIO_NUM_22}, {{&machine_pin_type}, GPIO_NUM_23}, {{NULL}, -1}, {{&machine_pin_type}, GPIO_NUM_25}, + #else + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + #endif {{&machine_pin_type}, GPIO_NUM_26}, {{&machine_pin_type}, GPIO_NUM_27}, {{NULL}, -1}, @@ -411,10 +418,17 @@ STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = { {{&machine_pin_irq_type}, GPIO_NUM_19}, {{NULL}, -1}, {{&machine_pin_irq_type}, GPIO_NUM_21}, + #if CONFIG_IDF_TARGET_ESP32 {{&machine_pin_irq_type}, GPIO_NUM_22}, {{&machine_pin_irq_type}, GPIO_NUM_23}, {{NULL}, -1}, {{&machine_pin_irq_type}, GPIO_NUM_25}, + #else + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + #endif {{&machine_pin_irq_type}, GPIO_NUM_26}, {{&machine_pin_irq_type}, GPIO_NUM_27}, {{NULL}, -1}, diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c index 7592f243b7..a7d7d29df8 100644 --- a/ports/esp32/machine_pwm.c +++ b/ports/esp32/machine_pwm.c @@ -50,7 +50,11 @@ STATIC int chan_gpio[LEDC_CHANNEL_MAX]; // 5khz #define PWFREQ (5000) // High speed mode +#if CONFIG_IDF_TARGET_ESP32 #define PWMODE (LEDC_HIGH_SPEED_MODE) +#else +#define PWMODE (LEDC_LOW_SPEED_MODE) +#endif // 10-bit resolution (compatible with esp8266 PWM) #define PWRES (LEDC_TIMER_10_BIT) // Timer 1 diff --git a/ports/esp32/machine_sdcard.c b/ports/esp32/machine_sdcard.c index 40686508a1..c9a9face7c 100644 --- a/ports/esp32/machine_sdcard.c +++ b/ports/esp32/machine_sdcard.c @@ -31,6 +31,8 @@ #include "py/mperrno.h" #include "extmod/vfs_fat.h" +#if MICROPY_HW_ENABLE_SDCARD + #include "driver/sdmmc_host.h" #include "driver/sdspi_host.h" #include "sdmmc_cmd.h" @@ -50,10 +52,6 @@ // Hosts are de-inited in __del__. Slots do not need de-initing. // -// Currently the ESP32 Library doesn't support MMC cards, so -// we don't enable on MICROPY_HW_ENABLE_MMCARD. -#if MICROPY_HW_ENABLE_SDCARD - // Forward declaration const mp_obj_type_t machine_sdcard_type; diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c index 6e5824094e..696127af77 100644 --- a/ports/esp32/machine_timer.c +++ b/ports/esp32/machine_timer.c @@ -30,12 +30,17 @@ #include #include -#include "driver/timer.h" #include "py/obj.h" #include "py/runtime.h" #include "modmachine.h" #include "mphalport.h" +#include "driver/timer.h" +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 1) +#include "hal/timer_ll.h" +#define HAVE_TIMER_LL (1) +#endif + #define TIMER_INTR_SEL TIMER_INTR_LEVEL #define TIMER_DIVIDER 8 @@ -127,6 +132,18 @@ STATIC void machine_timer_isr(void *self_in) { machine_timer_obj_t *self = self_in; timg_dev_t *device = self->group ? &(TIMERG1) : &(TIMERG0); + #if HAVE_TIMER_LL + + #if CONFIG_IDF_TARGET_ESP32 + device->hw_timer[self->index].update = 1; + #else + device->hw_timer[self->index].update.update = 1; + #endif + timer_ll_clear_intr_status(device, self->index); + timer_ll_set_alarm_enable(device, self->index, self->repeat); + + #else + device->hw_timer[self->index].update = 1; if (self->index) { device->int_clr_timers.t1 = 1; @@ -135,6 +152,8 @@ STATIC void machine_timer_isr(void *self_in) { } device->hw_timer[self->index].config.alarm_en = self->repeat; + #endif + mp_sched_schedule(self->callback, self); mp_hal_wake_main_task_from_isr(); } diff --git a/ports/esp32/machine_touchpad.c b/ports/esp32/machine_touchpad.c index 44efac3756..335157b154 100644 --- a/ports/esp32/machine_touchpad.c +++ b/ports/esp32/machine_touchpad.c @@ -24,18 +24,15 @@ * THE SOFTWARE. */ - -#include - -#include "esp_log.h" - -#include "driver/gpio.h" -#include "driver/touch_pad.h" - #include "py/runtime.h" #include "py/mphal.h" #include "modmachine.h" +#if CONFIG_IDF_TARGET_ESP32 + +#include "driver/gpio.h" +#include "driver/touch_pad.h" + typedef struct _mtp_obj_t { mp_obj_base_t base; gpio_num_t gpio_id; @@ -120,3 +117,5 @@ const mp_obj_type_t machine_touchpad_type = { .make_new = mtp_make_new, .locals_dict = (mp_obj_t)&mtp_locals_dict, }; + +#endif // CONFIG_IDF_TARGET_ESP32 diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c index 7fce83f2c4..e256b9be43 100644 --- a/ports/esp32/machine_uart.c +++ b/ports/esp32/machine_uart.c @@ -307,10 +307,12 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, self->rx = 9; self->tx = 10; break; + #if SOC_UART_NUM > 2 case UART_NUM_2: self->rx = 16; self->tx = 17; break; + #endif } // Remove any existing configuration diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 7413798d0c..0c2f56699f 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -37,7 +37,12 @@ #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" +#endif #include "py/stackctrl.h" #include "py/nlr.h" diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index aacdd40d31..63a221e4d6 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -84,7 +84,6 @@ set(IDF_COMPONENTS bootloader_support bt driver - esp32 esp_common esp_eth esp_event @@ -123,6 +122,12 @@ if(IDF_VERSION_MINOR GREATER_EQUAL 3) list(APPEND IDF_COMPONENTS hal) endif() +if(IDF_TARGET STREQUAL "esp32") + list(APPEND IDF_COMPONENTS esp32) +elseif(IDF_TARGET STREQUAL "esp32s2") + list(APPEND IDF_COMPONENTS esp32s2) +endif() + # Register the main IDF component. idf_component_register( SRCS diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c index 53ca7fdc60..3ed5343380 100644 --- a/ports/esp32/modesp32.c +++ b/ports/esp32/modesp32.c @@ -132,6 +132,8 @@ STATIC mp_obj_t esp32_wake_on_ext1(size_t n_args, const mp_obj_t *pos_args, mp_m } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext1_obj, 0, esp32_wake_on_ext1); +#if CONFIG_IDF_TARGET_ESP32 + STATIC mp_obj_t esp32_raw_temperature(void) { SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 3, SENS_FORCE_XPD_SAR_S); SET_PERI_REG_BITS(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_CLK_DIV, 10, SENS_TSENS_CLK_DIV_S); @@ -154,6 +156,8 @@ STATIC mp_obj_t esp32_hall_sensor(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp32_hall_sensor_obj, esp32_hall_sensor); +#endif + STATIC mp_obj_t esp32_idf_heap_info(const mp_obj_t cap_in) { mp_int_t cap = mp_obj_get_int(cap_in); multi_heap_info_t info; @@ -182,14 +186,18 @@ STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_wake_on_touch), MP_ROM_PTR(&esp32_wake_on_touch_obj) }, { MP_ROM_QSTR(MP_QSTR_wake_on_ext0), MP_ROM_PTR(&esp32_wake_on_ext0_obj) }, { MP_ROM_QSTR(MP_QSTR_wake_on_ext1), MP_ROM_PTR(&esp32_wake_on_ext1_obj) }, + #if CONFIG_IDF_TARGET_ESP32 { MP_ROM_QSTR(MP_QSTR_raw_temperature), MP_ROM_PTR(&esp32_raw_temperature_obj) }, { MP_ROM_QSTR(MP_QSTR_hall_sensor), MP_ROM_PTR(&esp32_hall_sensor_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_idf_heap_info), MP_ROM_PTR(&esp32_idf_heap_info_obj) }, { MP_ROM_QSTR(MP_QSTR_NVS), MP_ROM_PTR(&esp32_nvs_type) }, { MP_ROM_QSTR(MP_QSTR_Partition), MP_ROM_PTR(&esp32_partition_type) }, { MP_ROM_QSTR(MP_QSTR_RMT), MP_ROM_PTR(&esp32_rmt_type) }, + #if CONFIG_IDF_TARGET_ESP32 { MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) }, + #endif { MP_ROM_QSTR(MP_QSTR_WAKEUP_ALL_LOW), MP_ROM_FALSE }, { MP_ROM_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), MP_ROM_TRUE }, diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index 3925bcb64e..2eb5cd2fee 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -32,12 +32,18 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp32/rom/rtc.h" -#include "esp32/clk.h" #include "esp_sleep.h" #include "esp_pm.h" #include "driver/touch_pad.h" +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/rtc.h" +#include "esp32/clk.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/rtc.h" +#include "esp32s2/clk.h" +#endif + #include "py/obj.h" #include "py/runtime.h" #include "lib/utils/pyexec.h" @@ -71,7 +77,11 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { if (freq != 20 && freq != 40 && freq != 80 && freq != 160 && freq != 240) { mp_raise_ValueError(MP_ERROR_TEXT("frequency must be 20MHz, 40MHz, 80Mhz, 160MHz or 240MHz")); } + #if CONFIG_IDF_TARGET_ESP32 esp_pm_config_esp32_t pm; + #elif CONFIG_IDF_TARGET_ESP32S2 + esp_pm_config_esp32s2_t pm; + #endif pm.max_freq_mhz = freq; pm.min_freq_mhz = freq; pm.light_sleep_enable = false; @@ -260,7 +270,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, + #if CONFIG_IDF_TARGET_ESP32 { MP_ROM_QSTR(MP_QSTR_TouchPad), MP_ROM_PTR(&machine_touchpad_type) }, + #endif { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) }, { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&machine_dac_type) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_hw_i2c_type) }, diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index c9c4b6268b..8788963cb3 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -153,7 +153,9 @@ #define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_MACHINE_SPI_MSB (0) #define MICROPY_PY_MACHINE_SPI_LSB (1) +#ifndef MICROPY_HW_ENABLE_SDCARD #define MICROPY_HW_ENABLE_SDCARD (1) +#endif #define MICROPY_HW_SOFTSPI_MIN_DELAY (0) #define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly #define MICROPY_PY_USSL (1) diff --git a/ports/esp32/uart.c b/ports/esp32/uart.c index c837c8dcfe..bd3eea9f6b 100644 --- a/ports/esp32/uart.c +++ b/ports/esp32/uart.c @@ -49,7 +49,11 @@ STATIC void IRAM_ATTR uart_irq_handler(void *arg) { uart->int_clr.frm_err = 1; uart->int_clr.rxfifo_tout = 1; while (uart->status.rxfifo_cnt) { + #if CONFIG_IDF_TARGET_ESP32 uint8_t c = uart->fifo.rw_byte; + #elif CONFIG_IDF_TARGET_ESP32S2 + uint8_t c = READ_PERI_REG(UART_FIFO_AHB_REG(0)); // UART0 + #endif if (c == mp_interrupt_char) { mp_keyboard_interrupt(); } else { From c81d048bb3ad35d62c3c7afe9b770a32f8b49c8b Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 19 Feb 2021 12:08:11 +1100 Subject: [PATCH 168/174] esp32: Add support for USB with CDC ACM. The REPL will be available on the USB serial port. Signed-off-by: Damien George --- ports/esp32/boards/sdkconfig.usb | 4 ++ ports/esp32/main.c | 5 ++ ports/esp32/main/CMakeLists.txt | 6 +++ ports/esp32/mphalport.c | 7 ++- ports/esp32/usb.c | 92 ++++++++++++++++++++++++++++++++ ports/esp32/usb.h | 32 +++++++++++ 6 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 ports/esp32/boards/sdkconfig.usb create mode 100644 ports/esp32/usb.c create mode 100644 ports/esp32/usb.h diff --git a/ports/esp32/boards/sdkconfig.usb b/ports/esp32/boards/sdkconfig.usb new file mode 100644 index 0000000000..657edbc580 --- /dev/null +++ b/ports/esp32/boards/sdkconfig.usb @@ -0,0 +1,4 @@ +CONFIG_USB_ENABLED=y +CONFIG_USB_CDC_ENABLED=y +CONFIG_USB_CDC_RX_BUFSIZE=256 +CONFIG_USB_CDC_TX_BUFSIZE=256 diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 0c2f56699f..7ca3d84140 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -55,6 +55,7 @@ #include "lib/mp-readline/readline.h" #include "lib/utils/pyexec.h" #include "uart.h" +#include "usb.h" #include "modmachine.h" #include "modnetwork.h" #include "mpthreadport.h" @@ -77,7 +78,11 @@ void mp_task(void *pvParameter) { #if MICROPY_PY_THREAD mp_thread_init(pxTaskGetStackStart(NULL), MP_TASK_STACK_SIZE / sizeof(uintptr_t)); #endif + #if CONFIG_USB_ENABLED + usb_init(); + #else uart_init(); + #endif machine_init(); // TODO: CONFIG_SPIRAM_SUPPORT is for 3.3 compatibility, remove after move to 4.0. diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index 63a221e4d6..656045da90 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -37,6 +37,7 @@ set(MICROPY_SOURCE_DRIVERS set(MICROPY_SOURCE_PORT ${PROJECT_DIR}/main.c ${PROJECT_DIR}/uart.c + ${PROJECT_DIR}/usb.c ${PROJECT_DIR}/gccollect.c ${PROJECT_DIR}/mphalport.c ${PROJECT_DIR}/fatfs_port.c @@ -126,6 +127,7 @@ if(IDF_TARGET STREQUAL "esp32") list(APPEND IDF_COMPONENTS esp32) elseif(IDF_TARGET STREQUAL "esp32s2") list(APPEND IDF_COMPONENTS esp32s2) + list(APPEND IDF_COMPONENTS tinyusb) endif() # Register the main IDF component. @@ -185,6 +187,10 @@ if(IDF_VERSION_MINOR GREATER_EQUAL 2) # so add them explicitly. list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/soc/soc/${IDF_TARGET}/include) list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/soc/soc/include) + if(IDF_VERSION_MINOR GREATER_EQUAL 3) + list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/tinyusb/additions/include) + list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/tinyusb/tinyusb/src) + endif() endif() # Include the main MicroPython cmake rules. diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index 65fa88e4d0..cf668216df 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -43,10 +43,11 @@ #include "lib/timeutils/timeutils.h" #include "lib/utils/pyexec.h" #include "mphalport.h" +#include "usb.h" TaskHandle_t mp_main_task_handle; -STATIC uint8_t stdin_ringbuf_array[256]; +STATIC uint8_t stdin_ringbuf_array[260]; ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0}; // Check the ESP-IDF error code and raise an OSError if it's not ESP_OK. @@ -110,9 +111,13 @@ void mp_hal_stdout_tx_strn(const char *str, uint32_t len) { if (release_gil) { MP_THREAD_GIL_EXIT(); } + #if CONFIG_USB_ENABLED + usb_tx_strn(str, len); + #else for (uint32_t i = 0; i < len; ++i) { uart_tx_one_char(str[i]); } + #endif if (release_gil) { MP_THREAD_GIL_ENTER(); } diff --git a/ports/esp32/usb.c b/ports/esp32/usb.c new file mode 100644 index 0000000000..aa76321a7e --- /dev/null +++ b/ports/esp32/usb.c @@ -0,0 +1,92 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "py/runtime.h" +#include "py/mphal.h" +#include "usb.h" + +#if CONFIG_USB_ENABLED + +#include "tinyusb.h" +#include "tusb_cdc_acm.h" + +#define CDC_ITF TINYUSB_CDC_ACM_0 + +static uint8_t usb_rx_buf[CONFIG_USB_CDC_RX_BUFSIZE]; + +static void usb_callback_rx(int itf, cdcacm_event_t *event) { + // TODO: what happens if more chars come in during this function, are they lost? + for (;;) { + size_t len = 0; + esp_err_t ret = tinyusb_cdcacm_read(itf, usb_rx_buf, sizeof(usb_rx_buf), &len); + if (ret != ESP_OK) { + break; + } + if (len == 0) { + break; + } + for (size_t i = 0; i < len; ++i) { + if (usb_rx_buf[i] == mp_interrupt_char) { + mp_keyboard_interrupt(); + } else { + ringbuf_put(&stdin_ringbuf, usb_rx_buf[i]); + } + } + } +} + +void usb_init(void) { + // Initialise the USB with defaults. + tinyusb_config_t tusb_cfg = {0}; + ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); + + // Initialise the USB serial interface. + tinyusb_config_cdcacm_t amc_cfg = { + .usb_dev = TINYUSB_USBDEV_0, + .cdc_port = CDC_ITF, + .rx_unread_buf_sz = 256, + .callback_rx = &usb_callback_rx, + .callback_rx_wanted_char = NULL, + .callback_line_state_changed = NULL, + .callback_line_coding_changed = NULL + }; + ESP_ERROR_CHECK(tusb_cdc_acm_init(&amc_cfg)); +} + +void usb_tx_strn(const char *str, size_t len) { + while (len) { + size_t l = len; + if (l > CONFIG_USB_CDC_TX_BUFSIZE) { + l = CONFIG_USB_CDC_TX_BUFSIZE; + } + tinyusb_cdcacm_write_queue(CDC_ITF, (uint8_t *)str, l); + tinyusb_cdcacm_write_flush(CDC_ITF, pdMS_TO_TICKS(1000)); + str += l; + len -= l; + } +} + +#endif // CONFIG_USB_ENABLED diff --git a/ports/esp32/usb.h b/ports/esp32/usb.h new file mode 100644 index 0000000000..a103780333 --- /dev/null +++ b/ports/esp32/usb.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ +#ifndef MICROPY_INCLUDED_ESP32_USB_H +#define MICROPY_INCLUDED_ESP32_USB_H + +void usb_init(void); +void usb_tx_strn(const char *str, size_t len); + +#endif // MICROPY_INCLUDED_ESP32_USB_H From d97b8daf1a8d3bcb7f205bbffd4f2e122f973f9d Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Apr 2021 11:13:08 +1000 Subject: [PATCH 169/174] esp32/boards: Add GENERIC_S2 board definition. Signed-off-by: Damien George --- ports/esp32/boards/GENERIC_S2/mpconfigboard.cmake | 8 ++++++++ ports/esp32/boards/GENERIC_S2/mpconfigboard.h | 5 +++++ 2 files changed, 13 insertions(+) create mode 100644 ports/esp32/boards/GENERIC_S2/mpconfigboard.cmake create mode 100644 ports/esp32/boards/GENERIC_S2/mpconfigboard.h diff --git a/ports/esp32/boards/GENERIC_S2/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_S2/mpconfigboard.cmake new file mode 100644 index 0000000000..23d52e8b94 --- /dev/null +++ b/ports/esp32/boards/GENERIC_S2/mpconfigboard.cmake @@ -0,0 +1,8 @@ +set(IDF_TARGET esp32s2) + +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.usb +) + +set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py) diff --git a/ports/esp32/boards/GENERIC_S2/mpconfigboard.h b/ports/esp32/boards/GENERIC_S2/mpconfigboard.h new file mode 100644 index 0000000000..01ac2ce58e --- /dev/null +++ b/ports/esp32/boards/GENERIC_S2/mpconfigboard.h @@ -0,0 +1,5 @@ +#define MICROPY_HW_BOARD_NAME "ESP32S2 module" +#define MICROPY_HW_MCU_NAME "ESP32S2" + +#define MICROPY_PY_BLUETOOTH (0) +#define MICROPY_HW_ENABLE_SDCARD (0) From a9bbf7083ef6b79cf80bdbf34984d847a6c4aae9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Apr 2021 12:33:17 +1000 Subject: [PATCH 170/174] tools/ci.sh: Build esp32 using IDF v4.0.2 and v4.3. To test different IDF's, and also test building the GENERIC_S2 board. Signed-off-by: Damien George --- .github/workflows/ports_esp32.yml | 13 +++++++++++-- tools/ci.sh | 17 ++++++++++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ports_esp32.yml b/.github/workflows/ports_esp32.yml index 0ad3f87a25..09817ee126 100644 --- a/.github/workflows/ports_esp32.yml +++ b/.github/workflows/ports_esp32.yml @@ -13,11 +13,20 @@ on: - 'ports/esp32/**' jobs: - build: + build_idf402: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - name: Install packages - run: source tools/ci.sh && ci_esp32_setup + run: source tools/ci.sh && ci_esp32_idf402_setup + - name: Build + run: source tools/ci.sh && ci_esp32_build + + build_idf43: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - name: Install packages + run: source tools/ci.sh && ci_esp32_idf43_setup - name: Build run: source tools/ci.sh && ci_esp32_build diff --git a/tools/ci.sh b/tools/ci.sh index 3ce96a96a9..c018b55002 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -82,19 +82,27 @@ function ci_cc3200_build { ######################################################################################## # ports/esp32 -function ci_esp32_setup { +function ci_esp32_setup_helper { git clone https://github.com/espressif/esp-idf.git - git -C esp-idf checkout v4.0.2 + git -C esp-idf checkout $1 git -C esp-idf submodule update --init \ components/bt/controller/lib \ components/bt/host/nimble/nimble \ - components/esp_wifi/lib_esp32 \ + components/esp_wifi \ components/esptool_py/esptool \ components/lwip/lwip \ components/mbedtls/mbedtls ./esp-idf/install.sh } +function ci_esp32_idf402_setup { + ci_esp32_setup_helper v4.0.2 +} + +function ci_esp32_idf43_setup { + ci_esp32_setup_helper v4.3-beta2 +} + function ci_esp32_build { source esp-idf/export.sh make ${MAKEOPTS} -C mpy-cross @@ -102,6 +110,9 @@ function ci_esp32_build { make ${MAKEOPTS} -C ports/esp32 make ${MAKEOPTS} -C ports/esp32 clean make ${MAKEOPTS} -C ports/esp32 USER_C_MODULES=../../../examples/usercmodule/micropython.cmake + if [ -d $IDF_PATH/components/esp32s2 ]; then + make ${MAKEOPTS} -C ports/esp32 BOARD=GENERIC_S2 + fi } ######################################################################################## From e5d2ddde25351f1ede7d0d1b00be632301962fb0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Apr 2021 13:02:34 +1000 Subject: [PATCH 171/174] esp32/machine_pin: Use rtc_gpio_deinit instead of gpio_reset_pin. Commit 8a917ad2529ea3df5f47e2be5b4edf362d2d03f6 added the gpio_reset_pin() call to make sure that pins that were used as ADC inputs could subsequently be used as digital IO. But calling gpio_reset_pin() will enable the pull-up on the pin and so pull it high for a brief period. Instead use rtc_gpio_deinit() which will just reconfigure the pin as a digital IO and do nothing else. Fixes issue #7079 (see also #5771). Signed-off-by: Damien George --- ports/esp32/machine_pin.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c index 8290c77a48..8dbdd19849 100644 --- a/ports/esp32/machine_pin.c +++ b/ports/esp32/machine_pin.c @@ -30,6 +30,7 @@ #include #include "driver/gpio.h" +#include "driver/rtc_io.h" #include "py/runtime.h" #include "py/mphal.h" @@ -157,9 +158,11 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - // reset the pin first if this is a mode-setting init (grab it back from ADC) + // reset the pin to digital if this is a mode-setting init (grab it back from ADC) if (args[ARG_mode].u_obj != mp_const_none) { - gpio_reset_pin(self->id); + if (rtc_gpio_is_valid_gpio(self->id)) { + rtc_gpio_deinit(self->id); + } } // configure the pin for gpio From f842a40df4d26bd74b92a3903096fc6b1709222d Mon Sep 17 00:00:00 2001 From: Tim Radvan Date: Fri, 2 Apr 2021 19:35:18 +0100 Subject: [PATCH 172/174] rp2/rp2_pio: Add fifo_join support for PIO. The PIO state machines on the RP2040 have 4 word deep TX and RX FIFOs. If you only need one direction, you can "merge" them into either a single 8 word deep TX or RX FIFO. We simply add constants to the PIO object, and set the appropriate bits in `shiftctrl`. Resolves #6854. Signed-off-by: Tim Radvan --- examples/rp2/pio_uart_rx.py | 1 + ports/rp2/modules/rp2.py | 6 ++++-- ports/rp2/rp2_pio.c | 4 ++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/rp2/pio_uart_rx.py b/examples/rp2/pio_uart_rx.py index 41dfde3dad..080b6bd639 100644 --- a/examples/rp2/pio_uart_rx.py +++ b/examples/rp2/pio_uart_rx.py @@ -22,6 +22,7 @@ PIO_RX_PIN = Pin(3, Pin.IN, Pin.PULL_UP) autopush=True, push_thresh=8, in_shiftdir=rp2.PIO.SHIFT_RIGHT, + fifo_join=PIO.JOIN_RX, ) def uart_rx_mini(): # fmt: off diff --git a/ports/rp2/modules/rp2.py b/ports/rp2/modules/rp2.py index 17e35c73b7..c7e4d1fdd9 100644 --- a/ports/rp2/modules/rp2.py +++ b/ports/rp2/modules/rp2.py @@ -31,7 +31,8 @@ class PIOASMEmit: autopush=False, autopull=False, push_thresh=32, - pull_thresh=32 + pull_thresh=32, + fifo_join=0 ): # uarray is a built-in module so importing it here won't require # scanning the filesystem. @@ -40,7 +41,8 @@ class PIOASMEmit: self.labels = {} execctrl = 0 shiftctrl = ( - (pull_thresh & 0x1F) << 25 + fifo_join << 30 + | (pull_thresh & 0x1F) << 25 | (push_thresh & 0x1F) << 20 | out_shiftdir << 19 | in_shiftdir << 18 diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c index 5f93f10c26..44928c0a88 100644 --- a/ports/rp2/rp2_pio.c +++ b/ports/rp2/rp2_pio.c @@ -360,6 +360,10 @@ STATIC const mp_rom_map_elem_t rp2_pio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_SHIFT_LEFT), MP_ROM_INT(0) }, { MP_ROM_QSTR(MP_QSTR_SHIFT_RIGHT), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_JOIN_NONE), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_JOIN_TX), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_JOIN_RX), MP_ROM_INT(2) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_SM0), MP_ROM_INT(0x100) }, { MP_ROM_QSTR(MP_QSTR_IRQ_SM1), MP_ROM_INT(0x200) }, { MP_ROM_QSTR(MP_QSTR_IRQ_SM2), MP_ROM_INT(0x400) }, From 7d911d20698b3b11269f34ecec97d3b4bfabac94 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 18 Apr 2021 23:20:26 +1000 Subject: [PATCH 173/174] tests/net_inet: Add 'Strict-Transport-Security' to exp file. Because micropython.org now adds this to the headers. Signed-off-by: Damien George --- tests/net_inet/uasyncio_tcp_read_headers.py.exp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/net_inet/uasyncio_tcp_read_headers.py.exp b/tests/net_inet/uasyncio_tcp_read_headers.py.exp index c200238dc6..932d2674cb 100644 --- a/tests/net_inet/uasyncio_tcp_read_headers.py.exp +++ b/tests/net_inet/uasyncio_tcp_read_headers.py.exp @@ -5,6 +5,7 @@ b'Content-Length: 54' b'Connection: close' b'Vary: Accept-Encoding' b'ETag: "54306c85-36"' +b'Strict-Transport-Security: max-age=15768000' b'Accept-Ranges: bytes' close done From 321d1897c34f16243edf2c94913d7cf877a013d1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 19 Apr 2021 00:11:51 +1000 Subject: [PATCH 174/174] all: Bump version to 1.15. Signed-off-by: Damien George --- docs/conf.py | 2 +- py/mpconfig.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index dd6cc31fb8..53cbf9baed 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -74,7 +74,7 @@ copyright = '2014-2021, Damien P. George, Paul Sokolovsky, and contributors' # # We don't follow "The short X.Y version" vs "The full version, including alpha/beta/rc tags" # breakdown, so use the same version identifier for both to avoid confusion. -version = release = '1.14' +version = release = '1.15' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/py/mpconfig.h b/py/mpconfig.h index b26fa2137a..3dd83a34ab 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -28,7 +28,7 @@ // Current version of MicroPython #define MICROPY_VERSION_MAJOR 1 -#define MICROPY_VERSION_MINOR 14 +#define MICROPY_VERSION_MINOR 15 #define MICROPY_VERSION_MICRO 0 // Combined version as a 32-bit number for convenience