diff options
71 files changed, 2020 insertions, 715 deletions
@@ -13,21 +13,22 @@ changes. The software will not start to mature until March 2014 at the earliest. See the repository www.github.com/micropython/pyboard for the Micro -Python board. At the moment, finalising the design of the board is -the top priority. +Python board. Major components in this repository: - py/ -- the core Python implementation, including compiler and runtime. - unix/ -- a version of Micro Python that runs on Unix. -- stm/ -- a version of Micro Python that runs on the Micro Python board - with an STM32F405RG. +- stmhal/ -- a version of Micro Python that runs on the Micro Python board + with an STM32F405RG (using ST's new Cube HAL drivers). +- stm/ -- obsolete version of Micro Python for the Micro Python board + that uses ST's old peripheral drivers. - teensy/ -- a version of Micro Python that runs on the Teensy 3.1 (preliminary but functional). Additional components: - unix-cpy/ -- a version of Micro Python that outputs bytecode (for testing). - tests/ -- test framework and test scripts. -- tools/ -- various tools. +- tools/ -- various tools, including the pyboard.py module. - examples/ -- a few example Python scripts. "make" is used to build the components, or "gmake" on BSD-based systems. @@ -58,17 +59,21 @@ module (recommended, enable in unix/mpconfigport.mk), libffi-dev is required. The STM version --------------- -The "stm" part requires an ARM compiler, arm-none-eabi-gcc, and associated +The "stmhal" part requires an ARM compiler, arm-none-eabi-gcc, and associated bin-utils. For those using Arch Linux, you need arm-none-eabi-binutils and arm-none-eabi-gcc packages from the AUR. Otherwise, try here: https://launchpad.net/gcc-arm-embedded To build: - $ cd stm + $ cd stmhal $ make -Then to flash it via USB DFU to your device: +You then need to get your board into DFU mode. On the pyboard, connect the +3V3 pin to the P1/DFU pin with a wire (on PYBv1.0 they are next to each other +on the bottom left of the board, second row from the bottom). + +Then to flash the code via USB DFU to your device: $ dfu-util -a 0 -D build/flash.dfu diff --git a/py/builtin.h b/py/builtin.h index d9414045de..45da172d10 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -1,4 +1,4 @@ -mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args); +mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args); MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin___import___obj); @@ -6,7 +6,6 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin___repl_print___obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_abs_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_all_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_any_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_bytes_obj); // Temporary hack MP_DECLARE_CONST_FUN_OBJ(mp_builtin_callable_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_chr_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_dir_obj); @@ -30,9 +29,10 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin_range_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_repr_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sorted_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sum_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_str_obj); MP_DECLARE_CONST_FUN_OBJ(mp_namedtuple_obj); +extern const mp_obj_module_t mp_module_array; +extern const mp_obj_module_t mp_module_collections; extern const mp_obj_module_t mp_module_math; extern const mp_obj_module_t mp_module_micropython; diff --git a/py/builtinimport.c b/py/builtinimport.c index 2b9b3a30b9..882b128df1 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -12,6 +12,7 @@ #include "lexerunix.h" #include "parse.h" #include "obj.h" +#include "objmodule.h" #include "parsehelper.h" #include "compile.h" #include "runtime0.h" @@ -128,7 +129,7 @@ void do_load(mp_obj_t module_obj, vstr_t *file) { rt_globals_set(old_globals); } -mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { +mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) { /* printf("import:\n"); for (int i = 0; i < n_args; i++) { @@ -156,7 +157,7 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { const char *mod_str = (const char*)mp_obj_str_get_data(args[0], &mod_len); // check if module already exists - mp_obj_t module_obj = mp_obj_module_get(mp_obj_str_get_qstr(args[0])); + mp_obj_t module_obj = mp_module_get(mp_obj_str_get_qstr(args[0])); if (module_obj != MP_OBJ_NULL) { // If it's not a package, return module right away char *p = strchr(mod_str, '.'); @@ -169,7 +170,7 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { } // Otherwise, we need to return top-level package qstr pkg_name = qstr_from_strn(mod_str, p - mod_str); - return mp_obj_module_get(pkg_name); + return mp_module_get(pkg_name); } uint last = 0; @@ -200,7 +201,7 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "ImportError: No module named '%s'", qstr_str(mod_name))); } - module_obj = mp_obj_module_get(mod_name); + module_obj = mp_module_get(mod_name); if (module_obj == MP_OBJ_NULL) { // module not already loaded, so load it! diff --git a/py/builtintables.c b/py/builtintables.c new file mode 100644 index 0000000000..0aa0b66a72 --- /dev/null +++ b/py/builtintables.c @@ -0,0 +1,150 @@ +#include <stdlib.h> + +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "builtin.h" +#include "builtintables.h" +#include "objarray.h" + +// builtins +// we put these tables in ROM because they're always needed and take up quite a bit of room in RAM +// in fact, it uses less ROM here in table form than the equivalent in code form initialising a dynamic mp_map_t object in RAM +// at the moment it's a linear table, but we could convert it to a const mp_map_t table with a simple preprocessing script + +typedef struct _mp_builtin_elem_t { + qstr qstr; + mp_obj_t elem; +} mp_builtin_elem_t; + +STATIC const mp_builtin_elem_t builtin_object_table[] = { + // built-in core functions + { MP_QSTR___build_class__, (mp_obj_t)&mp_builtin___build_class___obj }, + { MP_QSTR___import__, (mp_obj_t)&mp_builtin___import___obj }, + { MP_QSTR___repl_print__, (mp_obj_t)&mp_builtin___repl_print___obj }, + + // built-in types + { MP_QSTR_bool, (mp_obj_t)&bool_type }, + { MP_QSTR_bytes, (mp_obj_t)&bytes_type }, +#if MICROPY_ENABLE_FLOAT + { MP_QSTR_complex, (mp_obj_t)&mp_type_complex }, +#endif + { MP_QSTR_dict, (mp_obj_t)&dict_type }, + { MP_QSTR_enumerate, (mp_obj_t)&enumerate_type }, + { MP_QSTR_filter, (mp_obj_t)&filter_type }, +#if MICROPY_ENABLE_FLOAT + { MP_QSTR_float, (mp_obj_t)&mp_type_float }, +#endif + { MP_QSTR_int, (mp_obj_t)&int_type }, + { MP_QSTR_list, (mp_obj_t)&list_type }, + { MP_QSTR_map, (mp_obj_t)&map_type }, + { MP_QSTR_object, (mp_obj_t)&mp_type_object }, + { MP_QSTR_set, (mp_obj_t)&set_type }, + { MP_QSTR_str, (mp_obj_t)&str_type }, + { MP_QSTR_super, (mp_obj_t)&super_type }, + { MP_QSTR_tuple, (mp_obj_t)&tuple_type }, + { MP_QSTR_type, (mp_obj_t)&mp_type_type }, + { MP_QSTR_zip, (mp_obj_t)&zip_type }, + + { MP_QSTR_classmethod, (mp_obj_t)&mp_type_classmethod }, + { MP_QSTR_staticmethod, (mp_obj_t)&mp_type_staticmethod }, + + // built-in user functions + { MP_QSTR_abs, (mp_obj_t)&mp_builtin_abs_obj }, + { MP_QSTR_all, (mp_obj_t)&mp_builtin_all_obj }, + { MP_QSTR_any, (mp_obj_t)&mp_builtin_any_obj }, + { MP_QSTR_callable, (mp_obj_t)&mp_builtin_callable_obj }, + { MP_QSTR_chr, (mp_obj_t)&mp_builtin_chr_obj }, + { MP_QSTR_dir, (mp_obj_t)&mp_builtin_dir_obj }, + { MP_QSTR_divmod, (mp_obj_t)&mp_builtin_divmod_obj }, + { MP_QSTR_eval, (mp_obj_t)&mp_builtin_eval_obj }, + { MP_QSTR_exec, (mp_obj_t)&mp_builtin_exec_obj }, + { MP_QSTR_hash, (mp_obj_t)&mp_builtin_hash_obj }, + { MP_QSTR_id, (mp_obj_t)&mp_builtin_id_obj }, + { MP_QSTR_isinstance, (mp_obj_t)&mp_builtin_isinstance_obj }, + { MP_QSTR_issubclass, (mp_obj_t)&mp_builtin_issubclass_obj }, + { MP_QSTR_iter, (mp_obj_t)&mp_builtin_iter_obj }, + { MP_QSTR_len, (mp_obj_t)&mp_builtin_len_obj }, + { MP_QSTR_max, (mp_obj_t)&mp_builtin_max_obj }, + { MP_QSTR_min, (mp_obj_t)&mp_builtin_min_obj }, + { MP_QSTR_next, (mp_obj_t)&mp_builtin_next_obj }, + { MP_QSTR_ord, (mp_obj_t)&mp_builtin_ord_obj }, + { MP_QSTR_pow, (mp_obj_t)&mp_builtin_pow_obj }, + { MP_QSTR_print, (mp_obj_t)&mp_builtin_print_obj }, + { MP_QSTR_range, (mp_obj_t)&mp_builtin_range_obj }, + { MP_QSTR_repr, (mp_obj_t)&mp_builtin_repr_obj }, + { MP_QSTR_sorted, (mp_obj_t)&mp_builtin_sorted_obj }, + { MP_QSTR_sum, (mp_obj_t)&mp_builtin_sum_obj }, + { MP_QSTR_bytearray, (mp_obj_t)&mp_builtin_bytearray_obj }, + + // built-in exceptions + { MP_QSTR_BaseException, (mp_obj_t)&mp_type_BaseException }, + { MP_QSTR_ArithmeticError, (mp_obj_t)&mp_type_ArithmeticError }, + { MP_QSTR_AssertionError, (mp_obj_t)&mp_type_AssertionError }, + { MP_QSTR_AttributeError, (mp_obj_t)&mp_type_AttributeError }, + { MP_QSTR_BufferError, (mp_obj_t)&mp_type_BufferError }, + { MP_QSTR_EOFError, (mp_obj_t)&mp_type_EOFError }, + { MP_QSTR_Exception, (mp_obj_t)&mp_type_Exception }, + { MP_QSTR_FloatingPointError, (mp_obj_t)&mp_type_FloatingPointError }, + { MP_QSTR_GeneratorExit, (mp_obj_t)&mp_type_GeneratorExit }, + { MP_QSTR_IOError, (mp_obj_t)&mp_type_IOError }, + { MP_QSTR_ImportError, (mp_obj_t)&mp_type_ImportError }, + { MP_QSTR_IndentationError, (mp_obj_t)&mp_type_IndentationError }, + { MP_QSTR_IndexError, (mp_obj_t)&mp_type_IndexError }, + { MP_QSTR_KeyError, (mp_obj_t)&mp_type_KeyError }, + { MP_QSTR_LookupError, (mp_obj_t)&mp_type_LookupError }, + { MP_QSTR_MemoryError, (mp_obj_t)&mp_type_MemoryError }, + { MP_QSTR_NameError, (mp_obj_t)&mp_type_NameError }, + { MP_QSTR_NotImplementedError, (mp_obj_t)&mp_type_NotImplementedError }, + { MP_QSTR_OSError, (mp_obj_t)&mp_type_OSError }, + { MP_QSTR_OverflowError, (mp_obj_t)&mp_type_OverflowError }, + { MP_QSTR_RuntimeError, (mp_obj_t)&mp_type_RuntimeError }, + { MP_QSTR_StopIteration, (mp_obj_t)&mp_type_StopIteration }, + { MP_QSTR_SyntaxError, (mp_obj_t)&mp_type_SyntaxError }, + { MP_QSTR_SystemError, (mp_obj_t)&mp_type_SystemError }, + { MP_QSTR_TypeError, (mp_obj_t)&mp_type_TypeError }, + { MP_QSTR_UnboundLocalError, (mp_obj_t)&mp_type_UnboundLocalError }, + { MP_QSTR_ValueError, (mp_obj_t)&mp_type_ValueError }, + { MP_QSTR_ZeroDivisionError, (mp_obj_t)&mp_type_ZeroDivisionError }, + // Somehow CPython managed to have OverflowError not inherit from ValueError ;-/ + // TODO: For MICROPY_CPYTHON_COMPAT==0 use ValueError to avoid exc proliferation + + // Extra builtins as defined by a port + MICROPY_EXTRA_BUILTINS + + { MP_QSTR_, MP_OBJ_NULL }, // end of list sentinel +}; + +STATIC const mp_builtin_elem_t builtin_module_table[] = { + { MP_QSTR_micropython, (mp_obj_t)&mp_module_micropython }, + + { MP_QSTR_array, (mp_obj_t)&mp_module_array }, + { MP_QSTR_collections, (mp_obj_t)&mp_module_collections }, + +#if MICROPY_ENABLE_FLOAT + { MP_QSTR_math, (mp_obj_t)&mp_module_math }, +#endif + + // extra builtin modules as defined by a port + MICROPY_EXTRA_BUILTIN_MODULES + + { MP_QSTR_, MP_OBJ_NULL }, // end of list sentinel +}; + +STATIC mp_obj_t mp_builtin_tables_lookup(const mp_builtin_elem_t *table, qstr q) { + for (; table->qstr != MP_QSTR_; table++) { + if (table->qstr == q) { + return table->elem; + } + } + return MP_OBJ_NULL; +} + +mp_obj_t mp_builtin_tables_lookup_object(qstr q) { + return mp_builtin_tables_lookup(&builtin_object_table[0], q); +} + +mp_obj_t mp_builtin_tables_lookup_module(qstr q) { + return mp_builtin_tables_lookup(&builtin_module_table[0], q); +} diff --git a/py/builtintables.h b/py/builtintables.h new file mode 100644 index 0000000000..9b22b66e03 --- /dev/null +++ b/py/builtintables.h @@ -0,0 +1,2 @@ +mp_obj_t mp_builtin_tables_lookup_object(qstr q); +mp_obj_t mp_builtin_tables_lookup_module(qstr q); diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 934bc43beb..7413365712 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -18,9 +18,9 @@ codepoint2name[ord('/')] = 'slash' # this must match the equivalent function in qstr.c def compute_hash(qstr): - hash = 0 + hash = 5381 for char in qstr: - hash += ord(char) + hash = (hash * 33) ^ ord(char) return hash & 0xffff def do_work(infiles): diff --git a/py/modarray.c b/py/modarray.c new file mode 100644 index 0000000000..2544f7ed59 --- /dev/null +++ b/py/modarray.c @@ -0,0 +1,25 @@ +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "map.h" +#include "builtin.h" + +STATIC const mp_map_elem_t mp_module_array_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_array) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&mp_type_array }, +}; + +STATIC const mp_map_t mp_module_array_globals = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = sizeof(mp_module_array_globals_table) / sizeof(mp_map_elem_t), + .alloc = sizeof(mp_module_array_globals_table) / sizeof(mp_map_elem_t), + .table = (mp_map_elem_t*)mp_module_array_globals_table, +}; + +const mp_obj_module_t mp_module_array = { + .base = { &mp_type_module }, + .name = MP_QSTR_array, + .globals = (mp_map_t*)&mp_module_array_globals, +}; diff --git a/py/modcollections.c b/py/modcollections.c new file mode 100644 index 0000000000..ad951d5e9e --- /dev/null +++ b/py/modcollections.c @@ -0,0 +1,25 @@ +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "map.h" +#include "builtin.h" + +STATIC const mp_map_elem_t mp_module_collections_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_collections) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_namedtuple), (mp_obj_t)&mp_namedtuple_obj }, +}; + +STATIC const mp_map_t mp_module_collections_globals = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = sizeof(mp_module_collections_globals_table) / sizeof(mp_map_elem_t), + .alloc = sizeof(mp_module_collections_globals_table) / sizeof(mp_map_elem_t), + .table = (mp_map_elem_t*)mp_module_collections_globals_table, +}; + +const mp_obj_module_t mp_module_collections = { + .base = { &mp_type_module }, + .name = MP_QSTR_collections, + .globals = (mp_map_t*)&mp_module_collections_globals, +}; diff --git a/py/builtinmath.c b/py/modmath.c index b814822531..b814822531 100644 --- a/py/builtinmath.c +++ b/py/modmath.c diff --git a/py/builtinmp.c b/py/modmicropython.c index 3b73517963..96ceb811c9 100644 --- a/py/builtinmp.c +++ b/py/modmicropython.c @@ -1,4 +1,3 @@ - #include "misc.h" #include "mpconfig.h" #include "qstr.h" diff --git a/py/mpconfig.h b/py/mpconfig.h index 5b13c46480..09cc37913a 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -125,10 +125,16 @@ typedef double mp_float_t; #define MICROPY_PATH_MAX (512) #endif -// Additional builtin function definitions - see runtime.c:builtin_table for format. +// Additional builtin function definitions - see builtintables.c:builtin_object_table for format. #ifndef MICROPY_EXTRA_BUILTINS #define MICROPY_EXTRA_BUILTINS #endif + +// Additional builtin module definitions - see builtintables.c:builtin_module_table for format. +#ifndef MICROPY_EXTRA_BUILTIN_MODULES +#define MICROPY_EXTRA_BUILTIN_MODULES +#endif + /*****************************************************************************/ /* Miscellaneous settings */ @@ -206,21 +206,29 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { } #endif -mp_obj_t *mp_obj_get_array_fixed_n(mp_obj_t o_in, machine_int_t n) { - if (MP_OBJ_IS_TYPE(o_in, &tuple_type) || MP_OBJ_IS_TYPE(o_in, &list_type)) { +void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items) { + if (MP_OBJ_IS_TYPE(o, &tuple_type)) { + mp_obj_tuple_get(o, len, items); + } else if (MP_OBJ_IS_TYPE(o, &list_type)) { + mp_obj_list_get(o, len, items); + } else { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o))); + } +} + +void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items) { + if (MP_OBJ_IS_TYPE(o, &tuple_type) || MP_OBJ_IS_TYPE(o, &list_type)) { uint seq_len; - mp_obj_t *seq_items; - if (MP_OBJ_IS_TYPE(o_in, &tuple_type)) { - mp_obj_tuple_get(o_in, &seq_len, &seq_items); + if (MP_OBJ_IS_TYPE(o, &tuple_type)) { + mp_obj_tuple_get(o, &seq_len, items); } else { - mp_obj_list_get(o_in, &seq_len, &seq_items); + mp_obj_list_get(o, &seq_len, items); } - if (seq_len != n) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "requested length %d but object has length %d", n, seq_len)); + if (seq_len != len) { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "requested length %d but object has length %d", len, seq_len)); } - return seq_items; } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o_in))); + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o))); } } @@ -175,7 +175,6 @@ struct _mp_obj_type_t { abs float complex hash bool int none str equal int str - get_array_n tuple list unpack seq list tuple */ @@ -192,17 +191,12 @@ extern const mp_obj_type_t mp_type_ArithmeticError; extern const mp_obj_type_t mp_type_AssertionError; extern const mp_obj_type_t mp_type_AttributeError; extern const mp_obj_type_t mp_type_BufferError; -extern const mp_obj_type_t mp_type_BytesWarning; -extern const mp_obj_type_t mp_type_DeprecationWarning; extern const mp_obj_type_t mp_type_EOFError; -extern const mp_obj_type_t mp_type_EnvironmentError; extern const mp_obj_type_t mp_type_Exception; extern const mp_obj_type_t mp_type_FloatingPointError; -extern const mp_obj_type_t mp_type_FutureWarning; extern const mp_obj_type_t mp_type_GeneratorExit; extern const mp_obj_type_t mp_type_IOError; extern const mp_obj_type_t mp_type_ImportError; -extern const mp_obj_type_t mp_type_ImportWarning; extern const mp_obj_type_t mp_type_IndentationError; extern const mp_obj_type_t mp_type_IndexError; extern const mp_obj_type_t mp_type_KeyError; @@ -212,43 +206,16 @@ extern const mp_obj_type_t mp_type_NameError; extern const mp_obj_type_t mp_type_NotImplementedError; extern const mp_obj_type_t mp_type_OSError; extern const mp_obj_type_t mp_type_OverflowError; -extern const mp_obj_type_t mp_type_PendingDeprecationWarning; -extern const mp_obj_type_t mp_type_ReferenceError; -extern const mp_obj_type_t mp_type_ResourceWarning; extern const mp_obj_type_t mp_type_RuntimeError; -extern const mp_obj_type_t mp_type_RuntimeWarning; +extern const mp_obj_type_t mp_type_StopIteration; extern const mp_obj_type_t mp_type_SyntaxError; -extern const mp_obj_type_t mp_type_SyntaxWarning; extern const mp_obj_type_t mp_type_SystemError; -extern const mp_obj_type_t mp_type_SystemExit; -extern const mp_obj_type_t mp_type_TabError; extern const mp_obj_type_t mp_type_TypeError; extern const mp_obj_type_t mp_type_UnboundLocalError; -extern const mp_obj_type_t mp_type_UserWarning; extern const mp_obj_type_t mp_type_ValueError; -extern const mp_obj_type_t mp_type_Warning; extern const mp_obj_type_t mp_type_ZeroDivisionError; -extern const mp_obj_type_t mp_type_StopIteration; -/*extern const mp_obj_type_t mp_type_BaseException; -extern const mp_obj_type_t mp_type_AssertionError; -extern const mp_obj_type_t mp_type_AttributeError; -extern const mp_obj_type_t mp_type_ImportError; -extern const mp_obj_type_t mp_type_IndentationError; -extern const mp_obj_type_t mp_type_IndexError; -extern const mp_obj_type_t mp_type_KeyError; -extern const mp_obj_type_t mp_type_NameError; -extern const mp_obj_type_t mp_type_SyntaxError; -extern const mp_obj_type_t mp_type_TypeError; -extern const mp_obj_type_t mp_type_ValueError; -extern const mp_obj_type_t mp_type_OverflowError; -extern const mp_obj_type_t mp_type_OSError; -extern const mp_obj_type_t mp_type_NotImplementedError; -extern const mp_obj_type_t mp_type_StopIteration; -extern const mp_obj_type_t mp_type_ZeroDivisionError;*/ - // Constant objects, globally accessible - extern const mp_obj_t mp_const_none; extern const mp_obj_t mp_const_false; extern const mp_obj_t mp_const_true; @@ -295,7 +262,7 @@ mp_obj_t mp_obj_new_module(qstr module_name); mp_obj_type_t *mp_obj_get_type(mp_obj_t o_in); const char *mp_obj_get_type_str(mp_obj_t o_in); -bool mp_obj_is_subclass_fast(mp_obj_t object, mp_obj_t classinfo); // arguments should be type objects +bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo); // arguments should be type objects void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind); void mp_obj_print(mp_obj_t o, mp_print_kind_t kind); @@ -312,7 +279,8 @@ mp_float_t mp_obj_get_float(mp_obj_t self_in); void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); #endif //qstr mp_obj_get_qstr(mp_obj_t arg); -mp_obj_t *mp_obj_get_array_fixed_n(mp_obj_t o, machine_int_t n); +void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items); +void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items); uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index, bool is_slice); mp_obj_t mp_obj_len_maybe(mp_obj_t o_in); /* may return NULL */ @@ -419,7 +387,7 @@ void mp_obj_slice_get(mp_obj_t self_in, machine_int_t *start, machine_int_t *sto extern const mp_obj_type_t zip_type; // array -extern const mp_obj_type_t array_type; +extern const mp_obj_type_t mp_type_array; uint mp_obj_array_len(mp_obj_t self_in); mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items); @@ -456,8 +424,6 @@ typedef struct _mp_obj_module_t { struct _mp_map_t *globals; } mp_obj_module_t; extern const mp_obj_type_t mp_type_module; -mp_obj_t mp_obj_new_module(qstr module_name); -mp_obj_t mp_obj_module_get(qstr module_name); struct _mp_map_t *mp_obj_module_get_globals(mp_obj_t self_in); // staticmethod and classmethod types; defined here so we can make const versions diff --git a/py/objarray.c b/py/objarray.c index ee43bde960..69f60e000a 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -121,7 +121,7 @@ STATIC mp_obj_t array_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { } STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) { - assert(MP_OBJ_IS_TYPE(self_in, &array_type)); + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_array)); mp_obj_array_t *self = self_in; if (self->free == 0) { int item_sz = mp_binary_get_size(self->typecode); @@ -154,7 +154,7 @@ STATIC const mp_method_t array_type_methods[] = { { NULL, NULL }, }; -const mp_obj_type_t array_type = { +const mp_obj_type_t mp_type_array = { { &mp_type_type }, .name = MP_QSTR_array, .print = array_print, @@ -169,7 +169,7 @@ const mp_obj_type_t array_type = { STATIC mp_obj_array_t *array_new(char typecode, uint n) { mp_obj_array_t *o = m_new_obj(mp_obj_array_t); - o->base.type = &array_type; + o->base.type = &mp_type_array; o->typecode = typecode; o->free = 0; o->len = n; @@ -190,7 +190,7 @@ mp_obj_t mp_obj_new_bytearray(uint n, void *items) { // Create bytearray which references specified memory area mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items) { mp_obj_array_t *o = m_new_obj(mp_obj_array_t); - o->base.type = &array_type; + o->base.type = &mp_type_array; o->typecode = BYTEARRAY_TYPECODE; o->free = 0; o->len = n; @@ -207,7 +207,7 @@ typedef struct _mp_obj_array_it_t { machine_uint_t cur; } mp_obj_array_it_t; -mp_obj_t array_it_iternext(mp_obj_t self_in) { +STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) { mp_obj_array_it_t *self = self_in; if (self->cur < self->array->len) { return mp_binary_get_val(self->array->typecode, self->array->items, self->cur++); @@ -222,7 +222,7 @@ STATIC const mp_obj_type_t array_it_type = { .iternext = array_it_iternext, }; -mp_obj_t array_iterator_new(mp_obj_t array_in) { +STATIC mp_obj_t array_iterator_new(mp_obj_t array_in) { mp_obj_array_t *array = array_in; mp_obj_array_it_t *o = m_new_obj(mp_obj_array_it_t); o->base.type = &array_it_type; diff --git a/py/objexcept.c b/py/objexcept.c index f96523ed23..c75e3d3a57 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -55,16 +55,31 @@ STATIC mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_ o->base.type = type; o->traceback = MP_OBJ_NULL; o->msg = NULL; + o->args.base.type = &tuple_type; o->args.len = n_args; memcpy(o->args.items, args, n_args * sizeof(mp_obj_t)); return o; } +STATIC void exception_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + mp_obj_exception_t *self = self_in; + if (attr == MP_QSTR_args) { + dest[0] = &self->args; + } else if (self->base.type == &mp_type_StopIteration && attr == MP_QSTR_value) { + if (self->args.len == 0) { + dest[0] = mp_const_none; + } else { + dest[0] = self->args.items[0]; + } + } +} + const mp_obj_type_t mp_type_BaseException = { { &mp_type_type }, .name = MP_QSTR_BaseException, .print = mp_obj_exception_print, .make_new = mp_obj_exception_make_new, + .load_attr = exception_load_attr, }; #define MP_DEFINE_EXCEPTION_BASE(base_name) \ @@ -76,13 +91,14 @@ const mp_obj_type_t mp_type_ ## exc_name = { \ .name = MP_QSTR_ ## exc_name, \ .print = mp_obj_exception_print, \ .make_new = mp_obj_exception_make_new, \ + .load_attr = exception_load_attr, \ .bases_tuple = (mp_obj_t)&mp_type_ ## base_name ## _base_tuple, \ }; // List of all exceptions, arranged as in the table at: // http://docs.python.org/3.3/library/exceptions.html MP_DEFINE_EXCEPTION_BASE(BaseException) -MP_DEFINE_EXCEPTION(SystemExit, BaseException) +//MP_DEFINE_EXCEPTION(SystemExit, BaseException) //MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException) MP_DEFINE_EXCEPTION(GeneratorExit, BaseException) MP_DEFINE_EXCEPTION(Exception, BaseException) @@ -96,7 +112,7 @@ MP_DEFINE_EXCEPTION(Exception, BaseException) MP_DEFINE_EXCEPTION(AssertionError, Exception) MP_DEFINE_EXCEPTION(AttributeError, Exception) MP_DEFINE_EXCEPTION(BufferError, Exception) - MP_DEFINE_EXCEPTION(EnvironmentError, Exception) + //MP_DEFINE_EXCEPTION(EnvironmentError, Exception) MP_DEFINE_EXCEPTION(EOFError, Exception) MP_DEFINE_EXCEPTION(ImportError, Exception) MP_DEFINE_EXCEPTION(IOError, Exception) @@ -126,7 +142,7 @@ MP_DEFINE_EXCEPTION(Exception, BaseException) MP_DEFINE_EXCEPTION(TimeoutError, OSError)*/ MP_DEFINE_EXCEPTION(FileExistsError, OSError) MP_DEFINE_EXCEPTION(FileNotFoundError, OSError) - MP_DEFINE_EXCEPTION(ReferenceError, Exception) + //MP_DEFINE_EXCEPTION(ReferenceError, Exception) MP_DEFINE_EXCEPTION(RuntimeError, Exception) MP_DEFINE_EXCEPTION_BASE(RuntimeError) MP_DEFINE_EXCEPTION(NotImplementedError, RuntimeError) @@ -134,7 +150,7 @@ MP_DEFINE_EXCEPTION(Exception, BaseException) MP_DEFINE_EXCEPTION_BASE(SyntaxError) MP_DEFINE_EXCEPTION(IndentationError, SyntaxError) MP_DEFINE_EXCEPTION_BASE(IndentationError) - MP_DEFINE_EXCEPTION(TabError, IndentationError) + //MP_DEFINE_EXCEPTION(TabError, IndentationError) MP_DEFINE_EXCEPTION(SystemError, Exception) MP_DEFINE_EXCEPTION(TypeError, Exception) MP_DEFINE_EXCEPTION(ValueError, Exception) @@ -193,20 +209,20 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char } // return true if the given object is an exception type -// TODO make this work for user defined exceptions bool mp_obj_is_exception_type(mp_obj_t self_in) { if (MP_OBJ_IS_TYPE(self_in, &mp_type_type)) { + // optimisation when self_in is a builtin exception mp_obj_type_t *self = self_in; - return self->make_new == mp_obj_exception_make_new; - } else { - return false; + if (self->make_new == mp_obj_exception_make_new) { + return true; + } } + return mp_obj_is_subclass_fast(self_in, &mp_type_BaseException); } // return true if the given object is an instance of an exception type -// TODO make this work for user defined exceptions bool mp_obj_is_exception_instance(mp_obj_t self_in) { - return mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new; + return mp_obj_is_exception_type(mp_obj_get_type(self_in)); } // return true if exception (type or instance) is a subclass of given @@ -218,26 +234,30 @@ bool mp_obj_exception_match(mp_obj_t exc, const mp_obj_type_t *exc_type) { void mp_obj_exception_clear_traceback(mp_obj_t self_in) { // make sure self_in is an exception instance - assert(mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new); - mp_obj_exception_t *self = self_in; + // TODO add traceback information to user-defined exceptions (need proper builtin subclassing for that) + if (mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new) { + mp_obj_exception_t *self = self_in; - // just set the traceback to the null object - // we don't want to call any memory management functions here - self->traceback = MP_OBJ_NULL; + // just set the traceback to the null object + // we don't want to call any memory management functions here + self->traceback = MP_OBJ_NULL; + } } void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block) { // make sure self_in is an exception instance - assert(mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new); - mp_obj_exception_t *self = self_in; + // TODO add traceback information to user-defined exceptions (need proper builtin subclassing for that) + if (mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new) { + mp_obj_exception_t *self = self_in; - // for traceback, we are just using the list object for convenience, it's not really a list of Python objects - if (self->traceback == MP_OBJ_NULL) { - self->traceback = mp_obj_new_list(0, NULL); + // for traceback, we are just using the list object for convenience, it's not really a list of Python objects + if (self->traceback == MP_OBJ_NULL) { + self->traceback = mp_obj_new_list(0, NULL); + } + mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)file); + mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)line); + mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)block); } - mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)file); - mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)line); - mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)block); } void mp_obj_exception_get_traceback(mp_obj_t self_in, machine_uint_t *n, machine_uint_t **values) { diff --git a/py/objmodule.c b/py/objmodule.c index e0778b4cf2..a388ca3f37 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -6,9 +6,12 @@ #include "mpconfig.h" #include "qstr.h" #include "obj.h" +#include "objmodule.h" #include "runtime.h" #include "map.h" -#include "builtin.h" +#include "builtintables.h" + +STATIC mp_map_t mp_loaded_modules_map; // TODO: expose as sys.modules STATIC void module_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { mp_obj_module_t *self = self_in; @@ -39,7 +42,7 @@ const mp_obj_type_t mp_type_module = { }; mp_obj_t mp_obj_new_module(qstr module_name) { - mp_map_elem_t *el = mp_map_lookup(rt_loaded_modules_get(), MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + mp_map_elem_t *el = mp_map_lookup(&mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); // We could error out if module already exists, but let C extensions // add new members to existing modules. if (el->value != MP_OBJ_NULL) { @@ -62,9 +65,27 @@ mp_obj_t mp_obj_new_module(qstr module_name) { return o; } -mp_obj_t mp_obj_module_get(qstr module_name) { +mp_map_t *mp_obj_module_get_globals(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_module)); + mp_obj_module_t *self = self_in; + return self->globals; +} + +/******************************************************************************/ +// Global module table and related functions + +void mp_module_init(void) { + mp_map_init(&mp_loaded_modules_map, 3); +} + +void mp_module_deinit(void) { + mp_map_deinit(&mp_loaded_modules_map); +} + +// returns MP_OBJ_NULL if not found +mp_obj_t mp_module_get(qstr module_name) { // lookup module - mp_map_elem_t *el = mp_map_lookup(rt_loaded_modules_get(), MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); + mp_map_elem_t *el = mp_map_lookup(&mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); // module found, return it if (el != NULL) { @@ -72,18 +93,10 @@ mp_obj_t mp_obj_module_get(qstr module_name) { } // module not found, look for builtin module names -#if MICROPY_ENABLE_FLOAT - if (module_name == MP_QSTR_math) { - return (mp_obj_t)&mp_module_math; - } -#endif - - // no module found, return NULL object - return MP_OBJ_NULL; + // it will return MP_OBJ_NULL if nothing found + return mp_builtin_tables_lookup_module(module_name); } -mp_map_t *mp_obj_module_get_globals(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_module)); - mp_obj_module_t *self = self_in; - return self->globals; +void mp_module_register(qstr qstr, mp_obj_t module) { + mp_map_lookup(&mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module; } diff --git a/py/objmodule.h b/py/objmodule.h new file mode 100644 index 0000000000..270551da4f --- /dev/null +++ b/py/objmodule.h @@ -0,0 +1,4 @@ +void mp_module_init(void); +void mp_module_deinit(void); +mp_obj_t mp_module_get(qstr module_name); +void mp_module_register(qstr qstr, mp_obj_t module); diff --git a/py/objstr.c b/py/objstr.c index 35a948700c..00586a3b3b 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -186,19 +186,26 @@ wrong_args: // like strstr but with specified length and allows \0 bytes // TODO replace with something more efficient/standard -STATIC const byte *find_subbytes(const byte *haystack, uint hlen, const byte *needle, uint nlen) { +STATIC const byte *find_subbytes(const byte *haystack, machine_uint_t hlen, const byte *needle, machine_uint_t nlen, machine_int_t direction) { if (hlen >= nlen) { - for (uint i = 0; i <= hlen - nlen; i++) { - bool found = true; - for (uint j = 0; j < nlen; j++) { - if (haystack[i + j] != needle[j]) { - found = false; - break; - } + machine_uint_t str_index, str_index_end; + if (direction > 0) { + str_index = 0; + str_index_end = hlen - nlen; + } else { + str_index = hlen - nlen; + str_index_end = 0; + } + for (;;) { + if (memcmp(&haystack[str_index], needle, nlen) == 0) { + //found + return haystack + str_index; } - if (found) { - return haystack + i; + if (str_index == str_index_end) { + //not found + break; } + str_index += direction; } } return NULL; @@ -260,7 +267,7 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { /* NOTE `a in b` is `b.__contains__(a)` */ if (MP_OBJ_IS_STR(rhs_in)) { GET_STR_DATA_LEN(rhs_in, rhs_data, rhs_len); - return MP_BOOL(find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len) != NULL); + return MP_BOOL(find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len, 1) != NULL); } break; @@ -382,7 +389,7 @@ STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) { return res; } -STATIC mp_obj_t str_find(uint n_args, const mp_obj_t *args) { +STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, machine_int_t direction) { assert(2 <= n_args && n_args <= 4); assert(MP_OBJ_IS_STR(args[0])); assert(MP_OBJ_IS_STR(args[1])); @@ -392,7 +399,6 @@ STATIC mp_obj_t str_find(uint n_args, const mp_obj_t *args) { machine_uint_t start = 0; machine_uint_t end = haystack_len; - /* TODO use a non-exception-throwing mp_get_index */ if (n_args >= 3 && args[2] != mp_const_none) { start = mp_get_index(&str_type, haystack_len, args[2], true); } @@ -400,20 +406,24 @@ STATIC mp_obj_t str_find(uint n_args, const mp_obj_t *args) { end = mp_get_index(&str_type, haystack_len, args[3], true); } - const byte *p = find_subbytes(haystack + start, haystack_len - start, needle, needle_len); + const byte *p = find_subbytes(haystack + start, end - start, needle, needle_len, direction); if (p == NULL) { // not found return MP_OBJ_NEW_SMALL_INT(-1); } else { // found - machine_int_t pos = p - haystack; - if (pos + needle_len > end) { - pos = -1; - } - return MP_OBJ_NEW_SMALL_INT(pos); + return MP_OBJ_NEW_SMALL_INT(p - haystack); } } +STATIC mp_obj_t str_find(uint n_args, const mp_obj_t *args) { + return str_finder(n_args, args, 1); +} + +STATIC mp_obj_t str_rfind(uint n_args, const mp_obj_t *args) { + return str_finder(n_args, args, -1); +} + // TODO: (Much) more variety in args STATIC mp_obj_t str_startswith(mp_obj_t self_in, mp_obj_t arg) { GET_STR_DATA_LEN(self_in, str, str_len); @@ -424,15 +434,6 @@ STATIC mp_obj_t str_startswith(mp_obj_t self_in, mp_obj_t arg) { return MP_BOOL(memcmp(str, prefix, prefix_len) == 0); } -STATIC bool chr_in_str(const byte* const str, const machine_uint_t str_len, int c) { - for (machine_uint_t i = 0; i < str_len; i++) { - if (str[i] == c) { - return true; - } - } - return false; -} - STATIC mp_obj_t str_strip(uint n_args, const mp_obj_t *args) { assert(1 <= n_args && n_args <= 2); assert(MP_OBJ_IS_STR(args[0])); @@ -457,7 +458,7 @@ STATIC mp_obj_t str_strip(uint n_args, const mp_obj_t *args) { bool first_good_char_pos_set = false; machine_uint_t last_good_char_pos = 0; for (machine_uint_t i = 0; i < orig_str_len; i++) { - if (!chr_in_str(chars_to_del, chars_to_del_len, orig_str[i])) { + if (find_subbytes(chars_to_del, chars_to_del_len, &orig_str[i], 1, 1) == NULL) { last_good_char_pos = i; if (!first_good_char_pos_set) { first_good_char_pos = i; @@ -547,7 +548,7 @@ STATIC mp_obj_t str_replace(uint n_args, const mp_obj_t *args) { const byte *old_occurrence; const byte *offset_ptr = str; machine_uint_t offset_num = 0; - while ((old_occurrence = find_subbytes(offset_ptr, str_len - offset_num, old, old_len)) != NULL) { + while ((old_occurrence = find_subbytes(offset_ptr, str_len - offset_num, old, old_len, 1)) != NULL) { // copy from just after end of last occurrence of to-be-replaced string to right before start of next occurrence if (data != NULL) { memcpy(data + replaced_str_index, offset_ptr, old_occurrence - offset_ptr); @@ -601,7 +602,6 @@ STATIC mp_obj_t str_count(uint n_args, const mp_obj_t *args) { machine_uint_t start = 0; machine_uint_t end = haystack_len; - /* TODO use a non-exception-throwing mp_get_index */ if (n_args >= 3 && args[2] != mp_const_none) { start = mp_get_index(&str_type, haystack_len, args[2], true); } @@ -648,27 +648,12 @@ STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, machine_int_t di result[2] = self_in; } - if (str_len >= sep_len) { - machine_uint_t str_index, str_index_end; - if (direction > 0) { - str_index = 0; - str_index_end = str_len - sep_len; - } else { - str_index = str_len - sep_len; - str_index_end = 0; - } - for (;;) { - if (memcmp(&str[str_index], sep, sep_len) == 0) { - result[0] = mp_obj_new_str(str, str_index, false); - result[1] = arg; - result[2] = mp_obj_new_str(str + str_index + sep_len, str_len - str_index - sep_len, false); - break; - } - if (str_index == str_index_end) { - break; - } - str_index += direction; - } + const byte *position_ptr = find_subbytes(str, str_len, sep, sep_len, direction); + if (position_ptr != NULL) { + machine_uint_t position = position_ptr - str; + result[0] = mp_obj_new_str(str, position, false); + result[1] = arg; + result[2] = mp_obj_new_str(str + position + sep_len, str_len - position - sep_len, false); } return mp_obj_new_tuple(3, result); @@ -697,6 +682,7 @@ STATIC machine_int_t str_get_buffer(mp_obj_t self_in, buffer_info_t *bufinfo, in } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj, 2, 4, str_rfind); STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, str_split); STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_startswith_obj, str_startswith); @@ -709,6 +695,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition); STATIC const mp_method_t str_type_methods[] = { { "find", &str_find_obj }, + { "rfind", &str_rfind_obj }, { "join", &str_join_obj }, { "split", &str_split_obj }, { "startswith", &str_startswith_obj }, diff --git a/py/objtype.c b/py/objtype.c index 4898c5ccb4..9cb29744c7 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -469,7 +469,7 @@ mp_obj_t mp_obj_new_super(mp_obj_t type, mp_obj_t obj) { // object and classinfo should be type objects // (but the function will fail gracefully if they are not) -bool mp_obj_is_subclass_fast(mp_obj_t object, mp_obj_t classinfo) { +bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) { for (;;) { if (object == classinfo) { return true; @@ -482,7 +482,7 @@ bool mp_obj_is_subclass_fast(mp_obj_t object, mp_obj_t classinfo) { return false; } - mp_obj_type_t *self = object; + const mp_obj_type_t *self = object; // for a const struct, this entry might be NULL if (self->bases_tuple == MP_OBJ_NULL) { @@ -74,8 +74,11 @@ PY_O_BASENAME = \ builtin.o \ builtinimport.o \ builtinevex.o \ - builtinmp.o \ - builtinmath.o \ + builtintables.o \ + modarray.o \ + modcollections.o \ + modmath.o \ + modmicropython.o \ vm.o \ showbc.o \ repl.o \ @@ -18,7 +18,7 @@ // A qstr is an index into the qstr pool. // The data for a qstr contains (hash, length, data). // For now we use very simple encoding, just to get the framework correct: -// - hash is 2 bytes (simply the sum of data bytes) +// - hash is 2 bytes (see function below) // - length is 2 bytes // - data follows // - \0 terminated (for now, so they can be printed using printf) @@ -28,10 +28,12 @@ #define Q_GET_LENGTH(q) ((q)[2] | ((q)[3] << 8)) #define Q_GET_DATA(q) ((q) + 4) +// this must match the equivalent function in makeqstrdata.py machine_uint_t qstr_compute_hash(const byte *data, uint len) { - machine_uint_t hash = 0; + // djb2 algorithm; see http://www.cse.yorku.ca/~oz/hash.html + machine_uint_t hash = 5381; for (const byte *top = data + len; data < top; data++) { - hash += *data; + hash = ((hash << 5) + hash) ^ (*data); // hash * 33 ^ data } return hash & 0xffff; } diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 898e67582f..1c8afe797d 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -17,6 +17,7 @@ Q(__repl_print__) Q(__bool__) Q(__len__) +Q(__iter__) Q(__getitem__) Q(__setitem__) Q(__add__) @@ -39,7 +40,6 @@ Q(AssertionError) Q(AttributeError) Q(BufferError) Q(EOFError) -Q(EnvironmentError) Q(Exception) Q(FileExistsError) Q(FileNotFoundError) @@ -56,16 +56,12 @@ Q(NameError) Q(NotImplementedError) Q(OSError) Q(OverflowError) -Q(ReferenceError) Q(RuntimeError) Q(SyntaxError) Q(SystemError) -Q(SystemExit) -Q(TabError) Q(TypeError) Q(UnboundLocalError) Q(ValueError) -Q(Warning) Q(ZeroDivisionError) Q(None) @@ -78,6 +74,7 @@ Q(NoneType) Q(abs) Q(all) Q(any) +Q(args) Q(array) Q(bool) Q(bytearray) @@ -123,6 +120,7 @@ Q(str) Q(sys) Q(tuple) Q(type) +Q(value) Q(zip) Q(append) diff --git a/py/runtime.c b/py/runtime.c index bbd12895af..3e0ef98d8b 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -12,12 +12,13 @@ #include "mpconfig.h" #include "qstr.h" #include "obj.h" +#include "objmodule.h" #include "parsenum.h" #include "runtime0.h" #include "runtime.h" #include "map.h" #include "builtin.h" -#include "objarray.h" +#include "builtintables.h" #include "bc.h" #include "intdivmod.h" @@ -35,7 +36,6 @@ STATIC mp_map_t *map_locals; STATIC mp_map_t *map_globals; STATIC mp_map_t map_builtins; -STATIC mp_map_t map_loaded_modules; // TODO: expose as sys.modules typedef enum { MP_CODE_NONE, @@ -72,119 +72,6 @@ STATIC mp_code_t *unique_codes = NULL; FILE *fp_write_code = NULL; #endif -// builtins -// we put this table in ROM because it's always needed and takes up quite a bit of room in RAM -// in fact, it uses less ROM here in table form than the equivalent in code form initialising a dynamic mp_map_t object in RAM -// at the moment it's a linear table, but we could convert it to a const mp_map_t table with a simple preprocessing script -// if we wanted to allow dynamic modification of the builtins, we could provide an mp_map_t object which is searched before this one - -typedef struct _mp_builtin_elem_t { - qstr qstr; - mp_obj_t fun; -} mp_builtin_elem_t; - -STATIC const mp_builtin_elem_t builtin_table[] = { - // built-in core functions - { MP_QSTR___build_class__, (mp_obj_t)&mp_builtin___build_class___obj }, - { MP_QSTR___import__, (mp_obj_t)&mp_builtin___import___obj }, - { MP_QSTR___repl_print__, (mp_obj_t)&mp_builtin___repl_print___obj }, - - // built-in types - { MP_QSTR_bool, (mp_obj_t)&bool_type }, - { MP_QSTR_bytes, (mp_obj_t)&bytes_type }, -#if MICROPY_ENABLE_FLOAT - { MP_QSTR_complex, (mp_obj_t)&mp_type_complex }, -#endif - { MP_QSTR_dict, (mp_obj_t)&dict_type }, - { MP_QSTR_enumerate, (mp_obj_t)&enumerate_type }, - { MP_QSTR_filter, (mp_obj_t)&filter_type }, -#if MICROPY_ENABLE_FLOAT - { MP_QSTR_float, (mp_obj_t)&mp_type_float }, -#endif - { MP_QSTR_int, (mp_obj_t)&int_type }, - { MP_QSTR_list, (mp_obj_t)&list_type }, - { MP_QSTR_map, (mp_obj_t)&map_type }, - { MP_QSTR_object, (mp_obj_t)&mp_type_object }, - { MP_QSTR_set, (mp_obj_t)&set_type }, - { MP_QSTR_str, (mp_obj_t)&str_type }, - { MP_QSTR_super, (mp_obj_t)&super_type }, - { MP_QSTR_tuple, (mp_obj_t)&tuple_type }, - { MP_QSTR_type, (mp_obj_t)&mp_type_type }, - { MP_QSTR_zip, (mp_obj_t)&zip_type }, - - { MP_QSTR_classmethod, (mp_obj_t)&mp_type_classmethod }, - { MP_QSTR_staticmethod, (mp_obj_t)&mp_type_staticmethod }, - - // built-in user functions - { MP_QSTR_abs, (mp_obj_t)&mp_builtin_abs_obj }, - { MP_QSTR_all, (mp_obj_t)&mp_builtin_all_obj }, - { MP_QSTR_any, (mp_obj_t)&mp_builtin_any_obj }, - { MP_QSTR_callable, (mp_obj_t)&mp_builtin_callable_obj }, - { MP_QSTR_chr, (mp_obj_t)&mp_builtin_chr_obj }, - { MP_QSTR_dir, (mp_obj_t)&mp_builtin_dir_obj }, - { MP_QSTR_divmod, (mp_obj_t)&mp_builtin_divmod_obj }, - { MP_QSTR_eval, (mp_obj_t)&mp_builtin_eval_obj }, - { MP_QSTR_exec, (mp_obj_t)&mp_builtin_exec_obj }, - { MP_QSTR_hash, (mp_obj_t)&mp_builtin_hash_obj }, - { MP_QSTR_id, (mp_obj_t)&mp_builtin_id_obj }, - { MP_QSTR_isinstance, (mp_obj_t)&mp_builtin_isinstance_obj }, - { MP_QSTR_issubclass, (mp_obj_t)&mp_builtin_issubclass_obj }, - { MP_QSTR_iter, (mp_obj_t)&mp_builtin_iter_obj }, - { MP_QSTR_len, (mp_obj_t)&mp_builtin_len_obj }, - { MP_QSTR_max, (mp_obj_t)&mp_builtin_max_obj }, - { MP_QSTR_min, (mp_obj_t)&mp_builtin_min_obj }, - { MP_QSTR_next, (mp_obj_t)&mp_builtin_next_obj }, - { MP_QSTR_ord, (mp_obj_t)&mp_builtin_ord_obj }, - { MP_QSTR_pow, (mp_obj_t)&mp_builtin_pow_obj }, - { MP_QSTR_print, (mp_obj_t)&mp_builtin_print_obj }, - { MP_QSTR_range, (mp_obj_t)&mp_builtin_range_obj }, - { MP_QSTR_repr, (mp_obj_t)&mp_builtin_repr_obj }, - { MP_QSTR_sorted, (mp_obj_t)&mp_builtin_sorted_obj }, - { MP_QSTR_sum, (mp_obj_t)&mp_builtin_sum_obj }, - { MP_QSTR_bytearray, (mp_obj_t)&mp_builtin_bytearray_obj }, - - // built-in exceptions - { MP_QSTR_BaseException, (mp_obj_t)&mp_type_BaseException }, - { MP_QSTR_ArithmeticError, (mp_obj_t)&mp_type_ArithmeticError }, - { MP_QSTR_AssertionError, (mp_obj_t)&mp_type_AssertionError }, - { MP_QSTR_AttributeError, (mp_obj_t)&mp_type_AttributeError }, - { MP_QSTR_BufferError, (mp_obj_t)&mp_type_BufferError }, - { MP_QSTR_EOFError, (mp_obj_t)&mp_type_EOFError }, - { MP_QSTR_EnvironmentError, (mp_obj_t)&mp_type_EnvironmentError }, - { MP_QSTR_Exception, (mp_obj_t)&mp_type_Exception }, - { MP_QSTR_FloatingPointError, (mp_obj_t)&mp_type_FloatingPointError }, - { MP_QSTR_GeneratorExit, (mp_obj_t)&mp_type_GeneratorExit }, - { MP_QSTR_IOError, (mp_obj_t)&mp_type_IOError }, - { MP_QSTR_ImportError, (mp_obj_t)&mp_type_ImportError }, - { MP_QSTR_IndentationError, (mp_obj_t)&mp_type_IndentationError }, - { MP_QSTR_IndexError, (mp_obj_t)&mp_type_IndexError }, - { MP_QSTR_KeyError, (mp_obj_t)&mp_type_KeyError }, - { MP_QSTR_LookupError, (mp_obj_t)&mp_type_LookupError }, - { MP_QSTR_MemoryError, (mp_obj_t)&mp_type_MemoryError }, - { MP_QSTR_NameError, (mp_obj_t)&mp_type_NameError }, - { MP_QSTR_NotImplementedError, (mp_obj_t)&mp_type_NotImplementedError }, - { MP_QSTR_OSError, (mp_obj_t)&mp_type_OSError }, - { MP_QSTR_OverflowError, (mp_obj_t)&mp_type_OverflowError }, - { MP_QSTR_ReferenceError, (mp_obj_t)&mp_type_ReferenceError }, - { MP_QSTR_RuntimeError, (mp_obj_t)&mp_type_RuntimeError }, - { MP_QSTR_SyntaxError, (mp_obj_t)&mp_type_SyntaxError }, - { MP_QSTR_SystemError, (mp_obj_t)&mp_type_SystemError }, - { MP_QSTR_SystemExit, (mp_obj_t)&mp_type_SystemExit }, - { MP_QSTR_TabError, (mp_obj_t)&mp_type_TabError }, - { MP_QSTR_TypeError, (mp_obj_t)&mp_type_TypeError }, - { MP_QSTR_UnboundLocalError, (mp_obj_t)&mp_type_UnboundLocalError }, - { MP_QSTR_ValueError, (mp_obj_t)&mp_type_ValueError }, - { MP_QSTR_ZeroDivisionError, (mp_obj_t)&mp_type_ZeroDivisionError }, - { MP_QSTR_StopIteration, (mp_obj_t)&mp_type_StopIteration }, - // Somehow CPython managed to have OverflowError not inherit from ValueError ;-/ - // TODO: For MICROPY_CPYTHON_COMPAT==0 use ValueError to avoid exc proliferation - - // Extra builtins as defined by a port - MICROPY_EXTRA_BUILTINS - - { MP_QSTR_, MP_OBJ_NULL }, // end of list sentinel -}; - // a good optimising compiler will inline this if necessary STATIC void mp_map_add_qstr(mp_map_t *map, qstr qstr, mp_obj_t value) { mp_map_lookup(map, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; @@ -193,23 +80,17 @@ STATIC void mp_map_add_qstr(mp_map_t *map, qstr qstr, mp_obj_t value) { void rt_init(void) { // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New()) map_locals = map_globals = mp_map_new(1); - mp_map_add_qstr(map_globals, MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR___main__)); // init built-in hash table mp_map_init(&map_builtins, 3); - // init loaded modules table - mp_map_init(&map_loaded_modules, 3); + // init global module stuff + mp_module_init(); - // built-in objects + // add some builtins that can't be done in ROM + mp_map_add_qstr(map_globals, MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR___main__)); mp_map_add_qstr(&map_builtins, MP_QSTR_Ellipsis, mp_const_ellipsis); - mp_obj_t m_array = mp_obj_new_module(MP_QSTR_array); - rt_store_attr(m_array, MP_QSTR_array, (mp_obj_t)&array_type); - - mp_obj_t m_collections = mp_obj_new_module(MP_QSTR_collections); - rt_store_attr(m_collections, MP_QSTR_namedtuple, (mp_obj_t)&mp_namedtuple_obj); - #if MICROPY_CPYTHON_COMPAT // Precreate sys module, so "import sys" didn't throw exceptions. mp_obj_t m_sys = mp_obj_new_module(MP_QSTR_sys); @@ -221,10 +102,6 @@ void rt_init(void) { //sys_path = mp_obj_new_list(0, NULL); //rt_store_attr(m_sys, MP_QSTR_path, sys_path); - // we pre-import the micropython module - // probably shouldn't do this, so we are compatible with CPython - rt_store_name(MP_QSTR_micropython, (mp_obj_t)&mp_module_micropython); - // TODO: wastes one mp_code_t structure in mem next_unique_code_id = 1; // 0 indicates "no code" unique_codes_alloc = 0; @@ -238,8 +115,8 @@ void rt_init(void) { void rt_deinit(void) { m_del(mp_code_t, unique_codes, unique_codes_alloc); mp_map_free(map_globals); - mp_map_deinit(&map_loaded_modules); mp_map_deinit(&map_builtins); + mp_module_deinit(); #ifdef WRITE_CODE if (fp_write_code != NULL) { fclose(fp_write_code); @@ -428,10 +305,9 @@ mp_obj_t rt_load_global(qstr qstr) { if (elem == NULL) { elem = mp_map_lookup(&map_builtins, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP); if (elem == NULL) { - for (const mp_builtin_elem_t *e = &builtin_table[0]; e->qstr != MP_QSTR_; e++) { - if (e->qstr == qstr) { - return e->fun; - } + mp_obj_t o = mp_builtin_tables_lookup_object(qstr); + if (o != MP_OBJ_NULL) { + return o; } nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_NameError, "name '%s' is not defined", qstr_str(qstr))); } @@ -441,10 +317,13 @@ mp_obj_t rt_load_global(qstr qstr) { mp_obj_t rt_load_build_class(void) { DEBUG_OP_printf("load_build_class\n"); + // lookup __build_class__ in dynamic table of builtins first mp_map_elem_t *elem = mp_map_lookup(&map_builtins, MP_OBJ_NEW_QSTR(MP_QSTR___build_class__), MP_MAP_LOOKUP); if (elem != NULL) { + // found user-defined __build_class__, return it return elem->value; } else { + // no user-defined __build_class__, return builtin one return (mp_obj_t)&mp_builtin___build_class___obj; } } @@ -462,6 +341,11 @@ void rt_store_name(qstr qstr, mp_obj_t obj) { mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = obj; } +void rt_delete_name(qstr qstr) { + DEBUG_OP_printf("delete name %s\n", qstr_str(qstr)); + mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); +} + void rt_store_global(qstr qstr, mp_obj_t obj) { DEBUG_OP_printf("store global %s <- %p\n", qstr_str(qstr), obj); mp_map_lookup(map_globals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = obj; @@ -996,7 +880,8 @@ void rt_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { // no attribute/method called attr // following CPython, we give a more detailed error message for type objects if (MP_OBJ_IS_TYPE(base, &mp_type_type)) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "type object '%s' has no attribute '%s'", ((mp_obj_type_t*)base)->name, qstr_str(attr))); + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, + "type object '%s' has no attribute '%s'", qstr_str(((mp_obj_type_t*)base)->name), qstr_str(attr))); } else { nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr))); } @@ -1040,15 +925,21 @@ mp_obj_t rt_getiter(mp_obj_t o_in) { if (type->getiter != NULL) { return type->getiter(o_in); } else { - // check for __getitem__ method + // check for __iter__ method mp_obj_t dest[2]; - rt_load_method_maybe(o_in, MP_QSTR___getitem__, dest); + rt_load_method_maybe(o_in, MP_QSTR___iter__, dest); if (dest[0] != MP_OBJ_NULL) { - // __getitem__ exists, create an iterator - return mp_obj_new_getitem_iter(dest); + // __iter__ exists, call it and return its result + return rt_call_method_n_kw(0, 0, dest); } else { - // object not iterable - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(o_in))); + rt_load_method_maybe(o_in, MP_QSTR___getitem__, dest); + if (dest[0] != MP_OBJ_NULL) { + // __getitem__ exists, create an iterator + return mp_obj_new_getitem_iter(dest); + } else { + // object not iterable + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(o_in))); + } } } } @@ -1058,7 +949,15 @@ mp_obj_t rt_iternext(mp_obj_t o_in) { if (type->iternext != NULL) { return type->iternext(o_in); } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); + // check for __next__ method + mp_obj_t dest[2]; + rt_load_method_maybe(o_in, MP_QSTR___next__, dest); + if (dest[0] != MP_OBJ_NULL) { + // __next__ exists, call it and return its result + return rt_call_method_n_kw(0, 0, dest); + } else { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); + } } } @@ -1135,10 +1034,6 @@ void rt_globals_set(mp_map_t *m) { map_globals = m; } -mp_map_t *rt_loaded_modules_get(void) { - return &map_loaded_modules; -} - // these must correspond to the respective enum void *const rt_fun_table[RT_F_NUMBER_OF] = { rt_load_const_dec, diff --git a/py/runtime.h b/py/runtime.h index 7215cc8890..3980e50cc0 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -12,6 +12,7 @@ mp_obj_t rt_get_cell(mp_obj_t cell); void rt_set_cell(mp_obj_t cell, mp_obj_t val); void rt_store_name(qstr qstr, mp_obj_t obj); void rt_store_global(qstr qstr, mp_obj_t obj); +void rt_delete_name(qstr qstr); mp_obj_t rt_unary_op(int op, mp_obj_t arg); mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs); mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args); @@ -124,6 +124,7 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i // outer exception handling loop for (;;) { +outer_dispatch_loop: if (nlr_push(&nlr) == 0) { // If we have exception to inject, now that we finish setting up // execution context, raise it. This works as if RAISE_VARARGS @@ -283,6 +284,11 @@ dispatch_loop: sp -= 3; break; + case MP_BC_DELETE_NAME: + DECODE_QSTR; + rt_delete_name(qst); + break; + case MP_BC_DUP_TOP: obj1 = TOP(); PUSH(obj1); @@ -637,6 +643,15 @@ unwind_return: } else { // exception occurred + // check if it's a StopIteration within a for block + if (*save_ip == MP_BC_FOR_ITER && mp_obj_is_subclass_fast(mp_obj_get_type(nlr.ret_val), &mp_type_StopIteration)) { + ip = save_ip + 1; + DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward + --sp; // pop the exhausted iterator + ip += unum; // jump to after for-block + goto outer_dispatch_loop; // continue with dispatch loop + } + // set file and line number that the exception occurred at // TODO: don't set traceback for exceptions re-raised by END_FINALLY. // But consider how to handle nested exceptions. diff --git a/stm/main.c b/stm/main.c index 8279a9b7f4..44be4d348c 100644 --- a/stm/main.c +++ b/stm/main.c @@ -24,6 +24,7 @@ #include "lexerfatfs.h" #include "parse.h" #include "obj.h" +#include "objmodule.h" #include "parsehelper.h" #include "compile.h" #include "runtime0.h" @@ -272,9 +273,8 @@ soft_reset: rt_store_name(MP_QSTR_help, rt_make_function_n(0, pyb_help)); rt_store_name(MP_QSTR_open, rt_make_function_n(2, pyb_io_open)); - // we pre-import the pyb module - // probably shouldn't do this, so we are compatible with CPython - rt_store_name(MP_QSTR_pyb, (mp_obj_t)&pyb_module); + // load the pyb module + mp_module_register(MP_QSTR_pyb, (mp_obj_t)&pyb_module); // check if user switch held (initiates reset of filesystem) bool reset_filesystem = false; diff --git a/stm/pybmodule.c b/stm/pybmodule.c index ed705af73d..fde61b513d 100644 --- a/stm/pybmodule.c +++ b/stm/pybmodule.c @@ -181,7 +181,8 @@ STATIC mp_obj_t pyb_standby(void) { MP_DEFINE_CONST_FUN_OBJ_0(pyb_standby_obj, pyb_standby); STATIC mp_obj_t pyb_hid_send_report(mp_obj_t arg) { - mp_obj_t *items = mp_obj_get_array_fixed_n(arg, 4); + mp_obj_t *items; + mp_obj_get_array_fixed_n(arg, 4, &items); uint8_t data[4]; data[0] = mp_obj_get_int(items[0]); data[1] = mp_obj_get_int(items[1]); diff --git a/stmhal/Makefile b/stmhal/Makefile index 292bfdd61c..bf5db71867 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -72,10 +72,11 @@ SRC_C = \ malloc0.c \ gccollect.c \ pyexec.c \ + help.c \ input.c \ - pybmodule.c \ - osmodule.c \ - timemodule.c \ + modpyb.c \ + modos.c \ + modtime.c \ import.c \ lexerfatfs.c \ gpio.c \ @@ -91,11 +92,11 @@ SRC_C = \ lcd.c \ accel.c \ servo.c \ + dac.c \ + adc.c \ + i2c.c \ # timer.c \ -# audio.c \ -# i2c.c \ -# adc.c \ # pybwlan.c \ SRC_S = \ @@ -104,7 +105,11 @@ SRC_S = \ SRC_HAL = $(addprefix $(HAL_DIR)/src/,\ stm32f4xx_hal.c \ + stm32f4xx_hal_adc.c \ + stm32f4xx_hal_adc_ex.c \ stm32f4xx_hal_cortex.c \ + stm32f4xx_hal_dac.c \ + stm32f4xx_hal_dac_ex.c \ stm32f4xx_hal_dma.c \ stm32f4xx_hal_flash.c \ stm32f4xx_hal_flash_ex.c \ diff --git a/stmhal/accel.c b/stmhal/accel.c index cd513b3fe8..f791691619 100644 --- a/stmhal/accel.c +++ b/stmhal/accel.c @@ -3,11 +3,13 @@ #include <stm32f4xx_hal.h> +#include "nlr.h" #include "misc.h" #include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" +#include "i2c.h" #include "accel.h" #define MMA_ADDR (0x98) @@ -18,8 +20,6 @@ #define MMA_REG_MODE (7) #define MMA_AXIS_SIGNED_VALUE(i) (((i) & 0x3f) | ((i) & 0x20 ? (~0x1f) : 0)) -STATIC I2C_HandleTypeDef I2cHandle; - void accel_init(void) { GPIO_InitTypeDef GPIO_InitStructure; @@ -30,38 +30,12 @@ void accel_init(void) { GPIO_InitStructure.Speed = GPIO_SPEED_LOW; GPIO_InitStructure.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); - - // PB6=SCL, PB7=SDA - GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7; - GPIO_InitStructure.Mode = GPIO_MODE_AF_OD; - GPIO_InitStructure.Speed = GPIO_SPEED_FAST; - GPIO_InitStructure.Pull = GPIO_NOPULL; // have external pull-up resistors on both lines - GPIO_InitStructure.Alternate = GPIO_AF4_I2C1; - HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); - - // enable the I2C1 clock - __I2C1_CLK_ENABLE(); - - // set up the I2C1 device - memset(&I2cHandle, 0, sizeof(I2C_HandleTypeDef)); - I2cHandle.Instance = I2C1; - I2cHandle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; - I2cHandle.Init.ClockSpeed = 400000; - I2cHandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED; - I2cHandle.Init.DutyCycle = I2C_DUTYCYCLE_16_9; - I2cHandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED; - I2cHandle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED; - I2cHandle.Init.OwnAddress1 = 0xfe; // unused - I2cHandle.Init.OwnAddress2 = 0xfe; // unused - - if (HAL_I2C_Init(&I2cHandle) != HAL_OK) { - // init error - printf("accel_init: HAL_I2C_Init failed\n"); - return; - } } -STATIC void accel_init_device(void) { +STATIC void accel_start(void) { + // start the I2C bus + i2c_start(&I2cHandle_X); + // turn off AVDD, wait 20ms, turn on AVDD, wait 20ms again GPIOB->BSRRH = GPIO_PIN_5; // turn off HAL_Delay(20); @@ -72,7 +46,7 @@ STATIC void accel_init_device(void) { //printf("IsDeviceReady\n"); for (int i = 0; i < 10; i++) { - status = HAL_I2C_IsDeviceReady(&I2cHandle, MMA_ADDR, 10, 200); + status = HAL_I2C_IsDeviceReady(&I2cHandle_X, MMA_ADDR, 10, 200); //printf(" got %d\n", status); if (status == HAL_OK) { break; @@ -82,7 +56,7 @@ STATIC void accel_init_device(void) { //printf("MemWrite\n"); uint8_t data[1]; data[0] = 1; // active mode - status = HAL_I2C_Mem_Write(&I2cHandle, MMA_ADDR, MMA_REG_MODE, I2C_MEMADD_SIZE_8BIT, data, 1, 200); + status = HAL_I2C_Mem_Write(&I2cHandle_X, MMA_ADDR, MMA_REG_MODE, I2C_MEMADD_SIZE_8BIT, data, 1, 200); //printf(" got %d\n", status); } @@ -99,9 +73,22 @@ typedef struct _pyb_accel_obj_t { STATIC pyb_accel_obj_t pyb_accel_obj; +STATIC mp_obj_t pyb_accel_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { + // check arguments + if (!(n_args == 0 && n_kw == 0)) { + nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "Accel accepts no arguments")); + } + + // init accel object + pyb_accel_obj.base.type = &pyb_accel_type; + accel_start(); + + return &pyb_accel_obj; +} + STATIC mp_obj_t read_axis(int axis) { uint8_t data[1]; - HAL_I2C_Mem_Read(&I2cHandle, MMA_ADDR, axis, I2C_MEMADD_SIZE_8BIT, data, 1, 200); + HAL_I2C_Mem_Read(&I2cHandle_X, MMA_ADDR, axis, I2C_MEMADD_SIZE_8BIT, data, 1, 200); return mp_obj_new_int(MMA_AXIS_SIGNED_VALUE(data[0])); } @@ -125,7 +112,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_z_obj, pyb_accel_z); STATIC mp_obj_t pyb_accel_tilt(mp_obj_t self_in) { uint8_t data[1]; - HAL_I2C_Mem_Read(&I2cHandle, MMA_ADDR, MMA_REG_TILT, I2C_MEMADD_SIZE_8BIT, data, 1, 200); + HAL_I2C_Mem_Read(&I2cHandle_X, MMA_ADDR, MMA_REG_TILT, I2C_MEMADD_SIZE_8BIT, data, 1, 200); return mp_obj_new_int(data[0]); } @@ -137,7 +124,7 @@ STATIC mp_obj_t pyb_accel_filtered_xyz(mp_obj_t self_in) { memmove(self->buf, self->buf + NUM_AXIS, NUM_AXIS * (FILT_DEPTH - 1) * sizeof(int16_t)); uint8_t data[NUM_AXIS]; - HAL_I2C_Mem_Read(&I2cHandle, MMA_ADDR, MMA_REG_X, I2C_MEMADD_SIZE_8BIT, data, NUM_AXIS, 200); + HAL_I2C_Mem_Read(&I2cHandle_X, MMA_ADDR, MMA_REG_X, I2C_MEMADD_SIZE_8BIT, data, NUM_AXIS, 200); mp_obj_t tuple[NUM_AXIS]; for (int i = 0; i < NUM_AXIS; i++) { @@ -156,7 +143,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_filtered_xyz_obj, pyb_accel_filtered_ STATIC mp_obj_t pyb_accel_read_reg(mp_obj_t self_in, mp_obj_t reg) { uint8_t data[1]; - HAL_I2C_Mem_Read(&I2cHandle, MMA_ADDR, mp_obj_get_int(reg), I2C_MEMADD_SIZE_8BIT, data, 1, 200); + HAL_I2C_Mem_Read(&I2cHandle_X, MMA_ADDR, mp_obj_get_int(reg), I2C_MEMADD_SIZE_8BIT, data, 1, 200); return mp_obj_new_int(data[0]); } @@ -165,13 +152,13 @@ MP_DEFINE_CONST_FUN_OBJ_2(pyb_accel_read_reg_obj, pyb_accel_read_reg); STATIC mp_obj_t pyb_accel_write_reg(mp_obj_t self_in, mp_obj_t reg, mp_obj_t val) { uint8_t data[1]; data[0] = mp_obj_get_int(val); - HAL_I2C_Mem_Write(&I2cHandle, MMA_ADDR, mp_obj_get_int(reg), I2C_MEMADD_SIZE_8BIT, data, 1, 200); + HAL_I2C_Mem_Write(&I2cHandle_X, MMA_ADDR, mp_obj_get_int(reg), I2C_MEMADD_SIZE_8BIT, data, 1, 200); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_3(pyb_accel_write_reg_obj, pyb_accel_write_reg); -STATIC const mp_method_t accel_methods[] = { +STATIC const mp_method_t pyb_accel_methods[] = { { "x", &pyb_accel_x_obj }, { "y", &pyb_accel_y_obj }, { "z", &pyb_accel_z_obj }, @@ -182,16 +169,9 @@ STATIC const mp_method_t accel_methods[] = { { NULL, NULL }, }; -STATIC const mp_obj_type_t accel_obj_type = { +const mp_obj_type_t pyb_accel_type = { { &mp_type_type }, .name = MP_QSTR_Accel, - .methods = accel_methods, + .make_new = pyb_accel_make_new, + .methods = pyb_accel_methods, }; - -STATIC mp_obj_t pyb_Accel(void) { - pyb_accel_obj.base.type = &accel_obj_type; - accel_init_device(); - return &pyb_accel_obj; -} - -MP_DEFINE_CONST_FUN_OBJ_0(pyb_Accel_obj, pyb_Accel); diff --git a/stmhal/accel.h b/stmhal/accel.h index b2c0fd6b19..cfc54fcf67 100644 --- a/stmhal/accel.h +++ b/stmhal/accel.h @@ -1,3 +1,3 @@ -void accel_init(void); +extern const mp_obj_type_t pyb_accel_type; -MP_DECLARE_CONST_FUN_OBJ(pyb_Accel_obj); +void accel_init(void); diff --git a/stmhal/adc.c b/stmhal/adc.c new file mode 100644 index 0000000000..e357a00308 --- /dev/null +++ b/stmhal/adc.c @@ -0,0 +1,345 @@ +#include <stdio.h> +#include <stm32f4xx_hal.h> +#include <string.h> + +#include "misc.h" +#include "nlr.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "adc.h" +#include "pin.h" +#include "build/pins.h" + +// Usage Model: +// +// adc = pyb.ADC(pin) +// val = adc.read() +// +// adc = pyb.ADC_all(resolution) +// val = adc.read_channel(channel) +// val = adc.read_core_temp() +// val = adc.read_core_vbat() +// val = adc.read_core_vref() + +/* ADC defintions */ +#define ADCx (ADC1) +#define ADCx_CLK_ENABLE __ADC1_CLK_ENABLE +#define ADC_NUM_CHANNELS (19) +#define ADC_NUM_GPIO_CHANNELS (16) + +#if defined(STM32F405xx) || defined(STM32F415xx) || \ + defined(STM32F407xx) || defined(STM32F417xx) || \ + defined(STM32F401xC) || defined(STM32F401xE) +#define VBAT_DIV (2) +#elif defined(STM32F427xx) || defined(STM32F429xx) || \ + defined(STM32F437xx) || defined(STM32F439xx) +#define VBAT_DIV (4) +#endif + +/* Core temperature sensor definitions */ +#define CORE_TEMP_V25 (943) /* (0.76v/3.3v)*(2^ADC resoultion) */ +#define CORE_TEMP_AVG_SLOPE (3) /* (2.5mv/3.3v)*(2^ADC resoultion) */ + +typedef struct _pyb_obj_adc_t { + mp_obj_base_t base; + mp_obj_t pin_name; + int channel; + ADC_HandleTypeDef handle; +} pyb_obj_adc_t; + +void adc_init_single(pyb_obj_adc_t *adc_obj) { + if (!IS_ADC_CHANNEL(adc_obj->channel)) { + return; + } + + if (adc_obj->channel < ADC_NUM_GPIO_CHANNELS) { + // Channels 0-16 correspond to real pins. Configure the GPIO pin in + // ADC mode. + const pin_obj_t *pin = pin_adc1[adc_obj->channel]; + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.Pin = pin->pin_mask; + GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; + GPIO_InitStructure.Pull = GPIO_NOPULL; + HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure); + } + + ADCx_CLK_ENABLE(); + + ADC_HandleTypeDef *adcHandle = &adc_obj->handle; + adcHandle->Instance = ADCx; + adcHandle->Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2; + adcHandle->Init.Resolution = ADC_RESOLUTION12b; + adcHandle->Init.ScanConvMode = DISABLE; + adcHandle->Init.ContinuousConvMode = DISABLE; + adcHandle->Init.DiscontinuousConvMode = DISABLE; + adcHandle->Init.NbrOfDiscConversion = 0; + adcHandle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; + adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; + adcHandle->Init.DataAlign = ADC_DATAALIGN_RIGHT; + adcHandle->Init.NbrOfConversion = 1; + adcHandle->Init.DMAContinuousRequests = DISABLE; + adcHandle->Init.EOCSelection = DISABLE; + + HAL_ADC_Init(adcHandle); + + ADC_ChannelConfTypeDef sConfig; + + sConfig.Channel = adc_obj->channel; + sConfig.Rank = 1; + sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; + sConfig.Offset = 0; + + HAL_ADC_ConfigChannel(adcHandle, &sConfig); +} + +uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) { + uint32_t rawValue = 0; + + HAL_ADC_Start(adcHandle); + if (HAL_ADC_PollForConversion(adcHandle, 10) == HAL_OK && HAL_ADC_GetState(adcHandle) == HAL_ADC_STATE_EOC_REG) { + rawValue = HAL_ADC_GetValue(adcHandle); + } + HAL_ADC_Stop(adcHandle); + + return rawValue; +} + +/******************************************************************************/ +/* Micro Python bindings : adc object (single channel) */ + +STATIC void adc_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_obj_adc_t *self = self_in; + print(env, "<ADC on "); + mp_obj_print_helper(print, env, self->pin_name, PRINT_STR); + print(env, " channel=%lu>", self->channel); +} + +STATIC mp_obj_t adc_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { + // check number of arguments + if (!(n_args == 1 && n_kw == 0)) { + nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "ADC accepts 1 argument")); + } + + // 1st argument is the pin name + mp_obj_t pin_obj = args[0]; + + uint32_t channel; + + if (MP_OBJ_IS_INT(pin_obj)) { + channel = mp_obj_get_int(pin_obj); + } else { + const pin_obj_t *pin = pin_map_user_obj(pin_obj); + if ((pin->adc_num & PIN_ADC1) == 0) { + // No ADC1 function on that pin + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s does not have ADC capabilities", pin->name)); + } + channel = pin->adc_channel; + } + + if (!IS_ADC_CHANNEL(channel)) { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Not a valid ADC Channel: %d", channel)); + } + if (pin_adc1[channel] == NULL) { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Channel %d not available on this board", channel)); + } + + pyb_obj_adc_t *o = m_new_obj(pyb_obj_adc_t); + memset(o, 0, sizeof(*o)); + o->base.type = &pyb_adc_type; + o->pin_name = pin_obj; + o->channel = channel; + adc_init_single(o); + + return o; +} + +STATIC mp_obj_t adc_read(mp_obj_t self_in) { + pyb_obj_adc_t *self = self_in; + + uint32_t data = adc_read_channel(&self->handle); + return mp_obj_new_int(data); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read); + +STATIC const mp_method_t adc_methods[] = { + { "read", &adc_read_obj}, + { NULL, NULL }, +}; + +const mp_obj_type_t pyb_adc_type = { + { &mp_type_type }, + .name = MP_QSTR_ADC, + .print = adc_print, + .make_new = adc_make_new, + .methods = adc_methods, +}; + +/******************************************************************************/ +/* adc all object */ + +typedef struct _pyb_obj_adc_all_t { + mp_obj_base_t base; + ADC_HandleTypeDef handle; +} pyb_obj_adc_all_t; + +void adc_init_all(pyb_obj_adc_all_t *adc_all, uint32_t resolution) { + + switch (resolution) { + case 6: resolution = ADC_RESOLUTION6b; break; + case 8: resolution = ADC_RESOLUTION8b; break; + case 10: resolution = ADC_RESOLUTION10b; break; + case 12: resolution = ADC_RESOLUTION12b; break; + default: + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "resolution %d not supported", resolution)); + } + + for (uint32_t channel = 0; channel < ADC_NUM_GPIO_CHANNELS; channel++) { + // Channels 0-16 correspond to real pins. Configure the GPIO pin in + // ADC mode. + const pin_obj_t *pin = pin_adc1[channel]; + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.Pin = pin->pin_mask; + GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; + GPIO_InitStructure.Pull = GPIO_NOPULL; + HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure); + } + + ADCx_CLK_ENABLE(); + + ADC_HandleTypeDef *adcHandle = &adc_all->handle; + adcHandle->Instance = ADCx; + adcHandle->Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2; + adcHandle->Init.Resolution = resolution; + adcHandle->Init.ScanConvMode = DISABLE; + adcHandle->Init.ContinuousConvMode = DISABLE; + adcHandle->Init.DiscontinuousConvMode = DISABLE; + adcHandle->Init.NbrOfDiscConversion = 0; + adcHandle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; + adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; + adcHandle->Init.DataAlign = ADC_DATAALIGN_RIGHT; + adcHandle->Init.NbrOfConversion = 1; + adcHandle->Init.DMAContinuousRequests = DISABLE; + adcHandle->Init.EOCSelection = DISABLE; + + HAL_ADC_Init(adcHandle); +} + +uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t channel) { + ADC_ChannelConfTypeDef sConfig; + sConfig.Channel = channel; + sConfig.Rank = 1; + sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; + sConfig.Offset = 0; + HAL_ADC_ConfigChannel(adcHandle, &sConfig); + + return adc_read_channel(adcHandle); +} + +int adc_get_resolution(ADC_HandleTypeDef *adcHandle) { + uint32_t res_reg = __HAL_ADC_GET_RESOLUTION(adcHandle); + + switch (res_reg) { + case ADC_RESOLUTION6b: return 6; + case ADC_RESOLUTION8b: return 8; + case ADC_RESOLUTION10b: return 10; + } + return 12; +} + +int adc_read_core_temp(ADC_HandleTypeDef *adcHandle) { + int32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_TEMPSENSOR); + + // Note: constants assume 12-bit resolution, so we scale the raw value to + // be 12-bits. + raw_value <<= (12 - adc_get_resolution(adcHandle)); + + return ((raw_value - CORE_TEMP_V25) / CORE_TEMP_AVG_SLOPE) + 25; +} + +float adc_read_core_vbat(ADC_HandleTypeDef *adcHandle) { + uint32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_VBAT); + + // Note: constants assume 12-bit resolution, so we scale the raw value to + // be 12-bits. + raw_value <<= (12 - adc_get_resolution(adcHandle)); + + return raw_value * VBAT_DIV / 4096.0f * 3.3f; +} + +float adc_read_core_vref(ADC_HandleTypeDef *adcHandle) { + uint32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_VREFINT); + + // Note: constants assume 12-bit resolution, so we scale the raw value to + // be 12-bits. + raw_value <<= (12 - adc_get_resolution(adcHandle)); + + return raw_value * VBAT_DIV / 4096.0f * 3.3f; +} + +/******************************************************************************/ +/* Micro Python bindings : adc_all object */ + +STATIC void adc_all_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + print(env, "<ADC all>"); +} + +STATIC mp_obj_t adc_all_read_channel(mp_obj_t self_in, mp_obj_t channel) { + pyb_obj_adc_all_t *self = self_in; + + uint32_t chan = mp_obj_get_int(channel); + uint32_t data = adc_config_and_read_channel(&self->handle, chan); + return mp_obj_new_int(data); +} + +STATIC mp_obj_t adc_all_read_core_temp(mp_obj_t self_in) { + pyb_obj_adc_all_t *self = self_in; + + int data = adc_read_core_temp(&self->handle); + return mp_obj_new_int(data); +} + +STATIC mp_obj_t adc_all_read_core_vbat(mp_obj_t self_in) { + pyb_obj_adc_all_t *self = self_in; + + float data = adc_read_core_vbat(&self->handle); + return mp_obj_new_float(data); +} + +STATIC mp_obj_t adc_all_read_core_vref(mp_obj_t self_in) { + pyb_obj_adc_all_t *self = self_in; + + float data = adc_read_core_vref(&self->handle); + return mp_obj_new_float(data); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(adc_all_read_channel_obj, adc_all_read_channel); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_temp_obj, adc_all_read_core_temp); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vbat_obj, adc_all_read_core_vbat); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vref_obj, adc_all_read_core_vref); + +STATIC const mp_method_t adc_all_methods[] = { + { "read_channel", &adc_all_read_channel_obj}, + { "read_core_temp", &adc_all_read_core_temp_obj}, + { "read_core_vbat", &adc_all_read_core_vbat_obj}, + { "read_core_vref", &adc_all_read_core_vref_obj}, + { NULL, NULL }, +}; + +STATIC const mp_obj_type_t adc_all_type = { + { &mp_type_type }, + .name = MP_QSTR_ADC, + .print = adc_all_print, + .methods = adc_all_methods, +}; + +STATIC mp_obj_t pyb_ADC_all(mp_obj_t resolution) { + pyb_obj_adc_all_t *o = m_new_obj(pyb_obj_adc_all_t); + o->base.type = &adc_all_type; + adc_init_all(o, mp_obj_get_int(resolution)); + return o; +} + +MP_DEFINE_CONST_FUN_OBJ_1(pyb_ADC_all_obj, pyb_ADC_all); diff --git a/stmhal/adc.h b/stmhal/adc.h new file mode 100644 index 0000000000..c9f16932eb --- /dev/null +++ b/stmhal/adc.h @@ -0,0 +1,3 @@ +extern const mp_obj_type_t pyb_adc_type; + +MP_DECLARE_CONST_FUN_OBJ(pyb_ADC_all_obj); diff --git a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h index 412dede131..948b886819 100644 --- a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h +++ b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h @@ -16,7 +16,7 @@ #define MICROPY_HW_ENABLE_RTC (0) #define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) -#define MICROPY_HW_ENABLE_AUDIO (0) +#define MICROPY_HW_ENABLE_DAC (0) // USRSW is pulled low. Pressing the button makes the input go high. #define USRSW_PIN (pin_B11) diff --git a/stmhal/boards/PYBOARD3/mpconfigboard.h b/stmhal/boards/PYBOARD3/mpconfigboard.h index e0920f6859..1cd1d94818 100644 --- a/stmhal/boards/PYBOARD3/mpconfigboard.h +++ b/stmhal/boards/PYBOARD3/mpconfigboard.h @@ -12,7 +12,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) -#define MICROPY_HW_ENABLE_AUDIO (0) +#define MICROPY_HW_ENABLE_DAC (0) // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define USRSW_PIN (pin_A13) diff --git a/stmhal/boards/PYBOARD4/mpconfigboard.h b/stmhal/boards/PYBOARD4/mpconfigboard.h index c3d5e119c9..9a046ffffa 100644 --- a/stmhal/boards/PYBOARD4/mpconfigboard.h +++ b/stmhal/boards/PYBOARD4/mpconfigboard.h @@ -12,7 +12,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) -#define MICROPY_HW_ENABLE_AUDIO (1) +#define MICROPY_HW_ENABLE_DAC (1) // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define USRSW_PIN (pin_B3) diff --git a/stmhal/boards/PYBv10/mpconfigboard.h b/stmhal/boards/PYBv10/mpconfigboard.h index fba7ab4aba..f5ebe25cc4 100644 --- a/stmhal/boards/PYBv10/mpconfigboard.h +++ b/stmhal/boards/PYBv10/mpconfigboard.h @@ -12,7 +12,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) -#define MICROPY_HW_ENABLE_AUDIO (1) +#define MICROPY_HW_ENABLE_DAC (1) // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define USRSW_PIN (pin_B3) diff --git a/stmhal/boards/STM32F4DISC/mpconfigboard.h b/stmhal/boards/STM32F4DISC/mpconfigboard.h index f713f9b756..2a58b27bdf 100644 --- a/stmhal/boards/STM32F4DISC/mpconfigboard.h +++ b/stmhal/boards/STM32F4DISC/mpconfigboard.h @@ -12,7 +12,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_AUDIO (0) +#define MICROPY_HW_ENABLE_DAC (0) // USRSW is pulled low. Pressing the button makes the input go high. #define USRSW_PIN (pin_A0) diff --git a/stmhal/boards/make-pins.py b/stmhal/boards/make-pins.py index 8c1bedbf0c..ee11934985 100755 --- a/stmhal/boards/make-pins.py +++ b/stmhal/boards/make-pins.py @@ -94,6 +94,8 @@ class Pin(object): self.alt_fn = [] self.board_name = None self.alt_fn_count = 0 + self.adc_num = 0 + self.adc_channel = 0 def port_letter(self): return chr(self.port + ord('A')) @@ -101,6 +103,15 @@ class Pin(object): def pin_name(self): return '{:s}{:d}'.format(self.port_letter(), self.pin) + def parse_adc(self, adc_str): + if (adc_str[:3] != 'ADC'): + return + (adc,channel) = adc_str.split('_') + for idx in range(3, len(adc)): + adc_num = int(adc[idx]) # 1, 2, or 3 + self.adc_num |= (1 << (adc_num - 1)) + self.adc_channel = int(channel[2:]) + def parse_af(self, af_idx, af_strs_in): if len(af_strs_in) == 0: return @@ -113,10 +124,22 @@ class Pin(object): if alt_fn.is_supported(): self.alt_fn_count += 1 - def alt_fn_name(self): - if self.alt_fn_count > 0: - return 'pin_{:s}_af'.format(self.pin_name()) - return 'NULL' + def alt_fn_name(self, null_if_0=False): + if null_if_0 and self.alt_fn_count == 0: + return 'NULL' + return 'pin_{:s}_af'.format(self.pin_name()) + + def adc_num_str(self): + str = '' + for adc_num in range(1,4): + if self.adc_num & (1 << (adc_num - 1)): + if len(str) > 0: + str += ' | ' + str += 'PIN_ADC' + str += chr(ord('0') + adc_num) + if len(str) == 0: + str = '0' + return str def print(self): if self.alt_fn_count == 0: @@ -128,9 +151,10 @@ class Pin(object): print("// ", end='') print('};') print('') - print('const pin_obj_t pin_{:s} = PIN({:s}, {:d}, {:d}, {:s});'.format( + print('const pin_obj_t pin_{:s} = PIN({:s}, {:d}, {:d}, {:s}, {:s}, {:d});'.format( self.pin_name(), self.port_letter(), self.pin, - self.alt_fn_count, self.alt_fn_name())) + self.alt_fn_count, self.alt_fn_name(null_if_0=True), + self.adc_num_str(), self.adc_channel)) print('') def print_header(self, hdr_file): @@ -162,7 +186,10 @@ class Pins(object): continue pin = Pin(port_num, pin_num) for af_idx in range(af_col, len(row)): - pin.parse_af(af_idx - af_col, row[af_idx]) + if af_idx < af_col + 16: + pin.parse_af(af_idx - af_col, row[af_idx]) + elif af_idx == af_col + 16: + pin.parse_adc(row[af_idx]) self.pins.append(pin) def parse_board_file(self, filename): @@ -198,11 +225,30 @@ class Pins(object): print('') self.print_named('board', self.board_pins) + def print_adc(self, adc_num): + print(''); + print('const pin_obj_t * const pin_adc{:d}[] = {{'.format(adc_num)) + for channel in range(16): + adc_found = False + for pin in self.pins: + if (pin.board_name and + (pin.adc_num & (1 << (adc_num - 1))) and (pin.adc_channel == channel)): + print(' &pin_{:s}, // {:d}'.format(pin.pin_name(), channel)) + adc_found = True + break + if not adc_found: + print(' NULL, // {:d}'.format(channel)) + print('};') + + def print_header(self, hdr_filename): with open(hdr_filename, 'wt') as hdr_file: for pin in self.pins: if pin.board_name: pin.print_header(hdr_file) + hdr_file.write('extern const pin_obj_t * const pin_adc1[];\n') + hdr_file.write('extern const pin_obj_t * const pin_adc2[];\n') + hdr_file.write('extern const pin_obj_t * const pin_adc3[];\n') def main(): @@ -254,6 +300,9 @@ def main(): with open(args.prefix_filename, 'r') as prefix_file: print(prefix_file.read()) pins.print() + pins.print_adc(1) + pins.print_adc(2) + pins.print_adc(3) pins.print_header(args.hdr_filename) diff --git a/stmhal/boards/stm32f4xx-af.csv b/stmhal/boards/stm32f4xx-af.csv index fde7fcfc11..0a21fc87d6 100644 --- a/stmhal/boards/stm32f4xx-af.csv +++ b/stmhal/boards/stm32f4xx-af.csv @@ -1,13 +1,13 @@ Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15 -,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11,I2C1/2/3,SPI1/SPI2/I2S2/I2S2ext,SPI3/I2Sext/I2S3,USART1/2/3/I2S3ext,UART4/5/USART6,CAN1/CAN2/TIM12/13/14,OTG_FS/OTG_HS,ETH,FSMC/SDIO/OTG_FS,DCMI,, -PortA,PA0,,TIM2_CH1_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,ETH_MII_CRS,,,,EVENTOUT -PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,,,ETH_MII_RX_CLK/ETH_RMII__REF_CLK,,,,EVENTOUT -PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,ETH_MDIO,,,,EVENTOUT -PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,,EVENTOUT -PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,,EVENTOUT -PortA,PA5,,TIM2_CH1_ETR,,TIM8_CH1N,,SPI1_SCK,,,,,OTG_HS_ULPI_CK,,,,,EVENTOUT -PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCK,,EVENTOUT -PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,,,,EVENTOUT +,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11,I2C1/2/3,SPI1/SPI2/I2S2/I2S2ext,SPI3/I2Sext/I2S3,USART1/2/3/I2S3ext,UART4/5/USART6,CAN1/CAN2/TIM12/13/14,OTG_FS/OTG_HS,ETH,FSMC/SDIO/OTG_FS,DCMI,,,ADC +PortA,PA0,,TIM2_CH1_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,ETH_MII_CRS,,,,EVENTOUT,ADC123_IN0 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,,,ETH_MII_RX_CLK/ETH_RMII__REF_CLK,,,,EVENTOUT,ADC123_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,ETH_MDIO,,,,EVENTOUT,ADC123_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,,EVENTOUTADC123_IN3 +PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,,EVENTOUT,ADC12_IN4 +PortA,PA5,,TIM2_CH1_ETR,,TIM8_CH1N,,SPI1_SCK,,,,,OTG_HS_ULPI_CK,,,,,EVENTOUT,ADC12_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCK,,EVENTOUT,ADC12_IN6 +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,,,,EVENTOUT,ADC12_IN7 PortA,PA8,MCO1,TIM1_CH1,,,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,,EVENTOUT PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT @@ -16,8 +16,8 @@ PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT PortA,PA13,JTMS-SWDIO,,,,,,,,,,,,,,,EVENTOUT PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT -PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT -PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,AC12_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT,ADC12_IN9 PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCKI2S3_CK,,,,,,,,,EVENTOUT PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,,,,,,,EVENTOUT @@ -32,12 +32,12 @@ PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,CAN2_RX,OTG_HS_UL PortB,PB13,,TIM1_CH1N,,,,SPI2_SCKI2S2_CK,,USART3_CTS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,,SPI2_MISO,I2S2ext_SD,USART3_RTS,,TIM12_CH1,,,OTG_HS_DM,,,EVENTOUT PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,,,OTG_HS_DP,,,EVENTOUT -PortC,PC0,,,,,,,,,,,OTG_HS_ULPI_STP,,,,,EVENTOUT -PortC,PC1,,,,,,,,,,,,ETH_MDC,,,,EVENTOUT -PortC,PC2,,,,,,SPI2_MISO,I2S2ext_SD,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,,,,EVENTOUT -PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,,,,EVENTOUT -PortC,PC4,,,,,,,,,,,,ETH_MII_RXD0/ETH_RMII_RXD0,,,,EVENTOUT -PortC,PC5,,,,,,,,,,,,ETH_MII_RXD1/ETH_RMII_RXD1,,,,EVENTOUT +PortC,PC0,,,,,,,,,,,OTG_HS_ULPI_STP,,,,,EVENTOUT,ADC123_IN10 +PortC,PC1,,,,,,,,,,,,ETH_MDC,,,,EVENTOUT,ADC123_IN11 +PortC,PC2,,,,,,SPI2_MISO,I2S2ext_SD,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,,,,EVENTOUT,ADC123_IN12 +PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,,,,EVENTOUT,ADC123_IN13 +PortC,PC4,,,,,,,,,,,,ETH_MII_RXD0/ETH_RMII_RXD0,,,,EVENTOUT,ADC123_IN14 +PortC,PC5,,,,,,,,,,,,ETH_MII_RXD1/ETH_RMII_RXD1,,,,EVENTOUT,ADC123_IN15 PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,,,SDIO_D6,DCMI_D0,,EVENTOUT PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,,,SDIO_D7,DCMI_D1,,EVENTOUT PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,USART6_CK,,,,SDIO_D0,DCMI_D2,,EVENTOUT @@ -83,14 +83,14 @@ PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FSMC_D12,,,EVENTOUT PortF,PF0,,,,,I2C2_SDA,,,,,,,,FSMC_A0,,,EVENTOUT PortF,PF1,,,,,I2C2_SCL,,,,,,,,FSMC_A1,,,EVENTOUT PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FSMC_A2,,,EVENTOUT -PortF,PF3,,,,,,,,,,,,,FSMC_A3,,,EVENTOUT -PortF,PF4,,,,,,,,,,,,,FSMC_A4,,,EVENTOUT -PortF,PF5,,,,,,,,,,,,,FSMC_A5,,,EVENTOUT -PortF,PF6,,,,TIM10_CH1,,,,,,,,,FSMC_NIORD,,,EVENTOUT -PortF,PF7,,,,TIM11_CH1,,,,,,,,,FSMC_NREG,,,EVENTOUT -PortF,PF8,,,,,,,,,,TIM13_CH1,,,FSMC_NIOWR,,,EVENTOUT -PortF,PF9,,,,,,,,,,TIM14_CH1,,,FSMC_CD,,,EVENTOUT -PortF,PF10,,,,,,,,,,,,,FSMC_INTR,,,EVENTOUT +PortF,PF3,,,,,,,,,,,,,FSMC_A3,,,EVENTOUT,ADC3_IN9 +PortF,PF4,,,,,,,,,,,,,FSMC_A4,,,EVENTOUT,ADC3_IN14 +PortF,PF5,,,,,,,,,,,,,FSMC_A5,,,EVENTOUT,ADC3_IN15 +PortF,PF6,,,,TIM10_CH1,,,,,,,,,FSMC_NIORD,,,EVENTOUT,ADC3_IN4 +PortF,PF7,,,,TIM11_CH1,,,,,,,,,FSMC_NREG,,,EVENTOUT,ADC3_IN5 +PortF,PF8,,,,,,,,,,TIM13_CH1,,,FSMC_NIOWR,,,EVENTOUT,ADC3_IN6 +PortF,PF9,,,,,,,,,,TIM14_CH1,,,FSMC_CD,,,EVENTOUT,ADC3_IN7 +PortF,PF10,,,,,,,,,,,,,FSMC_INTR,,,EVENTOUT,ADC3_IN8 PortF,PF11,,,,,,,,,,,,,,DCMI_D12,,EVENTOUT PortF,PF12,,,,,,,,,,,,,FSMC_A6,,,EVENTOUT PortF,PF13,,,,,,,,,,,,,FSMC_A7,,,EVENTOUT diff --git a/stmhal/boards/stm32f4xx-prefix.c b/stmhal/boards/stm32f4xx-prefix.c index af3ed325cb..989b8f0048 100644 --- a/stmhal/boards/stm32f4xx-prefix.c +++ b/stmhal/boards/stm32f4xx-prefix.c @@ -21,7 +21,7 @@ .af_fn = (af_ptr) \ } -#define PIN(p_port, p_pin, p_num_af, p_af) \ +#define PIN(p_port, p_pin, p_num_af, p_af, p_adc_num, p_adc_channel) \ { \ { &pin_obj_type }, \ .name = #p_port #p_pin, \ @@ -31,4 +31,6 @@ .pin_mask = (1 << ((p_pin) & 0x0f)), \ .gpio = GPIO ## p_port, \ .af = p_af, \ + .adc_num = p_adc_num, \ + .adc_channel = p_adc_channel, \ } diff --git a/stmhal/dac.c b/stmhal/dac.c new file mode 100644 index 0000000000..3814039ccd --- /dev/null +++ b/stmhal/dac.c @@ -0,0 +1,279 @@ +#include <stdint.h> +#include <string.h> + +#include "stm32f4xx_hal.h" + +#include "nlr.h" +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "parse.h" +#include "obj.h" +#include "map.h" +#include "runtime.h" +#include "dac.h" + +TIM_HandleTypeDef TIM6_Handle; +STATIC DAC_HandleTypeDef DAC_Handle; + +void dac_init(void) { + DAC_Handle.Instance = DAC; + DAC_Handle.State = HAL_DAC_STATE_RESET; + HAL_DAC_Init(&DAC_Handle); +} + +STATIC void TIM6_Config(uint freq) { + // TIM6 clock enable + __TIM6_CLK_ENABLE(); + + // Compute the prescaler value so TIM6 triggers at freq-Hz + uint16_t period = (uint16_t) ((SystemCoreClock / 2) / freq) - 1; + + // time base clock configuration + TIM6_Handle.Instance = TIM6; + TIM6_Handle.Init.Period = period; + TIM6_Handle.Init.Prescaler = 0; // timer runs at SystemCoreClock / 2 + TIM6_Handle.Init.ClockDivision = 0; // unused for TIM6 + TIM6_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6 + HAL_TIM_Base_Init(&TIM6_Handle); + + // TIM6 TRGO selection + TIM_MasterConfigTypeDef config; + config.MasterOutputTrigger = TIM_TRGO_UPDATE; + config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + HAL_TIMEx_MasterConfigSynchronization(&TIM6_Handle, &config); + + // TIM6 start counter + HAL_TIM_Base_Start(&TIM6_Handle); +} + +/******************************************************************************/ +// Micro Python bindings + +typedef struct _pyb_dac_obj_t { + mp_obj_base_t base; + uint32_t dac_channel; // DAC_CHANNEL_1 or DAC_CHANNEL_2 + DMA_Stream_TypeDef *dma_stream; // DMA1_Stream5 or DMA1_Stream6 + machine_uint_t state; +} pyb_dac_obj_t; + +STATIC pyb_dac_obj_t pyb_dac_channel_1 = {{&pyb_dac_type}, DAC_CHANNEL_1, DMA1_Stream5}; +STATIC pyb_dac_obj_t pyb_dac_channel_2 = {{&pyb_dac_type}, DAC_CHANNEL_2, DMA1_Stream6}; + +// create the dac object +// currently support either DAC1 on X5 (id = 1) or DAC2 on X6 (id = 2) + +STATIC mp_obj_t pyb_dac_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { + // check arguments + if (!(n_args == 1 && n_kw == 0)) { + nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "Dac accepts 1 argument")); + } + + machine_int_t dac_id = mp_obj_get_int(args[0]); + uint32_t pin; + pyb_dac_obj_t *dac_obj; + + if (dac_id == 1) { + pin = GPIO_PIN_4; + dac_obj = &pyb_dac_channel_1; + } else if (dac_id == 2) { + pin = GPIO_PIN_5; + dac_obj = &pyb_dac_channel_2; + } else { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Dac %d does not exist", dac_id)); + } + + // GPIO configuration + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.Pin = pin; + GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; + GPIO_InitStructure.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + + // DAC peripheral clock + __DAC_CLK_ENABLE(); + + // stop anything already going on + HAL_DAC_Stop(&DAC_Handle, dac_obj->dac_channel); + HAL_DAC_Stop_DMA(&DAC_Handle, dac_obj->dac_channel); + + dac_obj->state = 0; + + // return object + return dac_obj; +} + +STATIC mp_obj_t pyb_dac_noise(mp_obj_t self_in, mp_obj_t freq) { + pyb_dac_obj_t *self = self_in; + + // set TIM6 to trigger the DAC at the given frequency + TIM6_Config(mp_obj_get_int(freq)); + + if (self->state != 2) { + // configure DAC to trigger via TIM6 + DAC_ChannelConfTypeDef config; + config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; + config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); + self->state = 2; + } + + // set noise wave generation + HAL_DACEx_NoiseWaveGenerate(&DAC_Handle, self->dac_channel, DAC_LFSRUNMASK_BITS10_0); + HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_L, 0x7ff0); + HAL_DAC_Start(&DAC_Handle, self->dac_channel); + + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_noise_obj, pyb_dac_noise); + +STATIC mp_obj_t pyb_dac_triangle(mp_obj_t self_in, mp_obj_t freq) { + pyb_dac_obj_t *self = self_in; + + // set TIM6 to trigger the DAC at the given frequency + TIM6_Config(mp_obj_get_int(freq)); + + if (self->state != 2) { + // configure DAC to trigger via TIM6 + DAC_ChannelConfTypeDef config; + config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; + config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); + self->state = 2; + } + + // set triangle wave generation + HAL_DACEx_TriangleWaveGenerate(&DAC_Handle, self->dac_channel, DAC_TRIANGLEAMPLITUDE_1023); + HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_R, 0x100); + HAL_DAC_Start(&DAC_Handle, self->dac_channel); + + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_triangle_obj, pyb_dac_triangle); + +// direct access to DAC (8 bit only at the moment) +STATIC mp_obj_t pyb_dac_write(mp_obj_t self_in, mp_obj_t val) { + pyb_dac_obj_t *self = self_in; + + if (self->state != 1) { + DAC_ChannelConfTypeDef config; + config.DAC_Trigger = DAC_TRIGGER_NONE; + config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE; + HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); + self->state = 1; + } + + HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_8B_R, mp_obj_get_int(val)); + HAL_DAC_Start(&DAC_Handle, self->dac_channel); + + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_write_obj, pyb_dac_write); + +// initiates a burst of RAM->DAC using DMA +// input data is treated as an array of bytes (8 bit data) +// TIM6 is used to set the frequency of the transfer +// TODO still needs some attention to get it working properly +mp_obj_t pyb_dac_dma(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + pyb_dac_obj_t *self = args[0]; + + // set TIM6 to trigger the DAC at the given frequency + TIM6_Config(mp_obj_get_int(args[2])); + + mp_obj_type_t *type = mp_obj_get_type(args[1]); + if (type->buffer_p.get_buffer == NULL) { + nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "buffer argument must support buffer protocol")); + } + buffer_info_t bufinfo; + type->buffer_p.get_buffer(args[1], &bufinfo, BUFFER_READ); + + __DMA1_CLK_ENABLE(); + + /* + DMA_Cmd(self->dma_stream, DISABLE); + while (DMA_GetCmdStatus(self->dma_stream) != DISABLE) { + } + + DAC_Cmd(self->dac_channel, DISABLE); + */ + + /* + // DAC channel configuration + DAC_InitTypeDef DAC_InitStructure; + DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO; + DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; + DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1; // unused, but need to set it to a valid value + DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; + DAC_Init(self->dac_channel, &DAC_InitStructure); + */ + + if (self->state != 3) { + DAC_ChannelConfTypeDef config; + config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; + config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); + self->state = 3; + } + + // DMA1_Stream[67] channel7 configuration + DMA_HandleTypeDef DMA_Handle; + DMA_Handle.Instance = self->dma_stream; + DMA_Handle.Init.Channel = DMA_CHANNEL_7; + DMA_Handle.Init.Direction = DMA_MEMORY_TO_PERIPH; + DMA_Handle.Init.PeriphInc = DMA_PINC_DISABLE; + DMA_Handle.Init.MemInc = DMA_MINC_ENABLE; + DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + mp_map_elem_t *kw_mode = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(qstr_from_str("mode")), MP_MAP_LOOKUP); + DMA_Handle.Init.Mode = kw_mode == NULL ? DMA_NORMAL : mp_obj_get_int(kw_mode->value); // normal = 0, circular = 0x100 + DMA_Handle.Init.Priority = DMA_PRIORITY_HIGH; + DMA_Handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + DMA_Handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL; + DMA_Handle.Init.MemBurst = DMA_MBURST_SINGLE; + DMA_Handle.Init.PeriphBurst = DMA_PBURST_SINGLE; + HAL_DMA_Init(&DMA_Handle); + + __HAL_LINKDMA(&DAC_Handle, DMA_Handle1, DMA_Handle); + + HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel, (uint32_t*)bufinfo.buf, bufinfo.len, DAC_ALIGN_8B_R); + + /* + // enable DMA stream + DMA_Cmd(self->dma_stream, ENABLE); + while (DMA_GetCmdStatus(self->dma_stream) == DISABLE) { + } + + // enable DAC channel + DAC_Cmd(self->dac_channel, ENABLE); + + // enable DMA for DAC channel + DAC_DMACmd(self->dac_channel, ENABLE); + */ + + //printf("DMA: %p %lu\n", bufinfo.buf, bufinfo.len); + + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_dac_dma_obj, 3, pyb_dac_dma); + +STATIC const mp_method_t pyb_dac_methods[] = { + { "noise", &pyb_dac_noise_obj }, + { "triangle", &pyb_dac_triangle_obj }, + { "write", &pyb_dac_write_obj }, + { "dma", &pyb_dac_dma_obj }, + // TODO add function that does double buffering: + // dma2(freq, buf1, buf2, callback) + // where callback is called when the buffer has been drained + { NULL, NULL }, +}; + +const mp_obj_type_t pyb_dac_type = { + { &mp_type_type }, + .name = MP_QSTR_DAC, + .make_new = pyb_dac_make_new, + .methods = pyb_dac_methods, +}; diff --git a/stmhal/dac.h b/stmhal/dac.h new file mode 100644 index 0000000000..65e609576d --- /dev/null +++ b/stmhal/dac.h @@ -0,0 +1,3 @@ +void dac_init(void); + +extern const mp_obj_type_t pyb_dac_type; diff --git a/stmhal/exti.c b/stmhal/exti.c index ec6d82e4fd..8aaa99d429 100644 --- a/stmhal/exti.c +++ b/stmhal/exti.c @@ -26,9 +26,7 @@ // def callback(line): // print("line =", line) // -// # Configure the pin as a GPIO input. -// pin = pyb.Pin.board.X1 -// pyb.gpio_in(pin, pyb.PULL_UP) +// # Note: Exti will automatically configure the gpio line as an input. // exti = pyb.Exti(pin, pyb.Exti.MODE_IRQ_FALLING, pyb.PULLUP, callback) // // Now every time a falling edge is seen on the X1 pin, the callback will be diff --git a/stmhal/help.c b/stmhal/help.c new file mode 100644 index 0000000000..9efe374524 --- /dev/null +++ b/stmhal/help.c @@ -0,0 +1,90 @@ +#include <stdio.h> + +#include "nlr.h" +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "map.h" + +STATIC const char *help_text = +"Welcome to Micro Python!\n" +"\n" +"For online help please visit http://micropython.org/help/.\n" +"\n" +"Specific commands for the board:\n" +" pyb.info() -- print some general information\n" +" pyb.gc() -- run the garbage collector\n" +" pyb.repl_info(<val>) -- enable/disable printing of info after each command\n" +" pyb.delay(<n>) -- wait for n milliseconds\n" +" pyb.udelay(<n>) -- wait for n microseconds\n" +" pyb.switch() -- return True/False if switch pressed or not\n" +" pyb.Led(<n>) -- create Led object for LED n (n=1,2,3,4)\n" +" Led methods: on(), off(), toggle(), intensity(<n>)\n" +" pyb.Servo(<n>) -- create Servo object for servo n (n=1,2,3,4)\n" +" Servo methods: angle(<x>)\n" +" pyb.Accel() -- create an Accelerometer object\n" +" Accelerometer methods: x(), y(), z(), tilt()\n" +" pyb.rng() -- get a 30-bit hardware random number\n" +" pyb.gpio(<port>) -- get port value (port='A4' for example)\n" +" pyb.gpio(<port>, <val>) -- set port value, True or False, 1 or 0\n" +" pyb.ADC(<port>) -- make an analog port object (port='C0' for example)\n" +" ADC methods: read()\n" +"\n" +"Control commands:\n" +" CTRL-A -- on a blank line, enter raw REPL mode\n" +" CTRL-B -- on a blank line, enter normal REPL mode\n" +" CTRL-C -- interrupt a running program\n" +" CTRL-D -- on a blank line, do a soft reset of the board\n" +; + +STATIC void pyb_help_print_info_about_object(mp_obj_t name_o, const char *name_str, mp_obj_t value) { + if (name_o != MP_OBJ_NULL) { + printf(" "); + mp_obj_print(name_o, PRINT_STR); + printf(" -- "); + } else { + printf(" %s -- ", name_str); + } + mp_obj_print(value, PRINT_STR); + printf("\n"); +} + +STATIC mp_obj_t pyb_help(uint n_args, const mp_obj_t *args) { + if (n_args == 0) { + // print a general help message + printf("%s", help_text); + + } else { + // try to print something sensible about the given object + + printf("object "); + mp_obj_print(args[0], PRINT_STR); + printf(" is of type %s\n", mp_obj_get_type_str(args[0])); + + mp_obj_type_t *type = mp_obj_get_type(args[0]); + mp_map_t *map = NULL; + if (type == &mp_type_module) { + map = mp_obj_module_get_globals(args[0]); + } else if (type->locals_dict != MP_OBJ_NULL && MP_OBJ_IS_TYPE(type->locals_dict, &dict_type)) { + map = mp_obj_dict_get_map(type->locals_dict); + } + if (map != NULL) { + for (uint i = 0; i < map->alloc; i++) { + if (map->table[i].key != MP_OBJ_NULL) { + pyb_help_print_info_about_object(map->table[i].key, NULL, map->table[i].value); + } + } + } + + if (type->methods != NULL) { + for (const mp_method_t *meth = type->methods; meth->name != NULL; meth++) { + pyb_help_print_info_about_object(MP_OBJ_NULL, meth->name, (mp_obj_t)meth->fun); + } + } + } + + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_help_obj, 0, 1, pyb_help); diff --git a/stmhal/i2c.c b/stmhal/i2c.c new file mode 100644 index 0000000000..b8608ad3ba --- /dev/null +++ b/stmhal/i2c.c @@ -0,0 +1,184 @@ +#include <stdio.h> +#include <string.h> + +#include <stm32f4xx_hal.h> + +#include "nlr.h" +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "runtime.h" +#include "i2c.h" + +I2C_HandleTypeDef I2cHandle_X; +I2C_HandleTypeDef I2cHandle_Y; + +void i2c_init(void) { + // init the I2C1 device + memset(&I2cHandle_X, 0, sizeof(I2C_HandleTypeDef)); + I2cHandle_X.Instance = I2C1; + + // init the I2C2 device + memset(&I2cHandle_Y, 0, sizeof(I2C_HandleTypeDef)); + I2cHandle_Y.Instance = I2C2; +} + +void i2c_start(I2C_HandleTypeDef *i2c_handle) { + GPIO_InitTypeDef GPIO_InitStructure; + + // init the GPIO lines + GPIO_InitStructure.Mode = GPIO_MODE_AF_OD; + GPIO_InitStructure.Speed = GPIO_SPEED_FAST; + GPIO_InitStructure.Pull = GPIO_NOPULL; // have external pull-up resistors on both lines + + if (i2c_handle == &I2cHandle_X) { + // X-skin: X9=PB6=SCL, X10=PB7=SDA + GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7; + GPIO_InitStructure.Alternate = GPIO_AF4_I2C1; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + // enable the I2C clock + __I2C1_CLK_ENABLE(); + } else { + // Y-skin: Y9=PB10=SCL, Y10=PB11=SDA + GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_11; + GPIO_InitStructure.Alternate = GPIO_AF4_I2C2; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + // enable the I2C clock + __I2C2_CLK_ENABLE(); + } + + // init the I2C device + i2c_handle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + i2c_handle->Init.ClockSpeed = 400000; + i2c_handle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLED; + i2c_handle->Init.DutyCycle = I2C_DUTYCYCLE_16_9; + i2c_handle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLED; + i2c_handle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLED; + i2c_handle->Init.OwnAddress1 = 0xfe; // unused + i2c_handle->Init.OwnAddress2 = 0xfe; // unused + + if (HAL_I2C_Init(i2c_handle) != HAL_OK) { + // init error + printf("accel_init: HAL_I2C_Init failed\n"); + return; + } +} + +/******************************************************************************/ +/* Micro Python bindings */ + +#define PYB_NUM_I2C (2) + +typedef struct _pyb_i2c_obj_t { + mp_obj_base_t base; + I2C_HandleTypeDef *i2c_handle; +} pyb_i2c_obj_t; + +STATIC pyb_i2c_obj_t pyb_i2c_obj[PYB_NUM_I2C] = {{{&pyb_i2c_type}, &I2cHandle_X}, {{&pyb_i2c_type}, &I2cHandle_Y}}; + +STATIC mp_obj_t pyb_i2c_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { + // check arguments + if (!(n_args == 1 && n_kw == 0)) { + nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "I2C accepts 1 argument")); + } + + // get i2c number + machine_int_t i2c_id = mp_obj_get_int(args[0]) - 1; + + // check i2c number + if (!(0 <= i2c_id && i2c_id < PYB_NUM_I2C)) { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "I2C bus %d does not exist", i2c_id + 1)); + } + + // get i2c object + pyb_i2c_obj_t *i2c_obj = &pyb_i2c_obj[i2c_id]; + + // start the peripheral + i2c_start(i2c_obj->i2c_handle); + + return &pyb_i2c_obj; +} + +STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) { + pyb_i2c_obj_t *self = self_in; + machine_uint_t i2c_addr = mp_obj_get_int(i2c_addr_o) << 1; + + //printf("IsDeviceReady\n"); + for (int i = 0; i < 10; i++) { + HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c_handle, i2c_addr, 10, 200); + //printf(" got %d\n", status); + if (status == HAL_OK) { + return mp_const_true; + } + } + + return mp_const_false; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_i2c_is_ready_obj, pyb_i2c_is_ready); + +STATIC mp_obj_t pyb_i2c_mem_read(uint n_args, const mp_obj_t *args) { + pyb_i2c_obj_t *self = args[0]; + machine_uint_t i2c_addr = mp_obj_get_int(args[1]) << 1; + machine_uint_t mem_addr = mp_obj_get_int(args[2]); + machine_uint_t n = mp_obj_get_int(args[3]); + + byte *data; + mp_obj_t o = mp_obj_str_builder_start(&bytes_type, n, &data); + HAL_StatusTypeDef status = HAL_I2C_Mem_Read(self->i2c_handle, i2c_addr, mem_addr, I2C_MEMADD_SIZE_8BIT, data, n, 200); + + //printf("Read got %d\n", status); + + if (status != HAL_OK) { + // TODO really need a HardwareError object, or something + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Mem_Read failed with code %d", status)); + } + + return mp_obj_str_builder_end(o); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_i2c_mem_read_obj, 4, 4, pyb_i2c_mem_read); + +STATIC mp_obj_t pyb_i2c_mem_write(uint n_args, const mp_obj_t *args) { + pyb_i2c_obj_t *self = args[0]; + machine_uint_t i2c_addr = mp_obj_get_int(args[1]) << 1; + machine_uint_t mem_addr = mp_obj_get_int(args[2]); + HAL_StatusTypeDef status; + mp_obj_type_t *type = mp_obj_get_type(args[3]); + if (type->buffer_p.get_buffer != NULL) { + buffer_info_t bufinfo; + type->buffer_p.get_buffer(args[3], &bufinfo, BUFFER_READ); + status = HAL_I2C_Mem_Write(self->i2c_handle, i2c_addr, mem_addr, I2C_MEMADD_SIZE_8BIT, bufinfo.buf, bufinfo.len, 200); + } else if (MP_OBJ_IS_INT(args[3])) { + uint8_t data[1] = {mp_obj_get_int(args[3])}; + status = HAL_I2C_Mem_Write(self->i2c_handle, i2c_addr, mem_addr, I2C_MEMADD_SIZE_8BIT, data, 1, 200); + } else { + nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "data argument must be an integer or support the buffer protocol")); + } + + //printf("Write got %d\n", status); + + if (status != HAL_OK) { + // TODO really need a HardwareError object, or something + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Mem_Write failed with code %d", status)); + } + + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_i2c_mem_write_obj, 4, 4, pyb_i2c_mem_write); + +STATIC const mp_method_t pyb_i2c_methods[] = { + { "is_ready", &pyb_i2c_is_ready_obj }, + { "mem_read", &pyb_i2c_mem_read_obj }, + { "mem_write", &pyb_i2c_mem_write_obj }, + { NULL, NULL }, +}; + +const mp_obj_type_t pyb_i2c_type = { + { &mp_type_type }, + .name = MP_QSTR_I2C, + .make_new = pyb_i2c_make_new, + .methods = pyb_i2c_methods, +}; diff --git a/stmhal/i2c.h b/stmhal/i2c.h new file mode 100644 index 0000000000..32cba42595 --- /dev/null +++ b/stmhal/i2c.h @@ -0,0 +1,6 @@ +extern I2C_HandleTypeDef I2cHandle_X; +extern I2C_HandleTypeDef I2cHandle_Y; +extern const mp_obj_type_t pyb_i2c_type; + +void i2c_init(void); +void i2c_start(I2C_HandleTypeDef *i2c_handle); diff --git a/stmhal/led.c b/stmhal/led.c index 102cbac5a7..688daefc81 100644 --- a/stmhal/led.c +++ b/stmhal/led.c @@ -3,6 +3,7 @@ #include "usbd_cdc_msc.h" #include "usbd_cdc_interface.h" +#include "nlr.h" #include "misc.h" #include "mpconfig.h" #include "qstr.h" @@ -183,14 +184,45 @@ void led_debug(int n, int delay) { typedef struct _pyb_led_obj_t { mp_obj_base_t base; - uint led_id; + machine_uint_t led_id; } pyb_led_obj_t; +STATIC const pyb_led_obj_t pyb_led_obj[NUM_LEDS] = { + {{&pyb_led_type}, 1}, +#if defined(PYB_LED2) + {{&pyb_led_type}, 2}, +#if defined(PYB_LED3) + {{&pyb_led_type}, 3}, +#if defined(PYB_LED4) + {{&pyb_led_type}, 4}, +#endif +#endif +#endif +}; + void led_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { pyb_led_obj_t *self = self_in; print(env, "<LED %lu>", self->led_id); } +STATIC mp_obj_t led_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { + // check arguments + if (!(n_args == 1 && n_kw == 0)) { + nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "Led accepts 1 argument")); + } + + // get led number + machine_int_t led_id = mp_obj_get_int(args[0]) - 1; + + // check led number + if (!(0 <= led_id && led_id < NUM_LEDS)) { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Led %d does not exist", led_id)); + } + + // return static led object + return (mp_obj_t)&pyb_led_obj[led_id]; +} + mp_obj_t led_obj_on(mp_obj_t self_in) { pyb_led_obj_t *self = self_in; led_state(self->led_id, 1); @@ -232,18 +264,10 @@ STATIC const mp_method_t led_methods[] = { { NULL, NULL }, }; -STATIC const mp_obj_type_t led_obj_type = { +const mp_obj_type_t pyb_led_type = { { &mp_type_type }, .name = MP_QSTR_Led, .print = led_obj_print, + .make_new = led_obj_make_new, .methods = led_methods, }; - -STATIC mp_obj_t pyb_Led(mp_obj_t led_id) { - pyb_led_obj_t *o = m_new_obj(pyb_led_obj_t); - o->base.type = &led_obj_type; - o->led_id = mp_obj_get_int(led_id); - return o; -} - -MP_DEFINE_CONST_FUN_OBJ_1(pyb_Led_obj, pyb_Led); diff --git a/stmhal/led.h b/stmhal/led.h index b3762271c1..ab2b2ea14e 100644 --- a/stmhal/led.h +++ b/stmhal/led.h @@ -21,4 +21,4 @@ void led_state(pyb_led_t led, int state); void led_toggle(pyb_led_t led); void led_debug(int value, int delay); -MP_DECLARE_CONST_FUN_OBJ(pyb_Led_obj); +extern const mp_obj_type_t pyb_led_type; diff --git a/stmhal/main.c b/stmhal/main.c index 9d88206978..1da7a9a649 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -21,22 +21,21 @@ #include "gc.h" #include "gccollect.h" #include "pyexec.h" -#include "pybmodule.h" -#include "osmodule.h" -#include "timemodule.h" #include "usart.h" #include "led.h" #include "exti.h" #include "usrsw.h" #include "usb.h" -#include "rng.h" #include "rtc.h" #include "storage.h" #include "sdcard.h" #include "ff.h" #include "lcd.h" +#include "rng.h" +#include "i2c.h" #include "accel.h" #include "servo.h" +#include "dac.h" #include "pin.h" #if 0 #include "timer.h" @@ -109,6 +108,7 @@ static const char fresh_boot_py[] = "# boot.py -- run on boot-up\n" "# can run arbitrary Python, but best to keep it minimal\n" "\n" +"import pyb\n" "pyb.source_dir('/src')\n" "pyb.main('main.py')\n" "#pyb.usb_usr('VCP')\n" @@ -121,34 +121,6 @@ static const char fresh_main_py[] = "# main.py -- put your code here!\n" ; -static const char *help_text = -"Welcome to Micro Python!\n\n" -"This is a *very* early version of Micro Python and has minimal functionality.\n\n" -"Specific commands for the board:\n" -" pyb.info() -- print some general information\n" -" pyb.gc() -- run the garbage collector\n" -" pyb.repl_info(<val>) -- enable/disable printing of info after each command\n" -" pyb.delay(<n>) -- wait for n milliseconds\n" -" pyb.udelay(<n>) -- wait for n microseconds\n" -" pyb.Led(<n>) -- create Led object for LED n (n=1,2)\n" -" Led methods: on(), off()\n" -" pyb.Servo(<n>) -- create Servo object for servo n (n=1,2,3,4)\n" -" Servo methods: angle(<x>)\n" -" pyb.switch() -- return True/False if switch pressed or not\n" -" pyb.accel() -- get accelerometer values\n" -" pyb.rand() -- get a 16-bit random number\n" -" pyb.gpio(<port>) -- get port value (port='A4' for example)\n" -" pyb.gpio(<port>, <val>) -- set port value, True or False, 1 or 0\n" -" pyb.ADC(<port>) -- make an analog port object (port='C0' for example)\n" -" ADC methods: read()\n" -; - -// get some help about available functions -static mp_obj_t pyb_help(void) { - printf("%s", help_text); - return mp_const_none; -} - int main(void) { // TODO disable JTAG @@ -249,37 +221,8 @@ soft_reset: lcd_init(); #endif -#if MICROPY_HW_ENABLE_RNG - // RNG - rng_init(); -#endif - -#if MICROPY_HW_ENABLE_SERVO - // servo - servo_init(); -#endif - -#if 0 -#if MICROPY_HW_ENABLE_TIMER - // timer - timer_init(); -#endif -#endif - pin_map_init(); - // add some functions to the builtin Python namespace - rt_store_name(MP_QSTR_help, rt_make_function_n(0, pyb_help)); - - // we pre-import the pyb module - // probably shouldn't do this, so we are compatible with CPython - rt_store_name(MP_QSTR_pyb, (mp_obj_t)&pyb_module); - - // pre-import the os and time modules - // TODO don't do this! (need a way of registering builtin modules...) - rt_store_name(MP_QSTR_os, (mp_obj_t)&os_module); - rt_store_name(MP_QSTR_time, (mp_obj_t)&time_module); - // check if user switch held (initiates reset of filesystem) bool reset_filesystem = false; #if MICROPY_HW_HAS_SWITCH @@ -398,6 +341,9 @@ soft_reset: } } } +#else + // Get rid of compiler warning if no SDCARD is configured. + (void)first_soft_reset; #endif #if defined(USE_HOST_MODE) @@ -408,11 +354,36 @@ soft_reset: pyb_usb_dev_init(USBD_DEVICE_CDC_MSC, usbd_medium_kind); #endif +#if MICROPY_HW_ENABLE_RNG + // RNG + rng_init(); +#endif + + // I2C + i2c_init(); + #if MICROPY_HW_HAS_MMA7660 // MMA accel: init and reset accel_init(); #endif +#if MICROPY_HW_ENABLE_SERVO + // servo + servo_init(); +#endif + +#if 0 +#if MICROPY_HW_ENABLE_TIMER + // timer + timer_init(); +#endif +#endif + +#if MICROPY_HW_ENABLE_DAC + // DAC + dac_init(); +#endif + // run main script { vstr_t *vstr = vstr_new(); @@ -477,7 +448,19 @@ soft_reset: #endif #endif - pyexec_repl(); + // enter REPL + // REPL mode can change, or it can request a soft reset + for (;;) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + } printf("PYB: sync filesystems\n"); storage_flush(); diff --git a/stmhal/osmodule.c b/stmhal/modos.c index 7f32fe6749..0ec9fcbb91 100644 --- a/stmhal/osmodule.c +++ b/stmhal/modos.c @@ -10,7 +10,7 @@ #include "rng.h" #include "storage.h" #include "ff.h" -#include "osmodule.h" +#include "modos.h" #if _USE_LFN static char lfn[_MAX_LFN + 1]; /* Buffer to store the LFN */ diff --git a/stmhal/osmodule.h b/stmhal/modos.h index e3c13f756e..e3c13f756e 100644 --- a/stmhal/osmodule.h +++ b/stmhal/modos.h diff --git a/stmhal/pybmodule.c b/stmhal/modpyb.c index 00a8c321db..432dc859c1 100644 --- a/stmhal/pybmodule.c +++ b/stmhal/modpyb.c @@ -20,17 +20,17 @@ #include "rng.h" #include "rtc.h" #include "usart.h" +#include "adc.h" #include "storage.h" #include "sdcard.h" #include "accel.h" #include "servo.h" +#include "dac.h" +#include "i2c.h" #if 0 #include "usb.h" -#include "i2c.h" -#include "adc.h" -#include "audio.h" #endif -#include "pybmodule.h" +#include "modpyb.h" #include "ff.h" // get lots of info about the board @@ -242,7 +242,7 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = { #if MICROPY_HW_ENABLE_SERVO { MP_OBJ_NEW_QSTR(MP_QSTR_pwm), (mp_obj_t)&pyb_pwm_set_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_servo), (mp_obj_t)&pyb_servo_set_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_Servo), (mp_obj_t)&pyb_Servo_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_Servo), (mp_obj_t)&pyb_servo_type }, #endif #if MICROPY_HW_HAS_SWITCH @@ -253,26 +253,24 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_SD), (mp_obj_t)&pyb_sdcard_obj }, #endif + { MP_OBJ_NEW_QSTR(MP_QSTR_Led), (mp_obj_t)&pyb_led_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_I2C), (mp_obj_t)&pyb_i2c_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_Usart), (mp_obj_t)&pyb_usart_type }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_ADC), (mp_obj_t)&pyb_adc_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ADC_all), (mp_obj_t)&pyb_ADC_all_obj }, + +#if MICROPY_HW_ENABLE_DAC + { MP_OBJ_NEW_QSTR(MP_QSTR_DAC), (mp_obj_t)&pyb_dac_type }, +#endif + #if MICROPY_HW_HAS_MMA7660 - { MP_OBJ_NEW_QSTR(MP_QSTR_Accel), (mp_obj_t)&pyb_Accel_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_Accel), (mp_obj_t)&pyb_accel_type }, #endif #if 0 { MP_OBJ_NEW_QSTR(MP_QSTR_hid), (mp_obj_t)&pyb_hid_send_report_obj }, #endif - { MP_OBJ_NEW_QSTR(MP_QSTR_Led), (mp_obj_t)&pyb_Led_obj }, -#if 0 - { MP_OBJ_NEW_QSTR(MP_QSTR_I2C), (mp_obj_t)&pyb_I2C_obj }, -#endif - { MP_OBJ_NEW_QSTR(MP_QSTR_Usart), (mp_obj_t)&pyb_Usart_obj }, -#if 0 - { MP_OBJ_NEW_QSTR(MP_QSTR_ADC_all), (mp_obj_t)&pyb_ADC_all_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ADC), (mp_obj_t)&pyb_ADC_obj }, - -#if MICROPY_HW_ENABLE_AUDIO - { MP_OBJ_NEW_QSTR(MP_QSTR_Audio), (mp_obj_t)&pyb_Audio_obj }, -#endif -#endif // input { MP_OBJ_NEW_QSTR(MP_QSTR_input), (mp_obj_t)&pyb_input_obj }, diff --git a/stmhal/pybmodule.h b/stmhal/modpyb.h index 955aaefe3f..955aaefe3f 100644 --- a/stmhal/pybmodule.h +++ b/stmhal/modpyb.h diff --git a/stmhal/timemodule.c b/stmhal/modtime.c index b2dac6a54c..4786c85c72 100644 --- a/stmhal/timemodule.c +++ b/stmhal/modtime.c @@ -6,7 +6,7 @@ #include "qstr.h" #include "obj.h" #include "map.h" -#include "timemodule.h" +#include "modtime.h" STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) { #if MICROPY_ENABLE_FLOAT diff --git a/stmhal/timemodule.h b/stmhal/modtime.h index 70e35b1fde..70e35b1fde 100644 --- a/stmhal/timemodule.h +++ b/stmhal/modtime.h diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index 59c91942a0..b187c43bbe 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -19,12 +19,23 @@ #define MICROPY_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ // extra built in names to add to the global namespace +extern const struct _mp_obj_fun_native_t mp_builtin_help_obj; extern const struct _mp_obj_fun_native_t mp_builtin_input_obj; extern const struct _mp_obj_fun_native_t mp_builtin_open_obj; #define MICROPY_EXTRA_BUILTINS \ + { MP_QSTR_help, (mp_obj_t)&mp_builtin_help_obj }, \ { MP_QSTR_input, (mp_obj_t)&mp_builtin_input_obj }, \ { MP_QSTR_open, (mp_obj_t)&mp_builtin_open_obj }, +// extra built in modules to add to the list of known ones +extern const struct _mp_obj_module_t os_module; +extern const struct _mp_obj_module_t pyb_module; +extern const struct _mp_obj_module_t time_module; +#define MICROPY_EXTRA_BUILTIN_MODULES \ + { MP_QSTR_os, (mp_obj_t)&os_module }, \ + { MP_QSTR_pyb, (mp_obj_t)&pyb_module }, \ + { MP_QSTR_time, (mp_obj_t)&time_module }, \ + // type definitions for the specific machine #define BYTES_PER_WORD (4) diff --git a/stmhal/pin.h b/stmhal/pin.h index d5d769058a..2aa50655b4 100644 --- a/stmhal/pin.h +++ b/stmhal/pin.h @@ -50,6 +50,12 @@ enum { AF_PIN_TYPE_SPI_NSS, }; +enum { + PIN_ADC1 = (1 << 0), + PIN_ADC2 = (1 << 1), + PIN_ADC3 = (1 << 2), +}; + typedef struct { mp_obj_base_t base; uint8_t idx; @@ -70,9 +76,11 @@ typedef struct { typedef struct { mp_obj_base_t base; const char *name; - uint16_t port : 4; - uint16_t pin : 4; - uint16_t num_af : 4; + uint16_t port : 4; + uint16_t pin : 4; + uint16_t num_af : 4; + uint16_t adc_channel : 4; + uint16_t adc_num : 3; // 1 bit per ADC uint16_t pin_mask; GPIO_TypeDef *gpio; const pin_af_obj_t *af; diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c index e17b9aea44..f1f28abde0 100644 --- a/stmhal/pyexec.c +++ b/stmhal/pyexec.c @@ -24,7 +24,8 @@ #include "usb.h" #include "usart.h" -static bool repl_display_debugging_info = 0; +pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; +STATIC bool repl_display_debugging_info = 0; void stdout_tx_str(const char *str) { if (pyb_usart_global_debug != PYB_USART_NONE) { @@ -279,12 +280,12 @@ bool parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bo return ret; } -void pyexec_raw_repl(void) { +int pyexec_raw_repl(void) { vstr_t line; vstr_init(&line, 32); raw_repl_reset: - stdout_tx_str("raw REPL; CTRL-C to exit\r\n"); + stdout_tx_str("raw REPL; CTRL-B to exit\r\n"); for (;;) { vstr_reset(&line); @@ -292,11 +293,19 @@ raw_repl_reset: for (;;) { char c = stdin_rx_chr(); if (c == VCP_CHAR_CTRL_A) { + // reset raw REPL goto raw_repl_reset; + } else if (c == VCP_CHAR_CTRL_B) { + // change to friendly REPL + stdout_tx_str("\r\n"); + vstr_clear(&line); + pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; + return 0; } else if (c == VCP_CHAR_CTRL_C) { + // clear line vstr_reset(&line); - break; } else if (c == VCP_CHAR_CTRL_D) { + // input finished break; } else if (c == '\r') { vstr_add_char(&line, '\n'); @@ -305,30 +314,35 @@ raw_repl_reset: } } + // indicate reception of command stdout_tx_str("OK"); - if (vstr_len(&line) == 0) { - // finished - break; + if (line.len == 0) { + // exit for a soft reset + stdout_tx_str("\r\n"); + vstr_clear(&line); + return 1; } - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0); + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line.buf, line.len, 0); parse_compile_execute(lex, MP_PARSE_FILE_INPUT, false); + // indicate end of output with EOF character stdout_tx_str("\004"); } - - vstr_clear(&line); - stdout_tx_str("\r\n"); } -void pyexec_repl(void) { +int pyexec_friendly_repl(void) { + vstr_t line; + vstr_init(&line, 32); + #if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD // in host mode, we enable the LCD for the repl mp_obj_t lcd_o = rt_call_function_0(rt_load_name(qstr_from_str("LCD"))); rt_call_function_1(rt_load_attr(lcd_o, qstr_from_str("light")), mp_const_true); #endif +friendly_repl_reset: stdout_tx_str("Micro Python build <git hash> on 25/1/2014; " MICROPY_HW_BOARD_NAME " with STM32F405RG\r\n"); stdout_tx_str("Type \"help()\" for more information.\r\n"); @@ -350,22 +364,29 @@ void pyexec_repl(void) { } */ - vstr_t line; - vstr_init(&line, 32); - for (;;) { vstr_reset(&line); int ret = readline(&line, ">>> "); if (ret == VCP_CHAR_CTRL_A) { - pyexec_raw_repl(); - continue; + // change to raw REPL + stdout_tx_str("\r\n"); + vstr_clear(&line); + pyexec_mode_kind = PYEXEC_MODE_RAW_REPL; + return 0; + } else if (ret == VCP_CHAR_CTRL_B) { + // reset friendly REPL + stdout_tx_str("\r\n"); + goto friendly_repl_reset; } else if (ret == VCP_CHAR_CTRL_C) { + // break stdout_tx_str("\r\n"); continue; } else if (ret == VCP_CHAR_CTRL_D) { - // EOF - break; + // exit for a soft reset + stdout_tx_str("\r\n"); + vstr_clear(&line); + return 1; } else if (vstr_len(&line) == 0) { continue; } @@ -385,8 +406,6 @@ void pyexec_repl(void) { mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0); parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, true); } - - stdout_tx_str("\r\n"); } bool pyexec_file(const char *filename) { diff --git a/stmhal/pyexec.h b/stmhal/pyexec.h index cad15af6fe..d191a2fc4e 100644 --- a/stmhal/pyexec.h +++ b/stmhal/pyexec.h @@ -1,5 +1,12 @@ -void pyexec_raw_repl(void); -void pyexec_repl(void); +typedef enum { + PYEXEC_MODE_RAW_REPL, + PYEXEC_MODE_FRIENDLY_REPL, +} pyexec_mode_kind_t; + +extern pyexec_mode_kind_t pyexec_mode_kind; + +int pyexec_raw_repl(void); +int pyexec_friendly_repl(void); bool pyexec_file(const char *filename); MP_DECLARE_CONST_FUN_OBJ(pyb_set_repl_info_obj); diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index 18fc345a81..4036dcd25e 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -33,7 +33,7 @@ Q(gpio_out) Q(Usart) Q(ADC) Q(ADC_all) -Q(Audio) +Q(DAC) Q(open) Q(File) // Entries for sys.path diff --git a/stmhal/servo.c b/stmhal/servo.c index b0e0e8695d..81b290bf52 100644 --- a/stmhal/servo.c +++ b/stmhal/servo.c @@ -148,12 +148,35 @@ STATIC mp_obj_t pyb_pwm_set(mp_obj_t period, mp_obj_t pulse) { MP_DEFINE_CONST_FUN_OBJ_2(pyb_pwm_set_obj, pyb_pwm_set); -STATIC void servo_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { +STATIC void pyb_servo_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { pyb_servo_obj_t *self = self_in; print(env, "<Servo %lu at %lu>", self->servo_id, self->pulse_cur); } -STATIC mp_obj_t servo_obj_angle(uint n_args, const mp_obj_t *args) { +STATIC mp_obj_t pyb_servo_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { + // check arguments + if (!(n_args == 1 && n_kw == 0)) { + nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "Servo accepts 1 argument")); + } + + // get servo number + machine_int_t servo_id = mp_obj_get_int(args[0]) - 1; + + // check servo number + if (!(0 <= servo_id && servo_id < PYB_SERVO_NUM)) { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Servo %d does not exist", servo_id)); + } + + // get and init servo object + pyb_servo_obj_t *s = &pyb_servo_obj[servo_id]; + s->pulse_dest = s->pulse_cur; + s->time_left = 0; + servo_init_channel(s); + + return s; +} + +STATIC mp_obj_t pyb_servo_angle(uint n_args, const mp_obj_t *args) { pyb_servo_obj_t *self = args[0]; if (n_args == 1) { // get angle @@ -180,31 +203,17 @@ STATIC mp_obj_t servo_obj_angle(uint n_args, const mp_obj_t *args) { } } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(servo_obj_angle_obj, 1, 3, servo_obj_angle); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_angle_obj, 1, 3, pyb_servo_angle); -STATIC const mp_method_t servo_methods[] = { - { "angle", &servo_obj_angle_obj }, +STATIC const mp_method_t pyb_servo_methods[] = { + { "angle", &pyb_servo_angle_obj }, { NULL, NULL }, }; -STATIC const mp_obj_type_t servo_obj_type = { +const mp_obj_type_t pyb_servo_type = { { &mp_type_type }, .name = MP_QSTR_Servo, - .print = servo_obj_print, - .methods = servo_methods, + .print = pyb_servo_print, + .make_new = pyb_servo_make_new, + .methods = pyb_servo_methods, }; - -STATIC mp_obj_t pyb_Servo(mp_obj_t servo_id_o) { - machine_int_t servo_id = mp_obj_get_int(servo_id_o) - 1; - if (0 <= servo_id && servo_id < PYB_SERVO_NUM) { - pyb_servo_obj_t *s = &pyb_servo_obj[servo_id]; - s->pulse_dest = s->pulse_cur; - s->time_left = 0; - servo_init_channel(s); - return s; - } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Servo %d does not exist", servo_id)); - } -} - -MP_DEFINE_CONST_FUN_OBJ_1(pyb_Servo_obj, pyb_Servo); diff --git a/stmhal/servo.h b/stmhal/servo.h index 753ca49598..d5fb6a8505 100644 --- a/stmhal/servo.h +++ b/stmhal/servo.h @@ -3,6 +3,7 @@ extern TIM_HandleTypeDef TIM2_Handle; void servo_init(void); void servo_timer_irq_callback(void); +extern const mp_obj_type_t pyb_servo_type; + MP_DECLARE_CONST_FUN_OBJ(pyb_servo_set_obj); MP_DECLARE_CONST_FUN_OBJ(pyb_pwm_set_obj); -MP_DECLARE_CONST_FUN_OBJ(pyb_Servo_obj); diff --git a/stmhal/usart.c b/stmhal/usart.c index bc8b0ec1c9..31308c22ad 100644 --- a/stmhal/usart.c +++ b/stmhal/usart.c @@ -1,7 +1,9 @@ #include <stdio.h> #include <string.h> -#include <stm32f4xx_hal.h> +#include "stm32f4xx_hal.h" + +#include "nlr.h" #include "misc.h" #include "mpconfig.h" #include "qstr.h" @@ -71,8 +73,8 @@ void usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) { break; } - /* Initialize USARTx */ - + // Initialize USARTx + GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Pin = GPIO_Pin; GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; @@ -135,7 +137,33 @@ void usart_tx_strn_cooked(pyb_usart_obj_t *usart_obj, const char *str, uint len) /******************************************************************************/ /* Micro Python bindings */ -static mp_obj_t usart_obj_status(mp_obj_t self_in) { +STATIC void usart_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_usart_obj_t *self = self_in; + print(env, "<Usart %lu>", self->usart_id); +} + +STATIC mp_obj_t usart_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { + // check arguments + if (!(n_args == 2 && n_kw == 0)) { + nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "Usart accepts 2 arguments")); + } + + if (mp_obj_get_int(args[0]) > PYB_USART_MAX) { + return mp_const_none; + } + + pyb_usart_obj_t *o = m_new_obj(pyb_usart_obj_t); + o->base.type = &pyb_usart_type; + o->usart_id = mp_obj_get_int(args[0]); + o->is_enabled = true; + + /* init USART */ + usart_init(o, mp_obj_get_int(args[1])); + + return o; +} + +STATIC mp_obj_t usart_obj_status(mp_obj_t self_in) { pyb_usart_obj_t *self = self_in; if (usart_rx_any(self)) { return mp_const_true; @@ -144,7 +172,7 @@ static mp_obj_t usart_obj_status(mp_obj_t self_in) { } } -static mp_obj_t usart_obj_rx_char(mp_obj_t self_in) { +STATIC mp_obj_t usart_obj_rx_char(mp_obj_t self_in) { mp_obj_t ret = mp_const_none; pyb_usart_obj_t *self = self_in; @@ -154,7 +182,7 @@ static mp_obj_t usart_obj_rx_char(mp_obj_t self_in) { return ret; } -static mp_obj_t usart_obj_tx_char(mp_obj_t self_in, mp_obj_t c) { +STATIC mp_obj_t usart_obj_tx_char(mp_obj_t self_in, mp_obj_t c) { pyb_usart_obj_t *self = self_in; uint len; const char *str = mp_obj_str_get_data(c, &len); @@ -164,7 +192,7 @@ static mp_obj_t usart_obj_tx_char(mp_obj_t self_in, mp_obj_t c) { return mp_const_none; } -static mp_obj_t usart_obj_tx_str(mp_obj_t self_in, mp_obj_t s) { +STATIC mp_obj_t usart_obj_tx_str(mp_obj_t self_in, mp_obj_t s) { pyb_usart_obj_t *self = self_in; if (self->is_enabled) { if (MP_OBJ_IS_STR(s)) { @@ -176,15 +204,10 @@ static mp_obj_t usart_obj_tx_str(mp_obj_t self_in, mp_obj_t s) { return mp_const_none; } -static void usart_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { - pyb_usart_obj_t *self = self_in; - print(env, "<Usart %lu>", self->usart_id); -} - -static MP_DEFINE_CONST_FUN_OBJ_1(usart_obj_status_obj, usart_obj_status); -static MP_DEFINE_CONST_FUN_OBJ_1(usart_obj_rx_char_obj, usart_obj_rx_char); -static MP_DEFINE_CONST_FUN_OBJ_2(usart_obj_tx_char_obj, usart_obj_tx_char); -static MP_DEFINE_CONST_FUN_OBJ_2(usart_obj_tx_str_obj, usart_obj_tx_str); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(usart_obj_status_obj, usart_obj_status); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(usart_obj_rx_char_obj, usart_obj_rx_char); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(usart_obj_tx_char_obj, usart_obj_tx_char); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(usart_obj_tx_str_obj, usart_obj_tx_str); STATIC const mp_method_t usart_methods[] = { { "status", &usart_obj_status_obj }, @@ -194,27 +217,10 @@ STATIC const mp_method_t usart_methods[] = { { NULL, NULL }, }; -STATIC const mp_obj_type_t usart_obj_type = { +const mp_obj_type_t pyb_usart_type = { { &mp_type_type }, .name = MP_QSTR_Usart, .print = usart_obj_print, + .make_new = usart_obj_make_new, .methods = usart_methods, }; - -mp_obj_t pyb_Usart(mp_obj_t usart_id, mp_obj_t baudrate) { - if (mp_obj_get_int(usart_id) > PYB_USART_MAX) { - return mp_const_none; - } - - pyb_usart_obj_t *o = m_new_obj(pyb_usart_obj_t); - o->base.type = &usart_obj_type; - o->usart_id = mp_obj_get_int(usart_id); - o->is_enabled = true; - - /* init USART */ - usart_init(o, mp_obj_get_int(baudrate)); - - return o; -} - -MP_DEFINE_CONST_FUN_OBJ_2(pyb_Usart_obj, pyb_Usart); diff --git a/stmhal/usart.h b/stmhal/usart.h index c7119c833e..02464080b8 100644 --- a/stmhal/usart.h +++ b/stmhal/usart.h @@ -15,6 +15,7 @@ typedef enum { typedef struct _pyb_usart_obj_t pyb_usart_obj_t; extern pyb_usart_obj_t *pyb_usart_global_debug; +extern const mp_obj_type_t pyb_usart_type; void usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate); bool usart_rx_any(pyb_usart_obj_t *usart_obj); @@ -23,6 +24,3 @@ void usart_tx_str(pyb_usart_obj_t *usart_obj, const char *str); void usart_tx_strn(pyb_usart_obj_t *usart_obj, const char *str, uint len); void usart_tx_strn_cooked(pyb_usart_obj_t *usart_obj, const char *str, uint len); -mp_obj_t pyb_Usart(mp_obj_t usart_id, mp_obj_t baudrate); - -MP_DECLARE_CONST_FUN_OBJ(pyb_Usart_obj); diff --git a/stmhal/usbd_cdc_interface.c b/stmhal/usbd_cdc_interface.c index a62f8a801f..c441e9c61c 100644 --- a/stmhal/usbd_cdc_interface.c +++ b/stmhal/usbd_cdc_interface.c @@ -363,7 +363,7 @@ void USBD_CDC_SetInterrupt(int chr, void *data) { void USBD_CDC_Tx(const char *str, uint32_t len) { for (int i = 0; i < len; i++) { uint timeout = 200; - while (UserTxBufPtrIn + 1 == UserTxBufPtrOut) { + while (((UserTxBufPtrIn + 1) & (APP_TX_DATA_SIZE - 1)) == UserTxBufPtrOut) { if (timeout-- == 0) { break; } diff --git a/tests/basics/exception1.py b/tests/basics/exception1.py index 71d5ad3041..739dd32753 100644 --- a/tests/basics/exception1.py +++ b/tests/basics/exception1.py @@ -7,3 +7,9 @@ print(str(IndexError("foo"))) a = IndexError(1, "test", [100, 200]) print(repr(a)) print(str(a)) +print(a.args) + +s = StopIteration() +print(s.value) +s = StopIteration(1, 2, 3) +print(s.value) diff --git a/tests/basics/exceptpoly.py b/tests/basics/exceptpoly.py index 0e5ac2d1a3..b2fc11afbe 100644 --- a/tests/basics/exceptpoly.py +++ b/tests/basics/exceptpoly.py @@ -38,25 +38,25 @@ try: except BufferError: print("Caught BufferError") -try: - raise BytesWarning -except Warning: - print("Caught BytesWarning via Warning") +#try: +# raise BytesWarning +#except Warning: +# print("Caught BytesWarning via Warning") -try: - raise BytesWarning -except BytesWarning: - print("Caught BytesWarning") +#try: +# raise BytesWarning +#except BytesWarning: +# print("Caught BytesWarning") -try: - raise DeprecationWarning -except Warning: - print("Caught DeprecationWarning via Warning") +#try: +# raise DeprecationWarning +#except Warning: +# print("Caught DeprecationWarning via Warning") -try: - raise DeprecationWarning -except DeprecationWarning: - print("Caught DeprecationWarning") +#try: +# raise DeprecationWarning +#except DeprecationWarning: +# print("Caught DeprecationWarning") try: raise EOFError @@ -68,15 +68,15 @@ try: except EOFError: print("Caught EOFError") -try: - raise EnvironmentError -except Exception: - print("Caught EnvironmentError via Exception") +#try: +# raise EnvironmentError +#except Exception: +# print("Caught EnvironmentError via Exception") -try: - raise EnvironmentError -except EnvironmentError: - print("Caught EnvironmentError") +#try: +# raise EnvironmentError +#except EnvironmentError: +# print("Caught EnvironmentError") try: raise Exception @@ -98,15 +98,15 @@ try: except FloatingPointError: print("Caught FloatingPointError") -try: - raise FutureWarning -except Warning: - print("Caught FutureWarning via Warning") +#try: +# raise FutureWarning +#except Warning: +# print("Caught FutureWarning via Warning") -try: - raise FutureWarning -except FutureWarning: - print("Caught FutureWarning") +#try: +# raise FutureWarning +#except FutureWarning: +# print("Caught FutureWarning") try: raise IOError @@ -128,15 +128,15 @@ try: except ImportError: print("Caught ImportError") -try: - raise ImportWarning -except Warning: - print("Caught ImportWarning via Warning") +#try: +# raise ImportWarning +#except Warning: +# print("Caught ImportWarning via Warning") -try: - raise ImportWarning -except ImportWarning: - print("Caught ImportWarning") +#try: +# raise ImportWarning +#except ImportWarning: +# print("Caught ImportWarning") try: raise IndentationError @@ -228,35 +228,35 @@ try: except OverflowError: print("Caught OverflowError") -try: - raise PendingDeprecationWarning -except Warning: - print("Caught PendingDeprecationWarning via Warning") +#try: +# raise PendingDeprecationWarning +#except Warning: +# print("Caught PendingDeprecationWarning via Warning") -try: - raise PendingDeprecationWarning -except PendingDeprecationWarning: - print("Caught PendingDeprecationWarning") +#try: +# raise PendingDeprecationWarning +#except PendingDeprecationWarning: +# print("Caught PendingDeprecationWarning") -try: - raise ReferenceError -except Exception: - print("Caught ReferenceError via Exception") +#try: +# raise ReferenceError +#except Exception: +# print("Caught ReferenceError via Exception") -try: - raise ReferenceError -except ReferenceError: - print("Caught ReferenceError") +#try: +# raise ReferenceError +#except ReferenceError: +# print("Caught ReferenceError") -try: - raise ResourceWarning -except Warning: - print("Caught ResourceWarning via Warning") +#try: +# raise ResourceWarning +#except Warning: +# print("Caught ResourceWarning via Warning") -try: - raise ResourceWarning -except ResourceWarning: - print("Caught ResourceWarning") +#try: +# raise ResourceWarning +#except ResourceWarning: +# print("Caught ResourceWarning") try: raise RuntimeError @@ -268,15 +268,15 @@ try: except RuntimeError: print("Caught RuntimeError") -try: - raise RuntimeWarning -except Warning: - print("Caught RuntimeWarning via Warning") +#try: +# raise RuntimeWarning +#except Warning: +# print("Caught RuntimeWarning via Warning") -try: - raise RuntimeWarning -except RuntimeWarning: - print("Caught RuntimeWarning") +#try: +# raise RuntimeWarning +#except RuntimeWarning: +# print("Caught RuntimeWarning") try: raise SyntaxError @@ -288,15 +288,15 @@ try: except SyntaxError: print("Caught SyntaxError") -try: - raise SyntaxWarning -except Warning: - print("Caught SyntaxWarning via Warning") +#try: +# raise SyntaxWarning +#except Warning: +# print("Caught SyntaxWarning via Warning") -try: - raise SyntaxWarning -except SyntaxWarning: - print("Caught SyntaxWarning") +#try: +# raise SyntaxWarning +#except SyntaxWarning: +# print("Caught SyntaxWarning") try: raise SystemError @@ -308,15 +308,15 @@ try: except SystemError: print("Caught SystemError") -try: - raise TabError -except IndentationError: - print("Caught TabError via IndentationError") +#try: +# raise TabError +#except IndentationError: +# print("Caught TabError via IndentationError") -try: - raise TabError -except TabError: - print("Caught TabError") +#try: +# raise TabError +#except TabError: +# print("Caught TabError") try: raise TypeError @@ -338,15 +338,15 @@ try: except UnboundLocalError: print("Caught UnboundLocalError") -try: - raise UserWarning -except Warning: - print("Caught UserWarning via Warning") +#try: +# raise UserWarning +#except Warning: +# print("Caught UserWarning via Warning") -try: - raise UserWarning -except UserWarning: - print("Caught UserWarning") +#try: +# raise UserWarning +#except UserWarning: +# print("Caught UserWarning") try: raise ValueError @@ -358,15 +358,15 @@ try: except ValueError: print("Caught ValueError") -try: - raise Warning -except Exception: - print("Caught Warning via Exception") +#try: +# raise Warning +#except Exception: +# print("Caught Warning via Exception") -try: - raise Warning -except Warning: - print("Caught Warning") +#try: +# raise Warning +#except Warning: +# print("Caught Warning") try: raise ZeroDivisionError diff --git a/tests/basics/string_rfind.py b/tests/basics/string_rfind.py new file mode 100644 index 0000000000..4d0e84018f --- /dev/null +++ b/tests/basics/string_rfind.py @@ -0,0 +1,23 @@ +print("hello world".rfind("ll")) +print("hello world".rfind("ll", None)) +print("hello world".rfind("ll", 1)) +print("hello world".rfind("ll", 1, None)) +print("hello world".rfind("ll", None, None)) +print("hello world".rfind("ll", 1, -1)) +print("hello world".rfind("ll", 1, 1)) +print("hello world".rfind("ll", 1, 2)) +print("hello world".rfind("ll", 1, 3)) +print("hello world".rfind("ll", 1, 4)) +print("hello world".rfind("ll", 1, 5)) +print("hello world".rfind("ll", -100)) +print("0000".rfind('0')) +print("0000".rfind('0', 0)) +print("0000".rfind('0', 1)) +print("0000".rfind('0', 2)) +print("0000".rfind('0', 3)) +print("0000".rfind('0', 4)) +print("0000".rfind('0', 5)) +print("0000".rfind('-1', 3)) +print("0000".rfind('1', 3)) +print("0000".rfind('1', 4)) +print("0000".rfind('1', 5)) diff --git a/tests/basics/try-as-var.py b/tests/basics/try-as-var.py new file mode 100644 index 0000000000..0a92f1caee --- /dev/null +++ b/tests/basics/try-as-var.py @@ -0,0 +1,10 @@ +try: + raise ValueError(534) +except ValueError as e: + print(repr(e)) + +# Var bound in except block is automatically deleted +try: + e +except NameError: + print("NameError") diff --git a/tests/basics/types1.py b/tests/basics/types1.py index 850b31b08c..57b33b842b 100644 --- a/tests/basics/types1.py +++ b/tests/basics/types1.py @@ -26,3 +26,8 @@ print(type(()) == tuple) print(type([]) == list) print(type({None}) == set) print(type({}) == dict) + +try: + bool.foo +except AttributeError: + print("AttributeError") diff --git a/tools/pyboard.py b/tools/pyboard.py new file mode 100644 index 0000000000..3ce6da5215 --- /dev/null +++ b/tools/pyboard.py @@ -0,0 +1,127 @@ +""" +pyboard interface + +This module provides the Pyboard class, used to communicate with and +control the pyboard over a serial USB connection. + +Example usage: + + import pyboard + pyb = pyboard.Pyboard('/dev/ttyACM0') + pyb.enter_raw_repl() + pyb.exec('pyb.Led(1).on()') + pyb.exit_raw_repl() + +""" + +import time +import serial + +class Pyboard: + def __init__(self, serial_device): + self.serial = serial.Serial(serial_device) + + def close(self): + self.serial.close() + + def enter_raw_repl(self): + self.serial.write(b'\r\x01') # ctrl-A: enter raw REPL + self.serial.write(b'\x04') # ctrl-D: soft reset + data = self.serial.read(1) + while self.serial.inWaiting() > 0: + data = data + self.serial.read(self.serial.inWaiting()) + time.sleep(0.1) + if not data.endswith(b'raw REPL; CTRL-B to exit\r\n>'): + print(data) + raise Exception('could not enter raw repl') + + def exit_raw_repl(self): + self.serial.write(b'\r\x02') # ctrl-B: enter friendly REPL + + def eval(self, expression): + ret = self.exec('print({})'.format(expression)) + ret = ret.strip() + return ret + + def exec(self, command): + command_bytes = bytes(command, encoding='ascii') + for i in range(0, len(command_bytes), 10): + self.serial.write(command_bytes[i:min(i+10, len(command_bytes))]) + time.sleep(0.01) + self.serial.write(b'\x04') + data = self.serial.read(2) + if data != b'OK': + raise Exception('could not exec command') + data = self.serial.read(2) + while self.serial.inWaiting() > 0: + data = data + self.serial.read(self.serial.inWaiting()) + time.sleep(0.1) + if not data.endswith(b'\x04>'): + print(data) + raise Exception('could not exec command') + if data.startswith(b'Traceback') or data.startswith(b' File '): + print(data) + raise Exception('command failed') + return data[:-2] + + def get_time(self): + t = str(self.exec('pyb.time()'), encoding='ascii').strip().split()[1].split(':') + return int(t[0]) * 3600 + int(t[1]) * 60 + int(t[2]) + +def run_test(): + device = '/dev/ttyACM0' + pyb = Pyboard(device) + pyb.enter_raw_repl() + print('opened device {}'.format(device)) + + print('seconds since boot:', pyb.get_time()) + + pyb.exec('def apply(l, f):\r\n for item in l:\r\n f(item)\r\n') + + pyb.exec('leds=[pyb.Led(l) for l in range(1, 5)]') + pyb.exec('apply(leds, lambda l:l.off())') + + ## USR switch test + + if True: + for i in range(2): + print("press USR button") + pyb.exec('while pyb.switch(): pyb.delay(10)') + pyb.exec('while not pyb.switch(): pyb.delay(10)') + + print('USR switch passed') + + ## accel test + + if True: + print("hold level") + pyb.exec('accel = pyb.Accel()') + pyb.exec('while abs(accel.x()) > 10 or abs(accel.y()) > 10: pyb.delay(10)') + + print("tilt left") + pyb.exec('while accel.x() > -10: pyb.delay(10)') + pyb.exec('leds[0].on()') + + print("tilt forward") + pyb.exec('while accel.y() < 10: pyb.delay(10)') + pyb.exec('leds[1].on()') + + print("tilt right") + pyb.exec('while accel.x() < 10: pyb.delay(10)') + pyb.exec('leds[2].on()') + + print("tilt backward") + pyb.exec('while accel.y() > -10: pyb.delay(10)') + pyb.exec('leds[3].on()') + + print('accel passed') + + print('seconds since boot:', pyb.get_time()) + + pyb.exec('apply(leds, lambda l:l.off())') + + pyb.exit_raw_repl() + pyb.close() + +if __name__ == "__main__": + run_test() |