summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--py/argcheck.c3
-rw-r--r--py/bc0.h1
-rw-r--r--py/binary.c16
-rw-r--r--py/builtinimport.c4
-rw-r--r--py/compile.c6
-rw-r--r--py/emit.h14
-rw-r--r--py/emitbc.c49
-rw-r--r--py/emitcpy.c55
-rw-r--r--py/emitglue.c15
-rw-r--r--py/emitglue.h2
-rw-r--r--py/emitnative.c22
-rw-r--r--py/emitpass1.c3
-rw-r--r--py/gc.c142
-rw-r--r--py/nlrx86.S4
-rw-r--r--py/obj.h2
-rw-r--r--py/objarray.c8
-rw-r--r--py/objcell.c15
-rw-r--r--py/objclosure.c29
-rw-r--r--py/objfun.c4
-rw-r--r--py/showbc.c5
-rw-r--r--py/vm.c27
-rw-r--r--py/vmentrytable.h1
-rw-r--r--stmhal/Makefile1
-rw-r--r--stmhal/accel.c14
-rw-r--r--stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h3
-rw-r--r--stmhal/boards/PYBV10/mpconfigboard.h3
-rw-r--r--stmhal/boards/PYBV3/mpconfigboard.h3
-rw-r--r--stmhal/boards/PYBV4/mpconfigboard.h5
-rw-r--r--stmhal/boards/STM32F4DISC/mpconfigboard.h3
-rw-r--r--stmhal/bufhelper.c29
-rw-r--r--stmhal/bufhelper.h2
-rw-r--r--stmhal/i2c.c332
-rw-r--r--stmhal/i2c.h3
-rw-r--r--stmhal/qstrdefsport.h34
-rw-r--r--stmhal/spi.c230
-rw-r--r--stmhal/usart.c280
-rw-r--r--unix/file.c1
-rw-r--r--unix/main.c6
-rw-r--r--unix/modsocket.c18
-rw-r--r--unix/qstrdefsport.h1
-rw-r--r--windows/Makefile23
-rw-r--r--windows/README10
-rw-r--r--windows/mpconfigport.h4
-rw-r--r--windows/mpconfigport.mk13
44 files changed, 1014 insertions, 431 deletions
diff --git a/py/argcheck.c b/py/argcheck.c
index 5c5ea1bf80..aea71d0bd8 100644
--- a/py/argcheck.c
+++ b/py/argcheck.c
@@ -40,7 +40,7 @@ void mp_arg_parse_all(uint n_pos, const mp_obj_t *pos, mp_map_t *kws, uint n_all
mp_obj_t given_arg;
if (i < n_pos) {
if (allowed[i].flags & MP_ARG_PARSE_KW_ONLY) {
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' argument must be given by a keyword", qstr_str(allowed[i].qstr)));
+ goto extra_positional;
}
pos_found++;
given_arg = pos[i];
@@ -69,6 +69,7 @@ void mp_arg_parse_all(uint n_pos, const mp_obj_t *pos, mp_map_t *kws, uint n_all
}
if (pos_found < n_pos) {
// TODO better error message
+ extra_positional:
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "extra positional arguments given"));
}
if (kws_found < kws->used) {
diff --git a/py/bc0.h b/py/bc0.h
index 57c2d2ea64..37bd904147 100644
--- a/py/bc0.h
+++ b/py/bc0.h
@@ -51,7 +51,6 @@
#define MP_BC_POP_JUMP_IF_FALSE (0x47) // rel byte code offset, 16-bit signed, in excess
#define MP_BC_JUMP_IF_TRUE_OR_POP (0x48) // rel byte code offset, 16-bit signed, in excess
#define MP_BC_JUMP_IF_FALSE_OR_POP (0x49) // rel byte code offset, 16-bit signed, in excess
-#define MP_BC_SETUP_LOOP (0x4a) // rel byte code offset, 16-bit unsigned
#define MP_BC_SETUP_WITH (0x4d) // rel byte code offset, 16-bit unsigned
#define MP_BC_WITH_CLEANUP (0x4e)
#define MP_BC_SETUP_EXCEPT (0x4f) // rel byte code offset, 16-bit unsigned
diff --git a/py/binary.c b/py/binary.c
index ee95d56e44..e57766b41c 100644
--- a/py/binary.c
+++ b/py/binary.c
@@ -49,6 +49,8 @@ int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
case 'q': case 'Q':
// TODO: This is for x86
align = sizeof(int); size = sizeof(long long); break;
+ case 'P': case 'O':
+ align = size = sizeof(void*); break;
}
}
}
@@ -131,7 +133,9 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
}
*ptr += size;
- if (is_signed(val_type)) {
+ if (val_type == 'O') {
+ return (mp_obj_t)val;
+ } else if (is_signed(val_type)) {
return mp_obj_new_int(val);
} else {
return mp_obj_new_int_from_uint(val);
@@ -156,8 +160,16 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
#if MP_ENDIANNESS_BIG
#error Not implemented
#endif
- machine_int_t val = mp_obj_int_get_checked(val_in);
+ machine_int_t val;
byte *in = (byte*)&val;
+ switch (val_type) {
+ case 'O':
+ in = (byte*)&val_in;
+ break;
+ default:
+ val = mp_obj_get_int(val_in);
+ }
+
int in_delta, out_delta;
uint val_sz = MIN(size, sizeof(val));
if (struct_type == '>') {
diff --git a/py/builtinimport.c b/py/builtinimport.c
index 262ee04a53..4a2f6510c3 100644
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -3,6 +3,10 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
+#ifdef __MINGW32__
+// For alloca()
+#include <malloc.h>
+#endif
#include "nlr.h"
#include "misc.h"
diff --git a/py/compile.c b/py/compile.c
index b0f1f9e00d..57f6f1546f 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -889,8 +889,7 @@ void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_d
if (nfree == 0) {
EMIT_ARG(make_function, this_scope, n_pos_defaults, n_kw_defaults);
} else {
- EMIT_ARG(build_tuple, nfree);
- EMIT_ARG(make_closure, this_scope, n_pos_defaults, n_kw_defaults);
+ EMIT_ARG(make_closure, this_scope, nfree, n_pos_defaults, n_kw_defaults);
}
}
@@ -957,6 +956,8 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
// we need to do this here before we start building the map for the default keywords
if (comp->num_default_params > 0) {
EMIT_ARG(build_tuple, comp->num_default_params);
+ } else {
+ EMIT(load_null); // sentinel indicating empty default positional args
}
// first default dict param, so make the map
EMIT_ARG(build_map, 0);
@@ -1009,6 +1010,7 @@ qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint
// the default keywords args may have already made the tuple; if not, do it now
if (comp->num_default_params > 0 && comp->num_dict_params == 0) {
EMIT_ARG(build_tuple, comp->num_default_params);
+ EMIT(load_null); // sentinel indicating empty default keyword args
}
#endif
diff --git a/py/emit.h b/py/emit.h
index 74cc5baa4a..5fca153163 100644
--- a/py/emit.h
+++ b/py/emit.h
@@ -41,10 +41,9 @@ typedef struct _emit_method_table_t {
void (*load_const_dec)(emit_t *emit, qstr qstr);
void (*load_const_id)(emit_t *emit, qstr qstr);
void (*load_const_str)(emit_t *emit, qstr qstr, bool bytes);
- void (*load_const_verbatim_str)(emit_t *emit, const char *str); // only needed for emitcpy
+ void (*load_null)(emit_t *emit);
void (*load_fast)(emit_t *emit, qstr qstr, uint id_flags, int local_num);
void (*load_deref)(emit_t *emit, qstr qstr, int local_num);
- void (*load_closure)(emit_t *emit, qstr qstr, int local_num); // only needed for emitcpy
void (*load_name)(emit_t *emit, qstr qstr);
void (*load_global)(emit_t *emit, qstr qstr);
void (*load_attr)(emit_t *emit, qstr qstr);
@@ -73,7 +72,6 @@ typedef struct _emit_method_table_t {
void (*pop_jump_if_false)(emit_t *emit, uint label);
void (*jump_if_true_or_pop)(emit_t *emit, uint label);
void (*jump_if_false_or_pop)(emit_t *emit, uint label);
- void (*setup_loop)(emit_t *emit, uint label);
void (*break_loop)(emit_t *emit, uint label, int except_depth);
void (*continue_loop)(emit_t *emit, uint label, int except_depth);
void (*setup_with)(emit_t *emit, uint label);
@@ -100,13 +98,21 @@ typedef struct _emit_method_table_t {
void (*unpack_sequence)(emit_t *emit, int n_args);
void (*unpack_ex)(emit_t *emit, int n_left, int n_right);
void (*make_function)(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults);
- void (*make_closure)(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults);
+ void (*make_closure)(emit_t *emit, scope_t *scope, uint n_closed_over, uint n_pos_defaults, uint n_kw_defaults);
void (*call_function)(emit_t *emit, int n_positional, int n_keyword, uint star_flags);
void (*call_method)(emit_t *emit, int n_positional, int n_keyword, uint star_flags);
void (*return_value)(emit_t *emit);
void (*raise_varargs)(emit_t *emit, int n_args);
void (*yield_value)(emit_t *emit);
void (*yield_from)(emit_t *emit);
+
+#if MICROPY_EMIT_CPYTHON
+ // these methods are only needed for emitcpy
+ void (*load_const_verbatim_str)(emit_t *emit, const char *str);
+ void (*load_closure)(emit_t *emit, qstr qstr, int local_num);
+ void (*setup_loop)(emit_t *emit, uint label);
+#endif
+
} emit_method_table_t;
void emit_common_load_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qstr);
diff --git a/py/emitbc.c b/py/emitbc.c
index d7b309a37f..f58cec1f1f 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -16,6 +16,8 @@
#include "emit.h"
#include "bc0.h"
+#if !MICROPY_EMIT_CPYTHON
+
struct _emit_t {
pass_kind_t pass;
int stack_size;
@@ -421,11 +423,6 @@ STATIC void emit_bc_load_const_str(emit_t *emit, qstr qstr, bool bytes) {
}
}
-STATIC void emit_bc_load_const_verbatim_str(emit_t *emit, const char *str) {
- // not needed/supported for BC
- assert(0);
-}
-
STATIC void emit_bc_load_null(emit_t *emit) {
emit_bc_pre(emit, 1);
emit_write_byte_code_byte(emit, MP_BC_LOAD_NULL);
@@ -447,11 +444,6 @@ STATIC void emit_bc_load_deref(emit_t *emit, qstr qstr, int local_num) {
emit_write_byte_code_byte_uint(emit, MP_BC_LOAD_DEREF, local_num);
}
-STATIC void emit_bc_load_closure(emit_t *emit, qstr qstr, int local_num) {
- // not needed/supported for BC
- assert(0);
-}
-
STATIC void emit_bc_load_name(emit_t *emit, qstr qstr) {
emit_bc_pre(emit, 1);
emit_write_byte_code_byte_qstr(emit, MP_BC_LOAD_NAME, qstr);
@@ -598,11 +590,6 @@ STATIC void emit_bc_jump_if_false_or_pop(emit_t *emit, uint label) {
emit_write_byte_code_byte_signed_label(emit, MP_BC_JUMP_IF_FALSE_OR_POP, label);
}
-STATIC void emit_bc_setup_loop(emit_t *emit, uint label) {
- emit_bc_pre(emit, 0);
- emit_write_byte_code_byte_unsigned_label(emit, MP_BC_SETUP_LOOP, label);
-}
-
STATIC void emit_bc_unwind_jump(emit_t *emit, uint label, int except_depth) {
if (except_depth == 0) {
emit_bc_jump(emit, label);
@@ -761,35 +748,21 @@ STATIC void emit_bc_make_function(emit_t *emit, scope_t *scope, uint n_pos_defau
emit_bc_pre(emit, 1);
emit_write_byte_code_byte_ptr(emit, MP_BC_MAKE_FUNCTION, scope->raw_code);
} else {
- if (n_pos_defaults == 0) {
- // load dummy entry for non-existent positional default tuple
- emit_bc_load_null(emit);
- emit_bc_rot_two(emit);
- } else if (n_kw_defaults == 0) {
- // load dummy entry for non-existent keyword default dict
- emit_bc_load_null(emit);
- }
emit_bc_pre(emit, -1);
emit_write_byte_code_byte_ptr(emit, MP_BC_MAKE_FUNCTION_DEFARGS, scope->raw_code);
}
}
-STATIC void emit_bc_make_closure(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) {
+STATIC void emit_bc_make_closure(emit_t *emit, scope_t *scope, uint n_closed_over, uint n_pos_defaults, uint n_kw_defaults) {
if (n_pos_defaults == 0 && n_kw_defaults == 0) {
- emit_bc_pre(emit, 0);
+ emit_bc_pre(emit, -n_closed_over + 1);
emit_write_byte_code_byte_ptr(emit, MP_BC_MAKE_CLOSURE, scope->raw_code);
+ emit_write_byte_code_byte(emit, n_closed_over);
} else {
- if (n_pos_defaults == 0) {
- // load dummy entry for non-existent positional default tuple
- emit_bc_load_null(emit);
- emit_bc_rot_three(emit);
- } else if (n_kw_defaults == 0) {
- // load dummy entry for non-existent keyword default dict
- emit_bc_load_null(emit);
- emit_bc_rot_two(emit);
- }
- emit_bc_pre(emit, -2);
+ assert(n_closed_over <= 255);
+ emit_bc_pre(emit, -2 - n_closed_over + 1);
emit_write_byte_code_byte_ptr(emit, MP_BC_MAKE_CLOSURE_DEFARGS, scope->raw_code);
+ emit_write_byte_code_byte(emit, n_closed_over);
}
}
@@ -869,10 +842,9 @@ const emit_method_table_t emit_bc_method_table = {
emit_bc_load_const_dec,
emit_bc_load_const_id,
emit_bc_load_const_str,
- emit_bc_load_const_verbatim_str,
+ emit_bc_load_null,
emit_bc_load_fast,
emit_bc_load_deref,
- emit_bc_load_closure,
emit_bc_load_name,
emit_bc_load_global,
emit_bc_load_attr,
@@ -901,7 +873,6 @@ const emit_method_table_t emit_bc_method_table = {
emit_bc_pop_jump_if_false,
emit_bc_jump_if_true_or_pop,
emit_bc_jump_if_false_or_pop,
- emit_bc_setup_loop,
emit_bc_unwind_jump,
emit_bc_unwind_jump,
emit_bc_setup_with,
@@ -936,3 +907,5 @@ const emit_method_table_t emit_bc_method_table = {
emit_bc_yield_value,
emit_bc_yield_from,
};
+
+#endif // !MICROPY_EMIT_CPYTHON
diff --git a/py/emitcpy.c b/py/emitcpy.c
index 119cf818cf..a041c4f1e0 100644
--- a/py/emitcpy.c
+++ b/py/emitcpy.c
@@ -221,11 +221,9 @@ STATIC void emit_cpy_load_const_str(emit_t *emit, qstr qstr, bool bytes) {
}
}
-STATIC void emit_cpy_load_const_verbatim_str(emit_t *emit, const char *str) {
- emit_pre(emit, 1, 3);
- if (emit->pass == PASS_3) {
- printf("LOAD_CONST %s\n", str);
- }
+STATIC void emit_cpy_load_null(emit_t *emit) {
+ // unused for cpy
+ assert(0);
}
STATIC void emit_cpy_load_fast(emit_t *emit, qstr qstr, uint id_flags, int local_num) {
@@ -242,13 +240,6 @@ STATIC void emit_cpy_load_deref(emit_t *emit, qstr qstr, int local_num) {
}
}
-STATIC void emit_cpy_load_closure(emit_t *emit, qstr qstr, int local_num) {
- emit_pre(emit, 1, 3);
- if (emit->pass == PASS_3) {
- printf("LOAD_CLOSURE %d %s\n", local_num, qstr_str(qstr));
- }
-}
-
STATIC void emit_cpy_load_name(emit_t *emit, qstr qstr) {
emit_pre(emit, 1, 3);
if (emit->pass == PASS_3) {
@@ -447,13 +438,6 @@ STATIC void emit_cpy_jump_if_false_or_pop(emit_t *emit, uint label) {
}
}
-STATIC void emit_cpy_setup_loop(emit_t *emit, uint label) {
- emit_pre(emit, 0, 3);
- if (emit->pass == PASS_3) {
- printf("SETUP_LOOP %d\n", emit->label_offsets[label]);
- }
-}
-
STATIC void emit_cpy_break_loop(emit_t *emit, uint label, int except_depth) {
emit_pre(emit, 0, 1);
if (emit->pass == PASS_3) {
@@ -764,7 +748,8 @@ STATIC void emit_cpy_make_function(emit_t *emit, scope_t *scope, uint n_pos_defa
}
}
-STATIC void emit_cpy_make_closure(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) {
+STATIC void emit_cpy_make_closure(emit_t *emit, scope_t *scope, uint n_closed_over, uint n_pos_defaults, uint n_kw_defaults) {
+ emit_cpy_build_tuple(emit, n_closed_over);
load_cpy_const_code_and_name(emit, scope->simple_name);
emit_pre(emit, -2 - n_pos_defaults - 2 * n_kw_defaults, 3);
if (emit->pass == PASS_3) {
@@ -792,6 +777,27 @@ STATIC void emit_cpy_yield_from(emit_t *emit) {
}
}
+STATIC void emit_cpy_load_const_verbatim_str(emit_t *emit, const char *str) {
+ emit_pre(emit, 1, 3);
+ if (emit->pass == PASS_3) {
+ printf("LOAD_CONST %s\n", str);
+ }
+}
+
+STATIC void emit_cpy_load_closure(emit_t *emit, qstr qstr, int local_num) {
+ emit_pre(emit, 1, 3);
+ if (emit->pass == PASS_3) {
+ printf("LOAD_CLOSURE %d %s\n", local_num, qstr_str(qstr));
+ }
+}
+
+STATIC void emit_cpy_setup_loop(emit_t *emit, uint label) {
+ emit_pre(emit, 0, 3);
+ if (emit->pass == PASS_3) {
+ printf("SETUP_LOOP %d\n", emit->label_offsets[label]);
+ }
+}
+
const emit_method_table_t emit_cpython_method_table = {
emit_cpy_set_native_types,
emit_cpy_start_pass,
@@ -814,10 +820,9 @@ const emit_method_table_t emit_cpython_method_table = {
emit_cpy_load_const_dec,
emit_cpy_load_const_id,
emit_cpy_load_const_str,
- emit_cpy_load_const_verbatim_str,
+ emit_cpy_load_null,
emit_cpy_load_fast,
emit_cpy_load_deref,
- emit_cpy_load_closure,
emit_cpy_load_name,
emit_cpy_load_global,
emit_cpy_load_attr,
@@ -846,7 +851,6 @@ const emit_method_table_t emit_cpython_method_table = {
emit_cpy_pop_jump_if_false,
emit_cpy_jump_if_true_or_pop,
emit_cpy_jump_if_false_or_pop,
- emit_cpy_setup_loop,
emit_cpy_break_loop,
emit_cpy_continue_loop,
emit_cpy_setup_with,
@@ -880,6 +884,11 @@ const emit_method_table_t emit_cpython_method_table = {
emit_cpy_raise_varargs,
emit_cpy_yield_value,
emit_cpy_yield_from,
+
+ // emitcpy specific functions
+ emit_cpy_load_const_verbatim_str,
+ emit_cpy_load_closure,
+ emit_cpy_setup_loop,
};
#endif // MICROPY_EMIT_CPYTHON
diff --git a/py/emitglue.c b/py/emitglue.c
index ce296f4321..8b1fd97021 100644
--- a/py/emitglue.c
+++ b/py/emitglue.c
@@ -158,10 +158,17 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
return fun;
}
-mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_obj_t closure_tuple, mp_obj_t def_args, mp_obj_t def_kw_args) {
- DEBUG_OP_printf("make_closure_from_raw_code %p\n", rc);
+mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args) {
+ DEBUG_OP_printf("make_closure_from_raw_code %p %u %p\n", rc, n_closed_over, argrs);
// make function object
- mp_obj_t ffun = mp_make_function_from_raw_code(rc, def_args, def_kw_args);
+ mp_obj_t ffun;
+ if (n_closed_over & 0x100) {
+ // default positional and keyword args given
+ ffun = mp_make_function_from_raw_code(rc, args[0], args[1]);
+ } else {
+ // default positional and keyword args not given
+ ffun = mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL);
+ }
// wrap function in closure object
- return mp_obj_new_closure(ffun, closure_tuple);
+ return mp_obj_new_closure(ffun, n_closed_over & 0xff, args + ((n_closed_over >> 7) & 2));
}
diff --git a/py/emitglue.h b/py/emitglue.h
index 2f9960bfa1..9aea2e4d45 100644
--- a/py/emitglue.h
+++ b/py/emitglue.h
@@ -37,4 +37,4 @@ void mp_emit_glue_assign_native_code(mp_raw_code_t *rc, void *f, uint len, int n
void mp_emit_glue_assign_inline_asm_code(mp_raw_code_t *rc, void *f, uint len, int n_args);
mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);
-mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_obj_t closure_tuple, mp_obj_t def_args, mp_obj_t def_kw_args);
+mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args);
diff --git a/py/emitnative.c b/py/emitnative.c
index d86456244a..79d6da67c1 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -695,9 +695,9 @@ STATIC void emit_native_load_const_str(emit_t *emit, qstr qstr, bool bytes) {
}
}
-STATIC void emit_native_load_const_verbatim_str(emit_t *emit, const char *str) {
- // not supported/needed for viper
- assert(0);
+STATIC void emit_native_load_null(emit_t *emit) {
+ emit_native_pre(emit);
+ emit_post_push_imm(emit, VTYPE_PYOBJ, 0);
}
STATIC void emit_native_load_fast(emit_t *emit, qstr qstr, uint id_flags, int local_num) {
@@ -735,11 +735,6 @@ STATIC void emit_native_load_deref(emit_t *emit, qstr qstr, int local_num) {
assert(0);
}
-STATIC void emit_native_load_closure(emit_t *emit, qstr qstr, int local_num) {
- // not implemented
- assert(0);
-}
-
STATIC void emit_native_load_name(emit_t *emit, qstr qstr) {
emit_native_pre(emit);
emit_call_with_imm_arg(emit, MP_F_LOAD_NAME, mp_load_name, qstr, REG_ARG_1);
@@ -985,11 +980,6 @@ STATIC void emit_native_jump_if_false_or_pop(emit_t *emit, uint label) {
assert(0);
}
-STATIC void emit_native_setup_loop(emit_t *emit, uint label) {
- emit_native_pre(emit);
- emit_post(emit);
-}
-
STATIC void emit_native_break_loop(emit_t *emit, uint label, int except_depth) {
emit_native_jump(emit, label); // TODO properly
}
@@ -1209,7 +1199,7 @@ STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, uint n_pos_d
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
}
-STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) {
+STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, uint n_closed_over, uint n_pos_defaults, uint n_kw_defaults) {
assert(0);
}
@@ -1334,10 +1324,9 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
emit_native_load_const_dec,
emit_native_load_const_id,
emit_native_load_const_str,
- emit_native_load_const_verbatim_str,
+ emit_native_load_null,
emit_native_load_fast,
emit_native_load_deref,
- emit_native_load_closure,
emit_native_load_name,
emit_native_load_global,
emit_native_load_attr,
@@ -1366,7 +1355,6 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
emit_native_pop_jump_if_false,
emit_native_jump_if_true_or_pop,
emit_native_jump_if_false_or_pop,
- emit_native_setup_loop,
emit_native_break_loop,
emit_native_continue_loop,
emit_native_setup_with,
diff --git a/py/emitpass1.c b/py/emitpass1.c
index ca34f220eb..64b58c4757 100644
--- a/py/emitpass1.c
+++ b/py/emitpass1.c
@@ -189,6 +189,9 @@ const emit_method_table_t emit_pass1_method_table = {
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
+#if MICROPY_EMIT_CPYTHON
+ (void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
+#endif
};
diff --git a/py/gc.c b/py/gc.c
index d39307464b..9a5f9d89bf 100644
--- a/py/gc.c
+++ b/py/gc.c
@@ -1,3 +1,4 @@
+#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
@@ -434,8 +435,14 @@ void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
if (n_bytes <= n_existing) {
return ptr;
} else {
- // TODO check if we can grow inplace
- void *ptr2 = gc_alloc(n_bytes);
+ // TODO false is incorrect! Should get value from current block!
+ void *ptr2 = gc_alloc(n_bytes,
+#if MICROPY_ENABLE_FINALISER
+ FTB_GET(BLOCK_FROM_PTR((machine_uint_t)ptr))
+#else
+ false
+#endif
+ );
if (ptr2 == NULL) {
return ptr2;
}
@@ -444,86 +451,101 @@ void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
return ptr2;
}
}
-#endif
+
+#else // Alternative gc_realloc impl
void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
if (gc_lock_depth > 0) {
return NULL;
}
- void *ptr_out = NULL;
- machine_uint_t block = 0;
- machine_uint_t ptr = (machine_uint_t)ptr_in;
-
+ // check for pure allocation
if (ptr_in == NULL) {
return gc_alloc(n_bytes, false);
}
- if (VERIFY_PTR(ptr) // verify pointer
- && (block = BLOCK_FROM_PTR(ptr)) // get first block
- && ATB_GET_KIND(block) == AT_HEAD) { // make sure it's a HEAD block
-
- byte block_type;
- machine_uint_t n_free = 0;
- machine_uint_t n_blocks = 1; // counting HEAD block
- machine_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
-
- // get the number of consecutive tail blocks and
- // the number of free blocks after last tail block
- // stop if we reach (or are at) end of heap
- while ((block + n_blocks + n_free) < max_block
- // stop as soon as we find enough blocks for n_bytes
- && (n_bytes > ((n_blocks+n_free) * BYTES_PER_BLOCK))
- // stop if block is HEAD
- && (block_type = ATB_GET_KIND(block + n_blocks + n_free)) != AT_HEAD) {
- switch (block_type) {
- case AT_FREE: n_free++; break;
- case AT_TAIL: n_blocks++; break;
- default: break;
- }
+ machine_uint_t ptr = (machine_uint_t)ptr_in;
+
+ // sanity check the ptr
+ if (!VERIFY_PTR(ptr)) {
+ return NULL;
+ }
+
+ // get first block
+ machine_uint_t block = BLOCK_FROM_PTR(ptr);
+
+ // sanity check the ptr is pointing to the head of a block
+ if (ATB_GET_KIND(block) != AT_HEAD) {
+ return NULL;
+ }
+
+ // compute number of new blocks that are requested
+ machine_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK;
+
+ // get the number of consecutive tail blocks and
+ // the number of free blocks after last tail block
+ // stop if we reach (or are at) end of heap
+ machine_uint_t n_free = 0;
+ machine_uint_t n_blocks = 1; // counting HEAD block
+ machine_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
+ while (block + n_blocks + n_free < max_block) {
+ if (n_blocks + n_free >= new_blocks) {
+ // stop as soon as we find enough blocks for n_bytes
+ break;
}
- // number of allocated bytes
- machine_uint_t n_existing = n_blocks * BYTES_PER_BLOCK;
-
- // check if realloc'ing to a smaller size
- if (n_bytes <= n_existing) {
- ptr_out = ptr_in;
- // free unneeded tail blocks
- for (machine_uint_t bl = block + n_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
- ATB_ANY_TO_FREE(bl);
- }
+ byte block_type = ATB_GET_KIND(block + n_blocks + n_free);
+ switch (block_type) {
+ case AT_FREE: n_free++; continue;
+ case AT_TAIL: n_blocks++; continue;
+ case AT_MARK: assert(0);
+ }
+ break;
+ }
- // check if we can expand in place
- } else if (n_bytes <= (n_existing + (n_free * BYTES_PER_BLOCK))) {
- // number of blocks needed to expand +1 if there's a remainder
- machine_uint_t n_diff = ( n_bytes - n_existing)/BYTES_PER_BLOCK+
- ((n_bytes - n_existing)%BYTES_PER_BLOCK!=0);
+ // return original ptr if it already has the requested number of blocks
+ if (new_blocks == n_blocks) {
+ return ptr_in;
+ }
- DEBUG_printf("gc_realloc: expanding " UINT_FMT " blocks (" UINT_FMT " bytes) to " UINT_FMT " blocks (" UINT_FMT " bytes)\n",
- n_existing/BYTES_PER_BLOCK, n_existing, n_existing/BYTES_PER_BLOCK+n_diff, n_existing + n_diff*BYTES_PER_BLOCK);
+ // check if we can shrink the allocated area
+ if (new_blocks < n_blocks) {
+ // free unneeded tail blocks
+ for (machine_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
+ ATB_ANY_TO_FREE(bl);
+ }
+ return ptr_in;
+ }
- // mark rest of blocks as used tail
- for (machine_uint_t bl = block + n_blocks; bl < (block + n_blocks + n_diff); bl++) {
- ATB_FREE_TO_TAIL(bl);
- }
- ptr_out = ptr_in;
+ // check if we can expand in place
+ if (new_blocks <= n_blocks + n_free) {
+ // mark few more blocks as used tail
+ for (machine_uint_t bl = block + n_blocks; bl < block + new_blocks; bl++) {
+ assert(ATB_GET_KIND(bl) == AT_FREE);
+ ATB_FREE_TO_TAIL(bl);
+ }
+ return ptr_in;
+ }
- // try to find a new contiguous chain
- } else if ((ptr_out = gc_alloc(n_bytes,
+ // can't resize inplace; try to find a new contiguous chain
+ void *ptr_out = gc_alloc(n_bytes,
#if MICROPY_ENABLE_FINALISER
- FTB_GET(block)
+ FTB_GET(block)
#else
- false
+ false
#endif
- )) != NULL) {
- DEBUG_printf("gc_realloc: allocating new block\n");
- memcpy(ptr_out, ptr_in, n_existing);
- gc_free(ptr_in);
- }
+ );
+
+ // check that the alloc succeeded
+ if (ptr_out == NULL) {
+ return NULL;
}
+ DEBUG_printf("gc_realloc: allocating new block\n");
+ memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK);
+ gc_free(ptr_in);
return ptr_out;
}
+#endif // Alternative gc_realloc impl
void gc_dump_info() {
gc_info_t info;
diff --git a/py/nlrx86.S b/py/nlrx86.S
index 003de5095f..145bdb9da0 100644
--- a/py/nlrx86.S
+++ b/py/nlrx86.S
@@ -61,7 +61,11 @@ nlr_jump:
#endif
mov nlr_top, %edx # load nlr_top
test %edx, %edx # check for nlr_top being NULL
+#ifdef _WIN32
+ je _nlr_jump_fail # fail if nlr_top is NULL
+#else
je nlr_jump_fail # fail if nlr_top is NULL
+#endif
mov 4(%esp), %eax # load return value
mov %eax, 4(%edx) # store return value
mov (%edx), %eax # load prev nlr_top
diff --git a/py/obj.h b/py/obj.h
index 44d9bf6a6d..d62d376ab4 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -357,7 +357,7 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_args, mp_obj_t def_args, const byte *code);
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun);
mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);
-mp_obj_t mp_obj_new_closure(mp_obj_t fun, mp_obj_t closure_tuple);
+mp_obj_t mp_obj_new_closure(mp_obj_t fun, uint n_closed, const mp_obj_t *closed);
mp_obj_t mp_obj_new_tuple(uint n, const mp_obj_t *items);
mp_obj_t mp_obj_new_list(uint n, mp_obj_t *items);
mp_obj_t mp_obj_new_dict(int n_args);
diff --git a/py/objarray.c b/py/objarray.c
index b7a84ba4cf..ce107ddf25 100644
--- a/py/objarray.c
+++ b/py/objarray.c
@@ -136,10 +136,18 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
if (value == MP_OBJ_NULL) {
// delete item
// TODO implement
+ // TODO: confirmed that both bytearray and array.array support
+ // slice deletion
return MP_OBJ_NOT_SUPPORTED;
} else {
mp_obj_array_t *o = self_in;
if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) {
+ if (value != MP_OBJ_SENTINEL) {
+ // Only getting a slice is suported so far, not assignment
+ // TODO: confirmed that both bytearray and array.array support
+ // slice assignment (incl. of different size)
+ return MP_OBJ_NOT_SUPPORTED;
+ }
machine_uint_t start, stop;
if (!m_seq_get_fast_slice_indexes(o->len, index_in, &start, &stop)) {
assert(0);
diff --git a/py/objcell.c b/py/objcell.c
index d8517587df..7fdf07b046 100644
--- a/py/objcell.c
+++ b/py/objcell.c
@@ -20,9 +20,24 @@ void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj) {
self->obj = obj;
}
+#if 0
+STATIC void cell_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
+ mp_obj_cell_t *o = o_in;
+ print(env, "<cell ");
+ if (o->obj == MP_OBJ_NULL) {
+ print(env, "(nil)");
+ } else {
+ //print(env, "%p", o->obj);
+ mp_obj_print_helper(print, env, o->obj, PRINT_REPR);
+ }
+ print(env, ">");
+}
+#endif
+
const mp_obj_type_t cell_type = {
{ &mp_type_type },
.name = MP_QSTR_, // should never need to print cell type
+ //.print = cell_print,
};
mp_obj_t mp_obj_new_cell(mp_obj_t obj) {
diff --git a/py/objclosure.c b/py/objclosure.c
index 9b4a3f8933..09371b0348 100644
--- a/py/objclosure.c
+++ b/py/objclosure.c
@@ -5,13 +5,14 @@
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
+#include "objtuple.h"
#include "runtime.h"
typedef struct _mp_obj_closure_t {
mp_obj_base_t base;
mp_obj_t fun;
- uint n_closed;
- mp_obj_t *closed;
+ machine_uint_t n_closed;
+ mp_obj_t closed[];
} mp_obj_closure_t;
mp_obj_t closure_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
@@ -37,16 +38,34 @@ mp_obj_t closure_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *
}
}
+#if 0
+STATIC void closure_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
+ mp_obj_closure_t *o = o_in;
+ print(env, "<closure %p, n_closed=%u ", o, o->n_closed);
+ for (int i = 0; i < o->n_closed; i++) {
+ if (o->closed[i] == MP_OBJ_NULL) {
+ print(env, "(nil)");
+ } else {
+ mp_obj_print_helper(print, env, o->closed[i], PRINT_REPR);
+ }
+ print(env, " ");
+ }
+ print(env, ">");
+}
+#endif
+
const mp_obj_type_t closure_type = {
{ &mp_type_type },
.name = MP_QSTR_closure,
+ //.print = closure_print,
.call = closure_call,
};
-mp_obj_t mp_obj_new_closure(mp_obj_t fun, mp_obj_t closure_tuple) {
- mp_obj_closure_t *o = m_new_obj(mp_obj_closure_t);
+mp_obj_t mp_obj_new_closure(mp_obj_t fun, uint n_closed_over, const mp_obj_t *closed) {
+ mp_obj_closure_t *o = m_new_obj_var(mp_obj_closure_t, mp_obj_t, n_closed_over);
o->base.type = &closure_type;
o->fun = fun;
- mp_obj_tuple_get(closure_tuple, &o->n_closed, &o->closed);
+ o->n_closed = n_closed_over;
+ memcpy(o->closed, closed, n_closed_over * sizeof(mp_obj_t));
return o;
}
diff --git a/py/objfun.c b/py/objfun.c
index c7144f3078..940b64a66e 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -2,6 +2,10 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
+#ifdef __MINGW32__
+// For alloca()
+#include <malloc.h>
+#endif
#include "nlr.h"
#include "misc.h"
diff --git a/py/showbc.c b/py/showbc.c
index bf25966e97..4a8e12e68b 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -287,11 +287,6 @@ void mp_byte_code_print(const byte *ip, int len) {
printf("JUMP_IF_FALSE_OR_POP " UINT_FMT, ip + unum - ip_start);
break;
- case MP_BC_SETUP_LOOP:
- DECODE_ULABEL; // loop labels are always forward
- printf("SETUP_LOOP " UINT_FMT, ip + unum - ip_start);
- break;
-
case MP_BC_SETUP_WITH:
DECODE_ULABEL; // loop-like labels are always forward
printf("SETUP_WITH " UINT_FMT, ip + unum - ip_start);
diff --git a/py/vm.c b/py/vm.c
index c8e4ba9f48..b1c1719b72 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -481,13 +481,6 @@ dispatch_loop:
}
DISPATCH();
- /* we are trying to get away without using this opcode
- ENTRY(MP_BC_SETUP_LOOP):
- DECODE_UINT;
- // push_block(MP_BC_SETUP_LOOP, ip + unum, sp)
- DISPATCH();
- */
-
ENTRY(MP_BC_SETUP_WITH):
obj1 = TOP();
SET_TOP(mp_load_attr(obj1, MP_QSTR___exit__));
@@ -759,19 +752,23 @@ unwind_jump:
SET_TOP(mp_make_function_from_raw_code((mp_raw_code_t*)unum, TOP(), obj1));
DISPATCH();
- ENTRY(MP_BC_MAKE_CLOSURE):
+ ENTRY(MP_BC_MAKE_CLOSURE): {
DECODE_PTR;
- // Stack layout: closure_tuple <- TOS
- SET_TOP(mp_make_closure_from_raw_code((mp_raw_code_t*)unum, TOP(), MP_OBJ_NULL, MP_OBJ_NULL));
+ machine_uint_t n_closed_over = *ip++;
+ // Stack layout: closed_overs <- TOS
+ sp -= n_closed_over - 1;
+ SET_TOP(mp_make_closure_from_raw_code((mp_raw_code_t*)unum, n_closed_over, sp));
DISPATCH();
+ }
- ENTRY(MP_BC_MAKE_CLOSURE_DEFARGS):
+ ENTRY(MP_BC_MAKE_CLOSURE_DEFARGS): {
DECODE_PTR;
- // Stack layout: def_tuple def_dict closure_tuple <- TOS
- obj1 = POP();
- obj2 = POP();
- SET_TOP(mp_make_closure_from_raw_code((mp_raw_code_t*)unum, obj1, TOP(), obj2));
+ machine_uint_t n_closed_over = *ip++;
+ // Stack layout: def_tuple def_dict closed_overs <- TOS
+ sp -= 2 + n_closed_over - 1;
+ SET_TOP(mp_make_closure_from_raw_code((mp_raw_code_t*)unum, 0x100 | n_closed_over, sp));
DISPATCH();
+ }
ENTRY(MP_BC_CALL_FUNCTION):
DECODE_UINT;
diff --git a/py/vmentrytable.h b/py/vmentrytable.h
index 2e1d1fb04f..c4d15427d7 100644
--- a/py/vmentrytable.h
+++ b/py/vmentrytable.h
@@ -45,7 +45,6 @@ static void* entry_table[256] = {
[MP_BC_POP_JUMP_IF_FALSE] = &&entry_MP_BC_POP_JUMP_IF_FALSE,
[MP_BC_JUMP_IF_TRUE_OR_POP] = &&entry_MP_BC_JUMP_IF_TRUE_OR_POP,
[MP_BC_JUMP_IF_FALSE_OR_POP] = &&entry_MP_BC_JUMP_IF_FALSE_OR_POP,
-// [MP_BC_SETUP_LOOP] = &&entry_MP_BC_SETUP_LOOP,
[MP_BC_SETUP_WITH] = &&entry_MP_BC_SETUP_WITH,
[MP_BC_WITH_CLEANUP] = &&entry_MP_BC_WITH_CLEANUP,
[MP_BC_UNWIND_JUMP] = &&entry_MP_BC_UNWIND_JUMP,
diff --git a/stmhal/Makefile b/stmhal/Makefile
index 3cd51c0166..c4c7f7bfc1 100644
--- a/stmhal/Makefile
+++ b/stmhal/Makefile
@@ -97,6 +97,7 @@ SRC_C = \
servo.c \
dac.c \
adc.c \
+ bufhelper.c \
i2c.c \
spi.c \
diff --git a/stmhal/accel.c b/stmhal/accel.c
index 339a93ea40..9890aa3c7f 100644
--- a/stmhal/accel.c
+++ b/stmhal/accel.c
@@ -12,6 +12,8 @@
#include "i2c.h"
#include "accel.h"
+#if MICROPY_HW_HAS_MMA7660
+
#define MMA_ADDR (0x98)
#define MMA_REG_X (0)
#define MMA_REG_Y (1)
@@ -33,7 +35,15 @@ void accel_init(void) {
}
STATIC void accel_start(void) {
- // start the I2C bus
+ // start the I2C bus in master mode
+ I2CHandle1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
+ I2CHandle1.Init.ClockSpeed = 400000;
+ I2CHandle1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
+ I2CHandle1.Init.DutyCycle = I2C_DUTYCYCLE_16_9;
+ I2CHandle1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
+ I2CHandle1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED;
+ I2CHandle1.Init.OwnAddress1 = PYB_I2C_MASTER_ADDRESS;
+ I2CHandle1.Init.OwnAddress2 = 0xfe; // unused
i2c_init(&I2CHandle1);
// turn off AVDD, wait 20ms, turn on AVDD, wait 20ms again
@@ -174,3 +184,5 @@ const mp_obj_type_t pyb_accel_type = {
.make_new = pyb_accel_make_new,
.locals_dict = (mp_obj_t)&pyb_accel_locals_dict,
};
+
+#endif // MICROPY_HW_HAS_MMA7660
diff --git a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h
index a01d37aea8..b70b56d9ce 100644
--- a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h
+++ b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h
@@ -17,6 +17,9 @@
#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (1)
#define MICROPY_HW_ENABLE_DAC (0)
+#define MICROPY_HW_ENABLE_I2C1 (0)
+#define MICROPY_HW_ENABLE_SPI1 (0)
+#define MICROPY_HW_ENABLE_SPI3 (0)
// USRSW is pulled low. Pressing the button makes the input go high.
#define MICROPY_HW_USRSW_PIN (pin_B11)
diff --git a/stmhal/boards/PYBV10/mpconfigboard.h b/stmhal/boards/PYBV10/mpconfigboard.h
index 9386c04a2d..00c6a1acfc 100644
--- a/stmhal/boards/PYBV10/mpconfigboard.h
+++ b/stmhal/boards/PYBV10/mpconfigboard.h
@@ -13,6 +13,9 @@
#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (1)
#define MICROPY_HW_ENABLE_DAC (1)
+#define MICROPY_HW_ENABLE_I2C1 (1)
+#define MICROPY_HW_ENABLE_SPI1 (1)
+#define MICROPY_HW_ENABLE_SPI3 (0)
// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
#define MICROPY_HW_USRSW_PIN (pin_B3)
diff --git a/stmhal/boards/PYBV3/mpconfigboard.h b/stmhal/boards/PYBV3/mpconfigboard.h
index f47a01bc4c..02ad78a64c 100644
--- a/stmhal/boards/PYBV3/mpconfigboard.h
+++ b/stmhal/boards/PYBV3/mpconfigboard.h
@@ -13,6 +13,9 @@
#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (1)
#define MICROPY_HW_ENABLE_DAC (0)
+#define MICROPY_HW_ENABLE_I2C1 (1)
+#define MICROPY_HW_ENABLE_SPI1 (1)
+#define MICROPY_HW_ENABLE_SPI3 (0)
// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
#define MICROPY_HW_USRSW_PIN (pin_A13)
diff --git a/stmhal/boards/PYBV4/mpconfigboard.h b/stmhal/boards/PYBV4/mpconfigboard.h
index 1846491c3a..550f1633f9 100644
--- a/stmhal/boards/PYBV4/mpconfigboard.h
+++ b/stmhal/boards/PYBV4/mpconfigboard.h
@@ -13,6 +13,9 @@
#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (1)
#define MICROPY_HW_ENABLE_DAC (1)
+#define MICROPY_HW_ENABLE_I2C1 (1)
+#define MICROPY_HW_ENABLE_SPI1 (1)
+#define MICROPY_HW_ENABLE_SPI3 (0)
// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
#define MICROPY_HW_USRSW_PIN (pin_B3)
@@ -20,7 +23,7 @@
#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING)
#define MICROPY_HW_USRSW_PRESSED (0)
-// LEDs
+// The pyboard has 4 LEDs
#define MICROPY_HW_LED1 (pin_A13) // red
#define MICROPY_HW_LED2 (pin_A14) // green
#define MICROPY_HW_LED3 (pin_A15) // yellow
diff --git a/stmhal/boards/STM32F4DISC/mpconfigboard.h b/stmhal/boards/STM32F4DISC/mpconfigboard.h
index 3bfdfbfb80..c83bb162bb 100644
--- a/stmhal/boards/STM32F4DISC/mpconfigboard.h
+++ b/stmhal/boards/STM32F4DISC/mpconfigboard.h
@@ -13,6 +13,9 @@
#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (0)
#define MICROPY_HW_ENABLE_DAC (0)
+#define MICROPY_HW_ENABLE_I2C1 (1)
+#define MICROPY_HW_ENABLE_SPI1 (1)
+#define MICROPY_HW_ENABLE_SPI3 (0)
// USRSW is pulled low. Pressing the button makes the input go high.
#define MICROPY_HW_USRSW_PIN (pin_A0)
diff --git a/stmhal/bufhelper.c b/stmhal/bufhelper.c
new file mode 100644
index 0000000000..5612a048dc
--- /dev/null
+++ b/stmhal/bufhelper.c
@@ -0,0 +1,29 @@
+#include "misc.h"
+#include "mpconfig.h"
+#include "qstr.h"
+#include "obj.h"
+#include "bufhelper.h"
+
+void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, uint8_t *tmp_data) {
+ if (MP_OBJ_IS_INT(o)) {
+ tmp_data[0] = mp_obj_get_int(o);
+ bufinfo->buf = tmp_data;
+ bufinfo->len = 1;
+ bufinfo->typecode = 'B';
+ } else {
+ mp_get_buffer_raise(o, bufinfo, MP_BUFFER_READ);
+ }
+}
+
+mp_obj_t pyb_buf_get_for_recv(mp_obj_t o, mp_buffer_info_t *bufinfo) {
+ if (MP_OBJ_IS_INT(o)) {
+ // allocate a new bytearray of given length
+ bufinfo->len = mp_obj_get_int(o);
+ bufinfo->typecode = 'B';
+ return mp_obj_str_builder_start(&mp_type_bytes, bufinfo->len, (byte**)&bufinfo->buf);
+ } else {
+ // get the existing buffer
+ mp_get_buffer_raise(o, bufinfo, MP_BUFFER_WRITE);
+ return MP_OBJ_NULL;
+ }
+}
diff --git a/stmhal/bufhelper.h b/stmhal/bufhelper.h
new file mode 100644
index 0000000000..9b58e817c8
--- /dev/null
+++ b/stmhal/bufhelper.h
@@ -0,0 +1,2 @@
+void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, uint8_t *tmp_data);
+mp_obj_t pyb_buf_get_for_recv(mp_obj_t o, mp_buffer_info_t *bufinfo);
diff --git a/stmhal/i2c.c b/stmhal/i2c.c
index 8a8dd7dc2d..d94a99ee9e 100644
--- a/stmhal/i2c.c
+++ b/stmhal/i2c.c
@@ -11,15 +11,23 @@
#include "runtime.h"
#include "pin.h"
#include "genhdr/pins.h"
+#include "bufhelper.h"
#include "i2c.h"
+#define PYB_I2C_MASTER (0)
+#define PYB_I2C_SLAVE (1)
+
+#if MICROPY_HW_ENABLE_I2C1
I2C_HandleTypeDef I2CHandle1 = {.Instance = NULL};
+#endif
I2C_HandleTypeDef I2CHandle2 = {.Instance = NULL};
void i2c_init0(void) {
// reset the I2C1 handles
+#if MICROPY_HW_ENABLE_I2C1
memset(&I2CHandle1, 0, sizeof(I2C_HandleTypeDef));
I2CHandle1.Instance = I2C1;
+#endif
memset(&I2CHandle2, 0, sizeof(I2C_HandleTypeDef));
I2CHandle2.Instance = I2C2;
}
@@ -32,20 +40,26 @@ void i2c_init(I2C_HandleTypeDef *i2c) {
GPIO_InitStructure.Pull = GPIO_NOPULL; // have external pull-up resistors on both lines
const pin_obj_t *pins[2];
- if (i2c == &I2CHandle1) {
+ if (0) {
+#if MICROPY_HW_ENABLE_I2C1
+ } else if (i2c == &I2CHandle1) {
// X-skin: X9=PB6=SCL, X10=PB7=SDA
pins[0] = &pin_B6;
pins[1] = &pin_B7;
GPIO_InitStructure.Alternate = GPIO_AF4_I2C1;
// enable the I2C clock
__I2C1_CLK_ENABLE();
- } else {
+#endif
+ } else if (i2c == &I2CHandle2) {
// Y-skin: Y9=PB10=SCL, Y10=PB11=SDA
pins[0] = &pin_B10;
pins[1] = &pin_B11;
GPIO_InitStructure.Alternate = GPIO_AF4_I2C2;
// enable the I2C clock
__I2C2_CLK_ENABLE();
+ } else {
+ // I2C does not exist for this board (shouldn't get here, should be checked by caller)
+ return;
}
// init the GPIO lines
@@ -54,66 +68,152 @@ void i2c_init(I2C_HandleTypeDef *i2c) {
HAL_GPIO_Init(pins[i]->gpio, &GPIO_InitStructure);
}
- // enable the I2C clock
- if (i2c == &I2CHandle1) {
- __I2C1_CLK_ENABLE();
- } else {
- __I2C2_CLK_ENABLE();
- }
-
// init the I2C device
- i2c->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
- i2c->Init.ClockSpeed = 400000;
- i2c->Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
- i2c->Init.DutyCycle = I2C_DUTYCYCLE_16_9;
- i2c->Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
- i2c->Init.NoStretchMode = I2C_NOSTRETCH_DISABLED;
- i2c->Init.OwnAddress1 = 0xfe; // unused
- i2c->Init.OwnAddress2 = 0xfe; // unused
-
if (HAL_I2C_Init(i2c) != HAL_OK) {
// init error
+ // TODO should raise an exception, but this function is not necessarily going to be
+ // called via Python, so may not be properly wrapped in an NLR handler
printf("HardwareError: HAL_I2C_Init failed\n");
return;
}
}
+void i2c_deinit(I2C_HandleTypeDef *i2c) {
+ HAL_I2C_DeInit(i2c);
+ if (0) {
+#if MICROPY_HW_ENABLE_I2C1
+ } else if (i2c->Instance == I2C1) {
+ __I2C1_FORCE_RESET();
+ __I2C1_RELEASE_RESET();
+ __I2C1_CLK_DISABLE();
+#endif
+ } else if (i2c->Instance == I2C2) {
+ __I2C2_FORCE_RESET();
+ __I2C2_RELEASE_RESET();
+ __I2C2_CLK_DISABLE();
+ }
+}
+
/******************************************************************************/
/* Micro Python bindings */
-#define PYB_NUM_I2C (2)
-
typedef struct _pyb_i2c_obj_t {
mp_obj_base_t base;
I2C_HandleTypeDef *i2c;
} pyb_i2c_obj_t;
-STATIC const pyb_i2c_obj_t pyb_i2c_obj[PYB_NUM_I2C] = {{{&pyb_i2c_type}, &I2CHandle1}, {{&pyb_i2c_type}, &I2CHandle2}};
+STATIC inline bool in_master_mode(pyb_i2c_obj_t *self) { return self->i2c->Init.OwnAddress1 == PYB_I2C_MASTER_ADDRESS; }
+
+STATIC const pyb_i2c_obj_t pyb_i2c_obj[] = {
+#if MICROPY_HW_ENABLE_I2C1
+ {{&pyb_i2c_type}, &I2CHandle1},
+#else
+ {{&pyb_i2c_type}, NULL},
+#endif
+ {{&pyb_i2c_type}, &I2CHandle2}
+};
+#define PYB_NUM_I2C (sizeof(pyb_i2c_obj) / sizeof(pyb_i2c_obj[0]))
+
+STATIC void pyb_i2c_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+ pyb_i2c_obj_t *self = self_in;
+
+ uint i2c_num;
+ if (self->i2c->Instance == I2C1) { i2c_num = 1; }
+ else { i2c_num = 2; }
+
+ if (self->i2c->State == HAL_I2C_STATE_RESET) {
+ print(env, "I2C(%u)", i2c_num);
+ } else {
+ if (in_master_mode(self)) {
+ print(env, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, self->i2c->Init.ClockSpeed);
+ } else {
+ print(env, "I2C(%u, I2C.SLAVE, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f);
+ }
+ }
+}
+
+STATIC const mp_arg_parse_t pyb_i2c_init_accepted_args[] = {
+ { MP_QSTR_mode, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_INT, {.u_int = 0} },
+ { MP_QSTR_addr, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 0x12} },
+ { MP_QSTR_baudrate, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 400000} },
+ { MP_QSTR_gencall, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_BOOL, {.u_bool = false} },
+};
+#define PYB_I2C_INIT_NUM_ARGS (sizeof(pyb_i2c_init_accepted_args) / sizeof(pyb_i2c_init_accepted_args[0]))
+
+STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ // parse args
+ mp_arg_parse_val_t vals[PYB_I2C_INIT_NUM_ARGS];
+ mp_arg_parse_all(n_args, args, kw_args, PYB_I2C_INIT_NUM_ARGS, pyb_i2c_init_accepted_args, vals);
+
+ // set the I2C configuration values
+ I2C_InitTypeDef *init = &self->i2c->Init;
+
+ if (vals[0].u_int == PYB_I2C_MASTER) {
+ // use a special address to indicate we are a master
+ init->OwnAddress1 = PYB_I2C_MASTER_ADDRESS;
+ } else {
+ init->OwnAddress1 = (vals[1].u_int << 1) & 0xfe;
+ }
+
+ init->AddressingMode = I2C_ADDRESSINGMODE_7BIT;
+ init->ClockSpeed = MIN(vals[2].u_int, 400000);
+ init->DualAddressMode = I2C_DUALADDRESS_DISABLED;
+ init->DutyCycle = I2C_DUTYCYCLE_16_9;
+ init->GeneralCallMode = vals[3].u_bool ? I2C_GENERALCALL_ENABLED : I2C_GENERALCALL_DISABLED;
+ init->NoStretchMode = I2C_NOSTRETCH_DISABLED;
+ init->OwnAddress2 = 0xfe; // unused
+
+ // init the I2C bus
+ i2c_init(self->i2c);
+
+ return mp_const_none;
+}
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
- mp_arg_check_num(n_args, n_kw, 1, 1, false);
+ mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
// 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)) {
+ if (!(0 <= i2c_id && i2c_id < PYB_NUM_I2C && pyb_i2c_obj[i2c_id].i2c != NULL)) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "I2C bus %d does not exist", i2c_id + 1));
}
- // get i2c object
+ // get I2C object
const pyb_i2c_obj_t *i2c_obj = &pyb_i2c_obj[i2c_id];
- // start the peripheral
- i2c_init(i2c_obj->i2c);
+ if (n_args > 1 || n_kw > 0) {
+ // start the peripheral
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+ pyb_i2c_init_helper(i2c_obj, n_args - 1, args + 1, &kw_args);
+ }
return (mp_obj_t)i2c_obj;
}
+STATIC mp_obj_t pyb_i2c_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ return pyb_i2c_init_helper(args[0], n_args - 1, args + 1, kw_args);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_init);
+
+STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) {
+ pyb_i2c_obj_t *self = self_in;
+ i2c_deinit(self->i2c);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_deinit_obj, pyb_i2c_deinit);
+
// Check if an I2C device responds to the given address.
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;
+
+ if (!in_master_mode(self)) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "I2C must be a master"));
+ }
+
machine_uint_t i2c_addr = mp_obj_get_int(i2c_addr_o) << 1;
for (int i = 0; i < 10; i++) {
@@ -125,13 +225,16 @@ STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) {
return mp_const_false;
}
-
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_i2c_is_ready_obj, pyb_i2c_is_ready);
// Scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond.
STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) {
pyb_i2c_obj_t *self = self_in;
+ if (!in_master_mode(self)) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "I2C must be a master"));
+ }
+
mp_obj_t list = mp_obj_new_list(0, NULL);
for (uint addr = 1; addr <= 127; addr++) {
@@ -146,88 +249,156 @@ STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) {
return list;
}
-
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_scan_obj, pyb_i2c_scan);
-STATIC mp_obj_t pyb_i2c_read(mp_obj_t self_in, mp_obj_t i2c_addr_in, mp_obj_t n_in) {
- pyb_i2c_obj_t *self = self_in;
- machine_uint_t i2c_addr = mp_obj_get_int(i2c_addr_in) << 1;
- machine_uint_t n = mp_obj_get_int(n_in);
+STATIC const mp_arg_parse_t pyb_i2c_send_accepted_args[] = {
+ { MP_QSTR_send, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_addr, MP_ARG_PARSE_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} },
+ { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} },
+};
+#define PYB_I2C_SEND_NUM_ARGS (sizeof(pyb_i2c_send_accepted_args) / sizeof(pyb_i2c_send_accepted_args[0]))
+
+STATIC mp_obj_t pyb_i2c_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ pyb_i2c_obj_t *self = args[0];
+
+ // parse args
+ mp_arg_parse_val_t vals[PYB_I2C_SEND_NUM_ARGS];
+ mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_I2C_SEND_NUM_ARGS, pyb_i2c_send_accepted_args, vals);
- byte *data;
- mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, n, &data);
- HAL_StatusTypeDef status = HAL_I2C_Master_Receive(self->i2c, i2c_addr, data, n, 500);
+ // get the buffer to send from
+ mp_buffer_info_t bufinfo;
+ uint8_t data[1];
+ pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data);
+
+ // send the data
+ HAL_StatusTypeDef status;
+ if (in_master_mode(self)) {
+ if (vals[1].u_int == PYB_I2C_MASTER_ADDRESS) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "addr argument required"));
+ }
+ machine_uint_t i2c_addr = vals[1].u_int << 1;
+ status = HAL_I2C_Master_Transmit(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len, vals[2].u_int);
+ } else {
+ status = HAL_I2C_Slave_Transmit(self->i2c, bufinfo.buf, bufinfo.len, vals[2].u_int);
+ }
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Master_Receive failed with code %d", status));
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_xxx_Transmit failed with code %d", status));
}
- return mp_obj_str_builder_end(o);
+ return mp_const_none;
}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_send_obj, 1, pyb_i2c_send);
-STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_i2c_read_obj, pyb_i2c_read);
+STATIC const mp_arg_parse_t pyb_i2c_recv_accepted_args[] = {
+ { MP_QSTR_recv, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_addr, MP_ARG_PARSE_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} },
+ { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} },
+};
+#define PYB_I2C_RECV_NUM_ARGS (sizeof(pyb_i2c_recv_accepted_args) / sizeof(pyb_i2c_recv_accepted_args[0]))
-STATIC mp_obj_t pyb_i2c_write(mp_obj_t self_in, mp_obj_t i2c_addr_in, mp_obj_t data_in) {
- pyb_i2c_obj_t *self = self_in;
- machine_uint_t i2c_addr = mp_obj_get_int(i2c_addr_in) << 1;
+STATIC mp_obj_t pyb_i2c_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ pyb_i2c_obj_t *self = args[0];
+
+ // parse args
+ mp_arg_parse_val_t vals[PYB_I2C_RECV_NUM_ARGS];
+ mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_I2C_RECV_NUM_ARGS, pyb_i2c_recv_accepted_args, vals);
+
+ // get the buffer to receive into
+ mp_buffer_info_t bufinfo;
+ mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &bufinfo);
+
+ // receive the data
HAL_StatusTypeDef status;
- if (MP_OBJ_IS_INT(data_in)) {
- uint8_t data[1] = {mp_obj_get_int(data_in)};
- status = HAL_I2C_Master_Transmit(self->i2c, i2c_addr, data, 1, 500);
+ if (in_master_mode(self)) {
+ if (vals[1].u_int == PYB_I2C_MASTER_ADDRESS) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "addr argument required"));
+ }
+ machine_uint_t i2c_addr = vals[1].u_int << 1;
+ status = HAL_I2C_Master_Receive(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len, vals[2].u_int);
} else {
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
- status = HAL_I2C_Master_Transmit(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len, 500);
+ status = HAL_I2C_Slave_Receive(self->i2c, bufinfo.buf, bufinfo.len, vals[2].u_int);
}
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Master_Transmit failed with code %d", status));
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_xxx_Receive failed with code %d", status));
}
- return mp_const_none;
+ // return the received data
+ if (o_ret == MP_OBJ_NULL) {
+ return vals[0].u_obj;
+ } else {
+ return mp_obj_str_builder_end(o_ret);
+ }
}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_recv_obj, 1, pyb_i2c_recv);
-STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_i2c_write_obj, pyb_i2c_write);
+STATIC const mp_arg_parse_t pyb_i2c_mem_read_accepted_args[] = {
+ { MP_QSTR_data, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_addr, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_INT, {.u_int = 0} },
+ { MP_QSTR_memaddr, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_INT, {.u_int = 0} },
+ { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} },
+};
+#define PYB_I2C_MEM_READ_NUM_ARGS (sizeof(pyb_i2c_mem_read_accepted_args) / sizeof(pyb_i2c_mem_read_accepted_args[0]))
-STATIC mp_obj_t pyb_i2c_mem_read(uint n_args, const mp_obj_t *args) {
+STATIC mp_obj_t pyb_i2c_mem_read(uint n_args, const mp_obj_t *args, mp_map_t *kw_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(&mp_type_bytes, n, &data);
- HAL_StatusTypeDef status = HAL_I2C_Mem_Read(self->i2c, i2c_addr, mem_addr, I2C_MEMADD_SIZE_8BIT, data, n, 200);
+ if (!in_master_mode(self)) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "I2C must be a master"));
+ }
+
+ // parse args
+ mp_arg_parse_val_t vals[PYB_I2C_MEM_READ_NUM_ARGS];
+ mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_I2C_MEM_READ_NUM_ARGS, pyb_i2c_mem_read_accepted_args, vals);
+
+ // get the buffer to read into
+ mp_buffer_info_t bufinfo;
+ mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &bufinfo);
- //printf("Read got %d\n", status);
+ // get the addresses
+ machine_uint_t i2c_addr = vals[1].u_int << 1;
+ machine_uint_t mem_addr = vals[2].u_int;
+
+ HAL_StatusTypeDef status = HAL_I2C_Mem_Read(self->i2c, i2c_addr, mem_addr, I2C_MEMADD_SIZE_8BIT, bufinfo.buf, bufinfo.len, vals[3].u_int);
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
nlr_raise(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);
+ // return the read data
+ if (o_ret == MP_OBJ_NULL) {
+ return vals[0].u_obj;
+ } else {
+ return mp_obj_str_builder_end(o_ret);
+ }
}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_read_obj, 1, pyb_i2c_mem_read);
-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) {
+STATIC mp_obj_t pyb_i2c_mem_write(uint n_args, const mp_obj_t *args, mp_map_t *kw_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;
- if (MP_OBJ_IS_INT(args[3])) {
- uint8_t data[1] = {mp_obj_get_int(args[3])};
- status = HAL_I2C_Mem_Write(self->i2c, i2c_addr, mem_addr, I2C_MEMADD_SIZE_8BIT, data, 1, 200);
- } else {
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
- status = HAL_I2C_Mem_Write(self->i2c, i2c_addr, mem_addr, I2C_MEMADD_SIZE_8BIT, bufinfo.buf, bufinfo.len, 200);
+
+ if (!in_master_mode(self)) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "I2C must be a master"));
}
- //printf("Write got %d\n", status);
+ // parse args (same as mem_read)
+ mp_arg_parse_val_t vals[PYB_I2C_MEM_READ_NUM_ARGS];
+ mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_I2C_MEM_READ_NUM_ARGS, pyb_i2c_mem_read_accepted_args, vals);
+
+ // get the buffer to write from
+ mp_buffer_info_t bufinfo;
+ uint8_t data[1];
+ pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data);
+
+ // get the addresses
+ machine_uint_t i2c_addr = vals[1].u_int << 1;
+ machine_uint_t mem_addr = vals[2].u_int;
+
+ HAL_StatusTypeDef status = HAL_I2C_Mem_Write(self->i2c, i2c_addr, mem_addr, I2C_MEMADD_SIZE_8BIT, bufinfo.buf, bufinfo.len, vals[3].u_int);
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
@@ -236,16 +407,22 @@ STATIC mp_obj_t pyb_i2c_mem_write(uint n_args, const mp_obj_t *args) {
return mp_const_none;
}
-
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_i2c_mem_write_obj, 4, 4, pyb_i2c_mem_write);
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_write_obj, 1, pyb_i2c_mem_write);
STATIC const mp_map_elem_t pyb_i2c_locals_dict_table[] = {
+ // instance methods
+ { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_i2c_init_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_i2c_deinit_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_is_ready), (mp_obj_t)&pyb_i2c_is_ready_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)&pyb_i2c_scan_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&pyb_i2c_read_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&pyb_i2c_write_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&pyb_i2c_send_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&pyb_i2c_recv_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_read), (mp_obj_t)&pyb_i2c_mem_read_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_write), (mp_obj_t)&pyb_i2c_mem_write_obj },
+
+ // class constants
+ { MP_OBJ_NEW_QSTR(MP_QSTR_MASTER), MP_OBJ_NEW_SMALL_INT(PYB_I2C_MASTER) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_SLAVE), MP_OBJ_NEW_SMALL_INT(PYB_I2C_SLAVE) },
};
STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table);
@@ -253,6 +430,7 @@ STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table);
const mp_obj_type_t pyb_i2c_type = {
{ &mp_type_type },
.name = MP_QSTR_I2C,
+ .print = pyb_i2c_print,
.make_new = pyb_i2c_make_new,
.locals_dict = (mp_obj_t)&pyb_i2c_locals_dict,
};
diff --git a/stmhal/i2c.h b/stmhal/i2c.h
index 00bb744f0c..d4f08efb75 100644
--- a/stmhal/i2c.h
+++ b/stmhal/i2c.h
@@ -1,3 +1,6 @@
+// use this for OwnAddress1 to configure I2C in master mode
+#define PYB_I2C_MASTER_ADDRESS (0xfe)
+
extern I2C_HandleTypeDef I2CHandle1;
extern I2C_HandleTypeDef I2CHandle2;
extern const mp_obj_type_t pyb_i2c_type;
diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h
index f59f6131bc..b7102b7267 100644
--- a/stmhal/qstrdefsport.h
+++ b/stmhal/qstrdefsport.h
@@ -79,12 +79,17 @@ Q(off)
Q(toggle)
Q(intensity)
-// for USART object
+// for USART class
Q(USART)
-Q(status)
-Q(recv_chr)
-Q(send_chr)
+Q(baudrate)
+Q(bits)
+Q(stop)
+Q(parity)
+Q(init)
+Q(deinit)
+Q(all)
Q(send)
+Q(recv)
// for ExtInt class
Q(ExtInt)
@@ -106,8 +111,19 @@ Q(EVT_RISING_FALLING)
// for I2C object
Q(I2C)
+Q(mode)
+Q(addr)
+Q(baudrate)
+Q(gencall)
+Q(data)
+Q(memaddr)
+Q(timeout)
+Q(init)
+Q(deinit)
Q(is_ready)
Q(scan)
+Q(send)
+Q(recv)
Q(mem_read)
Q(mem_write)
@@ -120,16 +136,18 @@ Q(recv)
Q(send_recv)
Q(mode)
Q(baudrate)
-Q(clkpol)
-Q(clkphase)
+Q(polarity)
+Q(phase)
Q(dir)
-Q(size)
+Q(bits)
Q(nss)
Q(firstbit)
Q(ti)
-Q(crcpoly)
+Q(crc)
Q(MASTER)
Q(SLAVE)
+Q(MSB)
+Q(LSB)
// for Accel object
Q(Accel)
diff --git a/stmhal/spi.c b/stmhal/spi.c
index 9e48bc899e..352c594c9e 100644
--- a/stmhal/spi.c
+++ b/stmhal/spi.c
@@ -11,9 +11,12 @@
#include "runtime.h"
#include "pin.h"
#include "genhdr/pins.h"
+#include "bufhelper.h"
#include "spi.h"
+#if MICROPY_HW_ENABLE_SPI1
SPI_HandleTypeDef SPIHandle1 = {.Instance = NULL};
+#endif
SPI_HandleTypeDef SPIHandle2 = {.Instance = NULL};
#if MICROPY_HW_ENABLE_SPI3
SPI_HandleTypeDef SPIHandle3 = {.Instance = NULL};
@@ -21,8 +24,10 @@ SPI_HandleTypeDef SPIHandle3 = {.Instance = NULL};
void spi_init0(void) {
// reset the SPI handles
+#if MICROPY_HW_ENABLE_SPI1
memset(&SPIHandle1, 0, sizeof(SPI_HandleTypeDef));
SPIHandle1.Instance = SPI1;
+#endif
memset(&SPIHandle2, 0, sizeof(SPI_HandleTypeDef));
SPIHandle2.Instance = SPI2;
#if MICROPY_HW_ENABLE_SPI3
@@ -37,16 +42,21 @@ void spi_init(SPI_HandleTypeDef *spi) {
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
- GPIO_InitStructure.Pull = GPIO_PULLUP; // ST examples use PULLUP
+ GPIO_InitStructure.Pull = spi->Init.CLKPolarity == SPI_POLARITY_LOW ? GPIO_PULLDOWN : GPIO_PULLUP;
const pin_obj_t *pins[4];
- if (spi->Instance == SPI1) {
+ if (0) {
+#if MICROPY_HW_ENABLE_SPI1
+ } else if (spi->Instance == SPI1) {
// X-skin: X5=PA4=SPI1_NSS, X6=PA5=SPI1_SCK, X7=PA6=SPI1_MISO, X8=PA7=SPI1_MOSI
pins[0] = &pin_A4;
pins[1] = &pin_A5;
pins[2] = &pin_A6;
pins[3] = &pin_A7;
GPIO_InitStructure.Alternate = GPIO_AF5_SPI1;
+ // enable the SPI clock
+ __SPI1_CLK_ENABLE();
+#endif
} else if (spi->Instance == SPI2) {
// Y-skin: Y5=PB12=SPI2_NSS, Y6=PB13=SPI2_SCK, Y7=PB14=SPI2_MISO, Y8=PB15=SPI2_MOSI
pins[0] = &pin_B12;
@@ -54,6 +64,8 @@ void spi_init(SPI_HandleTypeDef *spi) {
pins[2] = &pin_B14;
pins[3] = &pin_B15;
GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
+ // enable the SPI clock
+ __SPI2_CLK_ENABLE();
#if MICROPY_HW_ENABLE_SPI3
} else if (spi->Instance == SPI3) {
pins[0] = &pin_A4;
@@ -61,10 +73,11 @@ void spi_init(SPI_HandleTypeDef *spi) {
pins[2] = &pin_B4;
pins[3] = &pin_B5;
GPIO_InitStructure.Alternate = GPIO_AF6_SPI3;
+ // enable the SPI clock
+ __SPI3_CLK_ENABLE();
#endif
} else {
- // SPI does not exist for this board
- printf("HardwareError: invalid SPI\n");
+ // SPI does not exist for this board (shouldn't get here, should be checked by caller)
return;
}
@@ -73,18 +86,7 @@ void spi_init(SPI_HandleTypeDef *spi) {
HAL_GPIO_Init(pins[i]->gpio, &GPIO_InitStructure);
}
- // enable the SPI clock
- if (spi->Instance == SPI1) {
- __SPI1_CLK_ENABLE();
- } else if (spi->Instance == SPI2) {
- __SPI2_CLK_ENABLE();
-#if MICROPY_HW_ENABLE_SPI3
- } else {
- __SPI3_CLK_ENABLE();
-#endif
- }
-
- // init the I2C device
+ // init the SPI device
if (HAL_SPI_Init(spi) != HAL_OK) {
// init error
// TODO should raise an exception, but this function is not necessarily going to be
@@ -96,12 +98,21 @@ void spi_init(SPI_HandleTypeDef *spi) {
void spi_deinit(SPI_HandleTypeDef *spi) {
HAL_SPI_DeInit(spi);
- if (spi->Instance == SPI1) {
+ if (0) {
+#if MICROPY_HW_ENABLE_SPI1
+ } else if (spi->Instance == SPI1) {
+ __SPI1_FORCE_RESET();
+ __SPI1_RELEASE_RESET();
__SPI1_CLK_DISABLE();
+#endif
} else if (spi->Instance == SPI2) {
+ __SPI2_FORCE_RESET();
+ __SPI2_RELEASE_RESET();
__SPI2_CLK_DISABLE();
#if MICROPY_HW_ENABLE_SPI3
- } else {
+ } else if (spi->Instance == SPI3) {
+ __SPI3_FORCE_RESET();
+ __SPI3_RELEASE_RESET();
__SPI3_CLK_DISABLE();
#endif
}
@@ -110,14 +121,25 @@ void spi_deinit(SPI_HandleTypeDef *spi) {
/******************************************************************************/
/* Micro Python bindings */
-#define PYB_SPI_NUM (2)
-
typedef struct _pyb_spi_obj_t {
mp_obj_base_t base;
SPI_HandleTypeDef *spi;
} pyb_spi_obj_t;
-STATIC const pyb_spi_obj_t pyb_spi_obj[PYB_SPI_NUM] = {{{&pyb_spi_type}, &SPIHandle1}, {{&pyb_spi_type}, &SPIHandle2}};
+STATIC const pyb_spi_obj_t pyb_spi_obj[] = {
+#if MICROPY_HW_ENABLE_SPI1
+ {{&pyb_spi_type}, &SPIHandle1},
+#else
+ {{&pyb_spi_type}, NULL},
+#endif
+ {{&pyb_spi_type}, &SPIHandle2},
+#if MICROPY_HW_ENABLE_SPI3
+ {{&pyb_spi_type}, &SPIHandle3},
+#else
+ {{&pyb_spi_type}, NULL},
+#endif
+};
+#define PYB_NUM_SPI (sizeof(pyb_spi_obj) / sizeof(pyb_spi_obj[0]))
STATIC void pyb_spi_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_spi_obj_t *self = self_in;
@@ -141,29 +163,34 @@ STATIC void pyb_spi_print(void (*print)(void *env, const char *fmt, ...), void *
spi_clock = HAL_RCC_GetPCLK1Freq();
}
uint baudrate = spi_clock >> ((self->spi->Init.BaudRatePrescaler >> 3) + 1);
- print(env, "SPI(%u, SPI.MASTER, clock=%u, baudrate=%u)", spi_num, spi_clock, baudrate);
+ print(env, "SPI(%u, SPI.MASTER, baudrate=%u", spi_num, baudrate);
} else {
- print(env, "SPI(%u, SPI.SLAVE)", spi_num);
+ print(env, "SPI(%u, SPI.SLAVE", spi_num);
+ }
+ print(env, ", polarity=%u, phase=%u, bits=%u", self->spi->Init.CLKPolarity == SPI_POLARITY_LOW ? 0 : 1, self->spi->Init.CLKPhase == SPI_PHASE_1EDGE ? 1 : 2, self->spi->Init.DataSize == SPI_DATASIZE_8BIT ? 8 : 16);
+ if (self->spi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLED) {
+ print(env, ", crc=0x%x", self->spi->Init.CRCPolynomial);
}
+ print(env, ")");
}
}
STATIC const mp_arg_parse_t pyb_spi_init_accepted_args[] = {
{ MP_QSTR_mode, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_INT, {.u_int = 0} },
- { MP_QSTR_baudrate, MP_ARG_PARSE_INT, {.u_int = 328125} },
- { MP_QSTR_clkpol, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = SPI_POLARITY_LOW} },
- { MP_QSTR_clkphase, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = SPI_PHASE_1EDGE} },
+ { MP_QSTR_baudrate, MP_ARG_PARSE_INT, {.u_int = 328125} },
+ { MP_QSTR_polarity, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 1} },
+ { MP_QSTR_phase, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 1} },
{ MP_QSTR_dir, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = SPI_DIRECTION_2LINES} },
- { MP_QSTR_size, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 8} },
+ { MP_QSTR_bits, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 8} },
{ MP_QSTR_nss, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = SPI_NSS_SOFT} },
{ MP_QSTR_firstbit, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = SPI_FIRSTBIT_MSB} },
{ MP_QSTR_ti, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_BOOL, {.u_bool = false} },
- { MP_QSTR_crcpoly, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_crc, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_OBJ, {.u_obj = mp_const_none} },
};
#define PYB_SPI_INIT_NUM_ARGS (sizeof(pyb_spi_init_accepted_args) / sizeof(pyb_spi_init_accepted_args[0]))
STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
- // parse keyword args
+ // parse args
mp_arg_parse_val_t vals[PYB_SPI_INIT_NUM_ARGS];
mp_arg_parse_all(n_args, args, kw_args, PYB_SPI_INIT_NUM_ARGS, pyb_spi_init_accepted_args, vals);
@@ -191,8 +218,8 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, uint n_args, cons
else if (br_prescale <= 128) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128; }
else { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; }
- init->CLKPolarity = vals[2].u_int;
- init->CLKPhase = vals[3].u_int;
+ init->CLKPolarity = vals[2].u_int == 0 ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH;
+ init->CLKPhase = vals[3].u_int == 1 ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE;
init->Direction = vals[4].u_int;
init->DataSize = (vals[5].u_int == 16) ? SPI_DATASIZE_16BIT : SPI_DATASIZE_8BIT;
init->NSS = vals[6].u_int;
@@ -220,7 +247,7 @@ STATIC mp_obj_t pyb_spi_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
machine_int_t spi_id = mp_obj_get_int(args[0]) - 1;
// check SPI number
- if (!(0 <= spi_id && spi_id < PYB_SPI_NUM)) {
+ if (!(0 <= spi_id && spi_id < PYB_NUM_SPI && pyb_spi_obj[spi_id].spi != NULL)) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "SPI bus %d does not exist", spi_id + 1));
}
@@ -249,24 +276,28 @@ STATIC mp_obj_t pyb_spi_deinit(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_spi_deinit_obj, pyb_spi_deinit);
-STATIC mp_obj_t pyb_spi_send(mp_obj_t self_in, mp_obj_t data_in) {
+STATIC const mp_arg_parse_t pyb_spi_send_accepted_args[] = {
+ { MP_QSTR_send, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} },
+};
+#define PYB_SPI_SEND_NUM_ARGS (sizeof(pyb_spi_send_accepted_args) / sizeof(pyb_spi_send_accepted_args[0]))
+
+STATIC mp_obj_t pyb_spi_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
// TODO assumes transmission size is 8-bits wide
- // TODO accept timeout as keyword argument
- pyb_spi_obj_t *self = self_in;
+ pyb_spi_obj_t *self = args[0];
- uint8_t data[1];
+ // parse args
+ mp_arg_parse_val_t vals[PYB_SPI_SEND_NUM_ARGS];
+ mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_SPI_SEND_NUM_ARGS, pyb_spi_send_accepted_args, vals);
+
+ // get the buffer to send from
mp_buffer_info_t bufinfo;
- if (MP_OBJ_IS_INT(data_in)) {
- data[0] = mp_obj_get_int(data_in);
- bufinfo.buf = data;
- bufinfo.len = 1;
- bufinfo.typecode = 'B';
- } else {
- mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
- }
+ uint8_t data[1];
+ pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data);
- HAL_StatusTypeDef status = HAL_SPI_Transmit(self->spi, bufinfo.buf, bufinfo.len, 1000);
+ // send the data
+ HAL_StatusTypeDef status = HAL_SPI_Transmit(self->spi, bufinfo.buf, bufinfo.len, vals[1].u_int);
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
@@ -275,57 +306,104 @@ STATIC mp_obj_t pyb_spi_send(mp_obj_t self_in, mp_obj_t data_in) {
return mp_const_none;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_send_obj, pyb_spi_send);
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_send_obj, 1, pyb_spi_send);
+
+STATIC const mp_arg_parse_t pyb_spi_recv_accepted_args[] = {
+ { MP_QSTR_recv, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} },
+};
+#define PYB_SPI_RECV_NUM_ARGS (sizeof(pyb_spi_recv_accepted_args) / sizeof(pyb_spi_recv_accepted_args[0]))
-STATIC mp_obj_t pyb_spi_recv(mp_obj_t self_in, mp_obj_t n_in) {
+STATIC mp_obj_t pyb_spi_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
// TODO assumes transmission size is 8-bits wide
- // TODO accept timeout as keyword argument
- pyb_spi_obj_t *self = self_in;
- machine_uint_t n = mp_obj_get_int(n_in);
+ pyb_spi_obj_t *self = args[0];
+
+ // parse args
+ mp_arg_parse_val_t vals[PYB_SPI_RECV_NUM_ARGS];
+ mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_SPI_RECV_NUM_ARGS, pyb_spi_recv_accepted_args, vals);
+
+ // get the buffer to receive into
+ mp_buffer_info_t bufinfo;
+ mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &bufinfo);
- byte *data;
- mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, n, &data);
- HAL_StatusTypeDef status = HAL_SPI_Receive(self->spi, data, n, 1000);
+ // receive the data
+ HAL_StatusTypeDef status = HAL_SPI_Receive(self->spi, bufinfo.buf, bufinfo.len, vals[1].u_int);
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_SPI_Receive failed with code %d", status));
}
- return mp_obj_str_builder_end(o);
+ // return the received data
+ if (o_ret == MP_OBJ_NULL) {
+ return vals[0].u_obj;
+ } else {
+ return mp_obj_str_builder_end(o_ret);
+ }
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_recv_obj, pyb_spi_recv);
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_recv_obj, 1, pyb_spi_recv);
-STATIC mp_obj_t pyb_spi_send_recv(mp_obj_t self_in, mp_obj_t data_in) {
+STATIC const mp_arg_parse_t pyb_spi_send_recv_accepted_args[] = {
+ { MP_QSTR_send, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_recv, MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} },
+};
+#define PYB_SPI_SEND_RECV_NUM_ARGS (sizeof(pyb_spi_send_recv_accepted_args) / sizeof(pyb_spi_send_recv_accepted_args[0]))
+
+STATIC mp_obj_t pyb_spi_send_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
// TODO assumes transmission size is 8-bits wide
- // TODO accept timeout as keyword argument
- pyb_spi_obj_t *self = self_in;
+ pyb_spi_obj_t *self = args[0];
+ // parse args
+ mp_arg_parse_val_t vals[PYB_SPI_SEND_RECV_NUM_ARGS];
+ mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_SPI_SEND_RECV_NUM_ARGS, pyb_spi_send_recv_accepted_args, vals);
+
+ // get buffers to send from/receive to
+ mp_buffer_info_t bufinfo_send;
uint8_t data_send[1];
- mp_buffer_info_t bufinfo;
- if (MP_OBJ_IS_INT(data_in)) {
- data_send[0] = mp_obj_get_int(data_in);
- bufinfo.buf = data_send;
- bufinfo.len = 1;
- bufinfo.typecode = 'B';
+ mp_buffer_info_t bufinfo_recv;
+ mp_obj_t o_ret;
+
+ if (vals[0].u_obj == vals[1].u_obj) {
+ // same object for send and receive, it must be a r/w buffer
+ mp_get_buffer_raise(vals[0].u_obj, &bufinfo_send, MP_BUFFER_RW);
+ bufinfo_recv = bufinfo_send;
+ o_ret = MP_OBJ_NULL;
} else {
- mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
+ // get the buffer to send from
+ pyb_buf_get_for_send(vals[0].u_obj, &bufinfo_send, data_send);
+
+ // get the buffer to receive into
+ if (vals[1].u_obj == MP_OBJ_NULL) {
+ // only send argument given, so create a fresh buffer of the send length
+ bufinfo_recv.len = bufinfo_send.len;
+ bufinfo_recv.typecode = 'B';
+ o_ret = mp_obj_str_builder_start(&mp_type_bytes, bufinfo_recv.len, (byte**)&bufinfo_recv.buf);
+ } else {
+ // recv argument given
+ mp_get_buffer_raise(vals[1].u_obj, &bufinfo_recv, MP_BUFFER_WRITE);
+ o_ret = MP_OBJ_NULL;
+ }
}
- byte *data_recv;
- mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, bufinfo.len, &data_recv);
- HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(self->spi, bufinfo.buf, data_recv, bufinfo.len, 1000);
+ // send and receive the data
+ HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(self->spi, bufinfo_send.buf, bufinfo_recv.buf, bufinfo_send.len, vals[2].u_int);
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_SPI_TransmitReceive failed with code %d", status));
}
- return mp_obj_str_builder_end(o);
+ // return the received data
+ if (o_ret == MP_OBJ_NULL) {
+ return vals[1].u_obj;
+ } else {
+ return mp_obj_str_builder_end(o_ret);
+ }
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_send_recv_obj, pyb_spi_send_recv);
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_send_recv_obj, 1, pyb_spi_send_recv);
STATIC const mp_map_elem_t pyb_spi_locals_dict_table[] = {
// instance methods
@@ -336,21 +414,17 @@ STATIC const mp_map_elem_t pyb_spi_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_send_recv), (mp_obj_t)&pyb_spi_send_recv_obj },
// class constants
- { MP_OBJ_NEW_QSTR(MP_QSTR_MASTER), MP_OBJ_NEW_SMALL_INT(SPI_MODE_MASTER) },
- { MP_OBJ_NEW_QSTR(MP_QSTR_SLAVE), MP_OBJ_NEW_SMALL_INT(SPI_MODE_SLAVE) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_MASTER), MP_OBJ_NEW_SMALL_INT(SPI_MODE_MASTER) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_SLAVE), MP_OBJ_NEW_SMALL_INT(SPI_MODE_SLAVE) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_MSB), MP_OBJ_NEW_SMALL_INT(SPI_FIRSTBIT_MSB) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_LSB), MP_OBJ_NEW_SMALL_INT(SPI_FIRSTBIT_LSB) },
/* TODO
{ MP_OBJ_NEW_QSTR(MP_QSTR_DIRECTION_2LINES ((uint32_t)0x00000000)
{ MP_OBJ_NEW_QSTR(MP_QSTR_DIRECTION_2LINES_RXONLY SPI_CR1_RXONLY
{ MP_OBJ_NEW_QSTR(MP_QSTR_DIRECTION_1LINE SPI_CR1_BIDIMODE
- { MP_OBJ_NEW_QSTR(MP_QSTR_POLARITY_LOW ((uint32_t)0x00000000)
- { MP_OBJ_NEW_QSTR(MP_QSTR_POLARITY_HIGH SPI_CR1_CPOL
- { MP_OBJ_NEW_QSTR(MP_QSTR_PHASE_1EDGE ((uint32_t)0x00000000)
- { MP_OBJ_NEW_QSTR(MP_QSTR_PHASE_2EDGE SPI_CR1_CPHA
{ MP_OBJ_NEW_QSTR(MP_QSTR_NSS_SOFT SPI_CR1_SSM
{ MP_OBJ_NEW_QSTR(MP_QSTR_NSS_HARD_INPUT ((uint32_t)0x00000000)
{ MP_OBJ_NEW_QSTR(MP_QSTR_NSS_HARD_OUTPUT ((uint32_t)0x00040000)
- { MP_OBJ_NEW_QSTR(MP_QSTR_FIRSTBIT_MSB ((uint32_t)0x00000000)
- { MP_OBJ_NEW_QSTR(MP_QSTR_FIRSTBIT_LSB SPI_CR1_LSBFIRST
*/
};
diff --git a/stmhal/usart.c b/stmhal/usart.c
index 89770942be..c737955ac2 100644
--- a/stmhal/usart.c
+++ b/stmhal/usart.c
@@ -8,23 +8,26 @@
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
+#include "runtime.h"
+#include "bufhelper.h"
#include "usart.h"
struct _pyb_usart_obj_t {
mp_obj_base_t base;
pyb_usart_t usart_id;
bool is_enabled;
- UART_HandleTypeDef handle;
+ UART_HandleTypeDef uart;
};
pyb_usart_obj_t *pyb_usart_global_debug = NULL;
-bool usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) {
- USART_TypeDef *USARTx=NULL;
+// assumes Init parameters have been set up correctly
+bool usart_init2(pyb_usart_obj_t *usart_obj) {
+ USART_TypeDef *USARTx = NULL;
- uint32_t GPIO_Pin=0;
- uint8_t GPIO_AF_USARTx=0;
- GPIO_TypeDef* GPIO_Port=NULL;
+ uint32_t GPIO_Pin = 0;
+ uint8_t GPIO_AF_USARTx = 0;
+ GPIO_TypeDef* GPIO_Port = NULL;
switch (usart_obj->usart_id) {
// USART1 is on PA9/PA10, PB6/PB7
@@ -71,7 +74,7 @@ bool usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) {
__USART3_CLK_ENABLE();
break;
- // USART4 is on PA0/PA1, PC10/PC11
+ // UART4 is on PA0/PA1, PC10/PC11
case PYB_USART_4:
USARTx = UART4;
GPIO_AF_USARTx = GPIO_AF8_UART4;
@@ -97,8 +100,7 @@ bool usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) {
return false;
}
- // Initialize USARTx
-
+ // init GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_Pin;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
@@ -107,28 +109,62 @@ bool usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) {
GPIO_InitStructure.Alternate = GPIO_AF_USARTx;
HAL_GPIO_Init(GPIO_Port, &GPIO_InitStructure);
- UART_HandleTypeDef *uh = &usart_obj->handle;
+ // init USARTx
+ usart_obj->uart.Instance = USARTx;
+ HAL_UART_Init(&usart_obj->uart);
+
+ usart_obj->is_enabled = true;
+
+ return true;
+}
+
+bool usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) {
+ UART_HandleTypeDef *uh = &usart_obj->uart;
memset(uh, 0, sizeof(*uh));
- uh->Instance = USARTx;
uh->Init.BaudRate = baudrate;
- uh->Init.WordLength = USART_WORDLENGTH_8B;
- uh->Init.StopBits = USART_STOPBITS_1;
- uh->Init.Parity = USART_PARITY_NONE;
- uh->Init.Mode = USART_MODE_TX_RX;
+ uh->Init.WordLength = UART_WORDLENGTH_8B;
+ uh->Init.StopBits = UART_STOPBITS_1;
+ uh->Init.Parity = UART_PARITY_NONE;
+ uh->Init.Mode = UART_MODE_TX_RX;
uh->Init.HwFlowCtl = UART_HWCONTROL_NONE;
uh->Init.OverSampling = UART_OVERSAMPLING_16;
- HAL_UART_Init(uh);
+ return usart_init2(usart_obj);
+}
- return true;
+void usart_deinit(pyb_usart_obj_t *usart_obj) {
+ usart_obj->is_enabled = false;
+ UART_HandleTypeDef *uart = &usart_obj->uart;
+ HAL_UART_DeInit(uart);
+ if (uart->Instance == USART1) {
+ __USART1_FORCE_RESET();
+ __USART1_RELEASE_RESET();
+ __USART1_CLK_DISABLE();
+ } else if (uart->Instance == USART2) {
+ __USART2_FORCE_RESET();
+ __USART2_RELEASE_RESET();
+ __USART2_CLK_DISABLE();
+ } else if (uart->Instance == USART3) {
+ __USART3_FORCE_RESET();
+ __USART3_RELEASE_RESET();
+ __USART3_CLK_DISABLE();
+ } else if (uart->Instance == UART4) {
+ __UART4_FORCE_RESET();
+ __UART4_RELEASE_RESET();
+ __UART4_CLK_DISABLE();
+ } else if (uart->Instance == USART6) {
+ __USART6_FORCE_RESET();
+ __USART6_RELEASE_RESET();
+ __USART6_CLK_DISABLE();
+ }
}
bool usart_rx_any(pyb_usart_obj_t *usart_obj) {
- return __HAL_UART_GET_FLAG(&usart_obj->handle, USART_FLAG_RXNE);
+ return __HAL_UART_GET_FLAG(&usart_obj->uart, UART_FLAG_RXNE);
}
int usart_rx_char(pyb_usart_obj_t *usart_obj) {
uint8_t ch;
- if (HAL_UART_Receive(&usart_obj->handle, &ch, 1, 0) != HAL_OK) {
+ if (HAL_UART_Receive(&usart_obj->uart, &ch, 1, 0) != HAL_OK) {
ch = 0;
}
return ch;
@@ -136,19 +172,15 @@ int usart_rx_char(pyb_usart_obj_t *usart_obj) {
void usart_tx_char(pyb_usart_obj_t *usart_obj, int c) {
uint8_t ch = c;
- HAL_UART_Transmit(&usart_obj->handle, &ch, 1, 100000);
+ HAL_UART_Transmit(&usart_obj->uart, &ch, 1, 100000);
}
void usart_tx_str(pyb_usart_obj_t *usart_obj, const char *str) {
- for (; *str; str++) {
- usart_tx_char(usart_obj, *str);
- }
+ HAL_UART_Transmit(&usart_obj->uart, (uint8_t*)str, strlen(str), 100000);
}
void usart_tx_strn(pyb_usart_obj_t *usart_obj, const char *str, uint len) {
- for (; len > 0; str++, len--) {
- usart_tx_char(usart_obj, *str);
- }
+ HAL_UART_Transmit(&usart_obj->uart, (uint8_t*)str, len, 100000);
}
void usart_tx_strn_cooked(pyb_usart_obj_t *usart_obj, const char *str, uint len) {
@@ -163,17 +195,67 @@ void usart_tx_strn_cooked(pyb_usart_obj_t *usart_obj, const char *str, uint len)
/******************************************************************************/
/* Micro Python bindings */
-STATIC void usart_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+STATIC void pyb_usart_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);
+ if (!self->is_enabled) {
+ print(env, "USART(%lu)", self->usart_id);
+ } else {
+ print(env, "USART(%lu, baudrate=%u, bits=%u, stop=%u",
+ self->usart_id, self->uart.Init.BaudRate,
+ self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9,
+ self->uart.Init.StopBits == UART_STOPBITS_1 ? 1 : 2);
+ if (self->uart.Init.Parity == UART_PARITY_NONE) {
+ print(env, ", parity=None)");
+ } else {
+ print(env, ", parity=%u)", self->uart.Init.Parity == UART_PARITY_EVEN ? 0 : 1);
+ }
+ }
}
-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_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "USART accepts 2 arguments"));
+STATIC const mp_arg_parse_t pyb_usart_init_accepted_args[] = {
+ { MP_QSTR_baudrate, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_INT, {.u_int = 9600} },
+ { MP_QSTR_bits, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 8} },
+ { MP_QSTR_stop, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 1} },
+ { MP_QSTR_parity, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_OBJ, {.u_obj = mp_const_none} },
+};
+#define PYB_USART_INIT_NUM_ARGS (sizeof(pyb_usart_init_accepted_args) / sizeof(pyb_usart_init_accepted_args[0]))
+
+STATIC mp_obj_t pyb_usart_init_helper(pyb_usart_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ // parse args
+ mp_arg_parse_val_t vals[PYB_USART_INIT_NUM_ARGS];
+ mp_arg_parse_all(n_args, args, kw_args, PYB_USART_INIT_NUM_ARGS, pyb_usart_init_accepted_args, vals);
+
+ // set the USART configuration values
+ memset(&self->uart, 0, sizeof(self->uart));
+ UART_InitTypeDef *init = &self->uart.Init;
+ init->BaudRate = vals[0].u_int;
+ init->WordLength = vals[1].u_int == 8 ? UART_WORDLENGTH_8B : UART_WORDLENGTH_9B;
+ switch (vals[2].u_int) {
+ case 1: init->StopBits = UART_STOPBITS_1; break;
+ default: init->StopBits = UART_STOPBITS_2; break;
+ }
+ if (vals[3].u_obj == mp_const_none) {
+ init->Parity = UART_PARITY_NONE;
+ } else {
+ machine_int_t parity = mp_obj_get_int(vals[3].u_obj);
+ init->Parity = (parity & 1) ? UART_PARITY_ODD : UART_PARITY_EVEN;
+ }
+ init->Mode = UART_MODE_TX_RX;
+ init->HwFlowCtl = UART_HWCONTROL_NONE;
+ init->OverSampling = UART_OVERSAMPLING_16;
+
+ // init USART (if it fails, it's because the port doesn't exist)
+ if (!usart_init2(self)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "USART port %d does not exist", self->usart_id));
}
+ return mp_const_none;
+}
+
+STATIC mp_obj_t pyb_usart_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
+ // check arguments
+ mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
+
// create object
pyb_usart_obj_t *o = m_new_obj(pyb_usart_obj_t);
o->base.type = &pyb_usart_type;
@@ -200,17 +282,29 @@ STATIC mp_obj_t usart_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, con
o->usart_id = mp_obj_get_int(args[0]);
}
- // init USART (if it fails, it's because the port doesn't exist)
- if (!usart_init(o, mp_obj_get_int(args[1]))) {
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "USART port %d does not exist", o->usart_id));
+ if (n_args > 1 || n_kw > 0) {
+ // start the peripheral
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+ pyb_usart_init_helper(o, n_args - 1, args + 1, &kw_args);
}
- o->is_enabled = true;
-
return o;
}
-STATIC mp_obj_t usart_obj_status(mp_obj_t self_in) {
+STATIC mp_obj_t pyb_usart_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ return pyb_usart_init_helper(args[0], n_args - 1, args + 1, kw_args);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usart_init_obj, 1, pyb_usart_init);
+
+STATIC mp_obj_t pyb_usart_deinit(mp_obj_t self_in) {
+ pyb_usart_obj_t *self = self_in;
+ usart_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_usart_deinit_obj, pyb_usart_deinit);
+
+STATIC mp_obj_t pyb_usart_any(mp_obj_t self_in) {
pyb_usart_obj_t *self = self_in;
if (usart_rx_any(self)) {
return mp_const_true;
@@ -218,57 +312,91 @@ STATIC mp_obj_t usart_obj_status(mp_obj_t self_in) {
return mp_const_false;
}
}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_usart_any_obj, pyb_usart_any);
-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;
+STATIC const mp_arg_parse_t pyb_usart_send_accepted_args[] = {
+ { MP_QSTR_send, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} },
+};
+#define PYB_USART_SEND_NUM_ARGS (sizeof(pyb_usart_send_accepted_args) / sizeof(pyb_usart_send_accepted_args[0]))
- if (self->is_enabled) {
- ret = mp_obj_new_int(usart_rx_char(self));
- }
- return ret;
-}
+STATIC mp_obj_t pyb_usart_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ // TODO assumes transmission size is 8-bits wide
-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);
- if (len == 1 && self->is_enabled) {
- usart_tx_char(self, str[0]);
- }
- return mp_const_none;
-}
+ pyb_usart_obj_t *self = args[0];
-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)) {
- uint len;
- const char *data = mp_obj_str_get_data(s, &len);
- usart_tx_strn(self, data, len);
- }
+ // parse args
+ mp_arg_parse_val_t vals[PYB_USART_SEND_NUM_ARGS];
+ mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_USART_SEND_NUM_ARGS, pyb_usart_send_accepted_args, vals);
+
+ // get the buffer to send from
+ mp_buffer_info_t bufinfo;
+ uint8_t data[1];
+ pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data);
+
+ // send the data
+ HAL_StatusTypeDef status = HAL_UART_Transmit(&self->uart, bufinfo.buf, bufinfo.len, vals[1].u_int);
+
+ if (status != HAL_OK) {
+ // TODO really need a HardwareError object, or something
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_UART_Transmit failed with code %d", status));
}
+
return mp_const_none;
}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usart_send_obj, 1, pyb_usart_send);
+
+STATIC const mp_arg_parse_t pyb_usart_recv_accepted_args[] = {
+ { MP_QSTR_recv, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} },
+};
+#define PYB_USART_RECV_NUM_ARGS (sizeof(pyb_usart_recv_accepted_args) / sizeof(pyb_usart_recv_accepted_args[0]))
+
+STATIC mp_obj_t pyb_usart_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ // TODO assumes transmission size is 8-bits wide
-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);
+ pyb_usart_obj_t *self = args[0];
-STATIC const mp_map_elem_t usart_locals_dict_table[] = {
- { MP_OBJ_NEW_QSTR(MP_QSTR_status), (mp_obj_t)&usart_obj_status_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_recv_chr), (mp_obj_t)&usart_obj_rx_char_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_send_chr), (mp_obj_t)&usart_obj_tx_char_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&usart_obj_tx_str_obj },
+ // parse args
+ mp_arg_parse_val_t vals[PYB_USART_RECV_NUM_ARGS];
+ mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_USART_RECV_NUM_ARGS, pyb_usart_recv_accepted_args, vals);
+
+ // get the buffer to receive into
+ mp_buffer_info_t bufinfo;
+ mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &bufinfo);
+
+ // receive the data
+ HAL_StatusTypeDef status = HAL_UART_Receive(&self->uart, bufinfo.buf, bufinfo.len, vals[1].u_int);
+
+ if (status != HAL_OK) {
+ // TODO really need a HardwareError object, or something
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_UART_Receive failed with code %d", status));
+ }
+
+ // return the received data
+ if (o_ret == MP_OBJ_NULL) {
+ return vals[0].u_obj;
+ } else {
+ return mp_obj_str_builder_end(o_ret);
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usart_recv_obj, 1, pyb_usart_recv);
+
+STATIC const mp_map_elem_t pyb_usart_locals_dict_table[] = {
+ // instance methods
+ { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_usart_init_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_usart_deinit_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&pyb_usart_any_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&pyb_usart_send_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&pyb_usart_recv_obj },
};
-STATIC MP_DEFINE_CONST_DICT(usart_locals_dict, usart_locals_dict_table);
+STATIC MP_DEFINE_CONST_DICT(pyb_usart_locals_dict, pyb_usart_locals_dict_table);
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,
- .locals_dict = (mp_obj_t)&usart_locals_dict,
+ .print = pyb_usart_print,
+ .make_new = pyb_usart_make_new,
+ .locals_dict = (mp_obj_t)&pyb_usart_locals_dict,
};
diff --git a/unix/file.c b/unix/file.c
index a0a865a263..5bda34013f 100644
--- a/unix/file.c
+++ b/unix/file.c
@@ -1,3 +1,4 @@
+#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
diff --git a/unix/main.c b/unix/main.c
index 940fe48c14..4c86edeae5 100644
--- a/unix/main.c
+++ b/unix/main.c
@@ -250,7 +250,9 @@ int usage(char **argv) {
mp_obj_t mem_info(void) {
printf("mem: total=%d, current=%d, peak=%d\n", m_get_total_bytes_allocated(), m_get_current_bytes_allocated(), m_get_peak_bytes_allocated());
+#if MICROPY_ENABLE_GC
gc_dump_info();
+#endif
return mp_const_none;
}
@@ -392,7 +394,11 @@ int main(int argc, char **argv) {
return usage(argv);
}
} else {
+#ifdef __MINGW32__
+ char *basedir = _fullpath(NULL, argv[a], _MAX_PATH);
+#else
char *basedir = realpath(argv[a], NULL);
+#endif
if (basedir == NULL) {
fprintf(stderr, "%s: can't open file '%s': [Errno %d] ", argv[0], argv[1], errno);
perror("");
diff --git a/unix/modsocket.c b/unix/modsocket.c
index bfa5849c86..6a2ada91f1 100644
--- a/unix/modsocket.c
+++ b/unix/modsocket.c
@@ -2,6 +2,7 @@
#include <assert.h>
#include <string.h>
#include <unistd.h>
+#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
@@ -179,6 +180,22 @@ STATIC mp_obj_t socket_setsockopt(uint n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt);
+STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
+ mp_obj_socket_t *self = self_in;
+ int val = mp_obj_is_true(flag_in);
+ int flags = fcntl(self->fd, F_GETFL, 0);
+ RAISE_ERRNO(flags, errno);
+ if (val) {
+ flags &= ~O_NONBLOCK;
+ } else {
+ flags |= O_NONBLOCK;
+ }
+ flags = fcntl(self->fd, F_SETFL, flags);
+ RAISE_ERRNO(flags, errno);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
+
STATIC mp_obj_t socket_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
int family = AF_INET;
int type = SOCK_STREAM;
@@ -216,6 +233,7 @@ STATIC const mp_map_elem_t microsocket_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&socket_recv_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&socket_send_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&socket_setsockopt_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&socket_setblocking_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj },
#if MICROPY_SOCKET_EXTRA
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&mp_stream_read_obj },
diff --git a/unix/qstrdefsport.h b/unix/qstrdefsport.h
index 2e7a6aa1e1..f7990322ea 100644
--- a/unix/qstrdefsport.h
+++ b/unix/qstrdefsport.h
@@ -38,6 +38,7 @@ Q(listen)
Q(accept)
Q(recv)
Q(setsockopt)
+Q(setblocking)
Q(AF_UNIX)
Q(AF_INET)
diff --git a/windows/Makefile b/windows/Makefile
index 651de7c7f1..2f5418886f 100644
--- a/windows/Makefile
+++ b/windows/Makefile
@@ -1,4 +1,5 @@
include ../py/mkenv.mk
+-include mpconfigport.mk
# define main target
PROG = micropython.exe
@@ -14,14 +15,15 @@ INC += -I$(PY_SRC)
INC += -I$(BUILD)
# compiler settings
-CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -DUNIX
-LDFLAGS = -lm
+CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT)
+LDFLAGS = $(LDFLAGS_MOD) -lm
# Debugging/Optimization
ifdef DEBUG
-CFLAGS += -O0 -g
+CFLAGS += -g
+COPT = -O0
else
-CFLAGS += -Os #-DNDEBUG
+COPT = -Os #-DNDEBUG
endif
# source files
@@ -30,11 +32,16 @@ SRC_C = \
unix/file.c \
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
-LIB = -lreadline
-LIB += -lws2_32
-LIB += -lmman
+
+ifeq ($(MICROPY_USE_READLINE),1)
+CFLAGS_MOD += -DMICROPY_USE_READLINE=1
+LDFLAGS_MOD += -lreadline
# the following is needed for BSD
-#LIB += -ltermcap
+#LDFLAGS_MOD += -ltermcap
+endif
+
+LIB += -lws2_32
+#LIB += -lmman
include ../py/mkrules.mk
diff --git a/windows/README b/windows/README
new file mode 100644
index 0000000000..615ada2012
--- /dev/null
+++ b/windows/README
@@ -0,0 +1,10 @@
+This is experimental, community-supported Windows port of MicroPython.
+It is based on Unix port, and expected to remain so.
+
+To cross-compile under Debian/Ubuntu Linux system:
+
+sudo apt-get install mingw32 mingw32-binutils mingw32-runtime
+make CC=i586-mingw32msvc-gcc
+
+The port requires additional testing, debugging, and patches. Please
+consider to contribute.
diff --git a/windows/mpconfigport.h b/windows/mpconfigport.h
index 74fe749e1e..993fef9d59 100644
--- a/windows/mpconfigport.h
+++ b/windows/mpconfigport.h
@@ -2,10 +2,10 @@
// Linking with GNU readline causes binary to be licensed under GPL
#ifndef MICROPY_USE_READLINE
-#define MICROPY_USE_READLINE (1)
+#define MICROPY_USE_READLINE (0)
#endif
-#define MICROPY_EMIT_X64 (1)
+#define MICROPY_EMIT_X64 (0)
#define MICROPY_EMIT_THUMB (0)
#define MICROPY_EMIT_INLINE_THUMB (0)
#define MICROPY_MEM_STATS (1)
diff --git a/windows/mpconfigport.mk b/windows/mpconfigport.mk
new file mode 100644
index 0000000000..458f23dd1e
--- /dev/null
+++ b/windows/mpconfigport.mk
@@ -0,0 +1,13 @@
+# Enable/disable modules and 3rd-party libs to be included in interpreter
+
+# Build 32-bit binaries on a 64-bit host
+MICROPY_FORCE_32BIT = 0
+
+# Linking with GNU readline causes binary to be licensed under GPL
+MICROPY_USE_READLINE = 0
+
+# Subset of CPython time module
+MICROPY_MOD_TIME = 1
+
+# ffi module requires libffi (libffi-dev Debian package)
+MICROPY_MOD_FFI = 0